上一期链接:

我是怎么破解一个答题微信小程序的(一)

脱离Windows

我们要先把投影依赖去掉,彻底去除对投影软件的依赖,那要想办法用PC直接操纵安卓手机了, 这要用到我们之前说到的adb了,先普及一个常识,安卓是谷歌的儿子,谷歌官方有很多有关安卓开发很有用的程序,adb是这样一个东西,adb的全名是Android Debug Bridge,自此开始和以前不一样了,之前我们用的全都是可视化的界面,比如模拟器啊、投影啊,鼠标点击啊,都能直接的看到,而adb开始是小黑框了,你要从那个命令行小窗口输入一些命令来完成操作了。比如在命令行输入adb input tap 200 200,adb会通过数据线来操纵你的手机点击(200,200)这个像素点。

笔者也是很少用命令行工具……以前都是能用有界面的用有界面的,开始尝试adb的时候很痛苦,查了很多资料,每一步都要去测试这个是干嘛用的,掌握了adb的基本使用,可以使用adb的功能去完成上一个板块中我们实现的思路。然而看了很多资料之后觉得adb也没那么可怕,没有界面而已,但是本质上是把之前的一些函数替换一下,比如把截图从使用Python截图的函数改成使用adb命令来截图可以了,截图坐标重新测量一下,消除对Windows的依赖之后,甚至不需要像之前一样计算相对坐标,使用windows的api查询窗口。点击事件由之前的控制鼠标点击,换成使用adb发送点击坐标请求来完成。

很痛苦的是题库需要重新录入,因为手机的分辨率的原因,你投影在屏幕上的分辨率不是手机的原生分辨率,仔细看知道,它是手机界面的一个缩小,只要我们电脑上这个投影大小发生了变化,我们之前的代码都没用了,我们又说了一次依赖的恐怖……

那现在我们重新录入题库,思路相同,录入点击的坐标。可是之前的坐标是在windows上的,我们可以使用qq截图这样的东西来看有多少像素点,但是现在不行了,现在东西在安卓上,于是我想了个办法……

我是怎么破解一个答题微信小程序的(二)插图

左边每一个横线对应的是它的纵坐标,横坐标我们之前说过,ABCD在一条竖线上,横坐标是相同的,所以只需要看要选的点上下相近的两条线,简单估计一下可以了。我们录入完题库,这样的代码又可以完全跑起来了。同时它不依赖投影和Windows了,你把你的手机插到其他人电脑上,只要题库复制过去,adb环境配置好,可以在另一台电脑上刷题。

思考:说是去除依赖,其实是换了个工具,之前是对投影软件的依赖,现在是对adb套件的依赖,可是这样更稳定。因为投影软件是一个第三方的东西,根据测试,电脑屏幕上没有显示完整的安卓页面,而是按比例缩小了一些,那么说明这个投影软件,会根据不同的电脑不同的分辨率不同的屏幕大小有不同的显示效果,这些都叫做不稳定的因素,不稳定的因素越多,程序越不稳定。而adb是官方发布的套件,它对不同安卓设备都有适配(其实是对系统的适配),这样的套件不稳定的因素很少,依赖于这样的东西,会让你的代码更稳定。

举个更实际的例子,比如之前的代码依赖Windows和投影软件,换一个电脑换一个投影软件可能代码直接失效了。而现在使用了adb,消除了对Windows和投影软件的依赖,你换个电脑,换个分辨率,换个系统,只要adb环境配好了,你的代码仍然可以用,因为它变成了对当前手机的依赖。只要你这个手机不变,随便换电脑,它都能运行。

抓包

用完adb一身轻松,现在可以插根数据线打开程序后台刷题了,不用继续操控我的鼠标了,可是它仍然依赖着手机设备,是说,我换一台手机设备,之前录入的题库信息失效了,于是我开始寻找脱除设备依赖的技术。

之前我们提过,我在次做的时候觉得这个题目整体是一张图片,但是现在重新思考,它不可能是一张图片,不同的手机ABCD的位置是不一样的,屏幕窄一点,显示的题目短一点,屏幕宽一点呢,现实的题目长一点。图片肯定不会这么自适应,所以题目和答案一定是一些文本,然后这个显示题目有一个模板,在模板上的对应位置把文本放上去可以了。之后让这个模板适应手机的屏幕。这样才能解释不同手机显示的效果不同。

如果题目和答案都是文本的话,背景是一个模板,那我们所看到的这个小程序的页面,和正常的网络页面很相像了,正常的网络页面也是这样,一个模板留好多的空位,然后一个一个把数据放上去,成了网页。那是不是可以用网络爬虫的思路做?可是正常的网页我爬过,手机的小程序我没爬过啊……而且这是手机上的小程序,我电脑上也访问不到,怎么看到数据呢?

又一通查资料,终决定用抓包来解决问题,什么是抓包?我们可以思考一下通信流程,我们点击答题,然后小程序给我返回随机五十道题,然后我不停地答,答完了提交。那想一下,是谁给我们返回这随机的五十道题呢?是微信吗?微信肯定不会管这么多事,小程序那么多,不会是微信官方给你当服务器。是小程序自己吗?这里查了一些资料,小程序本质上是依附微信存在的,没有这么大的权限在你手机里调用这个调用那个。那只剩一个情况了,是有一个服务器在做这件事。我们把这个过程画个图:

我是怎么破解一个答题微信小程序的(二)插图1

那是手机向服务器发一个数据请求,服务器返回数据,这是非常简化之后的过程了,这个请求也不叫请求,发送过去的和接收回来的,都叫数据包,我们把这些数据包获取到,叫抓包。

抓吧,百度一大通手机抓包的资料,终找到了charles这个软件,按照网络教程配置好,抓包……失败,抓包……失败。包能能抓到,但是点进去什么都看不到,有些包能显示,有些包会告诉我unknown,不让我看。那不行,又查资料解决这个问题,了解到了其实各类网站可以分为两类,仔细看域名可以发现,有的是http开头,有的是https开头,查资料了解http和https的区别之后,大概明白了https的基本原理,是你想抓到http的包很容易,一抓抓到了,但是https的包呢,需要一个叫证书的东西,没这个证书你不能抓,抓了也看不了。这个证书你可以看做是访问https数据包的许可证,没证不行。

那解决这个问题吧,这个问题还是蛮多人遇到的,一查能查到,给手机装个证书,给电脑装个证书,可以抓到了。次抓包让我非常惊喜,有这样的包:

我是怎么破解一个答题微信小程序的(二)插图2

右边这一堆……似乎……题和答案直接给我了?我按照上面的答题顺序试了试,果然不错,直接按照这个答题行。那还是不行啊……我只抓到了题目和答案的包,可是没有网页模板的包,虽然告诉我答案ABCD了,但是我不知道这个ABCD对应屏幕的啥地方啊。

那我得想办法获取这个网页模板的数据包,但是怎么抓都抓不到……然后我放弃了,想办法去绕过这个问题。

思考:笔者后来想到,可能有两种方法会导致我抓不到包。一种是这个网页模板包含在了小程序里面,而我没法获得小程序的源码,另一种是可能这个页面是缓存在手机里了,每次用到的时候直接从手机内部取,而不是从服务器获取,可以使用清除微信应用数据的策略,重新抓包,测试看能不能抓到。

没有模板的包怎么办,那我能不能用安卓的一些东西来获取元素的位置呢,像一个网站页面一样,是HTML文件,每个数据都是找到自己的坑位放在那里。那我应该想办法通过安卓来获得一些东西啊。好像随便一个浏览器,假如我们不看页面代码,我们是怎么看到这些元素的呢?这些元素是怎么找到自己的位置把自己放上去的呢?

其实不是元素把自己放上去的,是浏览器把他们放上去的,给元素找到正确的位置放到它对应的位置上,这个过程叫渲染,是浏览器的工作,浏览器看到的本质上是一个页面模板,加上一些数据,我们却能看到完整的页面,这个工作其实都是浏览器做的。于是做爬虫的,可以通过浏览器的一些工具或者接口来获得网站页面上的数据。同样的,微信也有自己的渲染,这个把数据放到对应的位置上应该是微信这个app做的,而微信app是依赖安卓系统的,那我们能不能用安卓系统的一些东西来获取到数据呢?

答案那必然是可以,前提是要查足够多的资料。查到谷歌给安卓提供的开发套件中,有一个叫uiautomator的东西,它是帮助开发者做页面的,但是反过来,它也能帮助开发者拆页面。又查了一些关于这个工具的使用,简单学习了一下,发现adb中集成了一个和它有关的指令,可以使用这个指令来获取到一个XML文件,XML本质上来说和正常的文本没什么两样,是它多了一些东西,这个文件是这样的:

我是怎么破解一个答题微信小程序的(二)插图3

XML其实是给一些文本贴了标签,同时这些标签有上下级关系,一个标签可以包含另一个标签,比如大的这个背景页面包含了题目标签、选项标签等等,而题目标签里面包含了题目文本,选项标签包含了选项的文本,和选项的一些属性,比如这个bounds属性,是我们想要的,它标志着这个选项在什么位置。

好了,OK了,大功告成,我们的思路完美的成了一个闭环,通过抓包获取题目和答案,再通过uiautomator+adb获取题目答案位置,再通过adb点击位置,思路非常清晰,而且比我们版做得不知道高到哪里去了。

那问题来了,能通过抓包直接解决问题吗?是需要我做一次题抓一次包吗?其实是不行的,charles可以抓包是可以抓包,但是Python没法控制它,也不能直接的从charles中获取数据包,意思是说,Python不能直接获取到题目的数据和答案。那咋办?那我们可以延续之前一样的思路,构建题库,通过抓包来构建包含所有题的题库。

我遍想的思路是每次抓包获取数据,都将那个数据复制出来,交给Python处理,虽然Python不能直接从charles中获取数据,但是处理一些json数据还是手到擒来的。但是这个过程很苦逼,不像是一个高智慧的程序员干的事,那想办法自动化吧。

这个时候应该看看数据包了,我们只顾着能看到数据,却忘了数据怎么来的,看一下请求,思考一下,如果数据包不是从微信小程序里面发出去的,而是我自己随便发的,或者是从浏览器直接访问这个url来发起请求,或者我用Python构造一个请求,是否可行?

是否可行那得试一下,用Python构造了一下请求,看一下返回的数据,看完舒服了,和微信小程序发的请求返回的数据一模一样。那我只需要发足够多不同的请求,每次获取到的50道题相互叠加,慢慢的可以构成一个完整地题库了。

接下来可以机械的做一些劳动了,比如开始答题,退回开始界面,开始答题,退回开始界面,直到请求足够多了,把这些请求网址复制到一个文本文件中,让Python读取这个文本文件,对每一个网址都发一个请求,把这些获取到的数据叠加起来,题库构建完成了。

伪代码呼之欲出:

while 1:    通过uiautomator获取题目文本    通过题目文本搜索题库获取答案    通过uiautomator获取答案的坐标    通过adb点击答案坐标

简单易懂,到这里问题我们已经解决了90%了,还有后一个没通过的点,怎么通过uiautomator获取题目文本,uiautomator返回的是一个XML文件啊,虽然题目文本什么的都包含在里面,可是里面的关系错综复杂,怎么用代码提取出来?不能每次都自己看一遍XML文件人工提取出来题目文本来给Python输入进去吧?

这个时候我的爬虫基础发挥作用了,在XML文件中读取一个东西,可以用到xpath的东西,不过已经忘了差不多了……重新打开w3cschool学了一下,而Python有一些可以操纵XML文件的第三方库,简单学习一下,可以从XML文件中提取文本了。

大功告成!现在的代码, 只依赖adb和uiautomator,只要这个小程序没有变,任何安卓手机任何电脑任何PC的操作系统,都没关系,都可以用,我们依赖的adb和uiautomator都是很稳定的东西,很长时间都不会变的那种,所以我们的代码也非常稳定。

学习之路到此结束啦。

附言

这里可能更多的是我想和同学们说的话吧。同时这里没那么多科普,偏硬核一些,谨慎阅读。

破解小程序到底需要懂多少东西?

其实不用懂很多东西……有些不懂的可以查,有些不懂的你可能不知道怎么查。比如:不会读XML文件你可以百度如何用Python读取XML文件,会查到很多东西,比如我用的Python的lxml库读取的,你可能能查到你用着更顺手的库。不知道怎么用电脑操纵安卓可以百度怎么用电脑控制安卓,你可以搜到投屏,可以搜到adb,可以搜到一些远控软件,然后你可以每条路都走一走,找到你觉得用的舒服的。

但是有些东西你不会了是没法查的,比如如果你想不到你玩小程序的过程其实是你的手机和服务器交互的过程,那么你很难想到他们背后是数据包的接发过程,可能接触不到抓包这个东西了。如果你的基础还没有让你知道网站的本质是一些代码的组合,如果你还不知道浏览器是通过执行一些js代码来完成那些花里胡哨的界面的, 可能你想不到去用类似的思想去解决安卓小程序的问题,你可能想不到可以将页面拆开这种方法,也接触不到uiautomator了。

你看我文中写了多少个查资料,累得不行了才把这个东西做出来,所以要懂的更多的都是原理性的,是知道某些东西的工作原理,比如计算机网络中TCP/IP的原理、HTTP的原理,浏览器的工作原理甚至爬虫的工作原理等等,这些你要了解。而有些东西你可以遇到问题了再查,比如小程序的工作原理,抓包的工作原理,等等,只要你有了前面各种知识的基础,后面这些东西是前面东西的一些组合或者延伸。

优雅的代码

开发中一定要想着如何写更优雅的代码。

比如开始我们写的代码可能是一个循环,一些函数调用来调用去,能跑是真的,但是改代码很痛苦,比如你想修改你对题目的截图区域,它包括4个值,左上角坐标的x和y,右下角坐标的x和y,要改好多地方,截图的地方要改,相对坐标计算的位置要改,经常牵一发动全身,而这种还是极度负面性的。这个时候可以优化代码, 将这些值抽出来放到一个文件里面,这个文件叫配置文件,之后所有用到这些值的地方都从配置文件读取,这样你只需要修改一个配置,后面的工作流程会自动修改。

之后我们可以想到,整个破解小程序的流程无外乎这几步:在开始界面点击开始答题,在答题界面答题,在结束界面结束答题。把所有的流程都在主函数里面用if表示,if 是xxx界面做xxxx操作,也可以跑,可是如果要新增一个页面呢?比如多选页面?怎么办?你要在下面新加一套if,所有相关这个多选页面的东西都要写在里面。这个时候我们可以抽象一层,比如将每一个页面看做一个事件,事件有两个函数,一个条件函数,一个执行函数,条件函数是当这个为真的时候确定是这个事件,执行它的执行函数。而主函数中只需要不停地判断是不是这个事件,如果是执行,不是判断下一个事件。这样新增一个页面也是新增一个事件,在主函数的所有事件的列表中新增一个可以了,不会影响主代码。(可以反过来思考,不是事件,而是状态的改变,比如由主界面状态进入答题状态,由答题状态进入结束页面状态,这样可以用设计模式中的状态模式改写,这里涉及到计算理论中的有限状态机,值得一学)。

上面是随便举了两个例子,你代码写的越优雅,你之后改代码会越顺畅。

本文作者:王悟空

作者 nasiapp

在线客服
官方客服
我们将24小时内回复。
12:01
您好,有任何疑问请与我们联系!

选择聊天工具: