前言
最近答题类的应用实在是太火了,什么冲顶大会,百万英雄啊,动不动就几十上百万的奖金,着实让人看着很是眼红... 然后本弱鸡学疏才浅... 题目全靠蒙,便不凑什么热闹了.之后没过几日有个小程序倒是在办公室里面火了一把,就是这次需要拿来开刀的《头脑王者》,其实也是个答题的小程序,所以还是不擅长就是了.虽然我不擅长答题,但我好歹是个程序员呀,所以我走上了一条程序员的通顶之路...
成果
每轮游戏需要答 5 题,全对并且快速作答才能拿到满分,满分是 1200 分.有了这种战绩,世界第一不是梦!当然玩游戏是为了乐趣,本弱鸡只是出于兴趣使然,这种答题类的游戏还是自己玩比较有意思.
准备工作
在开始写这种游戏的辅助之前先思考几个问题.
如何伪造接口请求?
如何实现精准答题?
如何完成自动答题?
如何伪造接口请求?
首先小程序的接口请求都是基于 HTTPS 的,具体捕获 Https 的方式我这边还是采用 Anyproxy 去捕获,需要安装对应的 Https 证书才可以.之前的文章也有提及,这里再赘述一遍. 本文采用的 Anyproxy,使用其他的代理工具也是一样的.
1. 安装node.js
配置完以后,打开游戏就能抓取到头脑王者对应的请求包了.我先模拟了一次好友对战,然后需要分析了哪些包是需要的.这里我就直接把一些重要的接口给贴出来了
2.npm i - g anyproxy 3.anyproxy - ca // 生成证书
4.anyproxy - i // 以代理https的方式启动
// 然后手机端配置代理的IP及PORT,默认端口为8001,
// Anyproxy的webService的默认端口为8002,这里可以查看到接口
// 手机端配置代理以后需要下载证书并信任,
// 苹果端的可以在手机的Safiri里面输入xxx.xxx.xxx.xxx:8002/fetchCrtFile的方式下载到证书
// 高版本的iOS可能需要在两处地方信任.
login 接口(登录接口,这里重要的信息是 uid 和 token)
intoRoom 接口 (进入房间的接口)
beginFight 接口 (开始对战接口)
findQuiz 接口 (找题目接口)
choose 接口 (答题接口)
getResults 接口 (获取比赛结果的接口)
leaveRoom 接口 (离开房间接口)
先从接口看一下,这是一个非常顺畅的游戏流程,但是拿到这些接口我就可以开始为所欲为了吗?显然是不可能的,如果每个人都能有权限肆意使用别人的接口的话,岂不是可以很轻松的做到 DDoS 攻击或者很轻松地获取到自己想要的信息了吗?对于一家有经验的公司来说显然是不会犯这种错误的,那么我随便拿一个接口来稍作分析.
上图是天梯排位匹配接口,从 Body 中可以看到需要传给服务端 matchId,npcId,uid,t,sign 五个参数,这 5 个参数都是必须的,只有有一个参数出错,那请求就无法成功,前四个其实好理解,关键是第五个签名参数 sign,是怎么来的呢?
这里就需要用到逆向工程了... 简单的描述就是... 拿到小程序中头脑王者压缩后的源码,并分析出其中的加密规则,篇幅有限,这里就直接描述其加密规则了.
sign 的生成规则:
Body内所有的参数(除去sign) + token(login接口获取)并按照key值排序以后对齐进行MD5加密
, 比如 uid=111, t=222, token=333,那么加密前子串应为 t=222token=333uid=111
既然 sign 也有了,那其实就很简单了,然后我就用 node 写一个简单的 client 去做伪造了接口请求.
如何实现精准答题?
目前也有许多冲顶大会,百万英雄的辅助,他们的思路是答题的时候快速识别到题目并进行快速的搜索题目进行辅助答题,但对于这款游戏,如果想实现精准的答题的话,最好的办法就是匹配题库,那么问题就是题库怎么来?当然是通过爬虫去爬取的了,OK... 来让我们找一找题库的接口!显然这是不可能的!要是对外开放了题库的接口,这个游戏也太容易被攻破了把.但是从上述的一步中,其实我们已经实现了开房模拟对战了,那么是不是可以一直开房间一直对战的方式获取到题库呢?所以我这里采用的就是这种思路.
success 是脚本自动答题打对的题目(一共 5 题),total 是总共的题库数量.从这个规模可以看出来,正确率已经是极高的了,说明题库的数量应该估计只有 17000 左右的范围,但是由于剩下的题库仍然在补充且最后的 10% 会需要较大的成本才能覆盖到,其实题库做到这一步已经足够了,80% 的满分概率... 几乎已经是无人匹敌了吧?
如何实现自动答题?
自动答题的方案有两种:
类似跳一跳游戏,通过截屏 =>OCR 读取题目 => 匹配题库 => 模拟点击答案
Anyproxy 代理,写 rule 文件修改请求,捕获 findQuiz 请求接口,server 重新发起请求并等待数据返回 => 判断返回的题目是否已经存在于数据库 => 匹配答案直接作答或返回题目
本弱鸡在这里使用的就是第二种方案(具体实现就不赘述了,大家可以直接看源码)
总结
不太善于写文章,上述很多步骤都简单带过了,在这里只是简单地描述了一下过程,然后我会开源这部分的代码,写得有些简陋希望各位大佬们不要嘲笑 (由于在写 Anyproxy 的 rule 的时候没法使用 babel,所以我用 require 取代了 import).最后希望大家能给与我一点支持及肯定,给点 star 吧... 只要 10 个不过分吧!有好心能请我
来源: https://juejin.im/post/5a5b4097518825734d149423