腾讯2025游戏安全PC方向初赛题解
题目
小Q是一位热衷于PC客户端安全的技术爱好者,为了不断提升自己的技能,他经常参与各类CTF竞赛。某天,他收到了一封来自神秘人的邮件,内容如下:
“我可以引领你进入游戏安全的殿堂,但在此之前,你需要通过我的考验。打开这扇大门的钥匙就隐藏在附件中,你有能力找到它吗?”
评分标准:满分5分
(1)在64位Windows10+系统上运行exe, 找到正确的flag,作为答案提交(2分)。
(2)文档编写,详细描述解题过程,详述提供的解题程序的演示方法。(满1分)
(3)提供解题演示所用的源代码。编码工整风格优雅(1分)、注释详尽(1分)。
flag
flag{ACE_We1C0me!T0Z0Z5GamESecur1t9*CTf}
分析-Ring3
先说结论:
- 有点反调试
- 加载驱动,初始化驱动
- 检测flag的长度为36位,头必须为ACE_
- 截取出ACE_后面的东西进行base58编码(结果倒叙)
- 与”sxx”三个字符异或
- 发到内核层check
赛博厨子如下设置就能正确解密
详细分析
反调试
- 使用函数CheckRemoteDebuggerPresent查询调试状态
- 使用peb成员BeingDebugged判断调试状态(IsDebuggerPresent展开是这样的)
- 通过堆状态NtGlobalFlag来判断调试状态
详细分析
转到initterm加载的最后一个函数就可以发现其中使用std::thread库开启了一个反调试线程,其线程入口为sub_140001C90
我们可以跟进去看一下
可以发现经典的检测手段。后面那一大坨则是std::this_thread::sleep_for与std::chrono组合起来编写的等待函数,Release下优化导致的。
我们直接在开启反调试线程的地方ret掉就行了。
驱动加载
- 使用CreateService的方式注册服务
- 使用StartService开启服务
- 使用MiniFilter的FilterConnectCommunicationPort函数创建通信接口存在类中
详细分析
跟进去看一下原来就是调用其他函数
继续跟
会发现其他的成员函数
一个个来,先看服务安装,标准的通过注册表安装服务的方式安装了驱动,值得注意的是,由于安装的MiniFilter驱动,这里需要注册表 多创建Instances子健, 所以这里还是不太一样的
start的则是正常的开启服务
创建通信则是用的MiniFilter,并把句柄存在类中。
Base58
由于没有TlsCallBack我们直接转main前初始化的部分分析。着重分析initterm加载的函数。
我们在倒数第二个函数发现了点不一样的
当然图里是已经分析好的了,我们去分析初始化Base58的表。
我们会发现其就是单纯的字符串xor加密,直接动调拿表即可。
明显长度大于58位,我们直接缩减到58位即可(源于对base58的分析)
所以表为:
1 | abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ123456789 |
为什么是base58呢我们往下看,xref一下就能到base58的函数,这里写了58,很明显了。
不过有一点值得注意,我们往下翻的话会看到一个结果倒叙
这里需要特别注意一下
其他加密分析
首先看输入之后,发现这里的长度有一些限制,其应为:0x14+0x10 -> 0x24
输入的长度必须大于36(包含00),也就是35个字符。
然后前4位必须是ACE_
继续跟,后面会发现初始化了一个字符串内容为sxx
然后后面把ACE_后面的字符提出来了,做base58
做完之后把其与sxx字符进行异或。
后面就进入了r0进行check
然后后面就是卸载驱动了。
分析-Ring0
- 使用hook的方式修改check函数
- 接收来自应用层的内容
- 返回对应的值
回调分析
首先既然是通过MiniFilter进行的通信,我们直接找一下其注册函数就行,驱动入口被保护了,但是注册的地方没保护。直接看
直接看消息回调
首先会发现有点混淆,手算一下就能知道是到pop r10的位置
我们直接全nop了,后面也有一大堆,手动去一下就行了
F5一下发现有问题
patch一下
会发现其中会创建缓冲区然后复制,其还测试了传入的内存是否可读保证安全。
不过报错也是新思路直接跟过去
其里面依然有混淆,手动去一下,就会发现其实是消息分发函数
这里面呢其实有2个功能
值得注意的是,这里a1是个结构,其结构如下:
1 | struct Message |
第一个功能呢是在r3传入
时返回This is TestHello from r0
第二个则是重点,我们看检查flag的函数。
其中去了混淆长这样
值得注意的是其把明文按一个字符扩展成了unsigned int 所以有42个密文。
很明显key和密文都有了,里面就是个tea,但是呢怎么可能这么简单结束了?
smc分析
对着tea函数按x会发现一大堆引用,我们把混淆去一下挨个看看。
首先看第一个很明显在写tea函数,在做最后的patch
值得一提的是,代码写的很棒,首先提升了IRQL,然后判断了一下CR4寄存器的CET位,该位在开启时必须开启CR0的WP保护位,反过来说:CR4.CET开启时关闭CR0.WP会蓝屏,(Intel手册卷3 2.5节详细说了)所以其关闭了CR4.CET再去改CR0.WP让内存可写。同时加上了关闭外部中断,保证了其线程会一直占用CPU。恢复寄存器后重新开中断降低IRQL。该强写代码堪称简单又标准!
闲言少叙,我们直接来看到底写了什么。
函数贼长,不过看起来是在写一片内存,同时也在计算些什么。
显然的4048是跳板。
继续看其他的点呢,则是修改了原始tea加入了点新东西,rax,rcx的值则是上面算出来的。
理清逻辑之后就可以直接动调了,断加密前面给加密的代码抠出来就行了。
关于如何下断:这里动调偷懒断FltRegisterFilter就省的写回调下断点了。
输入内容后段下来,可以看到确实被改了
转过去把字节抠出来方便ida分析
存到本地,ida修一下就可以f5直接看到了
这个就是加密算法了,写一下解密算法这个题就完事了。
exp:
1 | #include <stdio.h> |
- 标题: 腾讯2025游戏安全PC方向初赛题解
- 作者: moshui
- 创建于 : 2025-03-31 14:01:34
- 更新于 : 2025-04-02 00:13:32
- 链接: https://www.moshui.eu.org/2025/03/31/2025TX/
- 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。