本文以一个开源的Android Crackme–KGB-Messenger,作为实验对象,把最近学习的Frida动态调试和Apktool回编译流程复习一下。
步骤参考自非虫-Android软件安全权威指南以及apk文件反编译、回编译和签名之完全教程
本次实验使用开源的Android逆向Crackme KGB-Messenger
安装apktool
- 下载 Windows版本的 wrapper script (右键链接另存为
apktool.bat
) - 下载 apktool (下载列表)
- 重命名上步下载的 jar 包为
apktool.jar
- 将
apktool.bat
和apktool.jar
移动到同一个目录下 (不运行apktool.bat) 并将此文件夹添加进环境变量 - 使用
apktool -version
验证是否配置成功,出现版本号则说明配置成功
逆向分析
该Crackme还是比较入门的,先拖进Jeb静态逆向分析,结合frida动态调试把flag找出来。
先是一个环境检查,要求设备的所属地区为Russia
,且用户名为RkxBR3s1N0VSTDFOR180UkNIM1J9Cg==
(解码为FLAG{57ERL1NG_4RCH3R}
),不然直接弹窗提示错误信息。直接Hook绕过。
1 | var System = Java.use("java.lang.System"); |
接下来验证用户名和密码。
通过伪代码可以看到,用户名得是codenameduchess
,且指定了密码的md5值。
把md5值去掉开头的6位和末尾的8位,然后到somd5去查,得到明文为guest
。
输入合法的用户名和密码,LoginActivity.i()
会Toast出第二个FLAG{GOOG13_PRO}
。
接下来来到聊天界面MessengerActivity
。
MessengerActivity.onSendMessage()
作为发送的监听函数,大致反应了最后一关的逻辑:
先后发送两句话,分别满足this.a(v1.toString()).equals(this.p)
和this.b(v1.toString()).equals(this.r)
的要求,然后在this.i()
方法中,基于这两句话构造出最后一个flag。this.a()
是一个可逆的加密算法,this.b()
不可逆,需要爆破然后手动补全,代码如下:
1 | pp = "V@]EAASB\u0012WZF\u0012e,a$7(&am2(3.\u0003" |
最终得到第三个flag:FLAG{p455w0rd_P134SE}
字符串00截断
MessengerActivity.r="\u0000dslp}oQ\u0000 dks$|M\u0000h +AYQg\u0000P*!M$gQ\u0000"
,该字符串以00开头,frida在处理时应该是默认截断了。
因此通过frida的console.log打印为空,事实上,通过JS代码的调用都不能获取到该字符串的真实值。
这个问题在frida的issue下面有所讨论,但是官方貌似还没修。
解包修改
先用apktool反编译出smali代码
1 | apktool d kgb-messenger.apk -o kgb |
使用VScode打开kgb
目录,配合支持smali高亮的插件,就可以便捷修改。
先过开屏校验-地区和用户,伪代码如下:
这里的检查结果对之后的运行没有影响,只决定是否发生activitiy之间的跳转。
所以粗暴处理,直接把红框中代码对应的smali全部删除。
当然,smali代码的排布跟java层的代码有所区别,并非线性对应,需要结合寄存器操作划定删除的部分。
我直接把setcontentview()
之后、包括调用a.a.a.a.a.a()
之间的代码全部注释,然后把末尾跳转到goto_0
的语句改成return-void
。
笔者也试过仅修改v.equals()的返回值校验,即两个if-nez
语句,不过没有成功。
过用户名和密码检查
在LoginActivity
中,把用户名和密码保存在this.n和this.o两个成员变量中,之后在调用成员变量进行校验。
所以直接在获取之后、调用校验之前,添加两行代码把this.n和this.o强行修改为合法值。
这样一来,即使不输入任何值,也能成功登录。
获取最终flag
来到MessengerActivity
修改的思路同前:修改equals()的返回值校验进入两个if语句分支,然后在合适的时机把对应的成员变量修改为合法值,只需要随便输入一句话,就能获得flag。
回编
修改完smali代码就需要回编译得到apk,仍然可以使用apktool回编。
1 | apktool b .\kgb\ |
在dist目录下找到回编得到的apk并安装,发现安装报错,因为这个apk还没有被签名。
先用keytool
来生成一份自签名证书,然后使用jarsigner
来签名apk文件。
这两个程序都在jdk中,有环境变量就能直接使用。(Windows Terminal 可能有编码问题,可以在cmd中进行)
1 | 根据提示设置密码并填入开发者信息,最后输入y确定 |
运行软件,通过环境检查,不输入用户名和密码也能直接进入聊天界面,相较于之前,现在随便发一句话就能获得flag。