论坛首页 安全工具分享区 阅读主题

[原创]2025腾讯游戏安全技术竞赛决赛题解

118 浏览 9 回复
#1 楼主 2026-06-01 21:08:54
(1)在intel CPU/64位Windows10系统上运行sys,成功加载驱动(0.5分)(2)能在双机环境运行驱动并调试(1分)(3)优化驱动中的耗时算法,并给出demo能快速计算得出正确的key(1分)(4)分析并给出flag的计算执行流程(1.5分),能准确说明其串联逻辑(0.5分)(5)正确解出flag(1分)(6)该题目使用了一种外挂常用的隐藏手段,请给出多种检测方法,要求demo程序能在题目驱动运行的环境下进行精确检测,方法越多分数越高(3分)(7)文档编写,详细描述解题过程,详述提供的解题程序的演示方法。做到清晰易懂,操作可以复现结果;编码工整风格优雅、注释详尽(1.5分)驱动带反调,且目测有 VMP 壳,于是选择 dump+Fix,由于驱动带反调,会蓝屏,于是 hook 蓝屏代码,选择该时机去 dump 内存,找到 Entry。随后跟进,遇到一些立即数的赋值,且有函数加密,直接选择模拟执行。最后得到一个注册表字符串 \\Machine\\System\\CurrentControlSet\\Services\\ACEDriver\\2025ACECTF正常直接加载驱动会返回 31 错误,猜测判定了注册表的某些东西,继续往下模拟可得一个字符串 Key。模拟执行可以尽量挑不依赖外部函数,且立即数比较多的片段,这样可以省略计算的过程。下面也可以模拟,但是根据题目描述也能猜个大概,有一个 Key,有一个 Flag。再结合该函数的定义和调用不难得到 Key 应该是一个 __int64 的值,Flag 是一个字符串,保存到全局变量当中,创建对应的注册表项,成功加载驱动。前面说过,有反调试,观察导入表遍历了 NtQuerySystemInformation,于是想到可能是检测到了 kdcom.dll 模块(因为之前有游戏做过类似的检测),那么直接 hook 把 kdcom.dll 改名。因为保护了 IAT,因此不能使用常规的 IAT hook,还是选择使用 inline hook。绕过之后加载驱动不会蓝屏,但是会出现另一个错误。随后查看 DbgView 发现似乎是 vmp 自带的,手上有 3.8 版本,尝试编译放进去加载,果然如此,一摸一样的错误代码。这个可以通过字符串定位,也可以由上面注册表继续往后分析得到。当输入的 Key 为 0 时,尝试使用算法生成。通过分析该函数,结合一些一些字符串可知,该算法自己实现了一个双端队列(deque),但是实际使用的时候是把它当成栈来用了,实现了一个深度优先搜索算法。第一步恢复 deque 结构体,第一个 8 字节是一个指向自身的指针,但是似乎没有用过,正常来说应该是虚表。双向队列会有全队列大小(队列最多容纳的元素个数),头指针还有尾指针,而通常情况下,后两者可以使用头指针 + 有效元素个数来实现,因此最后得到以下定义:应用到 IDA 之后,配合注释,算法一目了然。深入阅读它实现 deque 的源码其实可以明白,第一,它的 MAX_SIZE 一定是 2 的整数幂,并且它是环形队列。第二,在取模的时候更加高效(即 &(MAX_SIZE-1))。循环开头压入了 (44,22) 元素。每次循环开始,取得尾部的元素,判断 x1 是否为 0,或者说 x==y,如果是则删除该元素。否则尝试先往左走(即 x-1)并立刻将往左走的点压入栈中重新循环,经典的 DFS。往左走之后会将当前点标记为已经往左走过,这里 x4 的值有以下三种情况:当 x4==2 时,该点也会被删除,并将,结合图中的注释大概也能看懂这个算法了,这里画了一个图更好理解从黑色格子出发,只能向左或者向左上(y轴往下的情况下)。红色格子不能继续走,价值为1,同样在 y 0层也有一行红色格子价值为 1,其余格子价值均为 x%5,最后应该是计算黑色格子到红色格子的所有不同的路径的价值之和。优化可以使用记忆化搜索,或者直接使用动态规划,记忆化搜索简单无脑,三行搞定。反调试检测:绕过:尝试 hook NtQuerySystemInformation,KeBugCheckEx,找到蓝屏的函数在 0x74F0,于是考虑在 hook NtQuerySystemInformation 的某个节点,把该函数 hook 直接返回,不会蓝屏,但是调试器被剥离。调试发现是调用了 KdDisableDebugger 函数。同样也是直接返回,操作完成后,可以发现驱动已经可以正常运行,且调试器正常工作。这里代码实现仅仅变动了 hook 的 NtQuerySystemInformation 函数,因为有 vmp 壳,所以在加载的时候去 hook 是不明智的,直接在调用 NtQuerySystemInformation 的某一刻过掉即可。因为壳似乎有 API 防 hook 的检测,如果不及时下掉钩子则会加载失败,因此选择在第三次调用之后下掉钩子并做反调试的相关 hook。结论:从后续的逻辑来看,生成的 key 就是 flag 做某种加密的密钥。这里的 v10,经过动态调试,记录了最高有效位,例如我现在输入的 key=0x25312620c4fe,占用 6 字节,所以最高有效位为第五位(从零开始),如图所示因此第一步就是实现一个简单的异或加密,根据密钥的长度而定。紧随其后的是 TEA 加密,和初赛一样,每两个字符零扩展成 int 之后放入 TEA 加密。乍一看这里居然用了 key 的地址进行运算,实则不需要被他吓到,这么玩确实会导致每次加密的结果不一样,但是不代表就不可逆(后来嘎嘎被打脸),逆了一下发现逆推到第一个式子的时候推不动了。经过调试,发现是代码被 VT hook 了,联想到之前要求一定是 Intel CPU。可以看到单步执行得到的指令结果不符合预期,题目在此处开启 VT 环境。在 +0x5150 处的函数实现 hook 的分发。答案:flag: flag{ACE_C0n9raTs0nPA55TheZ02S9AmeScTf#}由于分发函数过于庞大,且 VT 的hook是无痕的,因此考虑能否使用加密的弱点去实现 flag 的解密,由于 TEA 加密的输入是被零扩展的,因此实际 8 字节的分组只有 2 字节是有效的。可以计算两字节的所有组合,获得它的密文结果,实施这个方法之前,需要确定,相同的密文,相同的 key,得到的一定是相同的输出,断 TEA 加密的 call,选中 RCX 的内存,改成全 0,得到 A9 59 CF AB EB 9D A3 0A,多个位置尝试发现得到的始终是这个结果,因此判定该方法可行。这里方法就多起来了,第一可以把注册表写满 0000-FFFF,然后指定 Key 为 0xFF,就可以 dump 得到一份表,或者可以直接写一个驱动去调用那个功能,这里我选择了后者。观察 windbg 的输出,得到了正确的运行结果:理论可行,那就直接 for 爆一遍,然后存到内存里面,最后 windbg 直接 dump 出来。但是发现直接 dump 无法直接查找得到,经检查,原来是 rdmsr 被 VT hook,做了一次异或加密,并且根据长度生成异或的密钥,很简单,直接把内存都置 0 就能直接拿到异或的密钥,并且密钥由输入

...(已截断)

---
来源: 看雪论坛
原文链接: https://bbs.kanxue.com/thread-286460.htm
#2 2026-06-01 21:08:54
太强了????,学习一波
#3 2026-06-01 21:08:54
学习了
#4 2026-06-01 21:08:54
学习了
#5 2026-06-01 21:08:54
666,收藏学习了
#6 2026-06-01 21:08:54
希望上传附件 学习
#7 2026-06-01 21:08:54
牛逼哥
#8 2026-06-01 21:08:54
能不能帮我做个软件
#9 2026-06-01 21:08:54
没有下载到附件,能上传吗
#10 2026-06-01 21:08:54
Vt太好玩啦

请登录后参与讨论

立即登录 注册账号