攻防世界 reverse android-app-100

 android-app-100  suctf-2016

jeb启动,找到点击事件:

验证流程:

输入作为参数 --> processObjectArrayFromNative 得到一返回值(ret_a) --> IsCorrect 返回0,失败;返回1,成功 --> 输出"Sharif_CTF("+md5(str(d+ret_a)+” “+”)“      (.d = 0x1BEBE)

可以发现flag的获取关键在于processObjectArrayFromNative 的返回值。

 1 public void onClick(View arg8) {
 2         new String(" ");
 3         String v0 = this.a.b.getText().toString();
 4         Log.v("EditText", this.a.b.getText().toString());
 5         new String("");
 6         int v1 = this.a.processObjectArrayFromNative(v0);
 7         int v2 = this.a.IsCorrect(v0);
 8         v0 = String.valueOf(this.a.d + v1) + " ";
 9         try {
10             MessageDigest v1_1 = MessageDigest.getInstance("MD5");
11             v1_1.update(v0.getBytes());
12             byte[] v1_2 = v1_1.digest();
13             StringBuffer v3 = new StringBuffer();
14             int v0_2;
15             for(v0_2 = 0; v0_2 < v1_2.length; ++v0_2) {
16                 v3.append(Integer.toString((v1_2[v0_2] & 0xFF) + 0x100, 16).substring(1));
17             }
18 
19             if(v2 == 1 && this.a.e != "unknown") {
20                 this.a.c.setText("Sharif_CTF(" + v3.toString() + ")");
21             }
22 
23             if(v2 == 1 && this.a.e == "unknown") {
24                 this.a.c.setText("Just keep Trying :-)");
25             }
26 
27             if(v2 == 0) {
28                 this.a.c.setText("Just keep Trying :-)");
29             }
30 
31             return;
32         }
33         catch(NoSuchAlgorithmException v0_1) {
34             v0_1.printStackTrace();
35             return;
36         }
37     }

程序有两个native方法:

public native int IsCorrect(String arg1)

public native int processObjectArrayFromNative(String arg1)

IDA启动,

发现有混淆,但我们还是能发现这两个native方法中调用了strcmp方法

Java_com_example_ctf2_MainActivity_processObjectArrayFromNative:

 1 ptr_chars = (env_2->functions->GetStringUTFChars)(env_2, jstring_2, 0);
 2           *p_chars = ptr_chars;
 3           temp_chars_ptr = *p_chars;
 4           v46 = &v8;
 5           v51 = 101;
 6           v8 = 926246501;
 7           v52 = 53;
 8           v45 = 55;
 9           v9 = 102;
10           v10 = 51;
11           v11 = 102;
12           v12 = 101;
13           v13 = 51;
14           v44 = 99;
15           v14 = 99;
16           v15 = 102;
17           v16 = 54;
18           v17 = 48;
19           v18 = 51;
20           v19 = 99;
21           v20 = 48;
22           v21 = 51;
23           v22 = 56;
24           v23 = 57;
25           v24 = 48;
26           v25 = 101;
27           v26 = 101;
28           v27 = 53;
29           v28 = 56;
30           v29 = 56;
31           v30 = 56;
32           v31 = 55;
33           v32 = 56;
34           v33 = 99;
35           v34 = 48;
36           v35 = 101;
37           v36 = 99;
38           v50_2 = v50;
39           v38 = 53;
40           v5 = j_strcmp(temp_chars_ptr, &v8);

processObjectArrayFromNative方法返回值:0或者0x57cbbd2

攻防世界 reverse android-app-100

Java_com_example_ctf2_MainActivity_IsCorrect方法内也进行了字符串比较,

通过脚本我们可以获取到进行比较的字符串:

 1 v51 = 'e';
 2 v8 = '75fe'[::-1];
 3 v52 = '5';
 4 v45 = '7';
 5 v9 = 'f';
 6 v10 = '3';
 7 v11 = 'f';
 8 v12 = 'e';
 9 v13 = '3';
10 v44 = 'c';
11 v14 = 'c';
12 v15 = 'f';
13 v16 = '6';
14 v17 = '0';
15 v18 = '3';
16 v19 = 'c';
17 v20 = '0';
18 v21 = '3';
19 v22 = '8';
20 v23 = '9';
21 v24 = '0';
22 v25 = 'e';
23 v26 = 'e';
24 v27 = '5';
25 v28 = '8';
26 v29 = '8';
27 v30 = '8';
28 v31 = '7';
29 v32 = '8';
30 v33 = 'c';
31 v34 = '0';
32 v35 = 'e';
33 v36 = 'c';
34 x=''
35 for i in range(8,37):
36   x+=locals()['v'+str(i)]
37 print(x)
38 print(len(x))
39 
40 v12 = 101;
41 v13 = 102;
42 v14 = 53;
43 v15 = 55;
44 v16 = 102;
45 v17 = 51;
46 v18 = 102;
47 v19 = 101;
48 v20 = 51;
49 v21 = 99;
50 v22 = 102;
51 v23 = 54;
52 v24 = 48;
53 v25 = 51;
54 v26 = 99;
55 v27 = 48;
56 v28 = 51;
57 v29 = 56;
58 v30 = 57;
59 v31 = 48;
60 v32 = 101;
61 v33 = 101;
62 v34 = 53;
63 v35 = 56;
64 v36 = 56;
65 v37 = 56;
66 v38 = 55;
67 v39 = 56;
68 v40 = 99;
69 v41 = 48;
70 v42 = 101;
71 v43 = 99;
72 
73 y=''
74 for i in range(12,44):
75   y+=chr(locals()['v'+str(i)])
76 print(y)
77 print(len(y))
78 
79 
80 '''
81 ef57f3fe3cf603c03890ee588878c0ec
82 32
83 ef57f3fe3cf603c03890ee588878c0ec
84 32
85 '''
View Code

ef57f3fe3cf603c03890ee588878c0ec

运行adb命令输入到编辑框

adb shell input text ef57f3fe3cf603c03890ee588878c0ec

攻防世界 reverse android-app-100

当然也可以静态获取:

1 ret_a=0x57CBBD2
2 d=0x1BEBE
3 d=str(d+ret_a)+' '
4 print(d)
5 import hashlib
6 m=hashlib.md5(d.encode()).hexdigest()
7 print('Sharif_CTF('+m+')')

Sharif_CTF(833489ef285e6fa80690099efc5d9c9d)

(一开始还原算法时得到的结果不对,又写了个frida脚本验证,返回值没问题,后来才发现要md5的字符串忘了加空格 0.0)

frida脚本:

  1 import frida, sys
  2 
  3 
  4 def on_message(message, data):
  5     if message['type'] == 'send':
  6         print("[*] {0}".format(message['payload']))
  7     else:
  8         print(message)
  9 
 10 
 11 jscode = """
 12 setImmediate(function () {
 13     Java.perform(function () {
 14         console.log("start");
 15         //so层hook
 16         //导出函数
 17         //var exports = Module.enumerateExportsSync("libadnjni.so");
 18         //for(var i=0;i<exports.length;i++){
 19         //    send("name:"+exports[i].name+"  address:"+exports[i].address);
 20         // }
 21         var str = Java.use("java.lang.String");
 22         //遍历模块找基址
 23         // Process.enumerateModules({
 24         //     onMatch: function (exp) {
 25         //         if (exp.name == 'libadnjni.so') {
 26         //             send('enumerateModules find');
 27         //             send(exp.name + "|" + exp.base + "|" + exp.size + "|" + exp.path);
 28         //             send(exp);
 29         //             return 'stop';
 30         //         }
 31         //     },
 32         //     onComplete: function () {
 33         //         send('enumerateModules stop');
 34         //     }
 35         // });
 36 
 37         //通过模块名直接查找基址
 38         var soAddr = Module.findBaseAddress("libadnjni.so");
 39         send("soAddr:" + soAddr);
 40 
 41         var parray=0x48c+1;
 42         var pcorrect=0x74c+1;
 43         //   hook导出函数 通过函数名
 44 
 45         //Module.findExportByName 找到的函数地址无效
 46         // var farray=Module.findExportByName("libadnjni.so", "Java_com_example_ctf2_MainActivity_processObjectArrayFromNative")
 47         // send("findExportByName farray() by Module.findExportByName:" +farray);
 48         var farray=new NativePointer(soAddr).add(parray);
 49         //NativePointer   简写ptr
 50         send("findExportByName farray() by ptr:" +farray );
 51 
 52         Interceptor.attach(farray, {
 53             onEnter: function (args) {
 54                 var s = Java.cast(args[2], str);
 55                 send("array()  jstring:" + s );
 56             },
 57             onLeave: function (retval) {
 58                 send("array() return:" + retval);
 59             }
 60         });
 61 
 62         //   hook导出函数 通过函数名
 63         // var fcorrect=Module.findExportByName("libadnjni.so", "Java_com_example_ctf2_MainActivity_IsCorrect");
 64         // send("findExportByName correct()  by Module.findExportByName:" +fcorrect );
 65         var fcorrect=new NativePointer(soAddr).add(pcorrect);
 66         send("findExportByName correct()  by ptr:" +fcorrect );
 67         Interceptor.attach(fcorrect, {
 68             onEnter: function (args) {
 69                 var s = Java.cast(args[2], str);
 70                 send("fcorrect() jstring:" + s );
 71             },
 72             onLeave: function (retval) {
 73                 send("fcorrect() return:" + retval);
 74             }
 75         });
 76         
 77     });
 78 });
 79 """
 80 # print(jscode)
 81 
 82 # 启动时hook   
 83 # devices=frida.get_usb_device()
 84 # pid=devices.spawn(['com.example.goal'])   
 85 # session=devices.attach(pid)
 86 # devices.resume(pid)    #创建完脚本, 恢复进程运行
 87 # script=session.create_script(jscode)
 88 
 89 # 命令行frida -U -f com.example.goal --no-pause -l <hook.js>
 90 
 91 # 运行中hook
 92 process = frida.get_usb_device().attach('com.example.ctf2')
 93 script = process.create_script(jscode)
 94 script.on('message', on_message)
 95 print('[*] Running test')
 96 script.load()
 97 sys.stdin.read()
 98 
 99 # ef57f3fe3cf603c03890ee588878c0ec
100 
101 '''
102 [*] Running test
103 start
104 [*] soAddr:0xcd562000
105 [*] findExportByName farray() by ptr:0xcd56248d
106 [*] findExportByName correct()  by ptr:0xcd56274d
107 [*] array()  jstring:Serial Number
108 [*] array() return:0x0
109 [*] fcorrect() jstring:Serial Number
110 [*] fcorrect() return:0x0
111 
112 
113 [*] array()  jstring:ef57f3fe3cf603c03890ee588878c0ec
114 [*] array() return:0x57cbbd2
115 [*] fcorrect() jstring:ef57f3fe3cf603c03890ee588878c0ec
116 [*] fcorrect() return:0x1
117 '''
View Code