使用按键精灵脚本实现《自由幻想》游戏内"神医"验证码自动校验

按键精灵编写的脚本简单方便,最直接的体验是可以代替我们处理简单重复的鼠标键盘操作。
《QQ自由幻想》这款游戏系统内置自动挂机功能,但是每隔1个小时就会自动弹出验证码校验,校验不通过就会被踢下线,然后只能通过①先花钱开通VIP-》②再花钱购买2/4/8小时免校验卡(道具)跳过校验,不氪金体验极差。

对于这款已经很老的游戏,情怀党表示还是要尝试实现自动过验证码,增加游戏体验

使用按键精灵脚本实现《自由幻想》游戏内
验证码示例

按键论坛可以搜到大漠插件建立字库识别验证码的教程:『笨海绵』用大漠插件实现QQ自由幻想验证码后台识别方法详解
这种方法主要原理是收集图片像素点数据建立字库并进行对比识别出验证码字符,缺点是建立字库繁杂,识别率也是个问题。

接下来说下处理过程,首先截取左边难处理的验证码区域,上传图片到打码平台(若快),然后截取右边列4个较为规则的答案选项上传到百度文字识别,最终对比返回结果得出第几个是正确答案就可以通过验证了,思路非常简单。

主要涉及下面几点:
  • 大漠插件的使用
  • 人工打码平台的对接(若快打码平台)
  • 百度文字识别api的使用
首先是大漠插件的使用
  1. 首先下载大漠插件V3.1233(最后免费版本),然后根据里边提供的大漠接口说明.CHM注册大漠插件
    使用按键精灵脚本实现《自由幻想》游戏内
    大漠接口说明.CHM

为什么要使用大漠插件?
优点:大漠插件建立字库找字的功能比较方便。
按键精灵自带命令也可以满足大部分的使用要求,大漠插件可以补充按键不足部分,混合使用。
大漠插件通过dm.BindWindow命令可以轻松切换前后台模式,而不需要修改脚本中的大量命令
测试过程中经常发现按键的后台截图方法截图失败时会导致按键程序直接崩溃,使用大漠插件就没有出现这种情况
缺点:注册多一个大漠插件意味着有更高的安全风险,360之类的就可能会报错。

  1. 然后在脚本中创建大漠对象就可以直接使用了(具体方法/参数说明可以查看大漠接口文档)
//首先获取当前游戏句柄(这里通过游戏类名获取,也可以直接鼠标获取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)
  1. 验证码区域的截图(具体方法/参数说明可以查看大漠接口文档)
  • 首先找到验证码区域的坐标,因为验证码是屏幕内随机区域出现的,这需要用到找字功能:目标是找到验证码左上角神医两个字。找字功能就需要我们先建字库:
    ①打开大漠综合工具,点击抓图截取需要的“神医”两个字
    使用按键精灵脚本实现《自由幻想》游戏内
    大漠综合工具

    ②然后调用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处理简单/规则的文字或数字
  1. 百度文字识别文档中有两种调用方式,第一种是先获取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);
}   
  1. 按键精灵中读取图片文件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,"")

  1. 图像数据,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长度变长,上面的这个方法执行速度会很慢。

  1. 调用百度文字识别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    
  1. 得到返回的json数据并进行解析,可以参考这篇文章:按键精灵中解析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/MM被识别成N/H,以及第三个字符是Y识别返回成V需要做一点判断处理

通过对比若快返回验证码识别结果以及百度OCR返回的选项列表可以确定第几个是正确的验证码选项,最后可以dm.CmpColor找特定点颜色(“神医”十字边缘点黄色),判断是否快到时间,则点击按钮开始校验。

你可能感兴趣的:(使用按键精灵脚本实现《自由幻想》游戏内"神医"验证码自动校验)