了解了Frida基本使用方法 之后,下面对Frida进行一些实践。 首先下载crackme1 ,安装到模拟器上并运行:
点击OK就会退出程序。将APK用JEB打开,查看MainActivity类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 package sg.vantagepoint.uncrackable1;import android.app.Activity;import android.app.AlertDialog$Builder;import android.app.AlertDialog;import android.content.Context;import android.os.Bundle;import android.view.View;import sg.vantagepoint.a.c;public class MainActivity extends Activity { public MainActivity () { super (); } private void a (String arg5) { AlertDialog v0 = new AlertDialog$Builder(((Context)this )).create(); v0.setTitle(((CharSequence)arg5)); v0.setMessage("This in unacceptable. The app is now going to exit." ); v0.setButton(-3 , "OK" , new b(this )); v0.setCancelable(false ); v0.show(); } protected void onCreate (Bundle arg2) { if ((c.a()) || (c.b()) || (c.c())) { this .a("Root detected!" ); } if (sg.vantagepoint.a.b.a(this .getApplicationContext())) { this .a("App is debuggable!" ); } super .onCreate(arg2); this .setContentView(2130903040 ); } public void verify (View arg5) { String v0 = this .findViewById(2131230720 ).getText().toString(); AlertDialog v1 = new AlertDialog$Builder(((Context)this )).create(); if (a.a(v0)) { v1.setTitle("Success!" ); v1.setMessage("This is the correct secret." ); } else { v1.setTitle("Nope..." ); v1.setMessage("That\'s not it. Try again." ); } v1.setButton(-3 , "OK" , new sg.vantagepoint.uncrackable1.c(this )); v1.show(); } }
程序onCreate就会对设备的root权限进行检查,如果已root则退出。按照之前的思路是将APK用baksmali反汇编,修改代码来解决,现在采用Frida方式来进行解决。 查看sg.vantagepoint.a.c
类,里面都是与root权限相关的检查。可以通过覆盖这些方法让它们返回false,但是用命令启动脚本:
1 2 3 $ frida -U -l checkroot.js -f sg.vantagepoint.uncrackable1 --no-pause ... Process terminated
检测root权限的方法在代码注入之前就执行了,注入没有起到应有的作用。 另一种方法是,先启动应用程序,当检测到了root权限,hook MainActivity中对话框调用的方法:
1 2 3 4 5 6 7 8 private void a (String arg5) { AlertDialog v0 = new AlertDialog$Builder(((Context)this )).create(); v0.setTitle(((CharSequence)arg5)); v0.setMessage("This in unacceptable. The app is now going to exit." ); v0.setButton(-3 , "OK" , new b(this )); v0.setCancelable(false ); v0.show(); }
对话框方法的代码如下:
1 2 3 4 5 6 7 8 9 class b implements DialogInterface $OnClickListener { b(MainActivity arg1) { this .a = arg1; super (); } public void onClick (DialogInterface arg2, int arg3) { System.exit(0 ); } }
点击对话框的OK就会调用onClick里的System.exit(0)
,退出程序。为了防止应用程序退出,hook这个onClick方法:
1 2 3 4 5 6 7 8 9 10 11 setImmediate(function ( ) { console .log("[*] Starting script" ); Java.perform(function ( ) { bClass = Java.use("sg.vantagepoint.uncrackable1.b" ); bClass.onClick.implementation = function (v ) { console .log("[*] onClick called" ); } console .log("[*] onClick handler modified" ) }); });
这里将onClick方法重写为只打印消息不退出程序,打开应用,注入脚本:
1 2 3 $ frida -U -l uncrackable1.js sg.vantagepoint.uncrackable1 ... [*] onClick handler modified
注入需要几秒钟的时间,注入完成后点击OK,程序就不会退出了: 下面就要找出需要的密码,即找到加密/解密例程以及结果和输入的对比。MainActivity中有一个verify
函数,它调用了sg.vantagepoint.uncrackable1.a
类的a
方法:
1 2 3 4 if (a.a(v0)) { v1.setTitle("Success!" ); v1.setMessage("This is the correct secret." ); }
下面是sg.vantagepoint.uncrackable1.a
类的反编译结果:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 public class a { public static boolean a (String arg6) { byte [] v0; String v2 = "8d127684cbc37c17616d806cf50473cc" ; byte [] v3 = Base64.decode("5UJiFctbmgbDoLXmpL12mkno8HT4Lv8dlat8FxR2GOc=" , 0 ); new byte [0 ]; try { v0 = sg.vantagepoint.a.a.a(a.b(v2), v3); } catch (Exception v2_1) { Log.d("CodeCheck" , "AES error:" + v2_1.getMessage()); } boolean v0_1 = arg6.equals(new String(v0)) ? true : false ; return v0_1; } public static byte [] b(String arg7) { int v1 = 16 ; int v2 = arg7.length(); byte [] v3 = new byte [v2 / 2 ]; int v0; for (v0 = 0 ; v0 < v2; v0 += 2 ) { v3[v0 / 2 ] = ((byte )((Character.digit(arg7.charAt(v0), v1) << 4 ) + Character.digit(arg7.charAt(v0 + 1 ), v1))); } return v3; } }
a
方法的最后,arg6.equals
比较输入的字符串和String(v0)
是否相等,v0是sg.vantagepoint.a.a
类的a
方法返回的值(字节数组的形式),所以要知道正确的输入,只要hook a
方法,将其返回值转换为可读字符串并打印到控制台即可。
1 2 3 4 5 6 7 8 9 10 11 aaClass = Java.use("sg.vantagepoint.a.a" ); aaClass.a.implementation = function (arg1, arg2 ) { retval = this .a(arg1, arg2); password = '' ; for (i = 0 ; i < retval.length; i++) { password += String .fromCharCode(retval[i]); } console .log("[*] Decrypted: " + password); return retval; } console .log("[*] sg.vantagepoint.a.a.a modified" );
将上述代码和之前的代码放到一起组成完整的脚本后运行,等到代码注入成功,点击Root Detected对话框OK按钮,在文本框中随意输入字符,点击VERIFY按钮:
1 2 3 4 5 6 $ frida -U -l uncrackable1.js sg.vantagepoint.uncrackable1 ... [*] onClick handler modified [*] sg.vantagepoint.a.a.a modified [*] onClick called [*] Decrypted: I want to believe
控制台上即可看到所需的正确输入:I want to believe
。将字符串输入文本框中:reference http://bobao.360.cn/learning/detail/3634.html