论坛首页 逆向工程技术区 阅读主题

[原创]KCTF 2025 第四题 WriteUp

457 浏览 0 回复
#1 楼主 2026-06-01 21:08:55
题目的核心算法是通过修改的 Base64 和 AES 组合成的加密与解密算法,来验证用户输入的 UserName 和 Serial 是否匹配。在 main 函数执行前,利用 TLS 回调来完成加解密常量的初始化和反调试检查,在 main 函数中未直接调用核心算法函数,而是将其藏在向量化异常处理器(VEH)中,通过 int 3 指令主动触发异常来执行。使用 Resource Hacker 查看程序的字符串表:TLS 函数中先初始化了一些加密常量:对这些加密常量进行交叉引用和调试分析,可以确定:经过尝试,发现 Base64 和 AES 的输出都和自己验证的代码输出对不上,猜测是进行了魔改。对 Base64 相关函数进行调试分析,自己实现一下:AES 加解密的话,一步步对比着或调试分析魔改了哪里太费劲了,考虑到程序中加密和解密的算法是成对出现的,最后我选择直接调试修改加解密执行时候的数据,dump 出来执行结果,来获取自己想要的加解密数据,这样快得多。TLS 函数中出了除了初始化一些加密常量,还进行了动态 API 解析来反调试,先遍历 Ntdll.dll 的导出表动态加载所有以 "Zw" 开头的 API 函数,再解密出字符串表中的 106, "KfeXm13d+R+hqh6T/TUN3QCibwL4dz3/JyO9Bo2dnSM=" 为 ZwQueryInformationProcess,可在 .text:0000000140003693 call sub_140005D6C 打断点执行查看,上面已分析出 sub_140005D6C 是组合的解密函数,后面的问 LLM 说是通过 syscall 直接调用 ZwQueryInformationProcess 检查 ProcessDebugPort 进行反调试,由于我是直接用 Windbg TTD 录制了程序执行过程(见<TTD 调试与 ttd-bindings 逆向工程实践>),无视各种反调试,这段我就没具体验证和绕过了。main 函数先通过 AddVectoredExceptionHandler 设置异常处理器,当程序发生异常时,请优先调用 sub_140006D40 这个函数来处理,再提示用户进行输入,随后程序会调用 sub_140007323 走到 int 3 主动触发断点异常,从而将执行权交给设置好的异常处理器。每次调用 sub_140007323 之前,程序会设置全局变量 dword_14000D890 的值作为传递给异常处理器的指令,告诉它该做什么,是处理 UserName 还是 Serial,最后在所有计算完成后,main 函数比较最终的计算结果和用户输入的 Serial,并输出验证成功或失败的消息。sub_140006D40 先通过 ExceptionInfo->ContextRecord->DrX = 0 几行代码设置清除 CPU 的调试寄存器(Dr0-Dr3)来反硬件断点调试,再检查捕获到的异常码是否为断点异常(0x80000003),如果不是则不处理。随后将 RIP 加一,跳过导致异常的 int 3 指令,这样当异常处理返回后,程序就可以从下一条指令继续执行,而不是再次触发异常。随后就是通过 dword_14000D890 来控制执行,当 dword_14000D890 == 2 时会调用加密相关的流程,当 dword_14000D890 == 3 时,它会调用解密相关的流程。分析和调试可知,会对 UserName 进行三次 Encrypt 操作(sub_14000618C),对 Serial 进行一次 Decrypt 操作(sub_140005D6C),最终在 main 函数进行 Encrypt(Encrypt(Encrypt(UserName))) == Decrypt(Serial) 的比较。user 指定为 KCTF,可以直接 main 函数的 .text:0000000140003FD1 call cs:memcmp 处 dump 三次 Encrypt 的结果,就是 Decrypt(Serial) 的值。现在求 Serial 就是对这些数据进行 Encrypt 操作即可。在上面对 sub_14000618C 的分析知道这是组合起来的加密过程,先使用主密钥进行 AES 加密,结果和使用 Tweak 密钥对固定序列常量进行 AES 加密的结果进行异或,最后进行 Base64 编码。先调试 dump 下来使用 Tweak 密钥对固定序列常量进行 AES 加密的结果为:进行异或操作得到:随后直接调试修改 AES 加密时候的执行时候的数据,得到结果为:最后执行 base64_encode(bytes(arr)) 即可得到正确的 Serial 为 "tSzQkyqcvZLgkwDltPF9RpInibA5fTpH/bJni2yvLzTKao2uL5eLZ5QIxPj8bsYWe48ZohC5/Jw3cNNAaX8/rA=="。按理说直接 x64dbg 调试修改 Encryt 函数 sub_14000618C 的输入可以直接得到结果,不过我没给 x64dbg 过反调试,为了方便直接改的是 TLS 函数中解密函数调用,.text:0000000140003693 call sub_140005D6C -> 使用 Tweak 密钥对固定序列常量进行 AES 加密 .text:0000000140005F99 call sub_140005B44 -> 修改过的 AES 加密函数 .text:0000000140005C75 call fn_140005684,在反调试操作之前可以直接走到这里,解出 flag 后就没再继续折腾了。STRINGTABLE

---
来源: 看雪论坛
原文链接: https://bbs.kanxue.com/thread-288175.htm

暂无回复,快来抢沙发吧!

请登录后参与讨论

立即登录 注册账号