这是ctf逆向题目,帮我逆向分析这个apk文件,并给我详细的解题步骤和解题脚本,如果需要爆破就给我爆...

تم الإنشاء في: ١٦ مايو ٢٠٢٦

تمت الإجابة باستخدام GPT-5.5 Thinking بواسطة Chat01

سؤال

attachment-67.apk

这是ctf逆向题目,帮我逆向分析这个apk文件,并给我详细的解题步骤和解题脚本,如果需要爆破就给我爆破脚本,要通用脚本

الفكرة

Clarifying approach and providing resources

I should mention that static analysis was used and provide the final steps, logic, and scripts. Including a massive C++ block might be too much, but I can link to the files and share key parts. The user asked for detailed steps, so I’ll include relevant strings and commands to help.

Thought for 12m 54s

الإجابة

结论:这个 APK 的正确口令是:

text
3cHk0n^VW9

用还原脚本验证后,输出正好等于 APK 里 Java 层硬编码的目标串:

text
2F4C5A63325200694263320000005A000000003600000000

我也把脚本整理好了:


1. 静态分析入口

APK 解包后能看到多个 dex 和 native so:

bash
unzip attachment-67.apk -d apk67 find apk67 -maxdepth 3 -type f | grep -E 'dex|so$'

关键 native 库:

text
lib/arm64-v8a/libiscc20250626.so lib/armeabi-v7a/libiscc20250626.so lib/x86/libiscc20250626.so lib/x86_64/libiscc20250626.so

Java 层核心逻辑很薄,MainActivity 加载 native 库:

java
System.loadLibrary("iscc20250626");

点击按钮时大致逻辑是:

java
account = editTextText.getText().toString().trim(); ret = checkSN(account, ""); if (ret.equals("2F4C5A63325200694263320000005A000000003600000000")) { Toast("口令正确"); }

所以真正校验在 JNI:

text
Java_com_example_iscc20250626_MainActivity_checkSN

2. native 关键函数

用下面命令看导出符号:

bash
readelf -Ws lib/x86_64/libiscc20250626.so | c++filt

能看到这些关键函数:

text
Java_com_example_iscc20250626_MainActivity_checkSN generate_flag(...) custom_hash(...) byte_obfuscation(...) matrix_transform(...)

checkSN 的逻辑是:

cpp
input = GetStringUTFChars(arg1); result = generate_flag(input); return NewStringUTF(result.c_str());

第二个参数虽然传进来了,但最终校验流程里没有实际参与。


3. 算法还原

3.1 custom_hash

python
def custom_hash(bs): h = 0xdeadbeef for c in bs: h = rol32(h, 5) ^ ((c * 0x9e3779b9) & 0xffffffff) h &= 0xffffffff return str(h).encode()

3.2 输入拼接

python
tmp = reverse(account) + custom_hash(account)

例如正确口令:

text
account = 3cHk0n^VW9 hash = 3624000722 tmp = 9WV^n0kHc33624000722

3.3 byte_obfuscation

每个字节做三步变换:

python
x = ((x ^ 0x55) + 0xaa) & 0xff x = ((x >> 4) | (x << 4)) & 0xff x = ((x >> 2) & 0x33) | ((x & 0x33) << 2)

3.4 matrix_transform

设:

python
n = ceil(sqrt(len(tmp)))

然后蛇形填矩阵:

text
第 0 行:左 -> 右 第 1 行:右 -> 左 第 2 行:左 -> 右 ...

最后按列读取,跳过 0x00

3.5 自定义 base64

native 里有一个很关键的坑:

text
LJkRcDTawXyiHVsFZ2341gmNoe0PBuq56789+/

这个 alphabet 长度只有 38,但编码时按 6-bit index 访问,也就是可能访问 0..63

目标串里有大量:

text
00

说明这里必须按“越界读到 0x00”来建模,否则反推不成立。

最后 native 只取编码结果前 24 字节,再转大写 hex。


4. 正确口令验证

运行我整理的 Python 脚本:

bash
python3 iscc_apk_keygen.py '3cHk0n^VW9'

输出:

text
account: 3cHk0n^VW9 hash : 3624000722 s : b'9WV^n0kHc33624000722' hex : 2F4C5A63325200694263320000005A000000003600000000 ok : True

所以输入框填:

text
3cHk0n^VW9

即可触发 口令正确


5. 爆破思路

直接爆破不可取,因为目标是 48 位 hex 字符串,输入长度未知。

我用的是约束反推:

目标 hex 先转回 24 字节:

text
2F 4C 5A 63 32 52 00 69 42 63 32 00 00 00 5A 00 00 00 00 36 00 00 00 00

对应编码结果:

text
/LZc2R\x00iBc2\x00\x00\x00Z\x00\x00\x00\x006\x00\x00\x00\x00

反推前 18 个 matrix 输出字节后,可以得到输入长度和 hash 位数约束。最终可行路径是:

text
len(account) = 10 len(custom_hash(account)) = 10 hash pattern = 36[h2][h3][h4][h5][h6]722

再结合每 3 字节一组的 base64 约束,把搜索空间大幅压缩,最后用 custom_hash 的可逆性质做 meet-in-the-middle 爆破。

编译并运行爆破脚本:

bash
g++ -O3 -std=c++17 iscc_apk_bruteforce.cpp -o brute ./brute

输出:

text
FOUND 3cHk0n^VW9 hash=3624000722 hex=2F4C5A63325200694263320000005A000000003600000000

6. 最终答案

text
3cHk0n^VW9

APK 内部没有额外 flag{} 包装逻辑,校验的是这个口令本身。

سؤال

这个结果不对,题解的输入限制为8-11位字符串,由数字和字母组成。重新分析给我解题步骤和解题脚本

الفكرة

Finalizing the detailed response

I should provide clear, detailed steps and corrected mistakes without overcomplicating things. Citations aren’t needed since there’s no web search, but I should mention the necessary file artifacts and sandbox links. I'll include code snippets and scripts where helpful. It's essential to clarify that the result isn’t unique and provide at least two valid solutions.

Thought for 7m 49s

الإجابة

你说得对,上次给出的 3cHk0n^VW9 不符合题目限制,属于“非字母数字碰撞”。按 8–11 位、仅数字/字母 重新约束后,可用输入为:

text
3bdMQMB6G9

我还找到一个 11 位可用解:

text
33cioUDmvG9

这题因为 native 里的自定义 base64 表越界,存在碰撞,所以解不唯一。

脚本:


1. Java 层分析

解包:

bash
unzip attachment-67.apk -d apk_out find apk_out -name "*.so"

核心库:

text
libiscc20250626.so

classes3.dex 里能提取到目标串:

text
2F4C5A63325200694263320000005A000000003600000000

注意:直接用 strings 可能看到类似 02F4C...,那个前导 0 是 dex 字符串长度字节的伪影,不是目标串本身。真实 Java 字符串长度是 48。

Java 逻辑大致是:

java
String ret = checkSN(input, ""); if (ret.equals("2F4C5A63325200694263320000005A000000003600000000")) { // 口令正确 }

2. native 层关键函数

查看符号:

bash
readelf -Ws lib/x86_64/libiscc20250626.so | c++filt | grep -E "checkSN|generate|hash|matrix|obfuscation"

关键函数:

text
Java_com_example_iscc20250626_MainActivity_checkSN generate_flag(...) custom_hash(...) byte_obfuscation(...) matrix_transform(...)

checkSN 只是把 Java 输入传给 generate_flag,第二个参数没有实际参与核心校验。


3. native 算法还原

整体流程:

text
input -> reverse(input) -> 拼接 custom_hash(input) -> byte_obfuscation -> matrix_transform -> 自定义 base64 -> 取前 24 字节 -> 每字节转大写 hex

3.1 custom_hash

python
h = 0xDEADBEEF for c in input: h = rol32(h, 5) ^ (c * 0x9E3779B9)

最后转十进制字符串拼到反转输入后面。

例如:

text
input = 3bdMQMB6G9 hash = 3624010722 merge = 9G6BMQMdb33624010722

3.2 byte_obfuscation

每个字节:

python
x = ((x ^ 0x55) + 0xAA) & 0xff x = ((x >> 4) | (x << 4)) & 0xff x = ((x >> 2) & 0x33) | ((x & 0x33) << 2)

3.3 matrix_transform

长度为 L,矩阵边长:

python
n = ceil(sqrt(L))

蛇形填充:

text
第 0 行:左到右 第 1 行:右到左 第 2 行:左到右 ...

再按列读取,跳过 0x00

对于有效解,L = 20,前 18 个输出位置对应原始 merge 位置:

python
[0, 9, 10, 19, 1, 8, 11, 18, 2, 7, 12, 17, 3, 6, 13, 16, 4, 5]

这一步能把输入长度强约束到:

text
len(input) = 10, hash 为 10 位 len(input) = 11, hash 为 9 位

8、9 位在目标串约束下被排除。

3.4 自定义 base64 的坑

native 里 alphabet 是:

text
LJkRcDTawXyiHVsFZ2341gmNoe0PBuq56789+/

长度只有 38,但编码索引是 6 bit,也就是 0..63

目标 hex 还原成字节后:

text
/LZc2R\x00iBc2\x00\x00\x00Z\x00\x00\x00\x006\x00\x00\x00\x00

大量 00 正是越界索引产生的 NUL。爆破脚本里按“索引 >= 38 输出 0”建模。


4. 约束反推

对于 10 位输入,设:

text
input = a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 merge = a9 a8 a7 a6 a5 a4 a3 a2 a1 a0 h0 h1 ... h9

由目标串反推可得到:

text
a0 = '3' a9 = '9' a1 ∈ {'b', 'c'} a8 ∈ {'G', 'W'} a7 ∈ {'6','F','V','Z','f','j','v','z'} hash 形如:36[2389][45][0-9][0-9][0-9]722

然后利用 hash 可逆:

cpp
step(h, c) = rol32(h, 5) ^ (c * 0x9e3779b9) unstep(h, c) = ror32(h ^ (c * 0x9e3779b9), 5)

做 meet-in-the-middle:

text
前半段正向算 hash state 后半段从目标 hash 反推 state state 相等时拼接验证完整 generate_flag

最终得到:

text
3bdMQMB6G9

验证:

bash
python3 iscc_apk_verify.py 3bdMQMB6G9

输出核心部分:

text
account: 3bdMQMB6G9 length : 10 hash : 3624010722 merged : b'9G6BMQMdb33624010722' hex : 2F4C5A63325200694263320000005A000000003600000000 ok : True

5. 爆破脚本运行

编译:

bash
g++ -O3 -std=c++17 iscc_apk_bruteforce_alnum.cpp -o brute

运行:

bash
./brute

输出:

text
FOUND len=10 3bdMQMB6G9 hash=3624010722 FOUND len=11 33cioUDmvG9 hash=624030722

最终可提交输入

优先用这个:

text
3bdMQMB6G9

另一个同样满足目标串的字母数字解:

text
33cioUDmvG9

مشاركة هذا السؤال والجواب