2026盘古石预赛 APK取证题解析
2026盘古石预赛 — APK取证 Writeup
- 作者:yagami
- 任务目录:
/mnt/d/文档/hermes-work/fangjunlang-zhouwenjie-linxiaowan-q1-to-q31 - 生成时间:2026-06-19
- 生成模式:完整 writeup
- 工具:Hermes Agent
- 模型:Qwen3.6-27B-Uncensored-HauhauCS-Aggressive-Q4_K_P.gguf
- 运行方式:本地
工具与模型
| 项目 | 内容 |
|---|---|
| 工具 | Hermes Agent |
| 模型 | Qwen3.6-27B-Uncensored-HauhauCS-Aggressive-Q4_K_P.gguf |
| 运行方式 | 本地 |
任务信息
- 题目范围:Q1-Q31(方俊朗 Q1-Q15,周文杰 Q16-Q25,林小婉 Q26-Q31)
- 检材:
- 方俊朗 phone.E01:
/mnt/z/方俊郎/phone.E01(挂载到/mnt/jsystem,/mnt/kdata) - 周文杰 Image.zip:
/mnt/z/周文杰/Image.zip(17GB) - 林小婉手机.zip:
/mnt/z/林小婉/林小婉手机.zip(542MB,模拟器数据导出格式) - 林小婉隐藏应用APK:
/mnt/d/文档/hermes-work/ctf/1778310207366_9eee4f1c.apk(com.jinritoutiao.news)
- 方俊朗 phone.E01:
- 验证策略:源码直接确认(Java/smali)、数据库交叉验证、APK二进制分析、Python脚本解密验证。全部31题已验证通过。
答案汇总总表
| 题号 | 答案 | 答案状态 | 验证等级 | 关键证据摘要 |
|---|---|---|---|---|
| Q1 | chat_history.db | 已验证 | L1 | find搜索.db文件,xxd确认非明文SQLite文件头 |
| Q2 | PBKDF2WithHmacSHA256 | 已验证 | L1 | jadx反编译decrypted_0.dex,KeyDeriver.java第33行SecretKeyFactory.getInstance() |
| Q3 | 10000 | 已验证 | L1 | KeyDeriver.java第16行常量 PBKDF2_ITERATIONS = 10000 |
| Q4 | 27042 | 已验证 | L1 | SecurityManager.java第68行 InetSocketAddress(“127.0.0.1”, 27042) |
| Q5 | Pr3d1ct0r | 已验证 | L1 | KeyDeriver.java getSaltPart1()直接返回 “Pr3d1ct0r” |
| Q6 | f4ll8ack_k3y_2024_pr3d1ct0r | 已验证 | L1 | KeyDeriver.java catch块fallback return |
| Q7 | de.robv.android.xposed.XposedBridge | 已验证 | L1 | SecurityManager.java Class.forName()检测Xposed |
| Q8 | db_integrity_check | 已验证 | L1 | KeyDeriver.java SharedPreferences键名 |
| Q9 | chat_records | 已验证 | L1 | ChatDatabaseHelper.java TABLE_CHAT常量 + CREATE TABLE语句 |
| Q10 | X9kZ!qW3 | 已验证 | L1 | KeyDeriver.java getSaltPart3()字符数组拼接 |
| Q11 | initDexFromMemory | 已验证 | L1 | ShellApplication.smali私有方法 initDexFromMemory([B) |
| Q12 | Sh3ll_L0ad3r_K3y_2024! | 已验证 | L2 | smali getKeyPart1/2/3 + Python拼接验证三部分密钥 |
| Q13 | java.lang.System.exit | 已验证 | L1 | smali反调试线程lambda调用 java/lang/System;->exit(I)V |
| Q14 | 2 | 已验证 | L1 | SQLCipher解密conversation表,type='G’计数=2(技术部群、话务组群) |
| Q15 | 32 | 已验证 | L2 | 聊天记录原文"32个高端用户的数据"+msg_000126交叉验证"32个高端小区的数据样本" |
| Q16 | com.socialchat.social_chat_app | 已验证 | L1 | Image.zip中data/data/目录结构直接确认 |
| Q17 | social_chat.db | 已验证 | L2 | databases/social_chat.db文件存在 + SQLCipher解密成功 |
| Q18 | FlutterSharedPreferences.xml | 已验证 | L1 | shared_prefs/FlutterSharedPreferences.xml含flutter.db_password键 |
| Q19 | s-dbw1776853545473Goo | 已验证 | L2 | substring(2,-1)截取 + SQLCipher解密social_chat.db成功确认 |
| Q20 | AES | 已验证 | L2 | AES-CBC解密247条消息全部成功 |
| Q21 | a3f8d9c2e1b4h7g6k9m2n5p8q1r4t7w | 已验证 | L1 | user表password_salt字段直接查询 |
| Q22 | com.jinghong.notebookkssjh | 已验证 | L2 | NotePal.db + 附件.md双源确认密码格式提示"英文2+数字6" |
| Q23 | mb202623 | 已验证 | L2 | 双重SHA256哈希精确匹配,符合"英文2+数字6"格式 |
| Q24 | 6 | 已验证 | L2 | extra_val=1计数 + APK源码确认查询条件 |
| Q25 | extra_val | 已验证 | L2 | APK SQL查询条件 + 数据库分布交叉确认(0:241, 1:6) |
| Q26 | 今日头条 | 已验证 | L1 | aapt dump badging确认 application-label:‘今日头条’ |
| Q27 | 20150412 | 已验证 | L2 | smali硬编码期望hash + PBKDF2日期范围暴力破解精确匹配 |
| Q28 | 备注 | 已验证 | L1 | vault_data.jth2解密后notes字段均为描述性备注文本 |
| Q29 | 192.168.1.200 | 已验证 | L1 | vault_data.jth2中c2[2] address=“192.168.1.200”(文件备份服务器) |
| Q30 | 把23年10月到24年6月的账本整理一下,发给我。 | 已验证 | L2 | 数据库state_bits=1(RECALLED) + APK libapp.so确认_buildRecalledMessage方法 |
| Q31 | DragonTeng@2024#$ | 已验证 | L1 | vault_data.jth2 password[6]完整值,长度=17无截断 |
解题过程
Q1 加密数据库文件名
题目:分析方俊朗phone.E01检材,筛选优质客户应用将用户查询记录存储在一个加密的本地数据库中。请问该加密数据库的文件名是什么?[答案格式:12_abc.db]
答案:chat_history.db
答案状态:已验证 | 验证等级:L1
解题思路:
在方俊朗phone.E01检材的data分区中搜索应用 com.example.predictor 的数据库文件,发现 databases/chat_history.db(12KB)。用xxd查看文件头,不是标准的 SQLite format 3 明文,确认为加密数据库。
关键证据:
- 文件位置:
/mnt/k/data/com.example.predictor/databases/chat_history.db - 文件大小:12KB
- 文件头非
SQLite format 3,确认为加密数据库
重点命令:
find /mnt/k/ -name "*.db"
# 发现 /mnt/k/data/com.example.predictor/databases/chat_history.db
xxd /mnt/k/data/com.example.predictor/databases/chat_history.db | head -1
# 文件头不是 "SQLite format 3",确认为加密数据库
Q2 密钥派生算法
题目:该应用使用了哪种密钥派生算法来生成数据库加密密钥?请写出完整的算法标识名称。[答案格式:DFBDSDFGG123]
答案:PBKDF2WithHmacSHA256
答案状态:已验证 | 验证等级:L1
解题思路:
通过APK加壳分析流程,先还原壳代码解密密钥(Q12),解密payload.dat得到3个DEX文件。其中 decrypted_0.dex(26KB)包含应用核心代码。用jadx反编译后查看 KeyDeriver.java 第33行:
SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256")
直接确认密钥派生算法为 PBKDF2WithHmacSHA256,使用 PBEKeySpec 构造,key length=256位。
关键证据:
- KeyDeriver.java 第33行:
SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256") - 使用 PBEKeySpec 构造密钥派生参数
Q3 迭代运算次数
题目:该应用的密钥派生过程中使用了多少次迭代运算?[答案格式:345678]
答案:10000
答案状态:已验证 | 验证等级:L1
解题思路:
KeyDeriver.java 第16行常量定义:
private static final int PBKDF2_ITERATIONS = 10000;
第32行将此常量用于 PBEKeySpec 构造函数的 iterationCount 参数。
关键证据:
- KeyDeriver.java 第16行:
PBKDF2_ITERATIONS = 10000
Q4 调试探测端口号
题目:该应用检测动态调试工具时探测了哪个本地端口号?[答案格式:64321]
答案:27042
答案状态:已验证 | 验证等级:L1
解题思路:
SecurityManager.java 第68行 Frida检测逻辑:
socket.connect(new InetSocketAddress("127.0.0.1", 27042), 500)
先检查 /proc/self/maps 是否包含 “frida”,然后尝试连接本地端口27042(frida-server默认端口)验证frida-server是否运行。
关键证据:
- SecurityManager.java 第68行:
InetSocketAddress("127.0.0.1", 27042)
Q5 第一个盐值片段
题目:该应用密钥由多个"盐值片段"拼接后派生而来。请问第一个盐值片段的具体内容是什么?[答案格式:SAltsaltsalt]
答案:Pr3d1ct0r
答案状态:已验证 | 验证等级:L1
解题思路:
KeyDeriver.java 第60-62行 getSaltPart1() 方法直接返回字符串字面量:
return "Pr3d1ct0r";
Q6 备用密钥
题目:当密钥派生过程出现异常时,应用会使用一个硬编码的备用密钥。请问该备用密钥的完整内容是什么?[答案格式:salt_dlefe_123_dfefaf]
答案:f4ll8ack_k3y_2024_pr3d1ct0r
答案状态:已验证 | 验证等级:L1
解题思路:
KeyDeriver.java 第39-40行 catch块中硬编码fallback密钥:
return "f4ll8ack_k3y_2024_pr3d1ct0r";
当 deriveKey() 异常时返回此备用密钥。
Q7 Hook框架检测类名
题目:该应用的安全检测模块通过检查一个特定的类名来判断设备是否安装了Hook框架。请问被检测的完整类名是什么?[答案格式:ru.foefn.DFeoagn.dfoandf.xoggdg]
答案:de.robv.android.xposed.XposedBridge
答案状态:已验证 | 验证等级:L1
解题思路:
SecurityManager.java 第88行 isXposedDetected() 方法通过 Class.forName 检测 Xposed 框架核心类:
Class.forName("de.robv.android.xposed.XposedBridge")
Q8 密钥校验值键名
题目:该应用在偏好设置文件中存储了一个密钥校验值。请问存储该校验值的键名(key)是什么?[答案格式:ab_dfefegad_cadfeg]
答案:db_integrity_check
答案状态:已验证 | 验证等级:L1
解题思路:
KeyDeriver.java 第79行 saveKeyChecksum() 方法将密钥的MD5校验值存入 SharedPreferences:
prefs.edit().putString("db_integrity_check", checksum)
同时存储 “key_version”=“PBKDF2_v1”, “key_iterations”=10000, “last_key_time”=时间戳。
Q9 对话记录表名
题目:该应用加密数据库中存储对话记录的数据表名是什么?[答案格式:liaotian_dfelge]
答案:chat_records
答案状态:已验证 | 验证等级:L1
解题思路:
ChatDatabaseHelper.java 第24行常量定义 + 第39行 CREATE TABLE 语句:
private static final String TABLE_CHAT = "chat_records";
// CREATE TABLE chat_records (id INTEGER PRIMARY KEY AUTOINCREMENT, province TEXT NOT NULL, age INTEGER NOT NULL, score INTEGER NOT NULL, level TEXT NOT NULL, recommendation TEXT, timestamp TEXT NOT NULL)
Q10 第三个盐值片段
题目:该应用中的第三个盐值片段是通过逐字符拼接生成的。请问该片段拼接后的完整内容是什么?[答案格式:K8m!pQ2x]
答案:X9kZ!qW3
答案状态:已验证 | 验证等级:L1
解题思路:
KeyDeriver.java 第68-70行 getSaltPart3() 方法逐字符拼接:
char[] chars = {'X', '9', 'k', 'Z', '!', 'q', 'W', '3'};
return new String(chars);
Q11 DEX内存加载Hook方法
题目:该应用使用了载荷在内存中直接加载而不在磁盘落地。若选手希望通过Frida动态拦截明文的DEX字节数组,应该Hook该应用壳的哪个私有方法?[答案格式:loadDexFromMemory]
答案:initDexFromMemory
答案状态:已验证 | 验证等级:L1
解题思路:
ShellApplication.smali 中定义了私有方法 initDexFromMemory([B),使用 dalvik.system.InMemoryDexClassLoader 加载DEX字节数组,通过反射合并dexElements到PathClassLoader。这是Frida拦截明文DEX字节数组的Hook点。
关键证据:
- ShellApplication.smali 私有方法签名:
initDexFromMemory([B) - 使用 InMemoryDexClassLoader 内存加载
Q12 壳解密密钥
题目:分析应用的壳代码逻辑,其解密密钥由3个字符串片段混淆拼接而成。请通过静态分析,还原用于解密的3个片段拼接合并后的完整密钥明文。[答案格式:Ab6de_a8bc4d_a5b_345d]
答案:Sh3ll_L0ad3r_K3y_2024!
答案状态:已验证 | 验证等级:L2
解题思路:
分析 ShellApplication.smali 的 getKeyPart1/2/3 三个方法,还原3个片段:
- Part1: Base64解码 “U2gzbGxf” → “Sh3ll_”
- Part2: XOR字节数组 [0x5d,0x21,0x70,0x75,0x22,0x63,0x4e,0x5a] ^ 0x11 → “L0ad3r_K”
- Part3: 反转 “!4202_y3” → “3y_2024!”
拼接后完整密钥:Sh3ll_L0ad3r_K3y_2024!
重点命令:
# 分析smali_classes3中ShellApplication.smali的getKeyPart1/2/3方法
cat smali/com/shell/loader/ShellApplication.smali | grep -A20 "getKeyPart"
# Python验证拼接结果
python3 -c "
import base64
p1 = base64.b64decode('U2gzbGxf').decode() # Sh3ll_
p2 = ''.join(chr(b ^ 0x11) for b in [0x5d,0x21,0x70,0x75,0x22,0x63,0x4e,0x5a]) # L0ad3r_K
p3 = '!4202_y3'[::-1] # 3y_2024!
print(p1 + p2 + p3) # Sh3ll_L0ad3r_K3y_2024!
"
关键输出:
Sh3ll_L0ad3r_K3y_2024!
Q13 进程自杀方法签名
题目:当选手尝试使用frida-dexdump等通用脱壳工具动态附加时,应用会立刻闪退。请分析该逻辑,写出该线程触发进程自杀所调用的完整Java系统方法签名。[答案格式:abcd.abcd.Abcdabc.abcd]
答案:java.lang.System.exit
答案状态:已验证 | 验证等级:L1
解题思路:
ShellApplication 启动反调试守护线程 startAntiDumperDaemon(),检测逻辑:
- 检查
/proc/self/status的 TracerPid(非0表示被调试) - 检查
/proc/self/maps中的 “frida-agent” 和 “frida-gadget” - 发现调试器时调用
java.lang.System.exit(0)自杀
smali代码中 lambda$startAntiDumperDaemon$0 调用 java/lang/System;->exit(I)V。
Q14 加入群数
题目:方俊朗使用其内部通联工具时,共加入过几个群?[答案格式:7]
答案:2
答案状态:已验证 | 验证等级:L1
解题思路:
应用包名 com.socialchat.social_chat_app(Flutter + SQLCipher加密)。从 shared_prefs 获取数据库密码 Pgs-dbw1776826167125Good,substring(2,-1) 截取为 s-dbw1776826167125Goo 解密 social_chat.db。
查询 conversation 表:
SELECT * FROM conversation WHERE type='G'
返回2条群会话记录:
- 技术部群 (conv_g_技术部群_usr_caishangwang)
- 话务组群 (conv_g_话务组群_usr_caishangwang)
另外2个会话是单聊(type=‘D’):军师、宰相。
Q15 物联网用户信息数
题目:方俊朗通过物联网设备漏洞,共获得多少用户信息?[答案格式:10]
答案:32
答案状态:已验证 | 验证等级:L2
解题思路:
解密 social_chat.db 消息表,msg_000057(与 usr_zaixiang/宰相的对话)原文:
“已经拿到32个高端用户的数据,主要是扫地机器人和安防摄像头”
交叉验证:msg_000126 提到"整理了32个高端小区的数据样本",数字一致。usr_caishangwang(方俊朗/财商网)向 usr_zaixiang 汇报智能家居漏洞利用成果。
Q16 内部通联包名
题目:分析周文杰Image.zip检材,周文杰跟其犯罪团伙人员内部通联工具包名是?[答案格式:com.apt.app]
答案:com.socialchat.social_chat_app
答案状态:已验证 | 验证等级:L1
解题思路:
解压 Image.zip 列出所有应用数据目录,发现 data/data/com.socialchat.social_chat_app/ 目录存在。与方俊朗案例相同的 Flutter + SQLCipher 内部通联工具。用户为 zhouwenjie (usr_jinlinwang / 金鳞王)。
重点命令:
unzip -l "/mnt/z/周文杰/Image.zip" | grep "data/data/" | head -20
# 发现 data/data/com.socialchat.social_chat_app/ 目录
Q17 聊天数据库名称
题目:内部通联app聊天数据库名称是?[答案格式:abc.db]
答案:social_chat.db
答案状态:已验证 | 验证等级:L2
解题思路:
在 data/data/com.socialchat.social_chat_app/databases/ 目录下找到 SQLCipher 加密数据库 social_chat.db(192KB)。用 flutter.db_password 解密成功。
Q18 数据库密码保存文件
题目:内部通联app聊天数据库密码保存在哪个文件中?[答案格式:Abc.txt]
答案:FlutterSharedPreferences.xml
答案状态:已验证 | 验证等级:L1
解题思路:
在 data/data/com.socialchat.social_chat_app/shared_prefs/FlutterSharedPreferences.xml 中找到 flutter.db_password = Pgs-dbw1776853545473Good。
Q19 聊天数据库密码
题目:内部通联app聊天数据库密码是?[答案格式:123-abc]
答案:s-dbw1776853545473Goo
答案状态:已验证 | 验证等级:L2
解题思路:
Flutter SQLCipher 标准模式:shared_prefs 中的完整密码 Pgs-dbw1776853545473Good,通过 substring(2,-1) 截取(去掉前2个字符和最后1个字符)得到数据库密钥 s-dbw1776853545473Goo。
用此密码 SQLCipher PRAGMA key 解密 social_chat.db 成功,确认密码正确。
重点命令:
import sqlcipher3 as sqlite3
full_pwd = "Pgs-dbw1776853545473Good"
sub_pwd = full_pwd[2:-1] # s-dbw1776853545473Goo
conn = sqlite3.connect("social_chat.db")
cursor = conn.cursor()
cursor.execute(f"PRAGMA key = '{sub_pwd}'")
tables = cursor.execute("SELECT name FROM sqlite_master WHERE type='table'").fetchall()
# 解密成功,返回表列表
Q20 聊天数据加密算法
题目:内部通联app聊天数据使用的什么加密算法?[答案格式:ABCDEF]
答案:AES
答案状态:已验证 | 验证等级:L2
解题思路:
解密 social_chat.db 后分析 user 表 config_data 字段,包含 enc_key(256-bit)和 enc_iv(128-bit),均为 Base64 编码。消息 content 字段为 Base64 编码的 AES-CBC 密文。
用 Python Crypto.Cipher.AES 成功解密所有247条消息内容,确认为 AES-CBC-256 加密。
重点命令:
from Crypto.Cipher import AES
import base64
# 从user表config_data获取enc_key和enc_iv(Base64编码)
key = base64.b64decode(enc_key_b64)
iv = base64.b64decode(enc_iv_b64)
cipher = AES.new(key, AES.MODE_CBC, iv)
plaintext = cipher.decrypt(base64.b64decode(content_b64))
# 247条消息全部解密成功 → 确认为AES-CBC
Q21 用户密码盐值
题目:内部通联app用户密码的盐值是?[答案格式:1234abcd]
答案:a3f8d9c2e1b4h7g6k9m2n5p8q1r4t7w
答案状态:已验证 | 验证等级:L1
解题思路:
解密 social_chat.db 后查询 user 表 password_salt 字段,直接获取周文杰的密码盐值。密码哈希算法为双重 SHA256:SHA256(SHA256(password+salt).hexdigest())。
Q22 密码提示应用包名
题目:记录周文杰内部通联app登录密码提示的应用包名是?[答案格式:com.temp.app]
答案:com.jinghong.notebookkssjh
答案状态:已验证 | 验证等级:L2
解题思路:
从 Image.zip 中找到笔记应用 com.jinghong.notebookkssjh,NotePal.db 中 gt_note 表记录"英文2 +数字6",标签为 mima(密码)。附件文件 20260423_100403_179.md 内容一致:“英文2 +数字6”。双源确认密码格式提示。
Q23 内部通联登录密码
题目:内部通联app登录密码是?[答案格式:123abc]
答案:mb202623
答案状态:已验证 | 验证等级:L2
解题思路:
多阶段破解流程:
阶段1 — APK确认算法:
从 libapp.so strings 提取关键字符串确认密码哈希逻辑:generateSalt, hashPassword, CryptoUtils。算法为 SHA256(SHA256(password+salt).hexdigest()) — 双重 SHA256。
阶段2 — 获取目标值:
- 目标 hash:
5d85b77d7d6d1a76cd589c3ba21d1839b1dd28568e39f1d2facc3a1b7d2e8bcb - 盐值:
a3f8d9c2e1b4h7g6k9m2n5p8q1r4t7w
阶段3 — 密码格式提示:
笔记应用记录"英文2 +数字6"(2字母+6数字=8字符)。
阶段4 — 暴力破解:
全量爆破所有2小写字母+6位数字组合(26×26×10^6 ≈ 6754万种),找到 mb202623 匹配。
验证:
import hashlib
salt = "a3f8d9c2e1b4h7g6k9m2n5p8q1r4t7w"
pwd = "mb202623"
h = hashlib.sha256(hashlib.sha256((pwd + salt).encode()).hexdigest().encode()).hexdigest()
# h == "5d85b77d7d6d1a76cd589c3ba21d1839b1dd28568e39f1d2facc3a1b7d2e8bcb" ✓
Q24 删除聊天记录数
题目:周文杰在内部通联app中删除了几条聊天记录?[答案格式:123]
答案:6
答案状态:已验证 | 验证等级:L2
解题思路:
APK libapp.so 确认查询条件 conversation_id = ? AND extra_val = 0(extra_val=0 为正常消息),即 extra_val=1 为已删除。数据库统计 extra_val=1 共6条记录:msg_000002, msg_000005, msg_000007, msg_000010, msg_000012, msg_000030。
数据库分布:extra_val=0(241条),extra_val=1(6条)。
Q25 删除标记字段
题目:聊天数据库中,显示聊天数据删除的是哪个字段?[答案格式:ab_cd]
答案:extra_val
答案状态:已验证 | 验证等级:L2
解题思路:
APK libapp.so 中 SQL 查询条件确认 extra_val 为删除标记字段:conversation_id = ? AND extra_val = 0。数据库验证分布:extra_val=0(241条正常),extra_val=1(6条已删除)。
Q26 隐藏应用名称
题目:分析林小婉手机检材,发现有个应用隐藏了很多信息,目前已经找到这个应用,它的程序名称是?[答案格式:微信]
答案:今日头条
答案状态:已验证 | 验证等级:L1
解题思路:
从模拟器数据导出中发现 com.jinritoutiao.news 应用目录。用 aapt dump badging 确认应用名称为"今日头条"。应用伪装成今日头条,实际是安全保险箱类应用(vault),内含加密数据 vault_data.jth2,包含钱包、银行、账本、密码、C2配置等隐藏数据。
重点命令:
aapt dump badging "/mnt/d/文档/hermes-work/ctf/1778310207366_9eee4f1c.apk" 2>/dev/null | grep -E "^package:|^application-label:" | head -3
# package: name='com.jinritoutiao.news' versionCode='1' versionName='9.8.5'
# application-label:'今日头条'
Q27 PIN码
题目:这个应用有一个安全加密的PIN码,它是多少?[答案格式:12345678]
答案:20150412
答案状态:已验证 | 验证等级:L2
解题思路:
多阶段破解流程:
阶段1 — APK反编译获取参数:
apktool 反编译 APK,分析 smali 代码:
- CryptoUtils.smali:DB_ENCRYPTION_KEY = “12345678901234567890123456789012”(32字节AES密钥)
- VaultDataLoader.smali:MASTER_SEED = “Jinritoutiao_Master_Key_2024_Secret”,PBKDF2_SALT = “JinriSalt_2024”,iterations=65536
阶段2 — PIN验证逻辑分析:
NativeCrypto.so 库中 verifyPin 函数使用 PBKDF2-HmacSHA256 计算 PIN hash,与 rodata 中硬编码的期望值进行 XOR 比较。smali 代码 verifyPinKotlin() 直接硬编码了所有参数:
- salt = “JinriPIN_Salt_”
- iterations =
const/16 v6, 0x2710= 10000(注意:非 so 库中的 65536!) - key length =
const/16 v7, 0x100= 256 bits = 32 bytes - expectedHash = “7e881d49322271f3dd4fa24846a5cc53d1e0506b46007caa4b27f1416b27b54c”
阶段3 — PIN提示发现:
NavigationKt.smali line 1477:
const-string v1, "\u5973\u513f\u751f\u65e5" → "女儿生日"
invoke-static {v1, ...}, mutableStateOf$default
pinHint = “女儿生日”,提示 PIN 为生日格式 YYYYMMDD。
阶段4 — 暴力破解:
在 2000-01-01 到 2026-12-31 范围内(共9500个日期),用 PBKDF2-Hmac-SHA256 计算每个日期的 hash,与期望值比较。
重点命令:
import hashlib, datetime
expected = bytes.fromhex("7e881d49322271f3dd4fa24846a5cc53d1e0506b46007caa4b27f1416b27b54c")
salt = b'JinriPIN_Salt_'
for d in range((datetime.date(2026,12,31)-datetime.date(2000,1,1)).days+1):
pin = (datetime.date(2000,1,1) + datetime.timedelta(d)).strftime("%Y%m%d")
h = hashlib.pbkdf2_hmac('sha256', pin.encode(), salt, 10000, 32)
if h == expected: print(f"FOUND: {pin}"); break
# 结果: FOUND: 20150412 (第5581个日期, 耗时8.0s)
踩坑与修正:
- so 库中 iterations=65536,但 smali verifyPinKotlin() 实际使用 iterations=10000(
const/16 v6, 0x2710)。以 smali 为准,因为 Kotlin 层直接调用 PBKDF2,不经过 so 库。
Q28 notes字段含义
题目:这个应用隐藏的数据中,每个标签数据里,notes字段表示多少?[答案格式:事项]
答案:备注
答案状态:已验证 | 验证等级:L1
解题思路:
解密 vault_data.jth2(AES-GCM + PBKDF2)后分析 JSON 结构,notes 字段在所有类别中均存储描述性备注文本:
- wallet.notes: “老板私人钱包”, “日常运营资金”, “应急使用”
- bank.notes: “主资金账户”, “备用账户”, “日常费用卡”
- c2.notes: “数据库连接”, “云ERP访问”, “财务数据备份”
- contacts.notes: “直接上级”, “日常付款对接”, “账务审核”
所有 notes 值均为对人/账户/服务器的描述性备注信息。
Q29 备份服务器IP
题目:这个应用隐藏的数据中,文件备份服务器的IP地址是多少?[答案格式:192.168.1.1]
答案:192.168.1.200
答案状态:已验证 | 验证等级:L1
解题思路:
解密 vault_data.jth2 后,c2 数组第3项:
{
"name": "文件备份服务器",
"type": "备份服务器",
"address": "192.168.1.200",
"port": "22",
"protocol": "SFTP",
"notes": "财务数据备份"
}
Q30 财神撤回消息内容
题目:发现内部通联中财神撤回了一条消息,这个消息的内容是?[答案格式:盘古石杯]
答案:把23年10月到24年6月的账本整理一下,发给我。
答案状态:已验证 | 验证等级:L2
解题思路:
解密林小婉 social_chat.db(数据库密码 s-dbw1776826167125Goo),用 AES-CBC 密钥从 user.config_data 获取后解密消息内容。
关键区分 — RECALLED vs DELETED:
state_bits=1= RECALLED(撤回)→ APK libapp.so 中有_buildRecalledMessage方法extra_val=1= DELETED(删除)→ APK libapp.so 中有_buildDeletedMessage方法
全表278条消息中只有 msg_000317 的 state_bits=1,且发送者是财神(usr_caishen):
- msg_000317: sender=usr_caishen, state_bits=1, extra_val=0 → RECALLED(撤回)
- content: “把23年10月到24年6月的账本整理一下,发给我。”
- msg_000319: sender=usr_zhanggui, extra_val=1, state_bits=0 → DELETED(删除)
- content: “【图片】账单.png”
重点命令:
# APK libapp.so确认RECALLED vs DELETED
strings /tmp/socialchat_libapp.so | grep -E "_buildRecalledMessage|_buildDeletedMessage|state_bits|extra_val"
# _buildRecalledMessage → state_bits=1 (RECALLED/撤回)
# _buildDeletedMessage → extra_val=1 (DELETED/删除)
踩坑与修正:
- 原答案"【图片】账单.png"对应 msg_000319(extra_val=1, DELETED/删除),非财神撤回的消息。
- 正确答案来自 msg_000317(state_bits=1, RECALLED/撤回),发送者是财神。
Q31 账本打开密码
题目:发现了账本,账本打开密码是什么?[答案格式:按实际填写]
答案:DragonTeng@2024#$
答案状态:已验证 | 验证等级:L1
解题思路:
解密 vault_data.jth2 后,password 数组第7项:
{
"website": "龙腾项目账本",
"username": "",
"password": "DragonTeng@2024#$",
"notes": "账单复合.png打开密码"
}
完整性检查:长度=17,包含特殊字符 @#$,无 .../<snip> 截断标记。题目要求"按实际填写",提交完整字面值。
未完成或不可提交题目
| 题号 | 当前答案 | 答案状态 | 原因 | 下一步 |
|---|---|---|---|---|
| (无) | — | — | 全部31题已完成并验证通过 | — |
附录
关键经验总结
-
APK加壳分析流程:apktool反编译smali → 分析壳代码(getKeyPart, decrypt, initDexFromMemory)→ Python还原密钥 → 解密payload.dat → jadx反编译所有DEX → 小DEX含应用核心代码。
-
Flutter SQLCipher数据库解密:shared_prefs中
flutter.db_password为完整密码,需 substring(2,-1) 截取后作为 PRAGMA key 值。 -
双重SHA256密码爆破:从APK libapp.so确认算法 → 从笔记应用获取格式提示 → 全量爆破 + 哈希验证。
-
RECALLED vs DELETED区分:state_bits=1(撤回)和 extra_val=1(删除)是两个独立字段,需通过APK源码确认UI方法对应关系。
-
PIN码暴力破解:smali代码中的 iterations 值可能与 so 库不同,以 Kotlin 层实际调用为准。提示"女儿生日"→ YYYYMMDD格式日期范围爆破。
-
vault_data.jth2解密:JTH3格式 = header(6 bytes) + IV(12) + ciphertext + tag(16) + hmac(32),使用 AES-GCM 模式,密钥通过 PBKDF2-Hmac-SHA256 从 MASTER_SEED 派生。