![从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=1738857916-PuTY54ojRIjh2QibW7Hn6GmQP0egpFaI-0-7171ba78b6e81892f072ec2c92f7d429)
图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=1738857916-FJFZQIxDzhK4vMjjotwtaqyJ0R0BgVkD-0-539f88ec8e4c2e17dfe12710f254991f)
图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=1738857916-xfBQmGcZw2EJ3gPO9DflLX0rTvCxvmbl-0-41c9c86cbce065478b9f98ff2450fe3c)
图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=1738857916-1h3SjJB5owXDNPpAqRBuphYtCBo1Bunn-0-5ea92b2909a62ec4edf6e98594f9f449)
强制将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=1738857916-d9ETvvUDXG4xL7F6biB5eRyFevWpwh6n-0-8564c249cbfba990238bb41864c4a129)
图4-2-4
IDA调试默认监听23946端口,需要使用adb forward指令将Android端口命令转发至本机:
![](https://epubservercos.yuewen.com/80F983/18822093501529406/epubprivate/OEBPS/Images/37695_244_3.jpg?sign=1738857916-duhMPUaLlgOfZzntA1XMSeRnKNZy2H3S-0-326c3900c3fa72830b4ef7a72009219c)
打开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=1738857916-OrbaUtkoVa0IdyYKgJURNCitAOu9k83k-0-c4f22d33644d187ba541418113fa025c)
图4-2-5
![](https://epubservercos.yuewen.com/80F983/18822093501529406/epubprivate/OEBPS/Images/37695_245_2.jpg?sign=1738857916-IpFmaeo1G6efV3kRxVORI6Oy9SAxThqP-0-b2580f9a1c3aa96afc04fa0ab58f2fd5)
图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=1738857916-4Nvrau8yj3Rt8jCgc4uPpnwwP2Od5BQf-0-51394c6948c8847a393b9e4f0931de5d)
![](https://epubservercos.yuewen.com/80F983/18822093501529406/epubprivate/OEBPS/Images/37695_246_1.jpg?sign=1738857916-SFXKmSLqKbB9K6tHN4cHSrZcTLWPTTBV-0-91d44c586355a0e1b5d03bb23bd35cf7)
图4-2-7
![](https://epubservercos.yuewen.com/80F983/18822093501529406/epubprivate/OEBPS/Images/37695_246_2.jpg?sign=1738857916-RtGOlffutvlLeNhekV1ue2i0JSxpczPg-0-8ed18a06ea6bd4960fc44e54cfaa5789)
图4-2-8
![](https://epubservercos.yuewen.com/80F983/18822093501529406/epubprivate/OEBPS/Images/37695_246_3.jpg?sign=1738857916-YWfQL7SUSSnslgv9nPF2QQQnPkg4cBrI-0-a766a92c77ddad42ad7d4c8cd539f548)
图4-2-9
![](https://epubservercos.yuewen.com/80F983/18822093501529406/epubprivate/OEBPS/Images/37695_247_1.jpg?sign=1738857916-Cxhir9jxOVhB1NFhKbKietMxPJXsrvnb-0-0ef222f15ed310c79e3f8a3a5efb591f)
图4-2-10
![](https://epubservercos.yuewen.com/80F983/18822093501529406/epubprivate/OEBPS/Images/37695_247_2.jpg?sign=1738857916-eBfvbQthXMHSjd06s6wugojKNzS3NihJ-0-2f338b76bc90d84854458788b46760d1)
其中,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=1738857916-73ClQgF2pzpOuHPRWsjoeJEnVq96NAjx-0-cb82417ab9e1399f0f7e17d33836ba54)
sync后,即可完成导入。
<3>编写Hook代码:
![](https://epubservercos.yuewen.com/80F983/18822093501529406/epubprivate/OEBPS/Images/37695_247_4.jpg?sign=1738857916-iEDvbyNXOWEcCcv3Ofx0SJDmmv1Rxeyp-0-bd6ec43f70b70433381cdb37318b16a2)
<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=1738857916-znB8wE26WNkpjmohnOJCXgqVCRGQC0wx-0-505b07ae9adeb38db5e8d0fa2c9d82e5)
②Hook Android Java函数:
![](https://epubservercos.yuewen.com/80F983/18822093501529406/epubprivate/OEBPS/Images/37695_248_2.jpg?sign=1738857916-HkD3dN4k99YVzu7yNkiZwWSVaja52nkF-0-b18c4c65f56800e0d7e84017e0903d5b)
③通过__fields__获取类成员变量:
![](https://epubservercos.yuewen.com/80F983/18822093501529406/epubprivate/OEBPS/Images/37695_248_3.jpg?sign=1738857916-wu8HtOPeu7GVrz4HoiHBHICJjDUHQOjS-0-e6843d967825a9d40713c2b3d4a70959)
④Native层下获取Android jni env:
![](https://epubservercos.yuewen.com/80F983/18822093501529406/epubprivate/OEBPS/Images/37695_248_4.jpg?sign=1738857916-kKT0LnrAMkdire0isCROmlBKoMBcMgFr-0-e11a0276cfbb48609513d479fa8bd1df)
⑤Java层获取类的field字段:
![](https://epubservercos.yuewen.com/80F983/18822093501529406/epubprivate/OEBPS/Images/37695_248_5.jpg?sign=1738857916-KvOMz9pVQaGwT1UP0QP9uxOeDMzfxxzD-0-fb98390cace50d41ee11a72786d9358f)
⑥获取Native特定地址:
![](https://epubservercos.yuewen.com/80F983/18822093501529406/epubprivate/OEBPS/Images/37695_248_6.jpg?sign=1738857916-e9WYNi1PYP8dkXSeE1DJpynt01NYNuDu-0-f788870225b0d2c2df9ca53fbb0d3b55)
⑦获取app context:
![](https://epubservercos.yuewen.com/80F983/18822093501529406/epubprivate/OEBPS/Images/37695_248_7.jpg?sign=1738857916-e3DtiHmJtoUnPkgVc4JBMQi9QR44rw8M-0-29c465e367a8115fa6be217280468ec1)
Frida需要在root环境下使用,但是提供了一种不需root环境的代码注入方式,通过反编译,在被测应用中注入代码,使其在初始化时加载Frida Gadget相关so,并且在lib目录下存放配置文件libgadget.config.so,说明动态注入的JS代码路径。重打包应用后,即可实现不需root的Frida Hook功能。