首页
课程
问答
CTF
社区
招聘
峰会
发现
排行榜
知识库
工具下载
看雪20年
看雪商城
证书查询
登录
注册
首页
社区
课程
招聘
发现
问答
CTF
排行榜
知识库
工具下载
峰会
看雪商城
证书查询
社区
CTF对抗
发新帖
0
0
[推荐]看雪CTF2026 第8题WP
发表于: 2026-8-21 15:06
33
[推荐]看雪CTF2026 第8题WP
geekfire
2026-8-21 15:06
33
# KCTF 2026 CrackMe08 附件不大,只有 27 KB,是个 x64 控制台程序。拿到手先跑一下,输入什么基本都是: ```text Input:fault ``` 这是一个典型的“小文件、代码不小”的题。导入表非常干净,除了几个 `Kernel32` 函数外几乎没有东西;但有 `VirtualProtect` 和 `FlushInstructionCache`,入口处也很快就开始改自身内存。显然不能指望把原始文件直接丢进反编译器就结束。 ## 先把真正的代码放出来 程序入口有两层解密。 第一层很直接:把映像中 RVA `0x1800` 开始的 `0x510` 个字节逐字节异或 `0x5a`,然后刷新指令缓存并跳进去。这一段解完以后,能看到下一层的解密循环。 下一层解的是 RVA `0x1d10` 开始、长度 `0x4962` 的区域。它先对第一层明文做两次 64 位 FNV-1a 哈希,再用哈希结果生成一个按字节变化的 XOR 流: ```c x = (uint64_t)i * 0x9e3779b97f4a7c15 ^ h0 ^ h1; x ^= x >> 33; x *= 0xff51afd7ed558ccd; buf[i] ^= x >> 56; ``` 这里的两个哈希值实际为: ```text h0 = 0x73fb4f498aab364f h1 = 0xb157c7e044b966df ``` 解完后把第二段按新的 section 写回 PE,Ghidra 就能正常识别主要逻辑。 ## 输入检查先看清楚 主函数的前半部分没有什么花活: - 输入必须刚好 16 字节; - 16 个字节的和必须是 `0x500`(1280); - 每个字符后续会按可打印 ASCII 的 base-94 数字处理,范围是 `0x21` 到 `0x7e`。 题目里有个很容易干扰人的 `0x501` 比较,它在外层包装逻辑里,不是最终成功条件。沿着真正返回值继续跟,核心校验明确要求的是 `0x500`。 这一步就已经排掉了不少随便 fuzz 的可能性,不过剩下的搜索空间依然不小,所以继续把校验还原。 ## 核心:有限域多项式加两套 Feistel 核心函数还会对解密后的代码区算两次 FNV-1a: ```text body_fnv = 0x553d3c5ef6ee11ff alt_fnv = 0x4aeee52b5738eb8f ``` 这些值不是用来直接比对输入,而是当作种子展开出: - 五次多项式的系数; - S 盒; - 两套各 20 轮的 Feistel 轮密钥; - 若干乘法常量。 所有大整数都在下面这个素数域上运算: ```text p = 2^127 - 39 ``` 输入会先被解释成一个 base-94 整数。也就是说,对每个字符 `c`: ```python m = 94 * m + (ord(c) - 0x21) ``` 随后程序计算: ```text P(m) = m^5 + k0*m^4 + k1*m^3 + k2*m^2 + k3*m + k4 (mod p) ``` 反编译看起来很长,主要是常量生成和轮函数把逻辑淹没了。把它们整理出来后,Feistel 的一轮其实只有这个结构: ```text mid = L xor F(R, key) L' = R xor F(mid, key xor 0x9e3779b97f4a7c15) R' = mid ``` 两套 Feistel 分别对同一个 `P(m)` 的高、低 64 位做校验。最终比较的是两个固定密文,因此不需要猜输入,直接倒着跑 20 轮即可。逆一轮为: ```text old_R = L' xor F(R', key xor 0x9e3779b97f4a7c15) old_L = R' xor F(old_R, key) ``` 倒完两条链得到相同的多项式值: ```text P(m) = 0x4be831b0ad3a2d361489375bba3fb8de ``` 到这里校验已经从“黑盒 crackme”变成了有限域上的一个五次方程。 ## 解方程并还原字符串 构造: ```text f(X) = X^5 + k0*X^4 + k1*X^3 + k2*X^2 + k3*X + k4 - P(m) ``` 因为域大小是素数 `p`,可以用 `gcd(f(X), X^p-X)` 取出域内根。实际只有一个同时满足 base-94/16 字节限制的根: ```text m = 0x174a5e1d4cf4f146e72f70092ac ``` 不断对 `m` 除以 94,余数再加 `0x21`,就得到: ```text kanxue@2o26o8!@# ```
传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!!
最后于
2026-8-21 15:06 被geekfire编辑 ,原因:
收藏
・
0
点赞
・
0
打赏
分享
分享到微信
分享到QQ
分享到微博
赞赏记录
参与人
雪币
留言
时间
查看更多
赞赏
×
1 雪花
5 雪花
10 雪花
20 雪花
50 雪花
80 雪花
100 雪花
150 雪花
200 雪花
支付方式:
微信支付
赞赏留言:
快捷留言
感谢分享~
精品文章~
原创内容~
精彩转帖~
助人为乐~
感谢分享~
最新回复
(
0
)
游客
登录
|
注册
方可回帖
回帖
表情
雪币赚取及消费
高级回复
返回
geekfire
10
发帖
4
回帖
143
RANK
关注
私信
他的文章
[推荐]看雪CTF2026 第9题WP
57
[推荐]看雪CTF2026 第8题WP
33
[推荐]看雪CTF2026 第七题 WP
24
KCTF 2026 第五题:申时·忆海倒带 WP
1504
[推荐]第二题:巳时·绿光幽语 WP
1817
关于我们
联系我们
企业服务
看雪公众号
专注于PC、移动、智能设备安全研究及逆向工程的开发者社区
看原图
赞赏
×
雪币:
+
留言:
快捷留言
为你点赞!
返回
顶部