按键精灵编写的脚本简单方便,最直接的体验是可以代替我们处理简单重复的鼠标键盘操作。
《QQ自由幻想》这款游戏系统内置自动挂机功能,但是每隔1个小时就会自动弹出验证码校验,校验不通过就会被踢下线,然后只能通过①先花钱开通VIP-》②再花钱购买2/4/8小时免校验卡(道具)跳过校验,不氪金体验极差。
对于这款已经很老的游戏,情怀党表示还是要尝试实现自动过验证码,增加游戏体验
按键论坛可以搜到大漠插件建立字库识别验证码的教程:『笨海绵』用大漠插件实现QQ自由幻想验证码后台识别方法详解
这种方法主要原理是收集图片像素点数据建立字库并进行对比识别出验证码字符,缺点是建立字库繁杂,识别率也是个问题。
接下来说下处理过程,首先截取左边难处理的验证码区域,上传图片到打码平台(若快),然后截取右边列4个较为规则的答案选项上传到百度文字识别,最终对比返回结果得出第几个是正确答案就可以通过验证了,思路非常简单。
主要涉及下面几点:
- 大漠插件的使用
- 人工打码平台的对接(若快打码平台)
- 百度文字识别api的使用
首先是大漠插件的使用
- 首先下载大漠插件V3.1233(最后免费版本),然后根据里边提供的
大漠接口说明.CHM
注册大漠插件
为什么要使用大漠插件?
优点:大漠插件建立字库找字的功能比较方便。
按键精灵自带命令也可以满足大部分的使用要求,大漠插件可以补充按键不足部分,混合使用。
大漠插件通过dm.BindWindow
命令可以轻松切换前后台模式,而不需要修改脚本中的大量命令
测试过程中经常发现按键的后台截图方法截图失败时会导致按键程序直接崩溃,使用大漠插件就没有出现这种情况
缺点:注册多一个大漠插件意味着有更高的安全风险,360之类的就可能会报错。
- 然后在脚本中创建大漠对象就可以直接使用了(具体方法/参数说明可以查看大漠接口文档)
//首先获取当前游戏句柄(这里通过游戏类名获取,也可以直接鼠标获取Plugin.Window.MousePoint)
Hwnd = Plugin.Window.Find("QQSwordWinClass", 0)
//创建大漠插件对象
set dm = createobject("dm.dmsoft")
//后台模式
dm_ret = dm.BindWindow(Hwnd,"dx2","windows","windows", 0)
//前台模式
//dm_ret = dm.BindWindowEx(Hwnd, "dx2", "normal", "normal", "", 0)
//大漠插件绑定句柄后就可以直接调用方法了,例如鼠标的移动点击
//dm.MoveTo X,Y
//dm.LeftClick
//屏幕截图保存到本地:先设置大漠插件统一保存的文件目录,再截图保存
//设置文件保存路径
//dm_ret = dm.SetPath("D:\temp\ZYHXCaptcha")
//验证码截图,在上面的目录可以找到截图
//dm_ret = dm.CaptureJpg(x1, y1, x2, y2, "captcha.jpg", 100)
- 验证码区域的截图(具体方法/参数说明可以查看大漠接口文档)
- 首先找到验证码区域的坐标,因为验证码是屏幕内随机区域出现的,这需要用到找字功能:目标是找到验证码左上角
神医
两个字。找字功能就需要我们先建字库:
①打开大漠综合工具,点击抓图截取需要的“神医”两个字
②然后调用dm.FindStr
就可以找到当前程序神医
两个字的坐标了
//注意要先设置使用的大漠字库
dm_ret = dm.SetDict(0, "C:\test_game\zyhx.txt")
//然后找字成功就会返回intX、intY坐标
dm_ret = dm.FindStr(0, 0, 2000, 2000, "神医", "ff0000-000000", 0.9, intX, intY)
If dm_ret = 0 And intX >0 And intY >0 Then
TracePrint "神医坐标=" & intX & ":" & intY
End If
- 对验证码区域进行截图
①截图需要确定截图范围即:左上角坐标(找字得到“神医”坐标),右下角坐标(按键自带抓抓工具简单计算出)
然后就可以调用dm.CaptureJpg
方法对左边验证码和右边答案选项列表进行截图了
//注意要先设置文件保存路径
//dm_ret = dm.SetPath("D:\temp\ZYHXCaptcha")
//验证码截图
dm_ret = dm.CaptureJpg(intX, intY + 60, intX + 160, intY + 170, "captcha.jpg", 100)
Delay 50
//答案选项截图
dm_ret = dm.CaptureJpg(intX+195, intY + 36, intX + 233, intY + 114, "answer.jpg", 65)
使用打码平台实现复杂验证码的处理
左边区域的复杂验证码使用打码平台进行处理,这里使用若快打码平台:http://wiki.ruokuai.com/ApiDemo_Spirit.ashx
可以直接调用示例中提供的方法实现上传并拿到返回值:
xml文本 = Lib.RK_API.上传本地验证码图片(用户名, 密码, 验证码类型, 超时时间, 软件id, 软件key, 图片路径)
TracePrint "若快识别结果:" & xml文本
response_captcha= Lib.RK_API.Xml解析(xml文本,""," ")
这里参数的用户名, 密码需要我们到若快官网注册一个
普通用户
并进行充值,可以先充1块得到2500快豆进行测试,这里验证码类型是3位英数混合3030
,验证一次需要消耗10快豆,而软件id和软件key则需要再注册一个开发者账号
,添加软件并审核通过后就可以拿到软件Id和软件Key了(具体查看若快官方接入文档)
调用百度OCR处理简单/规则的文字或数字
- 百度文字识别文档中有两种调用方式,第一种是先获取Token然后直接进行调用,请求参数为
image=图像数据(base64编码后进行urlencode)
这里我使用第二种带authorization
请求头的鉴权方式(推荐使用Token的方式一,简单方便)
- 先下载文档中的鉴权认证示例
我选择了下载了Java的示例:git clone https://github.com/baidubce/bce-sdk-java.git
- 然后在IDEA中打开,找到
BceV1Signer.java
,执行sign
方法就可以生成authorization
- 注意这里AK/SK需要登录百度云->用户账号->安全认证->获取Access Key/Secret Key,参考文档
-
headersTosign
是请求头中需要参与加密的项,这里为了简单只加密了必须的host
public static void main(String[] args) throws Exception {
BceV1Signer bs = new BceV1Signer();
InternalRequest request = new InternalRequest(HttpMethodName.POST,new URI("https://aip.baidubce.com/rest/2.0/ocr/v1/accurate_basic"));
//SimpleDateFormat sdf = new SimpleDateFormat("yyyy-mm-dd'T'hh:mm:ssZ");
//request.addHeader("x-bce-date",sdf.format(new Date()));
//request.addHeader("content-type","multipart/form-data");
//ak/sk
BceCredentials bceCredentials = new DefaultBceCredentials("your_AccessKey","your_SecretKey ");
SignOptions signOptions = new SignOptions();
signOptions.setExpirationInSeconds(3600*24*365);//有效期一年
Set headersTosign = new HashSet();
headersTosign.add("HOST");//对请求头中的host进行加密处理
//headersTosign.add("x-bce-date");
//headersTosign.add("content-type");
signOptions.setHeadersToSign(headersTosign);
bs.sign(request,bceCredentials,signOptions);
}
- 按键精灵中读取图片文件base64
按键中可以使用vbs,还保留VBSBegin...VBSEnd直接调用vbs代码的方式,参考vbscript将图片转换为base64字符串
'vbscript将图片2进制信息转为base64字符,参数FilePath为图片文件物理路径
'@return:ImagesToBase64返回图片base64格式字符串,前缀为data:image/图片类型;base64,base64数据
Function ImagesToBase64(FilePath)
Dim xml
Dim root
Dim fs
Dim objStream
Dim objXMLDoc
Dim Base64
Set objXMLDoc=CreateObject("msxml2.FreeThreadedDOMDocument")
objXMLDoc.loadXML ""
Set fs = createObject("Scripting.FileSystemObject") ''FSO组件
If fs.FileExists(FilePath) Then '判断File文件是否存在
'用 stream 来读取数据
Set objStream = CreateObject("ADODB.Stream")
objStream.Type = 1
objStream.Open
objStream.LoadFromFile FilePath
objXMLDoc.documentElement.dataType = "bin.base64"
objXMLDoc.documentElement.nodeTypedvalue = objStream.Read
'数据流读取结束.得到了值 objXMLDoc
'创建XML文件
Set xml = CreateObject("msxml2.FreeThreadedDOMDocument")
xml.load objXMLDoc
If xml.ReadyState>2 Then
Set root=xml.getElementsByTagName("data")
Base64 = root.Item(0).Text
Base64 = Replace(Base64,vbLf,"")
TracePrint "Base64=" & Base64
else
Base64=""
End If
Set xml=Nothing
Set objStream=Nothing
else
Base64=""
End If
Set fs=Nothing
Set objXMLDoc=Nothing
ImagesToBase64 = Base64
End Function
测试过程中发现base64后的字符串中间包含了多余的换行符需要去除
Replace(Base64,vbLf,"")
- 图像数据,base64编码后进行urlencode
Function URLEncode(strURL)
Dim I
Dim tempStr
For I = 1 To Len(strURL)
If Asc(Mid(strURL, I, 1)) < 0 Then
tempStr = "%" & Right(CStr(Hex(Asc(Mid(strURL, I, 1)))), 2)
tempStr = "%" & Left(CStr(Hex(Asc(Mid(strURL, I, 1)))), Len(CStr(Hex(Asc(Mid(strURL, I, 1))))) - 2) & tempStr
URLEncode = URLEncode & tempStr
ElseIf (Asc(Mid(strURL, I, 1)) >= 65 And Asc(Mid(strURL, I, 1)) <= 90) Or (Asc(Mid(strURL, I, 1)) >= 97 And Asc(Mid(strURL, I, 1)) <= 122) Or (Asc(Mid(strURL, I, 1)) >= 48 And Asc(Mid(strURL, I, 1)) <= 57) Then
URLEncode = URLEncode & Mid(strURL, I, 1)
Else
URLEncode = URLEncode & "%" & Hex(Asc(Mid(strURL, I, 1)))
End If
Next
End Function
图片质量高的时候base64长度变长,上面的这个方法执行速度会很慢。
- 调用百度文字识别api上传图片到百度云
这里使用鉴权方式二,填入请求头中的Authorization
参数,以及x-bce-date
时间在生成的Authorization
中可以找到,access_token
的调用方式一则不需要设置请求头。
Function postBaiduOCR(Url)
Set xmlHttp=CreateObject("Microsoft.XMLHTTP")
xmlHttp.Open "POST", Url, False
xmlHttp.setRequestHeader "Host", "aip.baidubce.com"
xmlHttp.setRequestHeader "x-bce-date", "2019-02-15T02:23:01Z"
authorization = "your_authorization"
xmlHttp.setRequestHeader "Authorization", authorization
//答案选项列表图片base64
base64str = ImagesToBase64("D:\temp\ZYHXCaptcha\answer.jpg")
//图片base64后再urlencode
tmp = URLEncode(base64str)
TracePrint "URLEncode="&tmp
xmlHttp.send "image="&tmp
If xmlHttp.readyState=4 then
response = xmlHttp.ResponseText
End If
xmlHttp.Abort
Set xmlHttp = Nothing
TracePrint "调用百度识别返回结果=" & response
postBaiduOCR = response
End Function
- 得到返回的json数据并进行解析,可以参考这篇文章:按键精灵中解析json数据
Set sc = CreateObject("MSScriptControl.ScriptControl")
sc.Language = "JScript"
sc.AddCode "var o = " & json_result & ";"
//获取第i个words并去除两边空格,然后统一转成大写
word_str = UCase(Trim(sc.Eval("o.words_result[1].words")))
//然后可以逐个字符跟若快返回结果进行比较 TODO
测试过程中发现识别误差率高的字符有
W
容易被识别成N
/M
,M
被识别成N
/H
,以及第三个字符是Y
识别返回成V
需要做一点判断处理
通过对比若快返回验证码识别结果以及百度OCR返回的选项列表可以确定第几个是正确的验证码选项,最后可以dm.CmpColor
找特定点颜色(“神医”十字边缘点黄色),判断是否快到时间,则点击按钮开始校验。