主要逻辑在 sub_402380 里,此函数非常长,不过 AI 的初步分析还是给出了很多有价值的信息: 接下来提示AI,a1是已知的name,a2是待求的serial,AI给出了进一步的分析: 从最终情况看,其中关于椭圆曲线/有限域的结论是错误的,但其他分析结论完全正确(而且此时提供给AI的上下文只包含 sub_402380 的反编译伪代码,还不包含任何它调用的子函数,因此这只是对sub_402380整体逻辑的初步印象),特别的是给出了a1(name)参数经过运算的比较串"KCTF2025" || MD5(a1)[0..11]、大数运算、++v262[0]的扰动这三项提示,对后续的人工分析启发很大。 优先查看 AI 指出的几个子函数,注意到引用了常量区的一些字符串: 容易查到这些字符串出自 freelip 大数计算库(2e6K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6Y4K9i4c8Z5N6h3u0Q4x3X3g2U0L8$3#2Q4x3V1k6D9M7X3!0T1L8%4c8Q4x3V1k6X3M7X3g2W2L8r3W2H3i4K6u0r3j5X3I4G2j5W2)9J5c8X3#2S2M7%4c8W2M7W2)9J5c8X3I4A6M7q4)9J5k6h3x3`.)
而在对a2(serial)参数做hexdecode的代码后面,第一段代码恰好调用到了这些函数: 其中sub_454440和sub_4541F0可以直接从函数里面引用的常量字符串确认是zmod和zinvmod,头尾的sub_455880和sub_4556D0按照常理应该是大数的导入和导出(与源代码对照后可以确认是zultoz和ztoul),那么中间的sub_4547E0必然是某种大数运算函数。 freelip这个库的大数内部表示有些奇怪,它内部的int数组好像每一项只使用了30bit左右,导致经过zultoz后内部的数组与原始字节并不一致,这点与其他常见库完全不同,导致不太方便通过调试判断sub_4547E0的变换,但是可以猜测大概率不是加法就是乘法 不过既然前面的zultoz以及后面的zmod和zinvmod已知,那么可以先从最上面0x402ADC处的zultoz导出v275的内存值确认v191的模数的值(记为pp),再分别测试一下x*(-3)%pp和x**(-3)%pp,然后调试查看ztoul导出的v274,即可确定sub_4547E0是zmul,执行的是乘法运算。
顺便导出了模数为 0x56f67550f16a00390dcf0b2715708e61c5b3f23101862fc1,是0x402780附近的赋值的常量。 通过yafu或factordb可以得到模数的质因数分解,它恰好可以分解为两个质数的乘积: 根据RSA的计算原理,对于 c = pow(m, e, n) ,在已知n的分解为p*q时,可以由c反向计算出m:phi = (p-1)*(q-1) , d = pow(e, -1, phi) , m = pow(c, d, n) 因此,这里对a2(serial)的第一次运算tmp1 = pow(a2, -3, pp)完全可逆。 再注意到 0x402C47 出的运算 ++*(_DWORD *)v275; (回顾开始,AI也注意到了这处扰动) ,在 tmp1 的大端内存表示的前四个字节做了一次自增。虽然运算很奇怪,但可逆,于是暂记结果为 tmp2。 再看接下来的一段代码: sub_406450函数被多次调用,它的传入参数有点混乱(除了栈,还包含ecx和eax)。在最后还调用了sub_4067B0和sub_4074B0,整体的调用模式与第一段看起来非常相似。
这里仍然先猜测是大数运算,这里应该是换了一个大数库,
但经过调试验证,容易验证sub_406450、sub_4067B0、sub_4074B0分别是mul、mod、invmod,模数与上面相同,计算结果为tmp3 = pow(tmp2, -7, pp)
加上最后0x402E19处的++*(_DWORD *)v275;,仍然是大端序高位DWORD自增扰动得到的tmp4接下来的一组sub_41A180、sub_41AB20、sub_41AF50分别也是mul、mod、invmod,以及0x402FC7处相同的扰动,得到tmp5 = pow(tmp4, -11, pp)和tmp6 以 ++*(_DWORD *)v275; 为支点,发现 sub_402380 大函数里相同的计算模式反复出现了9次,每次都换了一个大数库,但都是先对上一轮的结果做若干次乘法累加(后面几轮的中间穿插了取模)、一次取模、一次模逆、一次扰动。
因此,后面的逻辑无需再仔细逆向,直接找到每组重复次数最多的函数记为mul,然后静态计算出每轮mul的次数(这里也很有规律,每一轮最终的mul指数构成了递增的质数序列)并通过调试验证即可。 以下整理出每轮的三个大数运算函数以及最终的幂次: (注意不同库的参数不同(例如,有的是三参数且出参可以分别位于三个位置或返回值,有的是两参数且出参复用某个入参的位置,还有多参数包含一些额外的长度信息等),中间还会穿插大数构造/析构/复制等辅助函数,排除干扰即可) sub_402380的校验逻辑整理为python后非常短小: 根据name计算serial的反向代码为: 最终答案: zultoz((int)v275, 6, &v191);
---
来源: 看雪论坛
原文链接: https://bbs.kanxue.com/thread-288144.htm
[原创] 看雪 2025 KCTF 第三题 邪影显现
252 浏览
0 回复
暂无回复,快来抢沙发吧!