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

[原创] 腾讯2025游戏安全PC方向决赛题解

117 浏览 12 回复
#1 楼主 2026-06-01 21:08:55
(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分)很棒开局寄了,比赛开始的前两天想玩hyperdbg来着,发现电脑是AMDcpu没法玩,当时直接赌用不到。 结果一下子考了VT,天崩开局。但是呢也不都是祸,前几周给XYCTF2025出题的时候呢出了一道VMP的驱动题,这回正好考了VMP。
那怎么玩?翻遍家里就发现一个”田“牌平板(挂不了调试器)和一个N年前的笔记本能用。
于是激情下单了电脑,然后周一才能到。。
只能嗯调了,就有了这种old school逆向风,开着老版windbg,trace一下卡1s的电脑开始了。
首先dump 被VMP保护的驱动,并同时获取当前时刻系统API的导出表作为IAT修复用。通过对于VMP的了解可以知道,VMP在最后的时候会调用API函数KeRevertToUserAffinityThread来完成最后的操作,此时VMP是已经把资源解密、修复完成的,直接IAThook + dump就行了。dump出来后,使用特征码直接定位__security_init_cookie,进而定位入口点。48 8B 05 ?? ?? ?? ?? 48 85 C0 74 1B

有了入口点,FxDriverEntryWorker就出来了,进而DiverMain就出来了。

DriverMain经过分析如下:
该函数就是单纯初始化一些东西,包括获取CPU型号信息、电脑基础信息、初始化Table。
查询了CPU的厂商、版本、指令集,并把他们的数据保存起来先查版本和cpu厂商

然后查指令集,并把他们存起来
通过NtQuerySystemInformation获取电脑信息

M_GetNtdll则通过API获取了其中的SECTION_IMAGE_INFORMATION并保存为全局变量。

其他函数则是初始化一些表什么的。initterm_e与initterm的特征过于明显不再赘述转回主函数我们来看关键的函数


在该函数中,把从注册表输入的Key与Flag读取出来,进行检测。使用CPUid读出来CPU厂商信息,使用std::string把他们组合起来,并判断是不是名字为GenuineIntel 通过读取注册表\\Machine\\System\\CurrentControlSet\\\Services\\ACEDriver\\2025ACECTF下的项来获取Flag和Key,并返回是否获取到。


该函数为生成Key与CheckFlag的关键函数。
而在这步只需要发现当Key不是0的时候不会进入到非常耗时的生成key的函数中即可。根据经验,这种反调试一般都是通过创建线程或者各种各样的回调函数来完成的,一开始试了各种各样的api,包括但不限于:PsCreateSystemThreadEx、KeInitializeDpc、ExQueueWorkItem等,最终在ExQueueWorkItem中找到了回调函数。

该函数是被vmp变异了的,但是可以在里面发现另一个调用。跟进去后发现调用了蓝屏函数(包装过的),这里面还有个字符串(其实一开始就找到过这个函数但是没以为有什么用)

继续跟进去发现调用了一个用于安全调用蓝屏函数的函数和字符串。

跟进去可以发现,他把栈清了防止栈回溯找到他。

那么思路很明确了,把从Workitem里面调用一连串蓝屏函数的地方给他ret就行了。之所以ret这个,是因为交叉引用会发现其还在一个别的地方被调用,是循环的。
这个偏移是0x74f0,直接ret就行了。

ret之后会发现调试器无了,这很明显调用了KdDisableDebugger,同样的给他ret就行。转到intel的物理机中就可以正常加载调试了。首先可以很轻松找到Key生成算法上文已经说过了,稍微整理一下,然后给deepseek。

这里需要不断的重复,然后直到他说出来正确的算法。那么怎么测试呢?直接在windbg里面修改寄存器,让小的数进入计算函数,获取正确的结果。
比如这里算的是16,8。他结果应该跑出来是0xA949才对。当然前面也算过其他的小的数。然后会给我一个正确,但是没有优化的算法。此时继续调教他发现给我的算法不再正确,小的数据都是错的。果断使用chatgpt,然后他告诉我需要用这个带记忆缓存的。

然后把他给我的代码再次测试跑(循环几次)直到给我个对的。
故此结果出来了。代码如下:我觉得完美的展现了VT的强大*前提:必须识别出是hv库,这样就能对着源码进行分析,也省事。2bbK9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6Y4K9i4c8Z5N6h3u0Q4x3X3g2U0L8$3#2Q4x3V1k6B7L8$3&6G2L8h3q4F1k6$3!0Q4x3V1k6Z5N6R3`.`.以下内容按照逆向分析时的顺序编写,个人认为是最简单能看出来的方法。首先有VT可以想到经典的EPT hook,那么若要安装EPT hook,在hv框架中则需要通过 hv::vmx_vmcall 来调用。于是问题变成了找vmx_vmcall,我们可以直接编译一份hv库,然后bindiff,也可以手动匹配字节码。我这里是两者结合,先bindiff把一些识别出来的给自动重命名,有些没识别的就手动搞一下了。
无论如何我们都可以找到他,在Base+0x153C处。

我们下个断点就可以发现第一次竟然就上了EPT hook。

结合hv库的结构我们可以轻松发现首先上了EPThook。因为其调用代码为5,对应hv::emulate_vmcall的安装EPThook。

然后翻阅hv源码可以发现其hook的页和被替换的页存的结构,把被替换的页抠出来,就可以找到一个类似xtea的东西。
在调用加密函数时候可以发现有2次readmsr的指令请求,这很奇怪,通过调试可以发现第二次readmsr的时候flag被改了。那么应该是在readmsr模拟函数中做了操作。

我们可以从hv::rdmsr_safe来定位,其中使用了readmsr,直接特征码搜索就行了,然后往上跟一下就到了hv::emulate_rdmsr。转到hv::emulate_rdmsr,可以发现其在传入E8的时候对寄存器做了一些操作。
首先通过读取栈里面有没有这个魔术数字来判断是不是自己驱动调用的,如果是的话则进行了一个加密,这个只是异或,我们只要抄出来保证参数正确就可以解密。 此处CPU寄存器结构如下,是从hv库中抄出来的。
这个是最

...(已截断)

---
来源: 看雪论坛
原文链接: https://bbs.kanxue.com/thread-286462.htm
#2 2026-06-01 21:08:55
膜拜大佬!
#3 2026-06-01 21:08:55
写的很不错!cool wp!
#4 2026-06-01 21:08:55
学习了
#5 2026-06-01 21:08:55
神!
#6 2026-06-01 21:08:55
无敌哥,太强了
#7 2026-06-01 21:08:55
初级还能看懂,这个完全整不明白了
#8 2026-06-01 21:08:55
tql!
#9 2026-06-01 21:08:55
师傅写的很好。最后VT检测可以多考虑几种思路:比如利用常见引起VM-Exit的指令去看看赛题环境下会不会抛异常。另外EPT Hook也可以考虑利用时序的方法检测,原理就是被挂上Hook的函数读与执行的时间差距巨大
#10 2026-06-01 21:08:55
周旋久


师傅写的很好。最后VT检测可以多考虑几种思路:比如利用常见引起VM-Exit的指令去看看赛题环境下会不会抛异常。另外EPT Hook也可以考虑利用时序的方法检测,原理就是被挂上Hook的函数读与执行的 ...

很奇怪,我尝试用时序检测来检测EPT Hook,但是好像效果不好?可能是我代码的问题。确实我最后一天太困了状态不好,其实应该仔细再看一看的,感觉错失了很多点。

最后于 2025-4-15 22:05
被moshuiD编辑

,原因: 打错字了
#11 2026-06-01 21:08:55
问下他这个驱动前面获取各种信息的不加vmp吗?
#12 2026-06-01 21:08:55
yazigegeda


问下他这个驱动前面获取各种信息的不加vmp吗?

dump+修复iat,他里面很多函数没有加任何保护,反调试那部分加了变异而初始化VT的部分则是上了vm。
之所以能看到是有API都是我后面修的,最后呈现的结果
#13 2026-06-01 21:08:55
大佬有没有pc端的赛题附件,想学习一下

请登录后参与讨论

立即登录 注册账号