来自于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
> pip install frida frida-tools
下载对应版本frida-server,使用adb推送
> adb push frida-server /data/local/tmp/
root 下执行frida-server
> adb shell bullhead:/ $ su - bullhead:/ # cd /data/local/tmp bullhead:/ # chmod +x frida-server bullhead:/ # ./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"`.png
Crack
启动后会检测是否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.onClick
setImmediate(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]-> exit Thank you for using Frida!
尝试
i
中Hook onCreate
初步尝试在加上
--no-pause
Zygote启动后,由于取消挂起这时候代码并没有hook进去,而是在onCreate
结束后才开始注入,所以需要去掉--no-pause
等待 hook 后恢复进程,会比较耗时,但能正常 hook onCreate> frida -U -f package -l script_file
Hook脚本
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; } }) });
执行注入,就没有弹窗了
> 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]-> exit Thank 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; } }) });
执行代码,获取隐藏内容
> 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]-> exit Thank you for using Frida!