首页
社区
课程
招聘
[原创]KCTF2026 第八题:亥子合辰·塔影迷楼
发表于: 2026-8-21 16:39 29

[原创]KCTF2026 第八题:亥子合辰·塔影迷楼

2026-8-21 16:39
29

正确输入:

已经用原始未修改样本验证:

输入长度为 16 字节,字符和为:

主样本是:

最终使用的关键脚本:

程序要求输入长度为 16。

主 checker 入口在:

开头检查字符和:

所以必须有:

输入字符域是 printable:

随后按 base94 折叠成 128-bit 整数:

即:

最终校验位于:

clean timing 下,最终需要满足的四个核心状态是:

final sink 还计算两个 FNV-1a:

其中:

但 clean timing 下,如果前四个核心状态命中,上面的 FNV4 自动成立。

同时 FNV6 可以化成一个必要条件:

这个条件可以用来审计自洽性,但直接用 Z3 求这个前像很慢,不是最终突破口。

一开始遇到过一个很关键的假矛盾:

污染环境下 RHS 是:

这时:

看起来像程序无解或建模错了。

真正原因是 rdtsc timing 检测污染:

Unicorn 执行太慢,会让这个 timing flag 被置位。rbx 后续进入表生成逻辑,导致 final RHS 整体污染。

处理方式:

clean timing 后 RHS 变成:

并且:

这个修正非常关键。后续所有动态分析都必须使用 clean timing。

0x4EE9..0x5900 最终被化简为模有限域的 Horner 多项式。

模数:

常量:

语义:

也就是:

然后拆成第一段 20 轮入口:

这个模型用多个输入对拍通过,例如:

两段 20 轮都使用同一个核心结构。

先确认了大量看似复杂的乘法归约块其实是:

其中固定乘数:

核心函数可以写成:

虽然 [rbp+0x60] 的 256-byte S-box 不是置换,只有 166 个不同输出,但第一段整体是 Feistel 型可逆结构。

第一段每轮可以抽象为:

其中:

所以给定最终 (L', R') 可以倒推出上一轮 (L, R)。

final sink 要求第一段最终输出:

利用第一段 20 轮的可逆结构,从 (L20, R20) 反推第一段入口:

因此:

把这个入口再正向跑第二段,自动得到:

这说明 final 四个目标闭合,不需要再分别求第二段。

现在只剩一个有限域五次方程:

其中:

用 SymPy 在有限域 GF(p) 上分解:

得到一个合法线性根:

把 N 转回 16 位 base94 digit,再加回 0x21:

校验:

用原始 exe,通过 stdin 输入:

输出:

退出码:

这题耗时主要不在最终数学难度,而在被动态污染和复杂指令形态误导。

一开始过度相信静态视图里能直接看到完整校验逻辑,但真实 checker 是运行时解密出来的。仅靠静态反编译视图容易漏掉真实执行语义。

后面改成直接从原始 exe 解密 stage1/stage2,并用 Unicorn 跑真实路径,才避免继续被静态视图缺失误导。

sub_140001070 一度看起来像主校验的一部分。实际它只是另一个 16 字节 rolling hash,命中 0x1111111111111111 时改写 [0x140008000]。

曾经求到两个 prehash 命中样本:

其中第二个甚至满足 sum=0x500,但原始 exe 仍返回失败。原因是 [0x140008000] 和主 checker 使用的 [0x14000A000/0x14000A008/0x14000A010] 不是同一条关键链。

这个方向后来判定为诱导/环境 seed,不是最终约束。

这是最大坑。

Unicorn 下 rdtsc 时间差异常,导致:

被执行,污染后续表生成和 final RHS。

污染 RHS 下甚至出现:

这个矛盾容易让人误判为:

最终通过在 0x46ED 强制 rbx=0,clean RHS 变得自洽。

曾经尝试用 P*16 的 concrete block trace 引导符号执行,例如 second_phase_guided.py。

问题是不同输入会在中间分叉:

所以 P*16 trace 只是局部路径,不能当作全局路径约束。继续沿这个方向会让 solver 越来越大,而且语义假设不稳。

0x5930..0x646D 看起来是大量 ARX/MBA/查表/乘法/条件跳转。直接把指令级 AST 喂给 Z3,60 秒仍没有有效输出。

真正原因是这里有明显高层语义:

一旦识别出这些结构,问题从“大 SMT”变成:

复杂度直接降下来了。

[rbp+0x60] 的 256-byte 表不是置换:

这会让人以为整轮不可逆。实际第一段是 Feistel 型,内部函数不需要可逆,整体仍然可以反推。


[招生]科锐逆向工程师培训(2026年11月13日实地,远程教学同时开班, 第57期)

收藏
点赞 ・4
打赏
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回