吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 606|回复: 1
上一主题 下一主题
收起左侧

[Android CTF] [原创] Deep Archive {JiGuro} CrackMe 逆向分析:不止一个的秘密

[复制链接]
跳转到指定楼层
楼主
鸠山一茶 发表于 2026-5-19 22:39 回帖奖励
本帖最后由 鸠山一茶 于 2026-5-20 17:24 编辑

[原创] Deep Archive {JiGuro} CrackMe 逆向分析:不止一个的秘密

一、基本信息

项目 内容
软件名称 Deep Archive {JiGuro}
包名 com.jiguro.deeparchive.crackme
目标 找出正确的 Flag
最终Flag flag{Cr@ckme_JigUr0_5ZPoJie_MT8B5_2O26:05:1G_xV9qL7n_L0L}
原作者 @JiGuro
原帖地址 https://www.52pojie.cn/thread-2108082-1-1.html

二、核心陷阱:一明一暗,双层校验

作者在核心验证函数 sub_968096 中设计了双层校验,第一层是精心构造的干扰项(Decoy),用于误导和筛选。这完美呼应了故事中的那句提示:“不要轻易相信,你看到的一切”“秘密可能不止一个”

层级 算法 产物(Flag) 返回值 意义
第一层 Base64 + XOR flag{N0_0ne_Can_R3v3rse_Th1s_Pr0gr4m!} 2 干扰项 / 钥匙
第二层 APK签名块 + AES-256-CBC flag{Cr@ckme_JigUr0_5ZPoJie_MT8B5_2O26:05:1G_xV9qL7n_L0L} 1 真Flag

三、静态分析:从Java到Native

3.1 APK 解包与结构

首先使用 apktool 解包APK,观察其结构。除了常规的libresres/raw/目录下有一个名为 rundll32 的1194KB文件,内部是混淆数据。

decoded/
├── lib/.../libdeeparchive.so   # 核心Native库
├── res/raw/
│   ├── rundll32                # 混淆数据文件
│   └── *.mp3                   # 各种音效(成功/失败/背景音乐)
└── smali/com/jiguro/.../MainActivity.smali (153KB)
3.2 Java层逻辑梳理

MainActivity.smali 中,声明了10个Native方法,核心验证方法是 sub_968096

  • 按钮点击:触发 dm/l1.smali 中的 onClick 事件。
  • 验证线程:启动 dm/xt.smali 线程,在其中调用 sub_968096
  • 结果处理:返回值通过 dm/pg.smali 处理,分为三种情况。

关键返回值对照表:

返回值 界面反馈 含义
1 按钮显示“[ 已获取最高权限 ]”,背景变绿,播放成功音效,触发隐藏剧情 完全正确
2 按钮显示“[ 检测到未知凭证 ]”,背景变橙色 仅通过干扰项
其他 按钮恢复,显示“[ 权限验证失败 ]” 完全错误

四、Native决战:libdeeparchive.so 深度解析

4.1 函数调用链

通过分析 libdeeparchive.so (x86_64, stripped),定位到核心函数 sub_968096 的内部流程:

sub_968096(用户输入)
    │
    ├─ 1. 调用 sub_350158() 【第一层:XOR校验】
    │      ├─ 失败 → return 0
    │      └─ 成功 → 进入第二层
    │
    └─ 2. 调用 sub_375940() 【第二层:自定义SHA-256校验】
           ├─ 失败 → return 2 (仅第一层通过,落入陷阱)
           └─ 成功 → return 1 ★ (两层全通过,获得真Flag)
4.2 第一层:解密干扰项

数据被分割存放:6段Base64片段在数据段,而前缀 9r28/DC8 以立即数形式嵌入在代码段。XOR密钥在偏移 0xe30

解密过程(Python):

import base64

# 1. 拼接所有片段得到完整Base64串
b64_full = '9r28/DC8PBsB+ZaxUQ4O+MLiq6g5gWkbZf/CnU0/Epf3o+n2ao8='
# 2. Base64解码
decoded = base64.b64decode(b64_full)
# 3. XOR密钥(16字节循环)
xor_key = bytes.fromhex('90d1dd9b4bf20c443197f3ee126f60a7')
# 4. 逐字节异或
flag_decoy = bytes([decoded[i] ^ xor_key[i % 16] for i in range(len(decoded))])
print(flag_decoy.decode())

输出:

flag{N0_0ne_Can_R3v3rse_Th1s_Pr0gr4m!}

看起来真的很像答案,但是无法通过
再看一眼 No one can reverse this program!
????很好,落入圈套了

4.3 第二层:干扰项就是钥匙——真正的Flag藏在哪里?

这是整个CrackMe最精彩的设计。 干扰项 flag{N0_0ne_Can_R3v3rse_Th1s_Pr0gr4m!} 不是死胡同——它本身就是通往真Flag的钥匙

关键线索:rundll32 与 note 图片

当输入干扰项时,sub_968096 返回 2,应用在 dm/pg.smali 中进入 Partial 分支。这个分支会:

  1. 调用 sub_460339() 输出9条系统日志(其中明确写着 当前凭证已被标记为[伪造授权]
  2. 读取 res/raw/rundll32(1.14MB 加密数据)
  3. 用干扰项作为 XOR 密钥,对 rundll32 解密,得到一张 note 图片(PNG格式)

Note 图片中的关键提示:

  • 当前的"密钥"是伪造的,真正的密钥藏在更深的地方
  • 只依赖Native逻辑是不够的
  • 去原始 APK 的签名块(Signing Block)里找
  • AES-256-CBC / EREB0S

"不要轻易相信你看到的一切" —— 故事和提示都在告诉你:从静态分析SO找到的flag是假的,答案需要从更隐秘的地方获取。

关键线索:APK Signing Block 中的隐藏数据

APK 文件结构为:ZIP Entries → APK Signing Block → Central Directory → EOCD

APK Signing Block 位于 ZIP Central Directory 之前,不属于普通 ZIP Entry,因此 apktool / jadx 解包后完全不可见——只能在原始 APK 文件中直接读取。

在原始 APK 的 Signing Block 中,作者嵌入了一个自定义 ID-Value 对

字段
自定义 ID 0x45524542 (ASCII: EREB,呼应故事中空间站"EREBOS",内部编号 45524542
Value {"seed":"RVJFQjBTXzIxNDcwMzI3IQ==","archive":"RsxG28SwnXELKT6/i42/+npxR+t4H/ToXMxLpRrQZk9L8tVZQU5wVMjpI13kkxZlXgP2q9b7KEL2NRlfgXsy2g=="}
解密真Flag:AES-256-CBC

从 Signing Block 提取到的数据就是解密的全部原料:

干扰项 = "flag{N0_0ne_Can_R3v3rse_Th1s_Pr0gr4m!}"   ← 你自己的发现
                          │
                          ├─ 去掉 flag{} 包装 → AES-256 Key(恰好 32 字节)
                          │    Key = "N0_0ne_Can_R3v3rse_Th1s_Pr0gr4m!"
                          │
                          └─ Signing Block 中的 seed
                               Base64 解码 → AES IV(恰好 16 字节)
                               IV = "EREB0S_21470327!"

解密代码(Python):

import base64
from Crypto.Cipher import AES

# 从干扰项提取 AES-256 密钥(恰好 32 字节)
decoy = "flag{N0_0ne_Can_R3v3rse_Th1s_Pr0gr4m!}"
key = decoy[5:-1]  # "N0_0ne_Can_R3v3rse_Th1s_Pr0gr4m!" — 32 bytes = AES-256

# 从 APK Signing Block 提取
seed_b64    = "RVJFQjBTXzIxNDcwMzI3IQ=="
archive_b64 = "RsxG28SwnXELKT6/i42/+npxR+t4H/ToXMxLpRrQZk9L8tVZQU5wVMjpI13kkxZlXgP2q9b7KEL2NRlfgXsy2g=="

iv         = base64.b64decode(seed_b64)        # "EREB0S_21470327!"
ciphertext = base64.b64decode(archive_b64)

# AES-256-CBC 解密
cipher = AES.new(key.encode(), AES.MODE_CBC, iv)
plaintext = cipher.decrypt(ciphertext)
# 去除 PKCS#7 padding
real_flag = plaintext[:-plaintext[-1]].decode()

print(real_flag)
# flag{Cr@ckme_JigUr0_5ZPoJie_MT8B5_2O26:05:1G_xV9qL7n_L0L}
验证:自定义 SHA-256

Native 中 sub_375940() 实现了自定义初始常量的 SHA-256,用于在做最终校验时比对。但这不是找到Flag的途径——你不可能从哈希值反向推出输入。

常量 标准 SHA-256 本CrackMe
H0~H3 6a09e667, bb67ae85, 3c6ef372, a54ff53a 9ea9f03b, 428dd41f, 2671b8c3, 0a559ca7
H4~H7 510e527f, 9b05688c, 1f83d9ab, 5be0cd19 0d0d0d0d, 00000000, 00000000, 00000000
# 验证:真Flag通过自定义SHA-256,拿到预置的期望哈希
custom_sha256(real_flag)
# → 906dd0355d5a646b5a2425b04ed2b42e03d7f10de2cf53a049e5e589734b209e
# 这个值在 SO 的 sub_375940 中与硬编码期望值比对 → 匹配 → return 1

五、完整解题路线图

  [1] 静态分析 libdeeparchive.so
       ├─ 在数据段搜集 Base64 片段 + 立即数前缀
       ├─ Base64 解码 → XOR(密钥 0xe30)
       └─ 得到干扰项: flag{N0_0ne_Can_R3v3rse_Th1s_Pr0gr4m!}
                              │
  [2] 输入干扰项 → 返回 2 (Partial)                    │
       ├─ 应用触发 rundll32 解密(干扰项作 XOR key)     │
       └─ 得到 note 图片:"去原始 APK 的 Signing Block 找"│
                              │                          │
  [3] 解析原始 APK Signing Block  ←──────────────────────┘
       ├─ 找到自定义块 ID=0x45524542 ("EREB")
       └─ 提取 seed 和 archive
                              │
  [4] AES-256-CBC 解密         │
       ├─ Key = 干扰项去掉 flag{}(恰好32字节)
       ├─ IV  = Base64(seed) = "EREB0S_21470327!"
       └─ 解密 archive → flag{Cr@ckme_JigUr0_5ZPoJie_MT8B5_2O26:05:1G_xV9qL7n_L0L}
                              │
  [5] 输入真Flag → sub_968096 返回 1 → 完全通关 ✓

设计精髓:干扰项是"钥匙"而非"答案"。只有真正理解 rundll32 → note → Signing Block → AES 这一整条链路,才能找到真Flag。作者用一个逆向工程师最熟悉的 SO 静态分析作为第一层诱饵,真Flag则藏在 APK 文件结构中一个解包工具看不见的角落。

免费评分

参与人数 1吾爱币 +1 热心值 +1 收起 理由
Mask4414 + 1 + 1 谢谢@Thanks!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

沙发
PercyDan 发表于 2026-5-20 06:11
sha256最后从预期hash得到flag是爆破的吗
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - 52pojie.cn ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2026-5-21 04:01

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表