LLM 还是有极限的,还是人脑子好使(虽然高考完三个月脑子就没动过 导致好久才转过来弯 悲先用错误的 Flag 试一遍,看下程序输出
拉进 IDA,发现这些字符串并不存在,那就直接拉进 x64dbg,在输入 flag 前按下暂停,从堆栈找 mainFunc (0x140057A20)
通过对 mainFunc (0x140057A20) 伪代码 switch-case 结构的分析,得到下面的操作流程其中,case 5 会在一开始将a1 + 4580全部初始化为 0x2 然后将用户输入按照每 16 字符一次的顺序,将字符转化为 int (所以 a1 + 4580 和 a1 + 4718 这两个的大小都是 16 * 8 = 128 byte) 然后根据int对应的二进制将其映射,映射规则为 0 -> 0x2, 1 -> 0x3 这就是一个把整数 a2 按位拆成长度为 a3 的二值序列的函数,且0 位写成字节 2,1 位写成字节 3。它从 LSB→MSB 逐位取模/整除 2,并把结果右对齐写进输出缓冲(索引是 width-1-pos),超出 a3 还剩下非零高位会被当成错误处理(设置特殊的 vtable/类型标记)。伪代码还原如下(变量名照反编译语义化):最后把映射后的值填充到 a1 + 4580 和 a1 + 4718 中, 我们称这个原始映射为 p_1p1 在经过case 6/8/7后, p_1p1 会根据一定计算生成最终用于比较的 p_2p2, 而 p_2p2 的值是不等于 p_1p1 的 在case 9中,会将 p_2p2 与预定好的 byte_1400C89D0 比较,如果比较结果 a1 + 4576 大于等于42,那么在case 4就会输出Correct!,反之输出 Wrong! (从 a1 + 4576 也可以看出 Flag 长度应该为 42) 同时 case 3 -> case 5 -> case 6/8/7 -> case 9 -> case 3 的这个循环一共会经历三次,这个三次循环是由 a1 + 4708 决定的,而 a1 + 4708 由 case 9 赋值,可以得到 a1 + 4708 的变换为 0 -> 16 -> 32 -> 48 (跳入 case 4) 在经历了12小时逆不出来 p_1p1 到 p_2p2 的算法之后,我人已经麻了(╬▔皿▔)╯后来想了一下,有人能够1h就做出来,绝壁有简单的解法在推 mainFunc 逻辑的时候,我猜想 p_1p1 到 p_2p2 的算法会不会是可逆的(不要管旁边那个 Yes, 那是做出来之后写的【】)
(另外是byte不是bit,半夜脑子不清楚了) 于是我将 byte_1400C89D0 导出,用 Python 分割为 128 byte 的三个片段,在 x64dbg 动调的时候把 a1 + 4580 里面的映射替换掉 在 x64dbg 里面选中内存,Ctrl+E 进入编辑页面,将片段直接粘贴保存
最后在 case 9 dump这段 p_1p1 对应的 p_2p2
(上为 p_1p1,下为 p_2p2)
最后将 p_2p2 转化为字符串,得到 Flag
(首)[EnterPoint]
---
来源: 看雪论坛
原文链接: https://bbs.kanxue.com/thread-288371.htm
[原创]看雪·2025 KCTF 第十题 WriteUP
495 浏览
2 回复
弱弱问一句,你的Terminal背景是AB的那张立华奏和仲春由理的图吗
TurkeybraNC
弱弱问一句,你的Terminal背景是AB的那张立华奏和仲春由理的图吗
是的 :)
弱弱问一句,你的Terminal背景是AB的那张立华奏和仲春由理的图吗
是的 :)