1.环境
夜深模拟器6.5.0.3
ApkIDE3.5.0
UnCrackable-Level1.apk
2.安装APK
adb install UnCrackable-Level1.apk
运行apk
运行提示检测root权限
开始干掉root检测
3.反编译APK
使用ApkIDE打开APK
查看java代码
在onCreate()方法中,使用c中的a、b、c来检测root
a、b、c3个方法来检测root
4.patch root
修改3个方法的返回,使其一直为false
c的smali代码

当检测到不是root权限,就返回v0 我们就让他总是返回v0
const/4 v0, 0x0
这样就返回v0了
把a b c3个方法都改了
保存smali代码 重新编译apk
5.解题
删除原来的apk 安装新编译的apk
没有root检测了
随便输入内容
有个弹窗,尝试搜索字符串 看看有什么逻辑可绕过
如果代码量过大的话,我们可以通过adb shell dumpsys activity top | findstr ACTIVITY定位要找的界面的代码。
用jd-gui打开MainActivity 

发现a.a()中调用了加密的算法,之后将用户输入的值也就是arg5与加密后的结果进行比对,若比对成功的话,就说明我们输入的是正确的。明显这个crackme的意图不是要我们patch源代码然后得到弹窗Success, 而是获得flag, 也就是密文5UJiFctbmgbDoLXmpL12mkno8HT4Lv8dlat8FxR2GOc=解密后的结果。
CTF解题法
可以使用动态和静态两种方法获得明文, 用openssl和硬编码在源码中的密钥8d127684cbc37c17616d806cf50473cc解密5UJiFctbmgbDoLXmpL12mkno8HT4Lv8dlat8FxR2GOc=。
通过代码我们可以知道AES算法使用了ECB加密模式, 且在CTF中AES-128加密算法的密钥一般为32位, 输入命令echo 5UJiFctbmgbDoLXmpL12mkno8HT4Lv8dlat8FxR2GOc= | openssl enc -aes-128-ecb -base64 -d -nopad -K 8d127684cbc37c17616d806cf50473cc可获取flagI want to believe。


Xposed解法
不太理解 先把代码贴上
package com.example.unlock;import android.util.Log;import de.robv.android.xposed.IXposedHookLoadPackage;import de.robv.android.xposed.XC_MethodHook;import de.robv.android.xposed.XC_MethodReplacement;import de.robv.android.xposed.XposedBridge;import de.robv.android.xposed.XposedHelpers;import de.robv.android.xposed.callbacks.XC_LoadPackage;import static de.robv.android.xposed.XposedHelpers.findAndHookMethod;public class HookMain implements IXposedHookLoadPackage {public void handleLoadPackage(XC_LoadPackage.LoadPackageParam lpparam) throws Throwable {if(!lpparam.packageName.equals("owasp.mstg.uncrackable1")) //过滤包名return;XposedBridge.log("Loaded app: " + lpparam.packageName); //Hook a方法try {XposedHelpers.findAndHookMethod("sg.vantagepoint.a.a", lpparam.classLoader, "a", byte [].class, byte [].class, new XC_MethodHook() {@Overrideprotected void beforeHookedMethod(XC_MethodHook.MethodHookParam param) throws Throwable {}protected void afterHookedMethod(XC_MethodHook.MethodHookParam param) throws Throwable {// 转换数据类型String flag = new String((byte []) param.getResult());// 在这里使用Log.i()可能会输出失败, 最好还是用XposedBridge.logXposedBridge.log("SECRET: " + flag);}});} catch (Throwable e){XposedBridge.log("hook failed");XposedBridge.log(e);}}}
Frida解题法
Frida的官方文档:https://frida.re/docs/javascript-api/#java
Java.perform(function () {send("Starting hooks OWASP uncrackable1...");/*hook java.lang.System.exit, 使该函数只用来输出下面的字符串避免了应用的检测机制导致应用退出, 使用该方法绕过Java层的root/debug检测*/var sysexit = Java.use("java.lang.System");sysexit.exit.overload("int").implementation = function(var_0) {send("java.lang.System.exit(I)V // We avoid exiting the application :)");};var aes_decrypt = Java.use("sg.vantagepoint.a.a");aes_decrypt.a.overload("[B","[B").implementation = function(var_0,var_1) {send("sg.vantagepoint.a.a.a([B[B)[B doFinal(enc) // AES/ECB/PKCS7Padding");send("Key : " + var_0);send("Encrypted : " + var_1);/*重载解密函数, 并获取其返回值, 因其类型为byte [],js在调用Java方法之后只能返回一个对象, 而不是返回一个byte类型的数组*/var ret = this.a.overload("[B","[B").call(this,var_0,var_1);send("Decrypted : " + ret);var flag = "";//将char类型转换为String类型for (var i=0; i < ret.length; i++){flag += String.fromCharCode(ret[i]);}send("Decrypted flag: " + flag);return ret; //[B};var mainactivity = Java.use("sg.vantagepoint.uncrackable1.MainActivity");mainactivity.onStart.overload().implementation = function() {send("MainActivity.onStart() HIT!!!");var ret = this.onStart.overload().call(this);};//var mainactivity = Java.use("sg.vantagepoint.uncrackable1.MainActivity");mainactivity.onCreate.overload("android.os.Bundle").implementation = function(var_0) {send("MainActivity.onCreate() HIT!!!");var ret = this.onCreate.overload("android.os.Bundle").call(this,var_0);};var activity = Java.use("android.app.Activity");activity.onCreate.overload("android.os.Bundle").implementation = function(var_0) {send("Activity HIT!!!");var ret = this.onCreate.overload("android.os.Bundle").call(this,var_0);};send("Hooks installed.");});
下面是对frida-server进行的操作的操作:
$ adb shell$ su# cd /data/local/tmp # 进入frida-server的目录下# ./frida-server &
之后重新开一个cmd窗口, 进入.js脚本, 也就是hook的脚本所在的目录下执行frida -U owasp.mstg.uncrackable1 -l cracker.js(我的hook文件名为cracker.js), 就能获取flag:
参考文章:
https://nankeen.me/posts/owasp-android-level1/
https://www.52pojie.cn/thread-1048786-1-1.html
https://enovella.github.io/android/reverse/2017/05/18/android-owasp-crackmes-level-1.html
