UnCrackable-Level1分析

UnCrackable-Level1.apk

下载并安装,打开;一上来就被检测出root权限了。

image-20250224152934808

将apk丢入jeb中查看,通过ctrl + f搜索字符串。

image-20250224153359358

c.a()、c.b()、c.c()的逻辑如下图,我发现,在我的/system/bin中,确实有一个su。

image-20250224153529149

方案1,粗暴的解决方案,修改dex文件并重新签名。在onCreate的第一个if处,将判断结果改成false;

1
2
3
4
5
6
7
8
9
10
11
12
Java.perform(function(){
const root = Java.use("sg.vantagepoint.util.RootDetection");
root.checkRoot1.implementation = function(){
return false;
}
root.checkRoot2.implementation = function(){
return false;
}
root.checkRoot3.implementation = function(){
return false;
}
});

方案2,hook掉exit函数或者hook掉相关函数;

方案3,面具magisk里直接屏蔽掉UnCrackable-Level1.apk的root权限,让它检测不到root。

这里介绍一下第二个方法,js脚本如下,执行方法也如下,然后就绕过去了。

1
2
3
4
5
6
7
8
9
10
# frida -U -f owasp.mstg.uncrackable1 -l .\uncrackable-level1.js

Java.perform(function(){
var temp = Java.use("java.lang.System"); # 获得System类
# exit是静态函数,不需要实例化后再调用
# overload指定具体的重载版本
temp.exit.overload('int').implementation = function(arg0){
console.log("Exit called with " + arg0);
};
});

image-20250224160548124

通过jeb,可以发现在类a中,函数a会根据输入的内容进行比较,随后得出是否正确的答案。

image-20250224183527518

下面是写的一个js脚本,直接return true,或者通过sg.vantagepoint.a.a.a得到解密的明文。

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
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
# 直接改为true
Java.perform(function() {
// 获取目标类
var targetClass = Java.use('sg.vantagepoint.uncrackable1.a');

// Hook 静态方法 a(String)
targetClass.a.overload('java.lang.String').implementation = function(s) {
console.log("\n[*] 拦截验证方法调用");

// 打印原始输入
console.log("原始输入: " + s);

// 调用原始方法获取结果
var result = this.a(s); // [!code focus]

// 打印原始验证结果
console.log("原始验证结果: " + result);

// 强制返回 true(绕过验证)
console.log("[+] 强制返回 true");
return true;

// 若需保留原始逻辑,直接返回 result
// return result;
};
});

# 观察正确的输入
Java.perform(function() {
// 获取加密工具类
var crypto = Java.use('sg.vantagepoint.a.a');

// 获取验证类
var checker = Java.use('sg.vantagepoint.uncrackable1.a');

// Hook a() 方法获取密钥和密文
checker.a.overload('java.lang.String').implementation = function(s) {
// 原始密文(Base64)
var ciphertext_b64 = "5UJiFctbmgbDoLXmpL12mkno8HT4Lv8dlat8FxR2GOc=";

// 硬编码密钥(处理负数为无符号字节)
var key_bytes = [0x8D, 0x12, 0x76, 0x84, 0xCB, 0xC3, 0x7C, 0x17,
0x61, 0x6D, 0x80, 0x6C, 0xF5, 0x04, 0x73, 0xCC];

// 将密钥转换为 Java byte[]
var jKey = Java.array('byte', key_bytes);

// Base64 解码密文
var ciphertext = Java.use('android.util.Base64').decode(ciphertext_b64, 0);

try {
// 调用解密方法
var decrypted_bytes = crypto.a(jKey, ciphertext);

// 转换为字符串
var plaintext = Java.use('java.lang.String').$new(decrypted_bytes);
console.log("\n[+] 解密成功!Secret String: " + plaintext);
} catch(e) {
console.log("[-] 解密失败: " + e);
}

// 返回原始验证结果(或强制返回 true)
return this.a(s);
};
});

执行,得到结果。

image-20250224185351087