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

🏆 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"
  • 🛠️ 核心命令:
bash 复制代码
# jadx MCP读取AndroidManifest
mcp_jadx_get_android_manifest()
  • 📋 控制台回显:
text 复制代码
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")
  • 🛠️ 核心命令:
bash 复制代码
# jadx MCP获取DataUploadService类源码
mcp_jadx_get_class_source(class_name="DataUploadService")
  • 📋 控制台回显:
text 复制代码
方法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"),bytes8: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 byte16, 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自身
  • 🛠️ 核心命令:
bash 复制代码
# 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解析
  • 📋 控制台回显:
text 复制代码
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
  • 🛠️ 核心命令:
bash 复制代码
# 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
  • 📋 控制台回显:
text 复制代码
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"
  • 🛠️ 核心命令:
bash 复制代码
# 同Q4解密流程,解析JSON输出
  • 验证闭环:解密结果JSON中直接包含该字段,与反向加密验证一致。

🧩 Q6 --- PE编译器及版本

  • 标准答案 :B (Borland Delphi 6)

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

  • 解题主线 :

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

  1. 注册表路径 :Borland\Delphi\RTL、Software\Borland\Delphi\Locales
  2. Delphi特有字符串 :Delphi Picture、Delphi Component、Delphi%.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特征全部命中,无其他编译器特征干扰
  • 🛠️ 核心命令:
bash 复制代码
# IDA MCP字符串搜索
mcp_ida_find(type="string", targets=["Borland", "Delphi", "SysUtils"])
# IDA MCP导入表分析
mcp_ida_imports(offset=0, count=50)
  • 📋 控制台回显:
text 复制代码
字符串"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
  • 🛠️ 核心命令:
bash 复制代码
# 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()
  • 📋 控制台回显:
text 复制代码
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
  • 🛠️ 核心命令:
bash 复制代码
# 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()
  • 📋 控制台回显:
text 复制代码
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
  • 🛠️ 核心命令:
bash 复制代码
# IDA MCP字符串搜索
mcp_ida_find(type="string", targets=["ControlSet", "Services", "UsbStor"])
  • 📋 控制台回显:
text 复制代码
注册表路径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交互
  • 🛠️ 核心命令:
bash 复制代码
# IDA MCP综合字符串搜索
mcp_ida_find(type="string", targets=["USB Disabler", ".inf.disabled", "MoveFileA", "MessageBoxA"])
# IDA MCP导入表分析
mcp_ida_imports(offset=0, count=50)
  • 📋 控制台回显:
text 复制代码
字符串"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最终确认

- 全链路取证闭环完成 -

相关推荐
一技安身30 分钟前
【mysql】Windows MySQL 8.4.10 绿色免安装喂饭教程
windows·mysql·adb
传奇开心果编程1 小时前
【Compose Multiplatform 跨端开发学与练】第8课 资源管理与主题
android·windows·学习·ios·kotlin·web·composer
sukalot2 小时前
Windows 驱动实例分析系列:libwdi 驱动分析 - 应用篇(一)
windows·驱动开发
白帽攻防录2 小时前
SRC 挖洞:V8 Turbofan 沙箱逃逸深度复盘,CVE-2026-6307 一根长矛怎么刺穿 Chrome 两道边界
网络·chrome·安全·网络安全·浏览器安全
传奇开心果编程2 小时前
【Compose Multiplatform 跨端开发学与练】第9课 测试与调试
android·学习·macos·ios·kotlin·web·composer
小道士写程序3 小时前
Windows Rust 环境安装指导
开发语言·windows·rust
传奇开心果编程3 小时前
【Compose Multiplatform 跨端开发学与练】第4课 导航与路由
android·windows·学习·ui·ios·kotlin·composer
Tisfy3 小时前
两台旧电脑修复 —— 绕过WinXP密码登录、备份和恢复Win7数据、安装Win10
windows·数据恢复·系统重装
传奇开心果编程3 小时前
【Compose Multiplatform 跨端开发学与练】第6课 状态管理与架构
android·学习·ui·ios·架构·kotlin·composer
事圆则缓3 小时前
Android AOSP 定制常见概念:源码目录、系统镜像与刷机流程
android