在上PoRE前,我是Android零基础小白,Java也没写过。
刚刚接触那些Lab时,虽然挑战性也是有的,但终归是小打小闹的练习性质,只是助教出的题目。
然后那天,Proj1降临了。
真实软件逆向,而且参考目标还是微信。(微信是操作系统(雾))
开始前,前辈和我说过:没有做的时候都会以为这不可能,但其实你可以的。
现在做完了PJ1,我也想对后来的同学说:虽然这可能会耗费非常多的时间、精力,但我认为这是值得的!
这可是复杂度超高的真实软件、商用软件、以及操作系统软件,逆向成功就已经代表了——你已经有了在安卓世界中遨游的资格。
但是,我当然不会觉得耗费时间多是PJ1的优点。
我想在这里总结一些做PJ1的经验,能帮后来者节省一些时间就最好了。
工具 & 环境
在做PJ1时,我们需要准备一个好的调试环境。
最好的调试环境显然是真机,因为性能足够,可以提高调试的体验。如果你有一台备用手机的话,可以尝试网上查询root方法。我的备用手机是红米K30Ultra,使用root方法是Magisk。
root成功之后,推荐LSPosed模块,这是一个支持Xposed模块的框架,在安卓高版本也可以运行。Magisk有一个MagiskFrida模块可以开机自启Frida-Server,也十分推荐安装。这样一来,Frida和Xposed环境都准备好了。
在模拟器上的调试环境,参考助教的文档说明即可。中间不可避免会遇到问题,这是锻炼定位问题-搜索能力-解决问题能力的好机会。当然,在连续高强度STFW(Search The Friendly Web)之后,是人都不可避免出现头晕、昏昏沉沉、眼冒金星、可能还有腰酸背痛颈椎痛的情况。此时建议出去走走,今天的PJ1就写到这里……
然后就是一些工具的介绍了:
Frida:Hook主力
使用参考上一期
由于Frida脚本启动速度极快,对脚本进行修改后,只要在本机上重新启动python脚本就可以看到新的效果,而不需要重启模拟器啥的。因此,推荐即使要开发Xposed模块,也先用Frida进行hook测试。
Xposed框架:略
DDMS:动态调试工具
在网上搜索DDMS,可以发现这是一个Android Studio已经废弃的功能,但现在依然可以使用,请参考这篇文章找到它。
主要推荐其中的查看控件id功能。当我想要hook某个按钮绑定的onClick函数,可以直接用DDMS查看那个按钮的控件ID,在逆向工具中根据该ID搜索,就可以找到那个控件的引用,从而找到程序在哪里为其注册了onClick函数。
JEB:逆向工具
JEB不能搜索Java代码,我觉得比Jadx难用,并且占内存似乎也要更多。
Jadx:逆向工具
可以直接在生成的Java伪代码中搜索,功能十分强大好用。
可以在这里安装:https://github.com/skylot/jadx/releases
推荐安装 jadx-gui with bundled JRE
版本,这个版本可以直接在启动脚本里修改JVM的最大内存,防止Jadx在逆向微信的时候爆炸。方法是找到启动脚本(jadx-gui.bat)中的 "-XX:MaxRAMPercentage=xxx"
,然后将后面的那个 xx
改得大一点,比如 90.0
之类的。也可以把这条直接改成 -Xmx4g
来指定具体的内存数量。
PKiD:查壳工具
链接:http://www.legendsec.org/1888.html
可以查询APP有么有加壳,不过比较古老了。如果加了壳的话,很多代码逻辑都不会在APP里直接看到。我遇到的第一个目标就加壳了,用这个软件检测出来了。
FRIDA-DEXDump:脱壳工具
链接:https://github.com/hluwa/FRIDA-DEXDump
可以从内存里把dex代码给Dump出来,存到本地之后可以用jadx直接打开那个文件夹,用dump下来的代码进行分析。
思路
面对一个庞大的APP文件,眼花缭乱的代码(经过混淆之后确实是眼花缭乱),你是否迷茫?反正我是挺迷茫的。
思路很重要。我们需要有目标的逆向,而不是漫无目的的逆向。
我们首要思考的,就是逆向目标和软件逻辑之间的练习。比如想要做一个广告跳过功能,就可以思考:程序如何启动广告?程序如何关闭广告?最直接的入口,就是广告右上角的跳过或者关闭按钮。从按钮入手,找到点击按钮时的程序逻辑,就一定可以找到跳过广告的方法。
微信发送消息也是类似的。程序在什么时候会发送消息呢?当我们点击发送键的时候。所以发送消息的逻辑一定可以通过按钮来找到。
像跳过广告、发送消息这种有明确按钮,可以在手机上通过点击来进行的操作是最好逆向的。但我们也会遇到很多不好逆向的情况,比如我选的任务目标之一是破解一个软件的会员内购;又比如我的另一个目标是微信机器人,需要逆向找到接受消息的逻辑。这种情况下,没有明显的入口可供我们调用,我们就需要从其他的角度入手。
在破解会员内购中,一种思路是支付的时候伪造成功的回复消息;另一种思路是通过某个界面组件在开通VIP前后的变化,找到用以判断VIP的那个关键逻辑函数。这两者都比前者难找一些,不过都是可行的思路,我前后两个思路都试了一遍才成功。
在微信接受消息中,可能就需要从聊天框中显示的对方发来的消息组件入手,找到它的类、它的父类……不过,我并没有老老实实找,因为PJ1文档中给的一篇参考文章作者已经提供了一个非常有用的信息——微信会把聊天数据存到数据库中。(注意,由于很多数据库API都是以字符串为参数的,这大大方便了逆向时的信息获取)
Trick
有了思路以后,就需要在开始寻找目标了。在寻找目标时,也有一些能够帮助逆向的小技巧。
其中,最有用的技巧一定是jadx中的搜索功能。想要找“发送”按钮就搜索“发送”,想要搜索“跳过广告”就搜索“跳过广告”,想要搜索SQL处理逻辑就搜索“SQL”,想要搜索一个抽象接口类的实现类就搜索那个接口的名字……
由于jadx的搜索支持类名、函数名、代码、注释、资源,想要搜什么都可以Ctrl+Shift+F召喚出搜索界面!
此外,还推荐多多使用Frida动静态结合地调试。在jadx中右键某函数后,选择“复制为Frida片段”,粘贴到Frida脚本之后,运行脚本,马上就可以看到那个函数的调用情况、参数以及返回值。比如在一个函数中,有大量的在if中的语句,我们不知道它们是否会被执行,此时就可以hook住那个函数,通过打印参数、打印this的各个域等等方式来打印出真实情况下这些判断条件的值,从而得知真实的执行流是怎样的。
最后,我在逆向时遇到的一个比较逆天的情况是真机环境的微信函数名、类名和我本地的安装包中的函数名、类名是不一样的。我本地的安装包可是直接用真机上的微信导出的啊,真不知道哪里出了问题。一种可能是微信做了安装时混淆,另一种可能是我自己把安装包弄混了。遇到hook不上的情况,可以试试打印可以确定的类的各个域和成员函数,如下代码所示:
1 | let listener = Java.use("com.tencent.mm.pluginsdk.ui.chat.q"); |
领悟(建议)
面对一个新的情况,最好的办法是先网上搜一下。我感到使用谷歌进行搜索比百度要强一万倍,并且要多进行搜索,中文搜不到换英文再试试。比如像微信这样的软件,网络上一定会有许多已有的逆向资料(比如PJ1文档里助教给的参考文章),多搜多看,说不定就能遇到想找的东西。
在做PJ的时候,一定要注意保护好身体,注意坐姿和眼睛,不要沉迷逆向无法自拔!逆向的时间是过得很快的,并且有时会不断产生新的希望,让人在电脑面前坐着走不开。但很多时候,故意停下来去做别的事情,可能会产生更新更好的思路。
(Windows的话可以开个桌面专门当作逆向的工作桌面,这样停下来只要切换桌面就可以干别的事了)
此外,多和好同学交流一下思路、方法论非常有用,同学的思路往往能够大大地启发人!(可能比我写的破文章要更启发人)
最后,Proj1确实是很具有挑战性的一个作业,也是很难忘的一段旅途。我在Proj1里学到了一些东西,希望能帮助我以后解决更大的挑战,也希望能帮助到一些未来的同学~
P.S. 我也觉得PoRE这个难度坡度太大了,直接上真实的软件……或许可以在中间加一些小练习的,比如frida小练习(?)