-
-
[原创]KCTF2025 day6 wp
-
发表于: 2025-8-26 23:13 4677
-
以下分析都是做完题后进行的, 所以已经恢复了部分符号.
先简单运行一下程序, 会发现是一个易语言写的GUI, 结合文件大小应该是静态编译的. 然后随意输入一些数据点击登录没有反应, 题目说明中提到验证失败没有弹窗或弹出错误提示, 再试了一下更长的输入发现有错误提示的图片了, 二分法可以快速定位到这个临界值是31字节, 说明要提交的答案大概率就是31字节长的.
接下来开始分析, 既然是WindowsGUI程序, 获取输入框内容大概率要用到GetWindowTextW, 刚好题目也导入了这个函数, 为了避开一些初始化时的反调试(如果有的话), 下面的调试都是启动程序后附加调试的.
在GetWindowTextW下好断点后点击登录成功断下, step out发现获取到了输入:

硬件断点跟踪数据流到某个地方发现反汇编失败了:

观察一下会发现一条陌生的指令bextr, 应该就是它导致了这个错误, 并且这个错误发生后IDA的反汇编器会直接摆烂不再可以进行反汇编.
继续跟踪数据流发现了输入长度和一个熟悉的立即数进行了比较:

并且这个函数没有那条神必指令, 重启IDA来到这个函数进行反汇编, 若输入长度>= 0x1f就会把输入当参数进到do_check(12351552), 从f5结果来看输入只进到了这几个函数里进行处理:

调试可以发现前两个都是拷贝函数, 第三个函数真正进行了加密操作, 而为了确定加密的范围继续追踪这一步的密文, 下一次程序断下就来到了最后一个函数中, 并且和一段字节进行了比较:

在内存中搜索和加密结果比较的字节串可以在数据段找到:

修改比较结果发现可以弹出正确提示:

也就是说真正的加密逻辑只用看encrypt(12352547), 继续硬断追踪数据流, 第一步加密是将输入零扩展成DWORD:

再跟到下一步会发现在123533C6进行了写回:

在上面两个调用上下断点, 实际上callsm就是一个跳板函数, 用于调用放在EBX中的函数, 第一个跳板在每i次调用时从未被零扩展的ser取出ser[(4 - (i & 3)) * (i >> 2) : (i >> 2) << 2], 例如输入的是1234, 那么每次取出的就是:
这里1替换成?是因为调试会发现每次取出一个DWORD时最高字节都会变化, 这个变化才是真正的第二步加密, 这里的两个跳板实际上执行的就是第二步加密完后再零扩展存入.
取出的DWORD来自[ebp-30h], 向上溯源, 这个值来自:

跳板执行的do_xor实际上是将第二个参数和第五个参数进行异或:

再向上溯源, 这个异或的字节来自[ebp-0x64]:

是一个有意义的字节串, 应该就是异或的key, 到这里总结一下真正的第一步加密:
继续跟踪数据流, 第二个字节的处理先是加了0x100:

这里用浮点数实现貌似是易语言特性, 接下来这个值被当作下标从一个表中取出一个字节存回.
第三个字节的断点在12353581被触发, 准备通过跳板进行异或操作, 和它异或的字节就是上面加密完的第二个字节:

在这两个操作上下断点会发现它们是交替执行的, 总结一下这两步加密
接下来要解决的问题就是执行轮次的问题, 从f5的结果来看大概是执行114514 * 0x20轮:

在那两个操作上下条件断点分析轮次问题:

[培训]Windows内核深度攻防:从Hook技术到Rootkit实战!
赞赏
- [原创]KCTF2025 day10 wp 487
- [原创]KCTF2025 day9 wp 4809
- [原创]KCTF2025 day8 wp 4781
- [原创]KCTF2025 day7 wp 4587
- [原创]KCTF2025 day6 wp 4678