次次获得《头脑王者》满分的秘诀
前言
最近答题类的应用实在是太火了,什么冲顶大会、百万英雄啊,动不动就几十上百万的奖金,着实让人看着很是眼红...然后本弱鸡学疏才浅...题目全靠蒙,便不凑什么热闹了。之后没过几日有个小程序倒是在办公室里面火了一把,就是这次需要拿来开刀的《头脑王者》,其实也是个答题的小程序,所以还是不擅长就是了。虽然我不擅长答题,但我好歹是个程序员呀,所以我走上了一条程序员的通顶之路...
成果
每轮游戏需要答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)。
- 动态控制C4C UI元素的显示和隐藏
- 深度学习(deep learning)发展史
- 遗传算法简述
- Spark详解03Job 物理执行图Job 物理执行图
- 干货|Kotlin入门第一课:从对比Java开始
- Spark详解04Shuffle 过程Shuffle 过程
- Spark详解02Job 逻辑执行图Job 逻辑执行图
- Spark详解01概览|Spark部署|执行原理概览Job 例子
- Spark详解05架构Architecture架构
- SQL Server常用命令(平时不用别忘了)
- Spark详解06容错机制Cache 和 Checkpoint Cache 和 Checkpoint
- SQL Server 学习笔记
- Collaborative Filtering(协同过滤)算法详解
- 【Hadoop】三句话告诉你 mapreduce 中MAP进程的数量怎么控制?
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- JavaEE中,实现登录时进行校验验证码的功能
- JavaEE中为删除数据操作与退出操作添加确认提示框
- JavaWeb中的实现页面跳转的同卵双胞胎兄弟——重定向与请求转发
- JavaWeb中的异卵双胞胎——监听器与过滤器
- JavaEE中的el 表达式以及JSTL详解
- 基于Jsp和Servlet的简单项目
- 基于Servlet实现的简单登陆练习
- JavaScript初识
- 聊聊dubbo-go的DubboInvoker
- 如何在云开发Cloudbase中使用MySQL数据库
- Kubernetes笔记之基本概念
- 腾讯云语音识别之一句话识别
- 创建线程都有哪些方式?— Callable篇
- UiAutomator源码学习(3)-- UiObject
- RTSP协议视频流媒体播放器EasyPlayer-RTSP-OCX接口文档API接口函数定义