首页
社区
课程
招聘
[原创]【KCTF 2026】第五题:申时·忆海倒带 Writeup:"中间语言",把 RSA 诱饵从假死代码里挖出来
发表于: 2天前 149

[原创]【KCTF 2026】第五题:申时·忆海倒带 Writeup:"中间语言",把 RSA 诱饵从假死代码里挖出来

2天前
149

这道 Windows crackme 输入 88 位 hex 序列号,对了打印 verify success.。表面看就是"大整数解析 + 查表 + 几重校验"的常规套路,可偏偏就是那几个校验对不上,让我卡了很久。最后逼我发明了一套压缩语言(我管它叫 Z-Lang),把整个 main 从头到尾翻译一遍、再做一次代数化简,才发现真正的机关藏在一个被当成"死代码"的地址里。

这篇文章就当分享这个思路,也希望能给同样卡在"校验矛盾"上的朋友一点启发。

程序没有加壳,main 在 0x403D90,纯 MSVC 编译。麻烦的是里面塞满了花指令,典型几种:

写了个脚本按"无条件 jmp 跳过紧邻死代码"的规则线性清理,得到 522 条有效指令(main_clean_full.asm)。花指令本身不是难点,跳过。

把 main 翻译完,逻辑其实不复杂。88 位 hex 先解析成 2048 位大整数,再字节反转成 44 字节缓冲区 V,然后要过三关:

查表对象 D/P 是静态表(D=0x4263B0 字节表,P=0x4163B0 偏移表),元素经大数对象的 datap[perm[k]] 间接寻址。程序里还有一大段 RSA 模幂(exp=0x10001)和费雪耶茨洗牌,看起来跟验证毫无关系——这就是后面最大的坑。

约束 C 对目标串的每个字符,在 D[P[j]] 里恰好找到一个 j 命中,所以 44 字节的 V 被 C 逐字节唯一确定

可是拿这个 V 去算 A、B:

查表唯一确定的 V,过不了校验。 一个 CTF 题不可能无解,那一定是"三者作用于同一份 V"这个模型有问题。可汇编读来读去,A/B/C 都在读写同一个 [ebp-0x470](V),怎么看都是同一份。

卡了一下之后,我决定把所有内存写地址用符号代数化简一遍,不靠汇编直觉。重点看第 18 步——它要把 RSA 结果拷贝 16 字节,汇编里目标地址长得像"写到一个没用的地方":

把它写成 Z 记号再化简:

这一化简,整个题就通了——那条"拷贝 16 字节"根本不是死代码,它在执行 V[28..43] ← RSA 输出,把 V 的尾部 16 字节覆盖了!

重新梳理,三个约束其实针对的是两份不同的 V

也就是说:

这解释了一切矛盾。RSA 看似是诱饵,其实是通过隐藏的缓冲区覆盖,把 base 解密的必要性接进了主流程

sub_403500 从静态常量构造大数:

128 位模数直接分解:

求私钥 d = e⁻¹ mod φ(n) 后解出 base:

验证全部通过:

感谢阅读,欢迎交流。

; 模式A: jmp +6 跳过死代码
40435b:  eb 06        jmp  0x404363
40435d:  8b c0        mov  eax,eax      ; ← 死代码开始
40435f:  c3           ret
404360:  ff           (bad)
404361:  ff 33        push [ebx]
404363:  ...                             ; ← 真正代码

; 模式C: jmp +2 跳过两个 nop
403f6d:  eb 02        jmp  0x403f71
403f6f:  8b c9        mov  ecx,ecx
403f71:  8b 01        mov  eax,[ecx]

冰与火的战歌:Windows内核攻防实战高级班!从零到实战,融合AI与Windows内核攻防全技术栈,打造具备自动化能力的内核开发高手。

最后于 2天前 被落音吹雪编辑 ,原因:
收藏
免费 0
打赏
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回