Frida —— 初体验
来自于Awesome Frida的介绍
来自于Awesome Frida的介绍
Frida is Greasemonkey for native apps, or, put in more technical terms, it’s a dynamic code instrumentation toolkit. It lets you inject snippets of JavaScript into native apps that run on Windows, Mac, Linux, iOS and Android.
Frida可以认为是原生应用的油猴脚本,或其他更专业的技术术语。它是一种动态插桩工具集,可以将js代码插入到在Windows、Mac、Linux、iOS、Android上运行的原生应用中。
- 比较
| Frida | CydiaSubstrate | Substitute | Detours | Deviare | EasyHook | diStormX | |
|---|---|---|---|---|---|---|---|
| Open Source | ✔️ | ✘ | ✔️ | ✘ | ✔️ | ✔️ | ✔️ |
| Allows use in closed-source software¹ | ✔️ | ✔️ | ✔️ | ✘ | ✘ | ✔️ | ✔️ |
| Windows | ✔️ | ✘ | ✘ | ✔️ | ✔️ | ✔️ | ✔️ |
| Mac | ✔️ | ✘ | ✔️ | ✘ | ✘ | ✘ | ✘ |
| Linux | ✔️ | ✘ | ✘ | ✘ | ✘ | ✘ | ✘ |
| iOS | ✔️ | ✔️ | ✔️ | ✘ | ✘ | ✘ | ✘ |
| Android | ✔️ | ✔️ | ✘ | ✘ | ✘ | ✘ | ✘ |
| QNX | ✔️ | ✘ | ✘ | ✘ | ✘ | ✘ | ✘ |
| x86-32 | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ |
| x86-64 | ✔️ | ✘ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ |
| arm | ✔️ | ✔️ | ✔️ | ✘ | ✘ | ✘ | ✘ |
| arm64 | ✔️ | ✔️ | ✔️ | ✘ | ✘ | ✘ | ✘ |
| MIPS | ✔️ | ✘ | ✘ | ✘ | ✘ | ✘ | ✘ |
| Language bindings | ✔️ | ✘ | ✘ | ✘ | ✔️ | ✘ | ✘ |
| Instruction-level probes | ✔️ | ✘ | ✘ | ✘ | ✘ | ✘ | ✘ |
| Zero-knowledge before/after hooks² | ✔️ | ✘ | ✘ | ✘ | ✔️ | ✘ | ✘ |
| Transactional (batching) | ✔️ | ✘ | ✔️ | ✔️ | ✔️ | ✘ | ✔️ |
| Intelligent relocation³ | ✔️ | ✘ | ✔️ | ✘ | ✘ | ✘ | ✘ |
| Tiny functions (code caves) | ✔️ | ✘ | ✘ | ✘ | ✘ | ✘ | ✘ |
| Rollback | ✔️ | ✘ | ✘ | ✔️ | ✔️ | ✔️ | ✔️ |
0x01 安装
-
安装frida
Terminal window > pip install frida frida-tools -
下载对应版本frida-server,使用adb推送
Terminal window > adb push frida-server /data/local/tmp/ -
root 下执行frida-server
Terminal window > adb shellbullhead:/ $ su -bullhead:/ # cd /data/local/tmpbullhead:/ # chmod +x frida-serverbullhead:/ # ./frida-server
0x02 测试机选择
经测试最好还是使用物理机,x64架构虚拟机上很多app无法安装,arm虚拟机太卡且有时候frida会莫名报错
Android
选用Nexus 5X,刷8.1.0 & Magisk,具体操作可见参考资料1
iOS
待更新
0x0N Crackme
环境
-
主机
- frida
-
手机
- Nexus 5 (with Android 8.1.0) 已 root
- frida-server
注意
需要要注意几点
setImmediate据说可以避免一些执行时间过长问题- 使用
-f参数 新启动并暂时挂起进程,然后待布置好hook代码后再恢复进程运行,配合使用--no-pause取消挂起相当于直接创建一个新进程后进行hook,这里在hook onCreate时会有问题,下面会提到
一些常用命令
安装apk
> adb install UnCrackable-Level1.apk快捷截图
> adb shell screencap -p > `date "+%Y%m%d%H%M%S"`.pngCrack
-
启动后会检测是否Root

-
查看检测代码,将apk拖入到jadx-gui中
public class MainActivity extends Activity {private void a(String str) {AlertDialog create = new Builder(this).create();create.setTitle(str);create.setMessage("This in unacceptable. The app is now going to exit.");create.setButton(-3, "OK", new b(this));create.setCancelable(false);create.show();}protected void onCreate(Bundle bundle) {if (c.a() || c.b() || c.c()) {a("Root detected!");}if (b.a(getApplicationContext())) {a("App is debuggable!");}super.onCreate(bundle);setContentView(R.layout.activity_main);}public void verify(View view) {String obj = ((EditText) findViewById(R.id.edit_text)).getText().toString();AlertDialog create = new Builder(this).create();if (a.a(obj)) {create.setTitle("Success!");create.setMessage("This is the correct secret.");} else {create.setTitle("Nope...");create.setMessage("That's not it. Try again.");}create.setButton(-3, "OK", new c(this));create.show();}} -
这里有两种方法
-
通过所有检测,即Hook掉
c.a&c.b&c.c&b.a -
注意到弹窗的监听类为b,可Hook
b.onClick不执行退出class b implements OnClickListener {final /* synthetic */ MainActivity a;b(MainActivity mainActivity) {this.a = mainActivity;}public void onClick(DialogInterface dialogInterface, int i) {System.exit(0);}}
-
-
先尝试
ii中的Hook b.onClicksetImmediate(function () {Java.perform(function(){cClass = Java.use("sg.vantagepoint.uncrackable1.b");cClass.onClick.implementation = function () {console.log("[!] hook click");}})});注入脚本,点击ok按钮
> frida -U -f sg.vantagepoint.uncrackable1 -l 1.js --no-pause____/ _ | Frida 12.2.29 - A world-class dynamic instrumentation toolkit| (_| |> _ | Commands:/_/ |_| help -> Displays the help system. . . . object? -> Display information about 'object'. . . . exit/quit -> Exit. . . .. . . . More info at http://www.frida.re/docs/home/Spawned `sg.vantagepoint.uncrackable1`. Resuming main thread![LGE Nexus 5X::sg.vantagepoint.uncrackable1]-> [!] Hook click[LGE Nexus 5X::sg.vantagepoint.uncrackable1]-> exitThank you for using Frida! -
尝试
i中Hook onCreate初步尝试在加上
--no-pauseZygote启动后,由于取消挂起这时候代码并没有hook进去,而是在onCreate结束后才开始注入,所以需要去掉--no-pause等待 hook 后恢复进程,会比较耗时,但能正常 hook onCreateTerminal window > frida -U -f package -l script_fileHook脚本
setImmediate(function () {Java.perform(function(){cClass = Java.use("sg.vantagepoint.a.c");cClass.a.implementation = function () {console.log('[!] Hook c.a');return false;};cClass.b.implementation = function () {console.log('[!] Hook c.a');return false;};cClass.c.implementation = function () {console.log('[!] Hook c.c');return false;};bClass = Java.use("sg.vantagepoint.a.b");bClass.a.implementation = function () {console.log('[!] Hook b.a');return false;}})});执行注入,就没有弹窗了
Terminal window > frida -U -f sg.vantagepoint.uncrackable1 -l 1.js____/ _ | Frida 12.2.29 - A world-class dynamic instrumentation toolkit| (_| |> _ | Commands:/_/ |_| help -> Displays the help system. . . . object? -> Display information about 'object'. . . . exit/quit -> Exit. . . .. . . . More info at http://www.frida.re/docs/home/Spawned `sg.vantagepoint.uncrackable1`. Use %resume to let the main thread start executing![LGE Nexus 5X::sg.vantagepoint.uncrackable1]-> [!] Hook c.a[!] Hook c.a[!] Hook c.c[!] Hook b.a[LGE Nexus 5X::sg.vantagepoint.uncrackable1]-> exitThank you for using Frida! -
接下来是一个输入字符串返回比较结果,事件函数为
a.a,重要的是获取bArr,即sg.vantagepoint.a.a.a返回结果public class a {public static boolean a(String str) {byte[] bArr = new byte[0];try {bArr = sg.vantagepoint.a.a.a(b("8d127684cbc37c17616d806cf50473cc"), Base64.decode("5UJiFctbmgbDoLXmpL12mkno8HT4Lv8dlat8FxR2GOc=", 0));} catch (Exception e) {Log.d("CodeCheck", "AES error:" + e.getMessage());}return str.equals(new String(bArr));}public static byte[] b(String str) {int length = str.length();byte[] bArr = new byte[(length / 2)];for (int i = 0; i < length; i += 2) {bArr[i / 2] = (byte) ((Character.digit(str.charAt(i), 16) << 4) + Character.digit(str.charAt(i + 1), 16));}return bArr;}}sg.vantagepoint.a.a.a代码如下,我们不用在意代码内容,只要 hook 结果就好了public class a {public static byte[] a(byte[] bArr, byte[] bArr2) {Key secretKeySpec = new SecretKeySpec(bArr, "AES/ECB/PKCS7Padding");Cipher instance = Cipher.getInstance("AES");instance.init(2, secretKeySpec);return instance.doFinal(bArr2);}}Hook 代码,使用
this.a调用原a函数setImmediate(function () {Java.perform(function(){...aaClass = Java.use("sg.vantagepoint.a.a");aaClass.a.implementation = function (arg1, arg2) {pass = "";s = this.a(arg1, arg2);for(i=0; i<s.length; i++) {pass += String.fromCharCode(s[i]);}console.log("[*] content: " + pass);return s;}})});执行代码,获取隐藏内容
Terminal window > frida -U -f sg.vantagepoint.uncrackable1 -l 1.js --no-pause____/ _ | Frida 12.2.29 - A world-class dynamic instrumentation toolkit| (_| |> _ | Commands:/_/ |_| help -> Displays the help system. . . . object? -> Display information about 'object'. . . . exit/quit -> Exit. . . .. . . . More info at http://www.frida.re/docs/home/Spawned `sg.vantagepoint.uncrackable1`. Resuming main thread![LGE Nexus 5X::sg.vantagepoint.uncrackable1]-> [!] Hook click[*] content: I want to believe[LGE Nexus 5X::sg.vantagepoint.uncrackable1]-> exitThank you for using Frida!