描述

This app holds a secret inside. May include traces of native code.

目标

找到密码

APK下载

https://yhxx.lanzoub.com/iMZpZ0mx336d

题解

首先打开APP看一下,可以看到是需要输入注册码来进行注册,但是检测到了root,需要先过root检测。

CrackMe

在GitHub上有个脚本可以过很多root检测https://github.com/AshenOneYe/FridaAntiRootDetection,用这个脚本就可以过这个APP的root检测,不过还是看看具体代码中怎么过吧。 Jadx-GUI打开找到root检测的位置,发现用到了3个函数,当3个函数都返回true时就可以正常使用APP。

CrackMe

点进去发现3个函数都在一个类中,只要将3个函数都改为永远返回true就行,可以直接修改smali或者hook,hook方便一些。

CrackMe

写好hook的代码,使用frida重启注入frida -U --no-pause -f owasp.mstg.uncrackable2 -l crack.js

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
function passRoot() {
    Java.perform(function() {
        let b = Java.use("sg.vantagepoint.a.b");
        b["a"].implementation = function () {
            console.log(`b.a is called`);
            return false;
        };
        b["b"].implementation = function () {
            console.log(`b.b is called`);
            return false;
        };
        b["c"].implementation = function () {
            console.log(`b.c is called`);
            return false;
        };
    })
}

function main() {
    passRoot();
}

setImmediate(main);

打开后APP就可以正常使用,不会提示root了。

CrackMe

再找到验证密码的地方,看到是在verify()方法中,将用户输入的文本传入this.m.a()方法中进行检查。

CrackMe

进入this.m.a()方法,发现用到的关键方法bar()是一个返回值为bool的native方法。在MainActivity中看到有System.loadLibrary("foo"),于是去libfoo.so中找bar()方法。

CrackMe

用ida打开libfoo.so,通过字符串很容易找到静态注册的bar()方法,可以看到其中用到了strncmp()来做字符串对比,所以只需要hookstrncmp()即可。同时可以看到字符串长度为23位,这也缩小了hook范围,更加方便。

CrackMe

写出hook脚本,重启注入APPfrida -U --no-pause -f owasp.mstg.uncrackable2 -l crack.js,输入01234567890123456789012来查看返回值,可以看到输出为Thanks for all the fish

 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
function passRoot() {
    Java.perform(function() {
        let b = Java.use("sg.vantagepoint.a.b");
        b["a"].implementation = function () {
            console.log(`b.a is called`);
            return false;
        };
        b["b"].implementation = function () {
            console.log(`b.b is called`);
            return false;
        };
        b["c"].implementation = function () {
            console.log(`b.c is called`);
            return false;
        };
    })
}

function getSecret() {
    let libfoo_ptr = null;
    let modules = Process.enumerateModules();
    for (let i=0; i<modules.length; i++) {
        if (modules[i].name == "libfoo.so") libfoo_ptr = modules[i].base;
    }
    Interceptor.attach(Module.findExportByName(libfoo_ptr, "strncmp"), {
        onEnter: function (args) {
           if(args[2].toInt32() == 23 && Memory.readUtf8String(args[0],23) == "01234567890123456789012") {
                console.log("[*] Secret string at " + args[1] + ": " + Memory.readUtf8String(args[1],23));
            }
         },
        onLeave: function(retval) {
        }
    })
}

function main() {
    passRoot();
    getSecret();
}

setImmediate(main);
CrackMe

将密码输入APP,密码正确,密码为Thanks for all the fish

CrackMe