第四届黄河流域公安院校电子物证个人赛程序逆向分析

yagami 发表于 2 小时前 共 4,447 字、阅读约 14 分钟

🏆 2026第四届黄河流域公安院校电子物证个人赛 — 程序逆向分析 Writeup


💡 报告元数据

  • 首席取证官yagami
  • 任务目录/mnt/d/文档/hermes-work/2026黄河流域-程序逆向分析/
  • 生成时间:2026-08-04
  • 生成模式:完整型取证交付 Writeup

🛠️ 工具链与环境底座

1. 算力与架构

组件分类 部署详情
自动化编排 Hermes Agent
基座大模型 Qwen3.6-27B-Uncensored-HauhauCS-Aggressive-Q6_K_P
运行架构 本地 (WSL / Windows Subsystem for Linux)

2. 任务信息

  • 考核范围:程序逆向分析(APK静态分析 + PE二进制分析),共10题
  • 检材来源/mnt/z/2026第四届黄河流域公安院校电子物证个人赛检材/3.第三部分:程序逆向分析/
  • 检材内容:TuoxinTask-v3.2.1.zip(内含APK)、HuangHe2026.zip(内含PE)
  • 动态状态:Q1-Q10 全部已验证,全量收敛
  • 质控策略:L1-L3多级验证,Java↔native交叉验证,本地Python解密双向验证

📊 考题最终答案汇总看板

题号 核心考点 权威标准答案 状态 等级 核心证据链检索摘要
Q1 APK包名提取 com.tuoxin.task 🟢 已验证 L1 AndroidManifest.xml package字段直接确认
Q2 通讯录窃取写入文件 contacts_bak.json 🟢 已验证 L1 DataUploadService.a()方法openFileOutput参数硬编码
Q3 cfg.bin加密方式(多选) BCF 🟢 已验证 L2 Base64编码+AES-256-CBC+IV来自独立iv.bin,三源交叉
Q4 cfg.bin解密key 47f32b6c3c50f7474f3a14787ef790f46d326e7a33a758d0c7e452cb120e0700 🟢 已验证 L3 HARD_KEY hex = SHA-256(key source),Java↔native交叉+本地解密双向验证
Q5 cfg.bin备份IP及端口 121.43.187.92:8080 🟢 已验证 L2 cfg.bin解密后JSON中sdk_backup_server字段
Q6 PE编译器识别 B (Borland Delphi 6) 🟢 已验证 L2 Borland\Delphi\RTL字符串+Delphi单元引用+名称修饰+oleaut32 BSTR函数,多特征交叉
Q7 PE节区数量 8 🟢 已验证 L1 PE头NumberOfSections=8,IDA确认8个节区
Q8 PE入口点VA 0x492040 🟢 已验证 L1 ImageBase(0x400000)+RVA(0x92040)=0x492040,IDA交叉确认
Q9 注册表值名 Start 🟢 已验证 L1 IDA字符串搜索ControlSet\Services\UsbStor,值名Start
Q10 PE主要功能 D 🟢 已验证 L2 UsbStor+Start+.inf.disabled+MoveFileA+MessageBoxA,USB启用/禁用工具

⚔️ 深度取证与解题全链路复盘

🧩 Q1 — 刷单APP包名

  • 标准答案com.tuoxin.task

  • 状态等级:🟢 已验证 / L1

  • 解题主线
    使用jadx MCP直接读取AndroidManifest.xml,提取package属性值。APK反编译后manifest文件中的package字段即为应用包名。

  • 💡 关键证据

  • 证据编号:FINDING-Q1-001, CMD-20260804-002
  • AndroidManifest.xml中 package="com.tuoxin.task",versionName=“3.2.1”,application name=“com.tuoxin.task.app.TxApplication”
  • 🛠️ 核心命令
# jadx MCP读取AndroidManifest
mcp_jadx_get_android_manifest()
  • 📋 控制台回显
package="com.tuoxin.task", versionName="3.2.1", application name="com.tuoxin.task.app.TxApplication"
  • 验证闭环:AndroidManifest.xml是唯一权威来源,package字段直接确认。

🧩 Q2 — 通讯录数据写入的JSON文件

  • 标准答案contacts_bak.json

  • 状态等级:🟢 已验证 / L1

  • 解题主线
    使用jadx MCP搜索ContactsContract关键字定位通讯录读取点→找到DataUploadService类→分析a()方法完整数据流:从ContactsContract.CommonDataKinds.Phone读取通讯录→经ag0.xorFallback XOR加密→Base64编码→写入本地文件。文件名在openFileOutput()参数中硬编码为"contacts_bak.json",位于getFilesDir()目录下。

  • 💡 关键证据

  • 证据编号:FINDING-Q2-001, CMD-20260804-003
  • DataUploadService.a()方法完整链路:ContactsContract读取→XOR加密→Base64编码→openFileOutput(“contacts_bak.json”)
  • 🛠️ 核心命令
# jadx MCP获取DataUploadService类源码
mcp_jadx_get_class_source(class_name="DataUploadService")
  • 📋 控制台回显
方法a()读取通讯录ContactsContract.CommonDataKinds.Phone,写入文件 "contacts_bak.json"
  • 验证闭环:类源码中openFileOutput参数直接指定文件名,无歧义。

🧩 Q3 — cfg.bin加密方式(多选)

  • 标准答案BCF

  • 状态等级:🟢 已验证 / L2

  • 解题主线
    分析assets/cfg.bin文件的多层处理流程:

  1. 编码层:cfg.bin文件内容为Base64编码文本(B正确,排除A的Base32)
  2. 解码后结构:Base64解码后前8字节为header(“TX-WEB\0\x01\x00”),bytes[8:24]为IV(全0),byte24起为加密数据
  3. 加密算法:AES-256-CBC(C正确,排除D的AES-512-CBC),key由SHA-256派生(32字节)
  4. IV来源陷阱:Java代码中System.arraycopy(bArrDecode, 8, new byte[16], 0, 16)创建临时数组即丢弃,实际IV由native层从独立文件assets/iv.bin读取(16字节,9f4a2c18e6b7d053f8c1aa90d33b44e1)→ F正确,排除E
  • 💡 关键证据
  • 证据编号:FINDING-Q3-001, CMD-20260804-004/005/006
  • cfg.bin为Base64编码,解码后744字节
  • AES-256-CBC加密,key由SHA-256派生
  • IV实际来源:assets/iv.bin(独立文件),非cfg.bin自身
  • 🛠️ 核心命令
# jadx MCP分析decryptConfig类
mcp_jadx_get_class_source(class_name="a.ih")
# jadx MCP分析deriveKey方法
mcp_jadx_get_class_source(class_name="a.ag0")
# 提取并解密cfg.bin
# Python: Base64解码→IV从iv.bin读取→AES-256-CBC解密→JSON解析
  • 📋 控制台回显
Base64解码后744字节,IV从assets/iv.bin读取(9f4a2c18e6b7d053f8c1aa90d33b44e1),AES-256-CBC解密成功,JSON包含sdk_backup_server: "121.43.187.92:8080"
  • 验证闭环:本地Python用PyCryptodome AES-256-CBC解密cfg.bin成功→有效JSON,反向加密与原始密文完全一致(True)。三重证据交叉验证。

  • ⚠️ 修正复盘

  • IV来源是本题最大陷阱:Java代码中System.arraycopy看似从cfg.bin自身提取IV,但创建的临时数组立即丢弃,实际IV由native层从iv.bin读取
  • 多选题需逐项排除:A(Base32)→实际为Base64;D(AES-512-CBC)→实际为AES-256-CBC;E(IV来自文件自身)→实际来自独立iv.bin

🧩 Q4 — cfg.bin解密key

  • 标准答案47f32b6c3c50f7474f3a14787ef790f46d326e7a33a758d0c7e452cb120e0700

  • 状态等级:🟢 已验证 / L3 (三重交叉验证)

  • 解题主线
    阶段1 — Java层密钥派生
    jadx反编译a.ag0.deriveKey()方法,发现执行SHA-256(“tx2_LIVE_q1!v8c1a#|@0x7E::tuoxin.prod::”)得到32字节AES-256密钥。

阶段2 — native层HARD_KEY分析
IDA反编译native层obfuscate.cpp:17,发现HARD_KEY数组存储为混淆值"live_2026_q1_3f8c1a",运行时去混淆后还原。关键发现:HARD_KEY数组32字节的hex拼接值 = 47f32b6c3c50f7474f3a14787ef790f46d326e7a33a758d0c7e452cb120e0700。

阶段3 — 交叉验证

  • SHA-256("tx2_LIVE_q1!v8c1a#|@0x7E::tuoxin.prod:😊 = 47f32b6c…120e0700
  • HARD_KEY hex拼接 = 47f32b6c…120e0700
  • 两者完全一致(Match: True)

阶段4 — 本地解密验证
用该key + iv.bin中的IV,AES-256-CBC解密cfg.bin→有效JSON(含sdk_backup_server: 121.43.187.92:8080),反向加密与原始密文完全一致。

  • 💡 关键证据
  • 证据编号:FINDING-Q4-001/002/003, CMD-20260804-010/011/013
  • Java层:MessageDigest.getInstance(“SHA-256”).digest(“tx2_LIVE_q1!v8c1a#|@0x7E::tuoxin.prod::”.getBytes(“UTF-8”))
  • native层:obfuscate.cpp:17 HARD_KEY数组32字节hex = 47f32b6c…120e0700
  • ag0.verify()确认Java deriveKey == Native nativeGetKey
  • 🛠️ 核心命令
# Java层密钥派生分析
mcp_jadx_get_class_source(class_name="a.ag0")
# native层HARD_KEY交叉对比
# Python本地验证
import hashlib, binascii
key_source = "tx2_LIVE_q1!v8c1a#|@0x7E::tuoxin.prod::"
sha_key = hashlib.sha256(key_source.encode('utf-8')).hexdigest()
print(f"SHA-256 key: {sha_key}")
# 输出: 47f32b6c3c50f7474f3a14787ef790f46d326e7a33a758d0c7e452cb120e0700
# AES-256-CBC解密验证
from Crypto.Cipher import AES
from Crypto.Util.Padding import unpad
import base64
key = bytes.fromhex(sha_key)
iv = bytes.fromhex("9f4a2c18e6b7d053f8c1aa90d33b44e1")
cfg_raw = open("cfg.bin", "rb").read()
cfg_decoded = base64.b64decode(cfg_raw)
cipher = AES.new(key, AES.MODE_CBC, iv)
plaintext = unpad(cipher.decrypt(cfg_decoded[8:]), AES.block_size)
print(plaintext.decode('utf-8'))  # → 有效JSON
  • 📋 控制台回显
HARD_KEY = 47f32b6c3c50f7474f3a14787ef790f46d326e7a33a758d0c7e452cb120e0700
与SHA-256("tx2_LIVE_q1!v8c1a#|@0x7E::tuoxin.prod::")完全一致(Match: True)
AES-256-CBC解密cfg.bin成功→有效JSON(含sdk_backup_server: 121.43.187.92:8080)
  • 验证闭环:L3三重交叉验证 — (1)Java SHA-256输出 = (2)native HARD_KEY hex = (3)本地Python解密成功+反向加密一致。

  • ⚠️ 修正复盘

  • 旧答案tx2_LIVE_q1!v8c1a#|@0x7E::tuoxin.prod::(key source字符串)
  • 修正原因:用户指出obfuscate.cpp:17 HARD_KEY数组32字节hex拼接即为AES-256密钥,与SHA-256(key source)完全一致。题目问"解密key是多少",答案为实际的32字节密钥(hex形式),而非key source字符串
  • native层陷阱:HARD_KEY明文"live_2026_q1_3f8c1a"是混淆存储形式,SHA-256(HARD_KEY明文)解密→非UTF-8(失败),证明需取HARD_KEY数组的hex拼接值

🧩 Q5 — cfg.bin备份IP及端口

  • 标准答案121.43.187.92:8080

  • 状态等级:🟢 已验证 / L2

  • 解题主线
    cfg.bin经Q3/Q4流程解密后得到JSON配置文件,其中包含sdk_internal.sdk_backup_server = “121.43.187.92:8080”。此为备份服务器IP地址及端口。

  • 💡 关键证据

  • 证据编号:FINDING-Q5-001, CMD-20260804-005/006
  • cfg.bin解密后JSON内容:sdk_backup_server: “121.43.187.92:8080”
  • 🛠️ 核心命令
# 同Q4解密流程,解析JSON输出
  • 验证闭环:解密结果JSON中直接包含该字段,与反向加密验证一致。

🧩 Q6 — PE编译器及版本

  • 标准答案B (Borland Delphi 6)

  • 状态等级:🟢 已验证 / L2

  • 解题主线
    使用IDA MCP提取PE文件字符串和导入表,多维度识别编译器特征:

  1. 注册表路径Borland\Delphi\RTLSoftware\Borland\Delphi\Locales
  2. Delphi特有字符串Delphi PictureDelphi ComponentDelphi%.8X
  3. Delphi单元引用:SysUtils, Classes, Forms, Dialogs
  4. 名称修饰@@_@后缀(Delphi name decoration)
  5. oleaut32.dll BSTR函数:SysAllocStringLen, SysReAllocStringLen, SysFreeString

以上特征组合唯一指向Borland Delphi 6。

  • 💡 关键证据
  • 证据编号:FINDING-Q6-001, CMD-20260804-007/008
  • 5类Delphi特征全部命中,无其他编译器特征干扰
  • 🛠️ 核心命令
# IDA MCP字符串搜索
mcp_ida_find(type="string", targets=["Borland", "Delphi", "SysUtils"])
# IDA MCP导入表分析
mcp_ida_imports(offset=0, count=50)
  • 📋 控制台回显
字符串"Borland\Delphi\RTL"、"Software\Borland\Delphi\Locales"
Delphi单元引用:SysUtils, Classes, Forms, Dialogs
名称修饰:@@和_@后缀(Delphi name decoration)
oleaut32.dll BSTR函数:SysAllocStringLen, SysReAllocStringLen, SysFreeString
  • 验证闭环:5类独立特征全部指向Borland Delphi 6,多源交叉确认。

🧩 Q7 — PE节区数量

  • 标准答案8

  • 状态等级:🟢 已验证 / L1

  • 解题主线
    使用pefile解析PE文件头NumberOfSections字段,同时用IDA MCP确认实际节区列表。两者一致为8个节区:CODE, DATA, BSS, .idata, .tls, .rdata, .reloc, .rsrc。

  • 💡 关键证据

  • 证据编号:FINDING-Q7-001, CMD-20260804-007
  • PE头NumberOfSections=8,节区列表:CODE, DATA, BSS, .idata, .tls, .rdata, .reloc, .rsrc
  • 🛠️ 核心命令
# pefile分析
import pefile
pe = pefile.PE('HuangHe2026.exe')
print(f"NumberOfSections: {pe.FILE_HEADER.NumberOfSections}")
for sec in pe.sections:
    print(f"  {sec.Name.decode().strip(chr(0))}")
pe.close()
  • 📋 控制台回显
NumberOfSections=8,节区:CODE, DATA, BSS, .idata, .tls, .rdata, .reloc, .rsrc
  • 验证闭环:pefile与IDA MCP双源确认。

🧩 Q8 — PE入口点VA

  • 标准答案0x492040

  • 状态等级:🟢 已验证 / L1

  • 解题主线
    PE入口点VA = ImageBase + AddressOfEntryPoint(RVA)。pefile读取ImageBase=0x400000,RVA=0x92040,计算VA=0x492040。IDA MCP确认entrypoint地址为0x492040。

  • 💡 关键证据

  • 证据编号:FINDING-Q8-001, CMD-20260804-007/009
  • RVA=0x92040, ImageBase=0x400000, VA=0x492040
  • 🛠️ 核心命令
# pefile计算VA
import pefile
pe = pefile.PE('HuangHe2026.exe')
image_base = pe.OPTIONAL_HEADER.ImageBase
entry_rva = pe.OPTIONAL_HEADER.AddressOfEntryPoint
entry_va = image_base + entry_rva
print(f'Entry Point VA: 0x{entry_va:x}')
pe.close()
  • 📋 控制台回显
NumberOfSections=8,AddressOfEntryPoint RVA=0x92040,ImageBase=0x400000,VA=0x492040
IDA确认entrypoint地址为0x492040
  • 验证闭环:pefile计算与IDA MCP直接读取一致。

🧩 Q9 — 注册表值名

  • 标准答案Start

  • 状态等级:🟢 已验证 / L1

  • 解题主线
    使用IDA MCP搜索PE文件中的注册表相关字符串,找到程序操作的注册表路径ControlSet\Services\UsbStor,读写的值名为"Start"(DWORD类型,控制USB存储驱动加载状态:3=自动/启用,4=手动/禁用)。

  • 💡 关键证据

  • 证据编号:FINDING-Q9-001, CMD-20260804-008
  • 注册表路径:ControlSet\Services\UsbStor,值名:Start
  • 🛠️ 核心命令
# IDA MCP字符串搜索
mcp_ida_find(type="string", targets=["ControlSet", "Services", "UsbStor"])
  • 📋 控制台回显
注册表路径ControlSet\Services\UsbStor,值名Start;字符串"USB Disabler"、".inf.disabled"
  • 验证闭环:IDA字符串搜索直接定位,无歧义。

🧩 Q10 — PE主要功能

  • 标准答案D

  • 状态等级:🟢 已验证 / L2

  • 解题主线
    综合分析PE文件的多维度特征判定功能:

  1. 程序名:“USB Disabler” / “USBDisablerFree”
  2. 注册表操作:修改HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\UsbStor的Start值(3↔4)
  3. 驱动INF操作:重命名.inf ↔ .inf.disabled(使用MoveFileA)
  4. 用户交互:通过MessageBoxA与用户交互

综合判定为USB大容量存储设备启用/禁用工具,匹配选项D。

  • 💡 关键证据
  • 证据编号:FINDING-Q10-001, CMD-20260804-008
  • 4类特征:程序名+注册表Start值+.inf.disabled重命名+MessageBoxA交互
  • 🛠️ 核心命令
# IDA MCP综合字符串搜索
mcp_ida_find(type="string", targets=["USB Disabler", ".inf.disabled", "MoveFileA", "MessageBoxA"])
# IDA MCP导入表分析
mcp_ida_imports(offset=0, count=50)
  • 📋 控制台回显
字符串"USB Disabler"、".inf.disabled";Delphi特征(Borland\Delphi\RTL, SysUtils, Classes, Forms)
注册表路径ControlSet\Services\UsbStor,值名Start
  • 验证闭环:4类独立证据链交叉确认功能为USB启用/禁用工具。选项A(全盘加密)、B(永久移除)、C(日志审计)、E(HID模拟)均无对应特征。

🛑 未完成或不可提交题目审计

题号 当前临时结论 当前跟踪状态 挂起/阻断原因 下一步攻坚策略
全量收敛 Q1-Q10全部已验证,无未完成题目

📂 附录:自动化取证证据大索引

1. 物理证据链索引映射表 (Findings Matrix)

统一证据编号 证据物理源文件 / 捕获链路 核心留存特征内容摘要 支撑断言结论
FINDING-ENV-001 检材目录 HuangHe2026.zip(370KB), TuoxinTask-v3.2.1.zip(3.51MB) 环境确认
FINDING-Q1-001 AndroidManifest.xml package=“com.tuoxin.task” Q1包名
FINDING-Q2-001 DataUploadService.a() ContactsContract→XOR→Base64→contacts_bak.json Q2文件名
FINDING-Q3-001 cfg.bin分析 Base64+AES-256-CBC+IV来自iv.bin Q3加密方式BCF
FINDING-Q4-001 a.ag0.deriveKey() SHA-256("tx2_LIVE_q1!v8c1a# @0x7E::tuoxin.prod:😊
FINDING-Q4-002 obfuscate.cpp:17 HARD_KEY混淆存储"live_2026_q1_3f8c1a" Q4 native层
FINDING-Q4-003 交叉验证 HARD_KEY hex = SHA-256结果,解密成功 Q4最终答案
FINDING-Q5-001 cfg.bin解密JSON sdk_backup_server: “121.43.187.92:8080” Q5备份IP
FINDING-Q6-001 PE字符串+导入表 Borland\Delphi\RTL + 5类Delphi特征 Q6编译器B
FINDING-Q7-001 PE头分析 NumberOfSections=8 Q7节区数
FINDING-Q8-001 PE头+IDA RVA=0x92040, ImageBase=0x400000, VA=0x492040 Q8入口点VA
FINDING-Q9-001 IDA字符串搜索 ControlSet\Services\UsbStor, 值名Start Q9注册表值名
FINDING-Q10-001 PE综合特征 USB Disabler + Start + .inf.disabled + MoveFileA Q10功能D

2. 物理执行指令索引快照表 (Commands Log)

命令流水号 目标取证目的 挂载执行的绝对终端指令 关键输出 结论
CMD-20260804-001 检材目录确认 ls -la 检材目录 HuangHe2026.zip, TuoxinTask-v3.2.1.zip 环境就绪
CMD-20260804-002 APK包名提取 jadx get_android_manifest package=“com.tuoxin.task” Q1确认
CMD-20260804-003 通讯录写入文件 jadx get_class_source DataUploadService 写入"contacts_bak.json" Q2确认
CMD-20260804-004 cfg.bin解密流程 jadx get_class_source a.ih Base64→跳过header→nativeDecryptCfg Q3流程
CMD-20260804-005 密钥派生分析 jadx get_class_source a.ag0 SHA-256(key source) Q4来源
CMD-20260804-006 cfg.bin本地解密 Python PyCryptodome AES-256-CBC JSON含sdk_backup_server Q3/Q5验证
CMD-20260804-007 PE节区+入口点 IDA segments + pefile 8节区, VA=0x492040 Q7/Q8确认
CMD-20260804-008 PE字符串+导入 IDA imports/strings UsbStor/Start/Delphi特征 Q6/Q9/Q10
CMD-20260804-009 pefile独立验证 Python pefile分析 NumberOfSections=8, RVA=0x92040 Q7/Q8交叉
CMD-20260804-010 Q4反向加密验证 Python AES加密比对 重新加密与原始密文一致(True) Q4 L3验证
CMD-20260804-011 Q4 native交叉对比 HARD_KEY SHA-256 vs Java key ag0.verify()确认一致 Q4 L3验证
CMD-20260804-013 Q4 HARD_KEY hex确认 IDA + Python hashlib Match: True, 解密成功 Q4最终确认

- 全链路取证闭环完成 -

退回首页 留下一言