描述

A secret string is hidden somewhere in this app. Find a way to extract it.

目标

找到密码

APK 下载

点击下载

题解

首先打开 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.uncrackable1 -l crack.js

function passRoot() {
    Java.perform(function() {
        let c = Java.use("sg.vantagepoint.a.c");
        c["a"].implementation = function () {
            console.log(`c.a is called`);
            return false;
        };
        c["b"].implementation = function () {
            console.log(`c.b is called`);
            return false;
        };
        c["c"].implementation = function () {
            return false;
        };
    })
}

function main() {
    passRoot();
}

setImmediate(main);

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

CrackMe

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

CrackMe

进入 a.a() 方法,可以看到加密的方法还是比较简单的,本地还原一下就行。

CrackMe

将加密函数进行本地还原,输出结果为 I want to believe

from base64 import b64decode
from Crypto.Cipher import AES

def aes_decrypt(key_hex: str, data_base64: str) -> bytes:
    key = bytes.fromhex(key_hex)
    data = b64decode(data_base64)
    cipher = AES.new(key, AES.MODE_ECB)
    decrypted_data = cipher.decrypt(data)
    pad_len = decrypted_data[-1]
    decrypted_data = decrypted_data[:-pad_len]
    return decrypted_data

def get_string() -> str:
    try:
        decrypted_data = aes_decrypt("8d127684cbc37c17616d806cf50473cc", "5UJiFctbmgbDoLXmpL12mkno8HT4Lv8dlat8FxR2GOc=")
    except Exception as e:
        print(f"AES error: {str(e)}")
        decrypted_data = b''
    return decrypted_data.decode()

print(get_string())

# output: I want to believe

将密码输入 APP,密码正确,密码为 I want to believe

CrackMe