![从0到1:CTFer成长之路](https://wfqqreader-1252317822.image.myqcloud.com/cover/885/35276885/b_35276885.jpg)
4.2 APK逆向工具
本节主要介绍在APK逆向时主要使用的一些逆向工具和模块,好工具能大大加快逆向的速度。针对Android平台的逆向工具有很多,如Apktool、JEB、IDA、AndroidKiller、Dex2Jar、JD-GUI、smali、baksmali、jadx等,本节主要介绍JEB、IDA、Xposed和Frida。
4.2.1 JEB
针对Android平台有许多反编译器,其中JEB的功能最强大。JEB从早期的Android APK反编译器发展到现在,不仅支持Android APK文件反编译,还支持MIPS、ARM、ARM64、x86、x86-64、WebAssembly、EVM等反编译,展示页面和开放接口易用,大大降低了逆向工程的难度,见图4-2-1。
![](https://epubservercos.yuewen.com/80F983/18822093501529406/epubprivate/OEBPS/Images/37695_242_2.jpg?sign=1739131004-vX5qGLROMcjTR85epv3bVsVzmoX6iVhn-0-b4ea99e2ab619b193030780932fe56ec)
图4-2-1
JEB 2.0后增加了动态调试功能,动态调试功能简单易用,容易上手,可以调试任意开启调试模式的APK。
附加调试时,进程标记为D,表示该进程可以被调试,否则说明该进程没有打开调试开关,无法调试,见图4-2-2。
![](https://epubservercos.yuewen.com/80F983/18822093501529406/epubprivate/OEBPS/Images/37695_243_1.jpg?sign=1739131004-oKFhpgK4tmkyrfScLmmvuzpk3tg2Gvkt-0-51c48a544b3246641d989416cf355658)
图4-2-2
打开调试功能后,OSX系统通过Command+B在smali层面上布置断点,右侧VM/局部变量窗口下查看当前位置各寄存器的值,双击能修改任意寄存器值,见图4-2-3。
![](https://epubservercos.yuewen.com/80F983/18822093501529406/epubprivate/OEBPS/Images/37695_243_2.jpg?sign=1739131004-wuSN4cGEw2BJDJ5vxUCLa35Kx0DQWUMz-0-4576866e2f5d550f6bca5d138ccb42f9)
图4-2-3
没有开启调试功能的应用、非Eng版本的Android手机被root后,可能出现无法调试其他应用的情况,这时可以通过Hook系统接口强制开启调试模式来进行,如通过Xposed Hook实现非Eng手机下的JEB动态调试。Hook动态修改debug状态的代码如下:
![](https://epubservercos.yuewen.com/80F983/18822093501529406/epubprivate/OEBPS/Images/37695_244_1.jpg?sign=1739131004-sOigfgYFMcvO2Rm0F5PR5NBzoGO71UIo-0-93e808f6b056e64e5f8854404cc31edb)
强制将PackageManagerService的getPackageInfo函数中应用程序调试Flag改为调试状态,即可强制打开调试模式,在任意root设备中完成动态调试。
4.2.2 lDA
在遇到Native(本地服务)逆向时,IDA优于JEB等其他逆向工具,其动态调试能大大加速Android Native层逆向速度,本节主要介绍如何使用IDA进行Android so Native层逆向。
IDA进行Android Native层调试需要用到IDA自带工具android_server:对于32位Android手机,使用32位版android_server和32位版IDA;对于64位Android手机,使用64位版android_server和64位版IDA,将android_server存至手机目录,且修改权限,见图4-2-4。
![](https://epubservercos.yuewen.com/80F983/18822093501529406/epubprivate/OEBPS/Images/37695_244_2.jpg?sign=1739131004-9EPtPNb4hYVY4kXLho1Qc43QHmF6k48O-0-e0c8b40d1a5f278e0b117451f30edffc)
图4-2-4
IDA调试默认监听23946端口,需要使用adb forward指令将Android端口命令转发至本机:
![](https://epubservercos.yuewen.com/80F983/18822093501529406/epubprivate/OEBPS/Images/37695_244_3.jpg?sign=1739131004-l6MThJJIVYNJSYX7YFEOnCxzxrCJz2y3-0-98063ef72ff43ab8a86679288d35a543)
打开IDA远程ARM/Android调试器,见图4-2-5。
Hostname选择默认的127.0.0.1或本机IP地址,Port选择默认的23946,见图4-2-6。再选择需要调试的应用,见图4-2-7。
![](https://epubservercos.yuewen.com/80F983/18822093501529406/epubprivate/OEBPS/Images/37695_245_1.jpg?sign=1739131004-sxkxHppNGoTON9eKaNnWkgvTfudPExOG-0-794bee10e4b1baace5659c2e10f22e2e)
图4-2-5
![](https://epubservercos.yuewen.com/80F983/18822093501529406/epubprivate/OEBPS/Images/37695_245_2.jpg?sign=1739131004-RXldaG9KD9iEUSbVtZFCaBphuW6a1viG-0-26339d47a23d73d2137e1a6bd02ba648)
图4-2-6
进入IDA主页面后选择modules,找到该进程对应的native层so,见图4-2-8。
双击进入该so对应的导出表,找到需要调试的Native函数(见图4-2-9),然后双击进入函数页面,在主页面下断点、观察寄存器变化(见图4-2-10)。
某些Native函数(JNI_OnLoad、init_array)在so加载时会默认自动执行,对于这类函数无法直接使用上述方式进行调试,需要在动态库加载前断下,所有动态库都是通过linker加载,所以需要定位到linker中加载so的起始位置,然后在linker初始化该so时进入。
4.2.3 Xposed Hook
Xposed是一款在root设备下可以在不修改源码的情况下影响程序运行的Android Hook框架,其原理是将手机的孵化器zygote进程替换为Xposed自带的zygote,使其在启动过程中加载XposedBridge.jar,模块开发者可以通过JAR提供的API来实现对所有Function的劫持,在原Function执行的前后加上自定义代码。Xposed Hook的步骤如下。
<1>在AndroidManifest.xml中的application标签内添加Xposed相关的meta-data:
![](https://epubservercos.yuewen.com/80F983/18822093501529406/epubprivate/OEBPS/Images/37695_245_3.jpg?sign=1739131004-Yhu3PFLaBhbuwQGnevADiOjaUMZpSDJA-0-7708b94b77d2c196a0324a1c58915215)
![](https://epubservercos.yuewen.com/80F983/18822093501529406/epubprivate/OEBPS/Images/37695_246_1.jpg?sign=1739131004-KawSkhXeCz5LNgcdILiHsDFsr6tCntvK-0-7ee5e6344629bbc812cbe9ed6515b20d)
图4-2-7
![](https://epubservercos.yuewen.com/80F983/18822093501529406/epubprivate/OEBPS/Images/37695_246_2.jpg?sign=1739131004-uq64mPiyNZbumqph8sbBthR6QdYgF0YV-0-1a3f657addd719fae7b8896f48c201bd)
图4-2-8
![](https://epubservercos.yuewen.com/80F983/18822093501529406/epubprivate/OEBPS/Images/37695_246_3.jpg?sign=1739131004-sDD6YZ19ZnXlRlcEhbZZKSn7GpklmlRK-0-150264fdce50efaa749e45838502a393)
图4-2-9
![](https://epubservercos.yuewen.com/80F983/18822093501529406/epubprivate/OEBPS/Images/37695_247_1.jpg?sign=1739131004-90XvPKFrlO1cZtOvGbdOip3rBdFhvEBz-0-0a427e9f02277903c7d0095d3ba4494c)
图4-2-10
![](https://epubservercos.yuewen.com/80F983/18822093501529406/epubprivate/OEBPS/Images/37695_247_2.jpg?sign=1739131004-6wck9w1eXPOX4m7AzPZSmmhCxPZQ18LG-0-adb28307c96b19a869a76230c09f71c8)
其中,xposedmodule表示这是一个Xposed模块,xposeddescription描述该模块的用途,可以引用string.xml中的字符串,xposedminversion是要求支持的Xposed Framework最低版本。
<2>导入XposedBridgeApi jar包。在Android studio中修改app/build.gradle,添加如下内容:
![](https://epubservercos.yuewen.com/80F983/18822093501529406/epubprivate/OEBPS/Images/37695_247_3.jpg?sign=1739131004-mQ9ee8jAvbGMkEp33n6ALZ18mD5zdqey-0-a201c460cd6b289ade0d2859940c2737)
sync后,即可完成导入。
<3>编写Hook代码:
![](https://epubservercos.yuewen.com/80F983/18822093501529406/epubprivate/OEBPS/Images/37695_247_4.jpg?sign=1739131004-7RxWjwmfBf1ta4PZAXJc1ja0Af2ISCPq-0-3dbedc9a958c850c83263638d5e40c4e)
<4>声明Xposed入口。新建assets文件夹,并创建xposed_init文件,从中填写Xposed模块入口类名,如上述代码对应的类名为com.test.ctf.CTFDemo。
<5>激活Xposed模块。在Xposed应用中激活模块并且重启,即可观察Hook后的效果。
4.2.4 Frida Hook
Frida是一款跨平台的Hook框架,支持iOS、Android。对于Android应用,Frida不仅能Hook Java层函数,还能Hook Native函数,能大大提高逆向分析的速度。Frida的安装过程见官方文档,不再赘述,下面主要介绍Frida使用的技巧。
①Hook Android Native函数:
![](https://epubservercos.yuewen.com/80F983/18822093501529406/epubprivate/OEBPS/Images/37695_248_1.jpg?sign=1739131004-2Lco3g4ziRNqOSI9QxAJkigIPk2wlBqs-0-28789d99b5feb2efe0d88bfd3f844b0d)
②Hook Android Java函数:
![](https://epubservercos.yuewen.com/80F983/18822093501529406/epubprivate/OEBPS/Images/37695_248_2.jpg?sign=1739131004-4G1DHG36yMvPHb3Nhg5JyZ7XUUvG9SQi-0-1d9752e300a5f11acd40bb3bf625db12)
③通过__fields__获取类成员变量:
![](https://epubservercos.yuewen.com/80F983/18822093501529406/epubprivate/OEBPS/Images/37695_248_3.jpg?sign=1739131004-0vTR8GZRwAkkYSEu6lpbJCIiTe0pUisk-0-f66dfa63576f78b0874fd65d87f082a7)
④Native层下获取Android jni env:
![](https://epubservercos.yuewen.com/80F983/18822093501529406/epubprivate/OEBPS/Images/37695_248_4.jpg?sign=1739131004-IgkFSRpQd8X4Xq4vXGL4EyMGMfz3zXo4-0-916b3c1d002529afaff81c54063ae141)
⑤Java层获取类的field字段:
![](https://epubservercos.yuewen.com/80F983/18822093501529406/epubprivate/OEBPS/Images/37695_248_5.jpg?sign=1739131004-M9W5HG5GYUNR2CeOOxpheYbXETIxRI38-0-61568a5f76100d54a8c0137e6b451aa1)
⑥获取Native特定地址:
![](https://epubservercos.yuewen.com/80F983/18822093501529406/epubprivate/OEBPS/Images/37695_248_6.jpg?sign=1739131004-Jt4rGk4Mg2eKJDbCFYBC0J7DxUJMESsx-0-3154df6bee87021be18af4eb4e87806b)
⑦获取app context:
![](https://epubservercos.yuewen.com/80F983/18822093501529406/epubprivate/OEBPS/Images/37695_248_7.jpg?sign=1739131004-5NMZCi5RJehac2k80RfAzv94fJTTawpF-0-517ef5af402f519582aebd5ffa5be01c)
Frida需要在root环境下使用,但是提供了一种不需root环境的代码注入方式,通过反编译,在被测应用中注入代码,使其在初始化时加载Frida Gadget相关so,并且在lib目录下存放配置文件libgadget.config.so,说明动态注入的JS代码路径。重打包应用后,即可实现不需root的Frida Hook功能。