-
-
[原创]KCTF 2026 第五题 "忆海倒带" WriteUp
-
发表于: 2026-8-17 12:53 17
-
题目说明里提到成功条件是输出 verify success.,所以第一步先在 IDA 里看字符串引用。
关键字符串:
对 Enter your key:、verify success.、verify fail.retry it... 做 Xrefs,都会落到 _main,主函数地址为:
F5 后能看到主函数中先输出提示,再读取输入:
这里 sub_403C60(Buffer) 很显眼,但不要急着下结论。
sub_403C60 里面引用了大量提示性字符串,例如:
F5 伪代码如下:
继续看 sub_403230:
还有 sub_4032E0:
这些函数只制造 admin123、r3v3rs3!、password 和 int3 的干扰。真正的 verify success. 分支不依赖这些字符串,而是在 _main 后半段。
回到 _main,输入会先被复制到一个 std::string 风格对象,然后调用 sub_402100:
sub_402100 的核心逻辑是把字符串按 16 进制转成大整数:
之后 _main 检查输入字符和长度:
这里 v76 是大整数 DWORD 数量。n = 8 * v76,最终要求:
也就是说:
注册码最后确实是 88 位十六进制字符串。
程序把大整数按 DWORD 倒序拆成字节,放入 ArgList。简化逻辑如下:
所以 88 个 hex 字符会还原成 44 字节。
接着做两个校验。
IDA F5:
-113 按 unsigned char 看就是:
即:
F5:
v58 是 __int16,-16641 对应无符号值:
等价 Python:
第一层通过后,程序会进入最终比较逻辑:
也就是说,每个字节不是直接当 ASCII,而是当成一个 1-based 索引:
sub_404870 不是普通连续数组,它通过偏移表取字符:
sub_4033D0 会构造这个表对象:
实际关系:
目标字符串:
前 28 个字符可以直接反查表,得到前 28 字节:
对应注册码前 56 个 hex 字符:
前面还有一个关键点:最终比较前,程序会对输入后 16 字节做一次变换。
调用点:
sub_403500 内部会:
sub_402510 的结构很像快速模幂:
常量来源在 sub_403500 里构造:
通过 IDA 读取对应表,可还原:
目标字符串后 16 个字符是:
反查字符映射表,得到最终比较期望的后 16 字节:
也就是密文:
因为:
所以需要求:
分解 N:
计算:
得到输入后 16 字节:
对应注册码后 32 个 hex 字符:
前 28 字节来自字符表直接反查:
后 16 字节来自 RSA-like 逆运算:
拼接:
再验证第一层校验:
输出:
与程序校验一致。
PowerShell:
输出:
Enter your key:
verify success.
verify fail.retry it...
Welcome to KCTF2026! Come and give it a try.
admin123
r3v3rs3!
password
_main = 0x403D90