DeviceDataProcessImgui.exe 逆向分析报告
1. 目标概述
| 项目 |
详情 |
| 文件名 |
DeviceDataProcessImgui.exe |
| 架构 |
x86-64, MSVC 编译 |
| 函数总数 |
~3995 |
| 图形框架 |
DirectX 11 + Dear ImGui + ImPlot |
| 数据解析 |
nlohmann::json |
| 其他库 |
QR Code 生成器 (qrcodegen) |
| 性质 |
电流/功率测量数据可视化分析工具 (Current Meter) |
2. 授权系统架构总览
程序采用双文件授权机制,两个文件缺一不可:
用户输入卡密 (19位数字)
│
▼
┌─────────────────┐ ┌──────────────────────┐
│ credentials.bin │ │ activation.bin │
│ (加密存储卡密) │ │ (加密存储授权信息) │
└────────┬────────┘ └──────────┬───────────┘
│ │
▼ ▼
卡密验证通过 type|level|issued|expiry
│ │
└──────────┬──────────────┘
▼
程序解锁运行
文件位置: %APPDATA%\DeviceDataProcessImgui\
3. 序列号生成 (sub_140039470)
3.1 逻辑流程
序列号用于将授权绑定到具体机器,有两种来源(按优先级):
| 优先级 |
来源 |
格式 |
示例 |
| 1 |
注册表 MachineGuid |
MG-{GUID} |
MG-9049b63f-38fe-487c-a1ee-a2b422e59498 |
| 2 |
C:\ 卷序列号 |
VOL-%08lX |
VOL-1A2B3C4D |
3.2 注册表读取 (sub_140039700)
- 键路径:
HKLM\SOFTWARE\Microsoft\Cryptography
- 值名:
MachineGuid
- 访问标志:
0x20119 = KEY_READ | KEY_WOW64_64KEY
- 类型校验: 必须为
REG_SZ (1)
3.3 字符串混淆
所有敏感字符串在二进制中均混淆存储,运行时动态解码:
| 原始位置 |
解码算法 |
解码结果 |
| 0x14003973C (31 wchar) |
(wchar - 229) ^ 0x73 |
SOFTWARE\Microsoft\Cryptography |
| 0x14003982B (11 wchar) |
(wchar - 0xFE) ^ 0x38 |
MachineGuid |
| xmmword_140197260 (14 byte) |
(byte + 2) ^ 0x38 |
activation.bin |
| xmmword_140197280 (15 byte) |
(byte + 27) ^ 0x73 |
credentials.bin |
| 0x140039068 (22 wchar) |
(wchar - 184) ^ 0x8C |
DeviceDataProcessImgui |
3.4 序列号降级机制
当 MachineGuid 读取失败时 (注册表不可访问等):
- 调用
GetVolumeInformationW("C:\\") 获取卷序列号
- 格式化为
VOL-%08lX
证据: sub_140039470 @ 0x14003961B 调用 GetVolumeInformationW, @ 0x140039652 调用 swprintf 格式化
4. 密钥派生体系 (HMAC-SHA256 三层 KDF)
4.1 硬编码 HMAC 密钥
| 属性 |
值 |
| 密钥内容 |
kp9X_DDPI_credstore_2f7Aq_Lz0Wm_Rb4Nh_Vt6Ec_Sd8Yu |
| 长度 |
49 字节 |
| 存储位置 |
xmmword_1401972C0 / 1401972A0 / 1401972B0 |
| 解码算法 |
(byte + 72) ^ 0x8C |
证据: sub_14002D730 @ 0x14002D772 加载三组 xmmword, 循环解码 49 字节
4.2 三层密钥派生
硬编码密钥 (49 bytes)
│
│ HMAC-SHA256(secret, "ddpi-cred-v1|" + serial_utf8)
▼
Master Key (32 bytes)
│
├── HMAC-SHA256(master, 0x01 || IV_16) → Encryption Key (32 bytes)
│
└── HMAC-SHA256(master, 0x02 || IV_16) → MAC Key (32 bytes)
证据:
- KDF 标签
"ddpi-cred-v1|" 在 sub_14002D730 @ 0x14002D814 硬编码
- 模式字节 0x01/0x02 在
sub_14002D970 的参数 a2 中传递 (0x14002DCF4 / 0x14002DD12)
4.3 HMAC 实现验证
- ipad =
0x36 重复 (标准值), 存储于 xmmword_140197270
- opad =
0x5C 重复 (标准值), 存储于 xmmword_140197290
- SHA-256 初始向量:
0x6a09e667, 0xbb67ae85, ... (标准值)
证据: sub_14002E140 中 ipad/opad 与 FIPS 180-4 标准完全一致
5. DCR1 容器格式
5.1 文件结构
偏移 大小 内容
───────────────────────────────
0x00 4 bytes 魔术头 "DCR1"
0x04 16 bytes IV (随机 Nonce)
0x14 32 bytes HMAC-SHA256 签名
0x34 N bytes 密文 (HMAC-CTR 加密)
最小文件大小: 52 字节
5.2 加密算法: HMAC-CTR 流加密 (sub_14002E460)
- PRF: HMAC-SHA256
- 每块产生 32 字节密钥流:
keystream[i] = HMAC-SHA256(enc_key, counter_i_le32)
- 计数器: int32 小端序, 从 0 递增
- 对称操作:
plaintext XOR keystream (加密 == 解密)
证据: sub_14002E460 中计数器 v30[0] = v3, 4 字节喂入 HMAC, 输出 XOR 数据
5.3 MAC 方案: Encrypt-then-MAC
MAC = HMAC-SHA256(mac_key, "DCR1" || IV || ciphertext)
MAC 比较采用常量时间实现 (SIMD XOR + OR 归约), 防时序攻击。
证据: sub_14002D410 @ 0x14002D551 ~ 0x14002D59F 使用 SSE 指令做逐字节 XOR 累积
6. 卡密系统 (Card Key System)
6.1 卡密格式
19 位纯数字, 结构如下:
位置: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
含义: [C0 C1 L0][C2 C3 L1][C4 C5 L2][C6 C7 L3][D0 D1 L4][D2 D3 L5] [Luhn]
C = HMAC 校验码 (8位)
D = 有效天数 (4位, 最大 9999)
L = 授权等级 (6位)
Luhn = Luhn 校验位
交织规则: 每 3 位中, 前 2 位来自 code+days 序列, 第 3 位来自 level 序列。
证据: sub_14002C610 @ 0x14002C87A add r14d, 3, 循环 6 次到 18, 每次取 3 个字节分别存入两个缓冲区
6.2 卡密验证流程 (sub_14002C610)
输入卡密 (用户输入, 可含非数字分隔符)
│
▼
1. sub_14002C3B0: 过滤非数字字符, 仅保留 0-9
│
▼
2. 长度校验: 必须恰好 19 位
│
▼
3. Luhn 校验: 对前 18 位计算 Luhn, 与第 19 位比对
│
▼
4. 反交织: 从 19 位中分离出:
- code_str (8位): 位置 [0,1,3,4,6,7,9,10]
- days_str (4位): 位置 [12,13,15,16]
- level_str (6位): 位置 [2,5,8,11,14,17]
│
▼
5. 解析:
- code = strtoul(code_str, base=10)
- days = atoi(days_str) → 必须 1 ≤ days ≤ 9999
- level = strtoul(level_str, base=10)
│
▼
6. sub_14002C0A0: 计算期望校验码
msg = serial + "|" + f"{days:04d}|{level:06d}"
expected = HMAC-SHA256(CARD_HMAC_KEY, msg)[:8] (big-endian) % 100000000
│
▼
7. 比对: expected == code → 通过
6.3 卡密验证 HMAC 密钥
| 属性 |
值 |
| 密钥内容 |
HMJFCIXEENJQFMFSNZWXJKYKRYZS_FEXHOPSRJJAQUGD_QXJ |
| 长度 |
48 字节 |
| 存储位置 |
xmmword_140197120 / 140197110 / 140197100 |
| 解码算法 |
(byte + 72) ^ 0x8C |
证据: sub_14002C0A0 @ 0x14002C1BF 加载三组 xmmword, 解码后作为 HMAC 密钥
6.4 验证码计算 (sub_14002C0A0)
msg = f"{serial}|{days:04d}|{level:06d}"
hmac_result = HMAC-SHA256(CARD_HMAC_KEY, msg)
code = int.from_bytes(hmac_result[:8], 'big') % 100_000_000
证据: @ 0x14002C2F9 取 v31[0..7] 按大端拼接 8 字节, 对 0x5F5E100 (100000000) 取模
6.5 卡密激活后的处理 (sub_140032B30)
验证通过后:
- 写入
activation.bin: type=days高位 | level=level | issued=当前时间 | expiry=当前时间+days*86400
- 写入
credentials.bin: 加密存储卡密原文
- 设置内存标志
a1+97 = 1 (已激活)
过期判断: 当前时间 >= expiry → 显示 "卡密已过期,请更换新卡"
6.6 UI 提示字符串
| 场景 |
混淆位置 |
解码结果 |
| 未输入卡密 |
xmmword_140197370 |
请输入卡密 |
| 设备信息获取失败 |
xmmword_1401973E0 |
无法获取设备信息 |
| 卡密验证失败 |
xmmword_140197460+140197410 |
卡密无效,请检查后重试 |
| 卡密已过期 |
xmmword_140197450+140197430 |
卡密已过期,请更换新卡 |
7. 初始化流程 (sub_1400307F0)
程序启动时执行:
1. sub_140030640 → sub_140039470: 生成序列号, 存入对象偏移 +32
2. sub_14002E930: 尝试读取 activation.bin
→ 成功: 设置 a1+100=1 (已激活), a1+104=expiry
3. sub_14002ED70: 尝试读取 credentials.bin
→ 成功: 将解密后的卡密存入对象偏移 +0
证据: sub_1400307F0 按序调用三个函数, 分别初始化对象的三个区域
8. 安全评估
| 方面 |
评价 |
说明 |
| 字符串混淆 |
中等 |
简单算术+异或, 但每处使用不同参数 |
| 机器绑定 |
良好 |
MachineGuid + 降级卷序列号双重保障 |
| 加密方案 |
良好 |
标准 HMAC-SHA256, Encrypt-then-MAC |
| MAC 比较 |
优秀 |
常量时间 SIMD 实现 |
| IV 生成 |
良好 |
混合 atomic counter + QPC + RDTSC |
| 核心弱点 |
致命 |
HMAC 密钥硬编码在二进制中, 可完整提取 |
9. 产出文件清单
| 文件 |
说明 |
get_serial.py |
序列号生成独立脚本 |
credential_system.py |
完整卡密系统 (序列号+KDF+加解密+文件读写) |
generate_cardkey.py |
卡密生成器 (生成+验证+写入激活文件) |
analysis_report.md |
本报告 |
10. 关键地址速查表
| 地址 |
函数 |
功能 |
0x140039470 |
sub_140039470 |
序列号生成 (MG-/VOL-) |
0x140039700 |
sub_140039700 |
注册表读取 MachineGuid |
0x14002D1D0 |
sub_14002D1D0 |
解码文件名 "activation.bin" |
0x14002D360 |
sub_14002D360 |
解码文件名 "credentials.bin" |
0x140038F50 |
sub_140038F50 |
构造 AppData 目录路径 |
0x14002D730 |
sub_14002D730 |
Master Key 派生 |
0x14002D970 |
sub_14002D970 |
子密钥派生 (enc/mac) |
0x14002E140 |
sub_14002E140 |
HMAC-SHA256 实现 |
0x14002E460 |
sub_14002E460 |
HMAC-CTR 流加密 |
0x14002D410 |
sub_14002D410 |
DCR1 容器解密+验证 |
0x14002DBA0 |
sub_14002DBA0 |
DCR1 容器加密+签名 |
0x14002E930 |
sub_14002E930 |
读取 activation.bin |
0x14002F320 |
sub_14002F320 |
写入 activation.bin |
0x14002ED70 |
sub_14002ED70 |
读取 credentials.bin |
0x14002F690 |
sub_14002F690 |
写入 credentials.bin |
0x14002C610 |
sub_14002C610 |
卡密验证主逻辑 |
0x14002C0A0 |
sub_14002C0A0 |
卡密校验码计算 |
0x14002C3B0 |
sub_14002C3B0 |
输入过滤 (仅保留数字) |
0x140032B30 |
sub_140032B30 |
卡密激活处理+UI提示 |
0x1400307F0 |
sub_1400307F0 |
启动初始化 |
0x14002FA70 |
sub_14002FA70 |
SHA-256 块压缩 |
0x140030110 |
sub_140030110 |
SHA-256 最终化 |
0x14002F950 |
sub_14002F950 |
SHA-256 单次哈希 |