OWASP UnCrackable App分析 2018-09-22 05:32:39 Steven Xeldax 这次练习的是owasp出的三道安卓crackme破解,这三道题具有一定的代表意义,下载地址为: https://github.com/OWASP/owasp-mstg/tree/master/Crackmes ### UnCrackable App for Android Level 1 首先对UnCrackable-Level1.apk包进行静态分析,发现没有NDK,只有java层代码。界面输入的flag传入到verfiy函数进行校验,代码如下所示:  可以看到只要a.a(obj)结果为true则flag正确。 a.a函数如下:  我们输入的内容要和AES解密出来的内容相同。 其中b(str2)为密钥,5UJiFctbmgbDoLXmpL12mkno8HT4Lv8dlat8FxR2GOc=为解密数据。将代码拖入到eclipse跑一遍就可以得到结果。 > FLAG: I want to believe 此外可以使用动态调试来dump出flag,在做本题的时候也是采用调试得到flag,并没有静态跑flag。 由于UnCrackable全系列都有做反调试和检测root,所以我们必须要将这些检验函数给过掉。过掉的思路有两种,一种是rePack我们的apk包,第二种是在java无源码调试的时候跳过检验逻辑过程。 分析代码发现如下为反调试和检测逻辑。  检测的逻辑只在onCreate时候进行。  只要删掉 ``` if (c.a() || c.b() || c.c()) { a("Root detected!"); } if (b.a(getApplicationContext())) { a("App is debuggable!"); } ``` 代码就可以。 调试的时候有两种,一种是rePack的时候把AndroidMainfest.xml中debugable加上,一种是root下默认adb root后可以进行debug。由于对res进行反编译出现了错误,所以最后我选择的是第二种。 adb以debug启动app,然后打开ddms,在android studi选择remote连接8700端口后开始调试。 ### UnCrackable App for Android Level 2 分析app发现NDK代码,如下:  OnCreate逻辑如下:  其中init()到this.m=new CodeCheck()之间全部是安全检验检测,将代码注释rePack掉即可。 分析libfoo.so中的init函数和bar函数。  Init中调用了sub_820来进行so的反调试。  可以看到sub_820中fork了进程来利用ptrace(PTRACE_ATTACH, v0, 0, 0)实时检测自己的有没有被attach,如果被检测到则程序会被退出。 没有检测到调试后设置 byte_3008 = 1;然后return。 分析bar函数  可以看到清楚的看到flag了,就是Thanks for all the fish,那么不用调试直接输入flag即可。 ### UnCrackable App for Android Level 3 分析app中onCreate函数  ``` new AsyncTask<Void, String, String>() { protected String doInBackground(Void... voidArr) { while (Debug.isDebuggerConnected() == null) { SystemClock.sleep(100); } return null; } protected void onPostExecute(String str) { MainActivity.this.showDialog("Debugger detected!"); System.exit(null); } }.execute(new Void[]{null, null, null}); if (RootDetection.checkRoot1() || RootDetection.checkRoot2() || RootDetection.checkRoot3() || IntegrityCheck.isDebuggable(getApplicationContext()) || tampered != 0) { showDialog("Rooting or tampering detected."); } ``` 上述安全检测代码以及verifyLibs();函数注释掉然后rePack包。 分析libfoo.so  发现还是多了很多函数。 So层面做了很多的安全检测,主要函数的运行流程如下: 1. 加载SO 2. Init段中执行sub_2CC8 3. pthread_create((pthread_t *)&v1, 0, (void *(*)(void *))sub_2C0C, 0);调用sub_2CC8 4. sub_2CC8检测系统是否存在frida和xposed,如果存在执行goodbye raise异常直接apk奔溃 5. apk onCreate时候调用init,native执行init,调用sub_2D30();进行反调试然后初始化java层传入的xor密钥。 6. java层触发onClick调用了bar进行flag校验,函数满足dword_7044 == 2进行校验逻辑,sub_E80((int)&v11);初始化v11后于init中初始化的byte_7028进行异或,结果为flag。 分析bar发现输入数据长度为24  sub_E80(int a1)的逻辑极为复杂,只能建议动态获取v11。 动态调式breakpoint建议如下:   最后获取到flag为making owasp greate again 当然其实只要把v11给获取出来后就不用调试,直接跑一边flag即可。 V11=” 1d0811130f1749150d0003195a1d1315080e5a0017081314” ``` secret = "1d0811130f1749150d0003195a1d1315080e5a0017081314".decode("hex") xorkey = "pizzapizzapizzapizzapizz" def xor_strings(xs, ys): return "".join(chr(ord(x) ^ ord(y)) for x, y in zip(xs, ys)) user_input = xor_strings(secret,xorkey) print "The secret is: " + user_input ```