我去年看 RadareCon 的时候,我学习了一个动态二进制插桩框架 Frida 。而且,最初看起来仅仅是有意思的东西,其实是很有趣的。还记得在游戏里的上帝模式么?在原生应用中使用 Frida 就是这样的一种感觉。这是一篇介绍如何使用 Frida 来操作 Android apps 的文章。
什么是动态二进制插桩?
动态二进制插桩(Dynamic Binary Instrumentation)意味着我们要在已经存在(或者运行)的二进制文件中注入外部代码来使得它们去做一些它们之前没有做的事情。它并不需要我们写 exp,因为代码注入的发生并不依赖于你是否已经找到了漏洞。它也并不是在debugging,因为我们并不需要使用 debugger 调试 binary,但是我们仍然可以做一些类似的事情。那么我们可以使用 DBI 做什么呢?有以下一些炫酷的事情:
• 访问进程内存
• 在应用运行的时候覆盖函数
• 调用导入的类中的函数
• 寻找堆上的对象实例,并且利用它们
• Hook,记录以及拦截函数等等
当然你也可以利用 debugger 来做上面的这些事情,但是却会遇到一系列的问题。例如,在 Android 中,你需要反汇编并且重新编译一个应用之后,它才可以被 debug。一些 app 还会检测,并且会试图阻止 debugger,因此,你还要去想办法跳出对应的逻辑。当然,这是很有可能的,但是确实比较麻烦的。使用 Frida 的 DBI 使得我们不需要知道其中的细节就可以快速开始。
Frida
Frida 允许你将 JavaScript 的部分代码或者你自己的库注入到 windows、macos、linux、iOS、Android,以及 QNX 的原生应用中。它最初是基于 Google 的 V8 Javascript runtime,到了版本 9 之后,Frida就开始使用内部的 Duktape 了。但在你需要的情况下,你仍然可以切换到 V8。Frida 有很多模式的操作来和二进制文件进行交互(也有可能在没有 root 的设备上的 app 中插桩),但是在这里我们就是举一些常用的例子,并且不关心内部的情况。
首先,你需要如下软件:
-
Frida。在这个教程中我是用的是9.1.16版本
-
一个 release page 上的 Frida-server 可执行文件(在写这篇文章的时候,我使用的是 frida-server-9.1.16-android-arm.xz,这个可执行文件的版本应该和你的 Frida 版本匹配)
-
一个安卓模拟器或者被 root 的设备。Frida 是在 Android4.4 上开发的,但它应该也会支持之后的版本。我在这篇教程中成功地在 Android7.1.1 中使用了它。对于第二部分的 crackme,我们无论如何也需要 Android4.4 之后的版本。
同样,我假设你已经有了一个 linux 为主机的操作系统。当然,如果你正在使用 windows 或者 mac,你需要调整一下命令。
如果你想要跟着我在第二部分的讲解中解决 OWASP中的Unbreakable Crackme Level 1,你应该也需要下载:
-
OWASP Uncrackable Crackme Level 1(APK)
-
BytecodeViewer
-
dex2jar
Frida 提供了一系列的 API 以及方法来开始你的旅程。你可以使用命令行窗口或者像 frida-trace 的记录 low-level 函数(例如 libc.so 中的'open'调用)的工具来快速运行。你可以使用C,NodeJs或者Python绑定来完成更加复杂的工作。Frida 在内部使用了很多 JavaScript 语言,因此很多时候你可能都需要和这个语言打交道。因此,如果你也像我一样总是有点不喜欢 JavaScript (除了它的 XSS capabilities),Frida 就是一个你需要熟悉它的理由。
如果你还没有安装 Frida,那就使用下面的方法来安装(当然你也可以根据 README 采用其他的方法来安装):
pip install frida
npm install frida
然后启动你的模拟器或者连接到你的设备,并且确保 adb 可以运行,之后列出你的设备:
michael@sixtyseven:~$ adb devices
List of devices attached
emulator-5556 device
然后安装 frida-server。从压缩包中提取对应的文件,并把它 push 到设备上:
adb push /home/michael/Downloads/frida-server-9.1.16-android-arm /data/local/tmp/frida-server
使用设备的 adb 来打开一个 shell,并且切换到 root 状态,然后启动 frida
adb shell
su cd /data/local/tmp
chmod 755 frida-server
./frida-server
Note1
:
在另外一个终端中,一个正常的 OS 的 shell,检查 frida 是否正在运行,并且列出在 Android 上的进程
frida-ps -U
-U 代表着 USB,并且让 Frida 检查 USB-Device,但是使用模拟器也会有这样的效果,你会得到类似于下面的结果
michael@sixtyseven:~$ frida-ps -U
PID Name ---- --------------------------------------------------
696 adbd
5828 android.ext.services
6188 android.process.acore
5210 audioserver
5211 cameraserver
8334 com.android.calendar
6685 com.android.chrome
6245 com.android.deskclock
5528 com.android.inputmethod.latin
6120 com.android.phone
6485 com.android.printspooler
8355 com.android.providers.calendar
5844 com.android.systemui
7944 com.google.android.apps.nexuslauncher
6416 com.google.android.gms
[...]
你可以看到进程号 id(PID),以及正在运行的程序的名字。利用 Frida,你现在就可以 hook 其中任意一个进程,并且开始进行修改。
例如:你可以追踪 Chrome 的某些调用(如果它还没有运行的话,请记得先启动chrome)。
frida-trace -i "open" -U com.android.chrome
然后你会得到如下的结果
michael@sixtyseven:~$ frida-trace -i open -U -f com.android.chrome
Instrumenting functions...
open: Loaded handler at "/home/michael/__handlers__/libc.so/open.js"
Started tracing 1 function. Press Ctrl+C to stop.
/* TID 0x2740 */
282 ms open(pathname=0xa843ffc9, flags=0x80002)
/* TID 0x2755 */
299 ms open(pathname=0xa80d0c44, flags=0x2)
/* TID 0x2756 */
309 ms open(pathname=0xa80d0c44, flags=0x2)
/* TID 0x2740 */
341 ms open(pathname=0xa80d06f7, flags=0x2)
592 ms open(pathname=0xa77dd3bc, flags=0x0)
596 ms open(pathname=0xa80d06f7, flags=0x2)
699 ms open(pathname=0xa80d105e, flags=0x80000)