结果
对任意合法用户名(1–32 可打印 ASCII、无空格),有效 Key 为:
[Python] 纯文本查看 复制代码 key = CrockfordBase32(K_true XOR C1(user))
- `K_true = 39 42 d4 43 66 ce 5f a2 7d 25 d1 de 90 e0 1a 19 94 fa 8c 9e`(20 字节,从 .cmblob 中反演)
- `C1(user) = SHA256( ‖ 用户名 )[0:20]`,其中每个数据段前带 4 字节小端长度前缀
- Crockford Base32 打包为 **MSB-first 5-bit**:第 i 个字符的 5 位值 v,其 bit (4−b) 落在全局 bit 位 5i+b(字节内 MSB 在前)
示例(可直接验证,B 部分解出明文 `R-TYPE / RECOVER THE KEY / VERIFY WITH THE TRUSTED GRAD`):
[Asm] 纯文本查看 复制代码 | username | key |
| ----------- | ---------------------------------- |
| Alice | `TZFC2WT5EX373GFGX73NXJ4CQW6PEW8T` |
| Bob | `0XEY5CSZW33YKZ8D80D0HQDG4VVGHMQM` |
| a | `YR0PYTARTFCHSJ968ZF5WA8WJ8CTC4SZ` |
| ZxcUser2025 | `KQWHM0T2KDRW5AF9WPH6EZRKSS26SP6P` |
[Asm] 纯文本查看 复制代码 | username | key |
| ----------- | ---------------------------------- |
| Alice | `TZFC2WT5EX373GFGX73NXJ4CQW6PEW8T` |
| Bob | `0XEY5CSZW33YKZ8D80D0HQDG4VVGHMQM` |
| a | `YR0PYTARTFCHSJ968ZF5WA8WJ8CTC4SZ` |
| ZxcUser2025 | `KQWHM0T2KDRW5AF9WPH6EZRKSS26SP6P` |
B 部分 hex 还原即为 `R-TYPE / RECOVER THE KEY / VERIFY WITH THE TRUSTED GRAD`(尾随空格填充)。错误 key 的 B 部分是乱码;正确 key 的 B 部分是这条固定明文——这就是"有效性"的唯一判据(A 部分为带用户名/密钥绑定的 HMAC,随用户名变化)。
## 程序保护与架构
- **CMGUARD1(.cguard, RVA 0x30000, 0x5030 字节)**:完整性保护。`manifest = SHA256(len-pref "manifest-v1" ‖ cg[0:8] ‖ cg[8:12] ‖ cg[12:16] ‖ cg[0x30:0x5030])`,与存储在 `cg[0x10:0x30]` 的摘要异或得 G。**G=0 表示完好**;guard 输出仅 32 字节、之后被清零。.text 任何改动都会破坏 blob 解密链(实际并未直接参与密钥,但 guard eax=0 时 main 报错 4 退出)。
- **.cmblob(RVA 0x36000, 0x1d6b 字节)**:加密 blob。magic `CMR1S4`;[8:0x18]=salt1、[0x18:0x38]=salt2、[0x38:0x58]=扩散函数密钥、[0x58:0x83]=**期望扩展**(破解关键)、[0x83:0x183]=ce0 轮表(64×dword)、[0x183]=8 字节置换、[0x18b]=16 nibble 置换、[0x19b:0x1d2b]=加密 body、[0x1d2b:0x1d6b]=加密的 64 字节尾。
- **隐藏 `--worker` 参数**:独立运行静默退出码 5;配合 CMIPC1 IPC 协议(0x140006300,5000ms 超时同步),为多进程 body 解密执行架构,与 key 恢复无关。
- **防篡改陷阱**:`.text` 不可 patch(guard 哈希校验);DRx 硬件断点实测安全(输出与无插桩运行逐字节一致)。
完整算法链
[Asm] 纯文本查看 复制代码 1. keybits = CrockfordDecode(key_str) # 160 bit, MSB-first
2. C1 = SHA256(LP12"user-mask-v1" ‖ LP16 salt1 ‖ LP32 salt2 ‖ LPlen user)[0:20]
3. key20 = C1 XOR keybits
4. ext14 = ce0(key20) # 20B:5×dword LE 移位寄存器
state[j]=LE32(key[4j]); 64 轮:t=rol32(s1+LE32(blob[0x83+4i]),7);
new=t^s2^s0; state=[s1,s2,s3,s4,new]; 输出 LE 存 5×dword → key[0x14:0x28]
5. ext28 = 32c0(key20) # 23B 位扩散:chacha20(blob[0x38:0x58],
nonce@0x1400206a8,ctr0) 生成 0x48547 字节密钥流,
与 key20+1 起始的 161-bit 向量做与/移位累积 → key[0x28:0x3f]
6. digest = SHA256(LP8"state-v1" ‖ LP16 salt1 ‖ LP23(key[0x28:0x3f]^blob[0x58:0x6f])
‖ LP20(key[0x14:0x28]^blob[0x6f:0x83]) ‖ LP32(key[0x3f:0x5f]=固定))[0:32]
7. PRK = HMAC-SHA256(salt2, key20 ‖ digest) # HKDF-Extract
8. tailkey = HKDF-Expand(PRK, "data-v1", 32) # → key[0x5f:0x7f]
tagkey = HKDF-Expand(PRK, "tag-v1", 32) # → key[0x7f:0x9f]
9. B = hex(chacha20(tailkey, nonce"DATA-v1", ctr=1, blob[0x1d2b:0x1d6b]))
10. A = hex(HMAC-SHA256(tagkey, SHA256(LP10"binding-v1" ‖ LP16 salt1 ‖ LP user
‖ LP20 keybits ‖ LP135 B_text))[0:16])
11. OUT = "OUT:" + A + "|" + B_text
破解思路
[Asm] 纯文本查看 复制代码 1. **修复 zxc_call_remote**(把伪造调用栈放到新线程真实栈上,修复 SetThreadContext gle=87),得到目标进程内的**黑盒预言机**:任意函数可带最多 8 参数调用并取 RAX。支持 4 个寄存器参数 + 4 个栈参数。
2. 预言机逐段验证离线模型:`0x140003f50`(guard→G=0)、`0x140002ef0`(C1 推导,模型吻合)、`0x140002d70`(Crockford 解码,MSB-first 位打包由实测样本破译)、`0x140004c60`(blob_open 全链)、`0x140001000`(ChaCha20,注意参数序 key/nonce/ctr/**src=r9/dst=栈**/len)、HKDF 原语(0x140001b80 Extract / 0x140001a00 Expand / 0x140001bd0 HMAC)。
3. **密钥调度全图**:blob_open 在调用者的 key 缓冲上"就地"派生:+0x14 扩展(ce0 移位寄存器)、+0x28 扩展(32c0 位扩散)、+0x5f tailkey、+0x7f tagkey。
4. **决定性观察**:0x140003520 的 SHA 链把两个"派生扩展 XOR blob 常量"的缓冲(buf1=key[0x28:0x3f]^blob[0x58:0x6f]、buf2=key[0x14:0x28]^blob[0x6f:0x83])混入摘要——而 blob[0x58:0x83] 恰好 43 字节常量。**假设:正确 key20 使 buf1=buf2=0,即 ce0(K_true)=blob[0x6f:0x83]。**
5. **ce0 是可逆的**:64 轮每轮 t=rol32(s1+dw[i],7)、new=t^s2^s0、下移——由最终状态逐轮回退得初态即 key20。反演 blob[0x6f:0x83] 得 `K_true=3942d44366ce5fa27d25d1de90e01a1994fa8c9e`。
6. **验证闭环**:把 K_true 喂回预言机 blob_open——ext14 与 ext28 双双命中 blob 常量,tailkey 解出可读明文;再按公式生成用户 key,真实二进制输出正确 B 部分。Alice/Bob/单字符/带符号用户名全通过。 |