android-app-100-wp
0x00
之前一直没做过真正的apk的题目,今天遇到了。首先有:
在网上搜了搜,直接用jadx反编译,得到:
查了一下,Build.SERIAL这个方法被弃用了,使用手机试了一下,一直显示:
直接看wp,师傅们说发现有native方法之后,看到代码里有System.loadLibrary("adnjni");
,可以猜测到IsCorrect函数定义在了这里面,用ida打开后的确有adnjni.so这样一个文件,发现IsCorrect函数:
猜测要与这个字符串比较,试一试,发现:
还是不行,猜测是那个弃用方法的问题,换个mumu模拟器,得到:
0x01
仔细分析函数流程:
- 得到
int processObjectArrayFromNative
与int this.a.d
,之后计算processObjectArrayFromNative+this.a.d+空格
转字符串的md5值。
- 遍历对上述结果转化成
stringBuffer
然后输出。
分析this.a.processObjectArrayFromNative
函数,可以简化为:
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
| v3 = -1661035768 v25 = 0 v22 = 0 while True: while True: while True: while v3 <= -1303766071: v3 = 2063008300 if v3 > 441419317: break v3 = 1800572839 if not v25: v3 = 441419318
if v3 > 867851767: break v3 = 1405326207 if v3 <= 1405326206: break if v3 == 1405326207: v26 = v22 v3 = 867851768 elif v3 == 1800572839: v22 = 92060626 v3 = 441419318 else: v22 = 0 v3 = -18897425 v25 = 1 print(v26)
|
因此可以写脚本:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| import java.security.MessageDigest; import java.security.NoSuchAlgorithmException;
public class Test { public static void main(String []args) { int v1 = 114366; int v26 = 92060626; String str = String.valueOf(v1 + v26) + " "; try { MessageDigest messageDigest = MessageDigest.getInstance("MD5"); messageDigest.update(str.getBytes()); byte[] digest = messageDigest.digest(); StringBuffer stringBuffer = new StringBuffer(); for (byte b : digest) { stringBuffer.append(Integer.toString((b & 255) + 256, 16).substring(1)); } System.out.println(stringBuffer.toString()); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); }
} }
|
0x02
看别的师傅的frida脚本:
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 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121
| import frida, sys
def on_message(message, data): if message['type'] == 'send': print("[*] {0}".format(message['payload'])) else: print(message)
jscode = """ setImmediate(function () { Java.perform(function () { console.log("start"); //so层hook //导出函数 //var exports = Module.enumerateExportsSync("libadnjni.so"); //for(var i=0;i<exports.length;i++){ // send("name:"+exports[i].name+" address:"+exports[i].address); // } var str = Java.use("java.lang.String"); //遍历模块找基址 // Process.enumerateModules({ // onMatch: function (exp) { // send(exp.name) // if (exp.name == 'libadnjni.so') { // send('enumerateModules find'); // send(exp.name + "|" + exp.base + "|" + exp.size + "|" + exp.path); // send(exp); // return 'stop'; // } // }, // onComplete: function () { // send('enumerateModules stop'); // } // });
//通过模块名直接查找基址 //var soAddr = Module.findBaseAddress("libadnjni.so"); var soAddr = Module.findBaseAddress("libmedia_jni.so"); send("soAddr:" + soAddr);
var parray=0x48c+1; var pcorrect=0x74c+1; // hook导出函数 通过函数名
//Module.findExportByName 找到的函数地址无效 // var farray=Module.findExportByName("libadnjni.so", "Java_com_example_ctf2_MainActivity_processObjectArrayFromNative") // send("findExportByName farray() by Module.findExportByName:" +farray); var farray=new NativePointer(soAddr).add(parray); //NativePointer 简写ptr send("findExportByName farray() by ptr:" +farray );
Interceptor.attach(farray, { onEnter: function (args) { var s = Java.cast(args[2], str); send("array() jstring:" + s ); }, onLeave: function (retval) { send("array() return:" + retval); } });
// hook导出函数 通过函数名 // var fcorrect=Module.findExportByName("libadnjni.so", "Java_com_example_ctf2_MainActivity_IsCorrect"); // send("findExportByName correct() by Module.findExportByName:" +fcorrect ); var fcorrect=new NativePointer(soAddr).add(pcorrect); send("findExportByName correct() by ptr:" +fcorrect ); Interceptor.attach(fcorrect, { onEnter: function (args) { var s = Java.cast(args[2], str); send("fcorrect() jstring:" + s ); }, onLeave: function (retval) { send("fcorrect() return:" + retval); } });
}); }); """
process = frida.get_usb_device().attach(2164) script = process.create_script(jscode) script.on('message', on_message) print('[*] Running test') script.load() sys.stdin.read()
''' [*] Running test start [*] soAddr:0xcd562000 [*] findExportByName farray() by ptr:0xcd56248d [*] findExportByName correct() by ptr:0xcd56274d [*] array() jstring:Serial Number [*] array() return:0x0 [*] fcorrect() jstring:Serial Number [*] fcorrect() return:0x0
[*] array() jstring:ef57f3fe3cf603c03890ee588878c0ec [*] array() return:0x57cbbd2 [*] fcorrect() jstring:ef57f3fe3cf603c03890ee588878c0ec [*] fcorrect() return:0x1 '''
|
没跑出来,主要是没找到libadnjni.so
,很奇怪。
知识点1:
常见的安卓逆向工具
jadx-gui。方便的jadx工具,可以直接反编译apk。
知识点2:
frida 是一款基于 python+javascript 的 hook 框架,可运行在 android、ios、linux、win等各个平台,主要使用的动态二进制插桩技术。
插桩技术是指将额外的代码注入程序中以收集运行时的信息,可分为源代码插桩 SCI 和二进制插桩 BI。
知识点3:adb(android debug)使用
配置查看:https://blog.csdn.net/yi_rui_jie/article/details/115462824
链接mumu模拟器:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| adb connect 127.0.0.1:7555 # 7555为mumu模拟器端口号 adb disconnect 127.0.0.1:7555 # 断开连接 adb shell # 进入shell cat /proc/cpuinfo # adb查看电脑cpu架构 getprop ro.product.cpu.abi # 查看模拟器cpu架构 adb push file /data/local/tmp/ # 将文件push 进手机的指定目录下 adb -s emulator-5554 shell # 多个设备进入某一指定设备 su # 切换获取手机的root权限 adb forward tcp:27042 tcp:27042 # 进行端口转发(新打开一个cmd) adb forward tcp:27043 tcp:27043 # 进行端口转发(新打开一个cmd) frida-ps -U # 查看手机启动的进程(查看到则运行成功,frida安装完毕!) frida-ps -U -a # 不仅输出进程名称,还输出进程的Identifier frida -U -f 进程的Identifier -l xx.js # 将xx.js注入到进程中 adb devices # 查看adb连接的设备 linux 在命令的后面加一个 & 的作用是在后台执行
|