文章总结: 该文档为2026平航杯手机取证比赛的完整Writeup,涵盖17道题目的解题过程。核心要点包括:通过PhoneInfoJSON识别Pixel6手机型号;利用高德地图POI行为与预设搜索词双证据交叉验证确定西湖为最可能景点;通过MMKV提取FTS密码并解密SQLCipher数据库,定位好友验证时间2026-03-3015:13:08;从SnsMicroMsg.dbprotobuf解码获取朋友圈内容麻薯小蛋糕。文档展示了从数据提取、解密到逆向分析的全链路取证方法,工具链包括HermesAgent和Qwen3.6模型。 综合评分: 85 文章分类: 应急响应,逆向分析,数据恢复,移动安全,安全工具
- 验证闭环:备忘录原文是倩倩自己的记录,明确写的是”好友冰糖”。截图顶部”冰糖君酱”是微信中的备注名/显示名。题目问”这个好友叫什么名字”,以备忘录原文为准。
- ⚠️ 修正复盘:一度误将截图顶部”冰糖君酱”(微信备注名)作为答案,后经HarmonyOS备忘录原文交叉验证确认为”冰糖”。
🧩 Q8 倩倩的手机-4:推荐的游戏名
-
题目:分析倩倩的手机结合逆向包,推荐的游戏叫什么?【答案格式:far echo】
-
标准答案:
zero sievert -
状态等级:🟢 已验证 / L1
-
解题主线:解密加密截图 Snipaste_2026-04-03_10-56-53.jpg.tb,视觉分析聊天内容找到游戏名。
-
💡 关键证据:
-
解密截图中的聊天内容:
"话说回来我刚打了半天另一款平面射击的类塔科夫游戏呢,叫 zero sievert" -
推荐消息:
"冰糖若喜欢原版塔科夫的话,这个游戏大概也会对你的口味,可以了解下(就是画风和机制完全不一样)" -
验证闭环:截图视觉分析直接提取游戏名 “zero sievert”。
🧩 Q9 倩倩的手机-5:阅读搜狐新闻条数
-
题目:分析倩倩的手机,倩倩一共阅读过多少条搜狐新闻?【答案格式:11】
-
标准答案:
33 -
状态等级:🟢 已验证 / L1
-
解题主线:从HarmonyOS备份中解密
com.sohu.harmonynews模块,在gen_natural_store.db主库的sync_data表中统计 article 开头的记录数。 -
💡 关键证据:
-
gen_natural_store.db sync_data表:
SELECT COUNT(*) FROM sync_data WHERE key LIKE 'article%'→ 33条 -
总记录35条(33条article + CHANNEL_LIST_DATA + NEWS_LIST_DATA)
-
🛠️ 核心命令:
ounter(lineounter(linesqlite3 "$DB" "SELECT COUNT(*) FROM sync_data WHERE key LIKE 'article%';"# → 33
- 验证闭环:主库精确查询,排除非article记录。
- ⚠️ 修正复盘:原答案39来自WAL文件提取(可能包含已删除或重复记录),经主库精确查询修正为33条。
🧩 Q10 倩倩的手机-6:数据加密app包名
-
题目:分析倩倩手机逆向包,数据加密app的包名是什么?【答案格式:com.komeiji.satori】
-
标准答案:
com.koishi.fpt -
状态等级:🟢 已验证 / L1
-
解题主线:解压逆向包RAR,读取
module.json中的bundleName字段。 -
💡 关键证据:
-
module.json:
"bundleName": "com.koishi.fpt" -
🛠️ 核心命令:
ounter(lineounter(lineounter(lineounter(lineounter(lineounter(linemkdir -p /tmp/qianqian-reverse && cd /tmp/qianqian-reverseunrar x /mnt/z/1-手机/倩倩手机逆向包.rar
cd /tmp/qianqian-reverse/app_extract/hap_extractcat module.json | python3 -m json.tool | grep bundleName# "bundleName": "com.koishi.fpt"
- 验证闭环:module.json直接提取,无歧义。
🧩 Q11 倩倩的手机-7:初始化密码最少位数
-
题目:接上题,初始化app时需要至少几位数的密码?【答案格式:10】
-
标准答案:
6 -
状态等级:🟢 已验证 / L1
-
解题主线:从ABC字节码中提取字符串,找到密码长度校验提示。
-
💡 关键证据:
-
ABC字节码strings:
"密码长度至少为6位","请输入新密码(至少6位)" -
🛠️ 核心命令:
ounter(lineounter(lineounter(linestrings ets/modules.abc > /tmp/abc_strings.txtgrep "至少为6位" /tmp/abc_strings.txt# "密码长度至少为6位"
- 验证闭环:两处字符串均确认最少6位。
🧩 Q12 倩倩的手机-8:加密文件后缀
-
题目:接上题,加密后的文件名的后缀是什么?【答案格式:.enc】
-
标准答案:
.tb -
状态等级:🟢 已验证 / L1
-
解题主线:从ABC字节码中提取
.tb后缀字符串,vault目录中实际加密文件也使用.tb后缀。 -
💡 关键证据:
-
ABC字节码strings:
.tbsuffix found -
vault目录文件:
139346145_p0.png.tb,Snipaste_2026-04-03_10-56-53.jpg.tb,*.json.tb -
🛠️ 核心命令:
ounter(lineounter(linegrep "\.tb" /tmp/abc_strings.txt# .tb
- 验证闭环:ABC字节码 + vault目录实际文件双重确认。
🧩 Q13 倩倩的手机-9:自动识别图片后缀种类数
-
题目:接上题,app会自动识别几种后缀的文件为图片类型?【答案格式:8】
-
标准答案:
5 -
状态等级:🟢 已验证 / L1
-
解题主线:从ABC字节码中提取文件类型列表,区分图片和视频类型。
-
💡 关键证据:
-
图片类型(5种): jpg, jpeg, png, gif, webp
-
视频类型(4种): mp4, mov, avi, mkv
-
ABC字节码中文件类型列表:
-
题目问的是”图片类型”,答案为5
-
🛠️ 核心命令:
ounter(lineounter(lineounter(lineounter(lineounter(lineounter(linepython3 -c "with open('ets/modules.abc','rb') as f: data=f.read()pos = data.find(b'jpg')print(data[pos-10:pos+80].decode('utf-8',errors='replace'))"# jpg, jpeg, png, gif, webp (5种图片)
- 验证闭环:ABC字节码中明确列出5种图片后缀。
🧩 Q14 倩倩的手机-10:SO模块导入方法数
-
题目:接上题,app共从用于自定义加密的so模块导入了几个方法?【答案格式:8】
-
标准答案:
2 -
状态等级:🟢 已验证 / L2
-
解题主线:
-
阶段1 — ABC字节码初步分析:发现9个导入符号(t1,u1,v1,w1,z1,a2,b2,c2,d2),但其中q1(random)和s1(base64)是TypeScript工具函数,非SO导入
-
阶段2 — IDA反汇编验证:加载libcrypto.so,分析NAPI模块注册流程
-
阶段3 — 交叉确认:napi_define_properties调用时count=2,属性表仅rot13和xorEncrypt
-
💡 关键证据:
-
证据源1 — IDA反汇编:
sub_5D58调用napi_define_properties,参数W2=#2(AArch64调用约定x2=第三个参数=count),明确定义了2个NAPI属性 -
证据源2 — 属性表0xd8f0:方法1=
rot13(→sub_5DE0), 方法2=xorEncrypt(→sub_603C) -
证据源3 — NAPI module结构体0xed48:version=1, register_func=sub_5D58, module_name=”crypto”
-
ABC字节码中的9个符号(t1,u1,v1,w1,z1,a2,b2,c2,d2)是ArkTS编译后的局部混淆名,大部分对应标准C库函数(malloc,free,memcpy等),非NAPI注册方法
-
🛠️ 核心命令:
ounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(line# IDA MCP 工具调用 (非shell命令):# 1. 查看RegisterCryptoModule反汇编mcp_ida_disasm(addr="RegisterCryptoModule")# → NOP; ADR X0, unk_ED48; B .napi_module_register
# 2. 查看sub_5D58反汇编 (napi_define_properties调用者)mcp_ida_disasm(addr="sub_5D58")# → MOV W2, #2 (count=2个属性)# → BL .napi_define_properties
# 3. 读取属性表数据mcp_ida_get_string(addrs=["0x23f0", "0x3312"])# → "rot13", "xorEncrypt"
# 结论: Q14答案 = 2 (L2 IDA反汇编 + ABC交叉验证)
- 验证闭环:IDA MCP反汇编确认NAPI只注册了2个方法,ABC字节码9个导入符号中大部分是标准C库函数。
- ⚠️ 修正复盘:原答案9误将ABC字节码中的混淆名t1,u1,v1,w1,z1,a2,b2,c2,d2当作SO导入方法,经IDA反汇编确认实际只有2个NAPI方法(rot13, xorEncrypt)。
🧩 Q15 倩倩的手机-11:app设置的密码
-
题目:接上题,app设置的密码是多少?【答案格式:514aalla4191a98】
-
标准答案:
217cb94a01679e39 -
状态等级:🟢 已验证 / L2
-
解题主线:
-
阶段1 — vault_prefs分析:提取
password_hash=217sr94q01679u39 -
阶段2 — SO rot13函数IDA反汇编:发现rot13(sub_5DE0)实际是ROT+16算法
-
阶段3 — ROT-16逆运算恢复原始密码:对password_hash做ROT-16逆变换
-
💡 关键证据:
-
a→q(shift=16), b→r, c→s… z→p
-
vault_prefs:
password_hash=217sr94q01679u39(ROT+16变换后的存储值) -
IDA反汇编 sub_5DE0:
MOV W15,#0xAF+ 除法优化 =(ch+0xAF)%26+'a'= ROT+16算法 -
精确验证:对a-z全部26字母测试,shift均为16
-
密码变换链:用户输入
217cb94a01679e39→ ROT+16 →217sr94q01679u39→ vault_prefs存储 -
原始密码恢复:ROT-16(
217sr94q01679u39) =217cb94a01679e39 -
🛠️ 核心命令:
ounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(line# IDA MCP 工具调用:mcp_ida_disasm(addr="sub_5DE0")# 关键指令: MOV W15, #0xAF (175) -> 偏移量# 算法: (ch + 0xAF) % 26 + 'a' = ROT+16
# Python精确验证rot13=ROT+16python3 -c "def ida_rot(ch): c = ord(ch) w13 = (c + 0xAF) & 0xFFFF w15 = (w13 * 0x4F) >> 11 w13 = w13 - (w15 * 0x1A) w13 = w13 + 0x61 return chr(w13 & 0xFF)
for ch in 'abcdefghijklmnopqrstuvwxyz': r = ida_rot(ch) shift = (ord(r) - ord(ch)) % 26 print(f'{ch} -> {r} (shift={shift})')"# 全部shift=16,确认是ROT+16
# ROT-16逆运算恢复原始密码python3 -c "pw_hash = '217sr94q01679u39'result = ''for ch in pw_hash: if 'a' <= ch <= 'z': result += chr((ord(ch) - ord('a') - 16) % 26 + ord('a')) else: result += chprint(f'password_hash: {pw_hash}')print(f'ROT-16恢复: {result}')"# → 217cb94a01679e39
# 验证ROT+16正向变换python3 -c "original = '217cb94a01679e39'result = ''for ch in original: if 'a' <= ch <= 'z': result += chr((ord(ch) - ord('a') + 16) % 26 + ord('a')) else: result += chprint(f'original: {original}')print(f'ROT+16: {result}')"# → 217sr94q01679u39 (与vault_prefs一致)
- 验证闭环:正向ROT+16(217cb94a01679e39) = 217sr94q01679u39,与vault_prefs中password_hash完全一致。用存储值作为xorEncrypt key成功解密所有3个.tb文件(JSON完美、PNG 16/16匹配、JPG FFD8正确)。
🧩 Q16 倩倩的手机-12:门锁密码
-
题目:接上题,app中存储的门锁密码是多少?【答案格式:5141141919810】
-
标准答案:
1472580369123 -
状态等级:🟢 已验证 / L1
-
解题主线:用xorEncrypt算法解密notes JSON文件,提取门锁密码。
-
💡 关键证据:
-
xorEncrypt加密公式:
output[i] = data[i] ^ (key[i % key_len] + (i % key_len)) -
解密key =
217sr94q01679u39(vault_prefs存储值) -
解密后JSON内容:
{"id":"b88c3348-9389-4fad-8cd6-3490e6bbdd26","title":"门锁密码","content":"1472580369123","updatedAt":1775196161152} -
🛠️ 核心命令:
ounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(line# xorEncrypt解密 (Python)key = b'217sr94q01679u39'with open('b88c3348-9389-4fad-8cd6-3490e6bbdd26.json.tb', 'rb') as f: ct = f.read()pt = bytes(ct[i] ^ (key[i % len(key)] + (i % len(key))) for i in range(len(ct)))import jsondata = json.loads(pt)print(data['content'])# → 1472580369123
- 验证闭环:解密后JSON结构完整,title=”门锁密码”,content=”1472580369123″。
🧩 Q17 倩倩的手机-13:加密图片隐藏flag
-
题目:接上题,加密图片里面的隐藏的flag是多少?【答案格式:flag{123456!}】
-
标准答案:
flag{happy_forensics_2026!} -
状态等级:🟢 已验证 / L1
-
解题主线:用xorEncrypt解密PNG文件后,检查PNG结构发现IEND chunk后有27字节额外数据。
-
💡 关键证据:
-
解密后的PNG文件 (3200×2000, 5.7MB) 包含709个chunk
-
最后一个正常chunk是 IEND (0字节数据)
-
IEND之后有27字节额外数据:
flag{happy_forensics_2026!} -
标准PNG阅读器忽略IEND后的数据,属于文件末尾隐写
-
🛠️ 核心命令:
ounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(line# xorEncrypt解密PNGkey = b'217sr94q01679u39'with open('139346145_p0.png.tb', 'rb') as f: ct = f.read()pt = bytes(ct[i] ^ (key[i % len(key)] + (i % len(key))) for i in range(len(ct)))
# 检查PNG IEND后数据png_data = bytearray(pt)iend_pos = png_data.find(b'IEND')if iend_pos >= 0: after_iend = png_data[iend_pos+8:] # IEND + 4字节CRC print(after_iend[:50])# → b'flag{happy_forensics_2026!}'
- 验证闭环:PNG文件结构完整(709个chunk),IEND后27字节为纯文本flag。
🛑 未完成或不可提交题目审计
全量收敛:17/17题全部完成并验证,无未完成题目。
| 题号 | 状态 | 备注 | | — | — | — | | Q1-Q17 | 🟢 已验证 | 全部从原始检材独立复现验证通过 |
📂 附录:自动化取证证据大索引
证据索引
| 编号 | 题号 | 证据描述 | 来源文件 | | — | — | — | — | | FINDING-Q1-001 | Q1 | PhoneInfo JSON Model字段 | PhoneInfo-1775206177238 | | FINDING-Q2-001 | Q2 | 高德POI访问记录 | PoiDetailUserBehavior.xml | | FINDING-Q2-002 | Q2 | 高德预设搜索词 | pre_set_word_local_storage.xml | | FINDING-Q3-001 | Q3 | FTS5数据库解密成功 | FTS5IndexMicroMsg_encrypt.db | | FINDING-Q3-002 | Q3 | 联系人索引建档时间(非答案) | FTS5MetaContact | | FINDING-Q3-003 | Q3 | MMKV FTS密码查找方法验证 | mmkv_private/ConfigStorage2 | | FINDING-Q3-004 | Q3 | 好友验证消息时间戳修正 | FTS5MetaMessage docid=38 | | FINDING-Q4-001 | Q4 | 朋友圈protobuf解码内容 | SnsMicroMsg.db | | FINDING-Q5-001 | Q5 | 系统版本直接证据 | .info.json | | FINDING-Q6-001 | Q6 | “舔狗”微信ID从WAL提取 | fts_contact.db-wal | | FINDING-Q7-001 | Q7 | 截图视觉分析(冰糖君酱) | Snipaste_2026-04-03_10-56-53.jpg | | FINDING-Q7-002 | Q7 | 备忘录原文确认”冰糖” | notepad.db cloud_notes | | FINDING-Q7Q8-001 | Q7/Q8 | 游戏推荐截图完整分析 | Snipaste_2026-04-03_10-56-53.jpg | | FINDING-Q9-001 | Q9 | 搜狐新闻主库精确统计 | gen_natural_store.db sync_data | | FINDING-Q10-001 | Q10 | app包名从module.json提取 | module.json | | FINDING-Q11-001 | Q11 | 密码最少位数字符串 | ABC字节码strings | | FINDING-Q12-001 | Q12 | 加密后缀.tb | ABC字节码strings | | FINDING-Q13-001 | Q13 | 图片类型5种列表 | ABC字节码文件类型列表 | | FINDING-Q14-001 | Q14 | SO实际导出2个NAPI方法 | libcrypto.so反汇编 | | FINDING-Q14-IDA-001 | Q14 | IDA MCP验证NAPI方法数 | IDA反汇编 | | FINDING-Q15-001 | Q15 | xorEncrypt算法完整破解 | libcrypto.so + PNG已知明文攻击 | | FINDING-Q15-IDA-002 | Q15 | IDA确认rot13=ROT+16 | IDA反汇编 sub_5DE0 | | FINDING-Q16-001 | Q16 | 门锁密码从加密notes提取 | b88c3348…json.tb解密JSON | | FINDING-Q17-001 | Q17 | PNG IEND后隐藏flag | 解密PNG文件末尾27字节 | | FINDING-HarmonyOS-Backup-Decrypt | Q6-Q9 | HarmonyOS备份二次解密完整流程 | .info.json + PBKDF2 + AES-GCM |
命令索引
| 编号 | 描述 | | — | — | | CMD-20260707-001 | Q3 FTS5IndexMicroMsg_encrypt.db 独立解密验证 | | CMD-20260707-Q3V1 | Q3 答案验证 — 好友验证消息时间戳确认 | | CMD-20260707-Q5V1 | Q5 独立验证 — .info.json直接读取 | | CMD-20260707-Q14-IDA | Q14 IDA MCP 独立验证 — NAPI方法数 | | CMD-20260707-Q15-IDA | Q15 IDA MCP rot13=ROT+16 验证 | | CMD-20260708-V001 | 全量验证批次 — 17题从原始检材独立复现 |
- 全链路取证闭环完成 -
- END –
免责声明:
本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。
任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。
本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我。
本文转载自:取证与溯源 怪叔叔 怪叔叔《2026平航杯 手机取证题解析》
版权声明
本站仅做备份收录,仅供研究与教学参考之用。
读者将信息用于其他用途的,全部法律及连带责任由读者自行承担,本站不承担任何责任。










评论