如何利用 adb 去除投影依赖并直接操纵安卓手机

2024-06-16
来源:网络整理

上期链接:

摆脱

我们首先要解除投影的依赖,彻底解除对投影软件的依赖,那么就需要想办法用PC直接控制安卓手机了,这就需要用到我们前面提到的adb了。我们先普及一个常识,安卓是的儿子,有很多和安卓开发相关的好用的程序,adb就是这么一个东西,adb的全称是。从现在开始和以前不一样了,以前我们用的都是可视化的界面,什么模拟器啊,投影啊,鼠标点击啊,这些我们都可以直接看到,而adb一开始就是一个黑色的小框框,你要从那个小命令行窗口输入一些命令才能完成操作,比如在命令行输入adb tap 200 200,adb就会通过数据线控制你的手机点击(200,200)这个像素点。

我很少用命令行工具...以前只要有界面的我都用。第一次尝试adb的时候很痛苦,查了很多资料,每一步都要测试它是用来干什么的。一旦掌握了adb的基本使用,就可以使用adb的功能完成上一节我们实现的想法了。然而在看了很多资料之后,我觉得adb其实没有那么可怕,它只是没有界面而已,本质就是把之前的一些功能给替换了而已。比如可以将截图功能从使用函数改成使用adb命令截屏,截图坐标重新测量,消除了对的依赖之后,甚至不需要像以前那样计算相对坐标,使用api查询窗口即可。点击事件由使用adb发送点击坐标请求代替控制鼠标点击来代替。

痛苦的是题库需要重新录入,因为手机分辨率的原因,你投射到屏幕上的分辨率并不是手机原生分辨率,仔细看就知道是手机界面的缩小版,只要我们电脑上投射的尺寸发生变化,我们之前的代码就没用了,又说到依赖的恐怖了……

现在我们重新进入题库,思路是一样的,输入点击坐标。但是之前的坐标都是在上面的,我们可以用QQ截图看看有多少个像素,但是现在不行了,现在这个东西在安卓上,所以我就想到了一个办法……

左边的每一条横线都对应着它的纵坐标,前面我们说过了,ABCD在一条纵线上,横坐标也一样,所以你只需要看离你要选取的点最近的两条线,做一个简单的估算就可以了。我们输入题库之后,代码就可以完全跑起来了。同时,它不依赖投影和。你可以把手机插到别人的电脑上,只要把题库复制过来,配置好adb环境,就可以在另一台电脑上练题了。

思考:说是去掉依赖,其实就是换个工具而已,之前是依赖投影软件,现在依赖adb套件,不过比较稳定。因为投影软件是第三方的东西,根据测试,电脑屏幕显示的并不是完整的页面,而是缩小了一点,也就是说投影软件会根据不同的电脑,不同的分辨率,不同的屏幕尺寸,显示效果会有所不同。这些就叫不稳定因素,不稳定因素越多,程序就越不稳定。adb是官方发布的套件,可以兼容不同的设备(其实就是对系统的一种适配),这样的套件,不稳定因素就少了。依赖这样的东西,会让你的代码更加稳定。

举个更实际的例子,比如之前的代码依赖投影软件,你换电脑或者换投影软件,代码可能就失效了。现在有了adb,对投影软件的依赖就消除了。你可以换电脑,换分辨率,换系统,只要配置好adb环境,你的代码还是可以用的,因为它依赖的是现在的手机,只要你的手机不换,换电脑也能跑起来。

数据包捕获

用了 adb 之后,感觉轻松多了,现在只要插上数据线,打开程序就可以在后台练题了,再也不用控制鼠标了。不过还是依赖于移动设备,也就是说如果换了移动设备,之前输入的题库信息就失效了。于是我开始寻找摆脱设备依赖的技术。

我们之前提到过,我刚开始做的时候以为整个题目就是一张图片,现在我又想,不可能是一张图片。ABCD的位置在不同的手机上是不一样的,如果屏幕窄一点,显示的题目就短一点,如果屏幕宽一点,实际的题目就长一点。图片肯定不会那么自适应,所以题目和答案肯定是一些文字,然后有一个显示题目的模板。把文字放到模板上对应的位置就行了。然后让这个模板去适应手机的屏幕。这就能解释不同手机显示效果的不同了。

如果问题和答案都是文字,背景是一个模板,那么我们看到的这个小程序的页面就跟正常的网页很像了。正常的网页也是这样,一个模板留出很大的空间,然后把数据一个一个的放上去,就变成了一个网页。那么我们能不能用网络爬虫的思路来做呢?但是我爬过正常的网页,却没爬过手机上的小程序……而且这是手机上的小程序,我在电脑上是访问不到的,那怎么才能看到数据呢?

经过又一轮的研究,最后我决定用抓包的方式来解决问题。什么是抓包呢?我们可以想一下通讯的过程,我们点击回答问题,然后小程序返回五十个随机问题给我,然后我不断的回答,回答完之后提交。那么你想想,这五十个随机问题是谁返回给我们的呢?是微信吗?微信肯定不会管那么多事情,小程序那么多,不是微信官方给你充当服务器的,是小程序自己管吗?我这里查了一些资料,小程序本质上是依赖于微信的,它没有那么大的权限去调用你手机上的这个,那个。那么就只剩下一种情况了,就是有服务器在干这件事情。我们来画一下这个过程:

也就是手机向服务器发送一个数据请求,服务器返回数据,这是一个非常简化的过程,这个请求不叫请求,发送的和接收的数据包都叫数据包,我们获取这些数据包的时候就叫抓包。

我们来抓包吧,百度搜了下手机抓包的资料,最后找到了这个软件,按照网上的教程配置了一下,抓包了…失败了,抓包了…失败了,能抓到包,但是点击之后什么都看不到,有的包能显示出来,但是有的包会告诉我看不到,这样不行,为了解决这个问题,我查了资料,了解到各种网站可以分为两类,仔细看域名可以发现,有的以http开头,有的以 开头。 查了资料了解了http和 的区别之后,大致明白了基本的原理。 就是http的包很容易抓,一下子就能抓到,但是对于 ,需要一个叫证书的东西,没有这个证书,就抓不到,抓到也看不到。 你可以把这个证书看成是访问数据包的许可证,没有证书,就不行。

我们来解决这个问题,这个问题还是很多人遇到的,你查一下就能发现。在手机上装一个证书,在电脑上也装一个证书,就可以抓包了。第一次抓包的时候,我很惊讶,有一个这样的包:

右边那堆...好像...直接给我问题和答案?我按照上面回答问题的顺序试了一下,成功了。我就按照这个顺序回答问题。但是还是不行...我只拿到了问题和答案的包,没有拿到网页模板的包。虽然它告诉我答案ABCD,但我不知道这些ABCD在屏幕上对应的是哪个。

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

思考:后来想到可能抓不到包的原因有两个,一个是网页模板包含在小程序中,我拿不到小程序的源码,另一个是页面可能缓存在手机中,每次使用都是直接从手机中取,而不是从服务器取。可以采用清除微信应用数据的策略,重新抓包,测试能否抓到。

如果没有模板包怎么办?我可以用一些的东西来获取元素的位置吗?就像一个网站页面,它是一个HTML文件,每个数据都放在那里。那我就要想办法通过来获取一些东西。就像任何一个浏览器一样,如果我们不看页面代码,我们怎么能看到这些元素?这些元素如何找到自己的位置,把自己放在那里?

其实不是元素自己把自己放到了那里,而是浏览器把它们放到了那里。元素找到正确的位置,并放到相应的位置的过程就叫渲染,这是浏览器的工作。浏览器看到的本质上是一个页面模板,再加上一些数据,我们就能看到完整的页面,而这个工作其实就是浏览器做的。所以爬虫可以使用浏览器的一些工具或者接口来获取网站页面的数据。同样的,微信也有自己的渲染,这个把数据放到相应的位置应该是微信客户端做的,而微信客户端是依赖安卓系统的。那么我们能不能利用安卓系统的一些东西来获取数据呢?

答案当然是可以的,前提是你有足够的信息。我发现在为提供的开发工具包中,有一个叫 的东西,它可以帮助开发者制作页面,但反过来说,它也可以帮开发者拆页面。我查了一些关于这个工具的使用信息,简单学习了一下。发现adb中已经集成了一个与之相关的命令,这个命令可以用来获取一个XML文件。XML本质上和普通的文本没什么区别,只是多了一些额外的东西。这个文件是这样的:

软件开发配置管理工具_小程序开发工具服务器哪里配置_配置开发工程师是干嘛的

XML其实就是对一些文本进行标签化,这些标签是有层级关系的,一个标签里面可以包含另外一个标签,比如说最大的背景页面里面就包含一个标签,标签等等,标签里面包含了标题的文本,标签里面包含了的文本,还有一些的属性,比如说这个属性就是我们最想要的,表示这个在哪里。

好了好了完成了,我们的思路已经形成了一个完美的闭环,通过抓包获取问答,通过+adb获取问答的位置,然后通过adb点击位置,思路非常清晰,比我们第一个版本好太多了。

现在的问题是,我可以直接通过抓包的方式来解决问题吗?难道每次做题都要抓包吗?其实是不行的。你可以抓包,但是你无法控制它,也不能直接从它那里获得数据包。也就是说,你不能直接获得题目的数据和答案。那怎么办呢?那我们可以继续之前的思路,建题库,通过抓包的方式建立一个包含所有题目的题库。

我第一个想法是每次抓包的时候把数据复制一份然后处理一下。虽然不能直接从里面拿到数据,但是处理一些 JSON 数据还是很容易的。但这个过程很痛苦,看起来不像是一个高智商的程序员会做的事情,所以我想到了一个自动化的方法。

这时候我们就应该看数据包了,我们只关心能看到数据,但是忘记了数据从哪里来的,看请求,想想如果这个数据包不是微信小程序发过来的,而是我随便发过来的,或者我直接从浏览器访问这个URL发起请求,或者我构造一个请求,这样可行吗?

我得试试看可行不,我构造了一个请求,看了看返回的数据,看了之后心里舒坦,微信小程序发送的请求返回的数据一模一样,那我只要发送足够多的不同请求,每次得到的50道题相互叠加,慢慢就能形成一个完整的题库了。

接下来就可以做一些机械的工作了,比如开始答题,返回开始界面,开始答题,返回开始界面,直到有足够多的请求,将这些请求URL复制到一个文本文件中,读取这个文本文件,对每一个URL发送一次请求,将得到的数据加起来,题库就建起来了。

伪代码已准备好:

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

很好理解,我们已经解决了 90% 的问题,还有最后一点没通过,如何获取试题文本?返回的文件是一个 XML 文件,里面虽然包含了试题文本和其他东西,但是里面的关系很复杂,如何用代码提取出来?总不能每次都手动把试题文本从 XML 文件中提取出来再输入进去吧?

这时候我基本的爬虫知识就派上用场了,以前用过一些知识可以读取 XML 文件中的内容,但是我几乎忘记了……我重新打开,稍微研究了一下,有一些第三方库可以操作 XML 文件,简单学习了一下,我就可以从 XML 文件中提取文本了。

大功告成!目前的代码只依赖 adb 和 。只要这个小程序不变,它可以在任何 手机、任何电脑或任何 PC 操作系统上使用。我们依赖的 adb 和 .txt 是非常稳定的东西,很长时间内都不会改变,所以我们的代码也很稳定。

学习之旅到此结束。

后记

这大概更多的是我想对同学们说的话。同时,这里科普的不多,比较硬核,请谨慎阅读。

破解一个小程序你需要知道多少?

其实很多东西你都不需要知道…有些东西你不懂可以去查,但是有些东西你不懂可能不知道怎么去查。比如你不懂怎么读XML文件,可以去百度搜怎么读XML文件,会搜到很多东西。比如我是用lxml库去读的,你也许可以找到一个你比较顺手的库。如果你不懂怎么用电脑控制安卓,可以去百度搜怎么用电脑控制安卓,可以搜索投屏、adb、一些远程控制软件,然后每一条路你都可以试一试,找到一条你觉得用起来最顺手的。

但是有些东西你不知道怎么做的话是查不出来的。比如你不认为玩小程序的过程其实就是你手机跟服务端交互的过程,那么你就很难想到它们背后还有一个发送和接收数据包的过程,也可能无法接触到抓包这个东西。如果你的基础还没有让你知道一个网站的本质就是一些代码的组合,如果你不知道浏览器是通过执行一些js代码来完成那些花哨的界面的,你可能不会想到用类似的思路去解决安卓小程序的问题,你可能也不会想到分页这种做法,所以你就接触不到它。

你看文章里我查了多少次资料,在做这个东西之前已经累得筋疲力尽了,所以你需要了解的更多的是原理,也就是知道某些东西是怎样运作的,比如计算机网络中TCP/IP和HTTP的原理,浏览器的工作原理甚至爬虫的工作原理等等,这些你都需要了解,而有些东西你遇到问题可以去查,比如小程序的工作原理,抓包的工作原理等等,只要你有前面知识的基础,后面的东西就是前面东西的一些组合或者延伸。

优雅的代码

在开发过程中,你必须思考如何写出更加优雅的代码。

比如说我们一开始写的代码可能就是一个循环,里面来回调用一些函数。虽然能实现,但是修改代码就比较痛苦了。比如说你要修改你这个问题的截图区域,里面包括了4个值,左上角坐标的x和y,右下角坐标的x和y。你需要修改很多地方,包括截图位置,相对坐标计算位置。往往一个事情就影响了整个系统,这是极其负面的。这时候你可以优化代码,把这些值提取出来放到一个文件中,这个文件就叫配置文件。之后所有用到这些值的地方都从配置文件中读取。这样,你只需要修改一个配置,后面的工作流程就会自动修改了。

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

以上只是两个例子,你的代码写得越优雅,后期修改代码就会越顺畅。

分享