首页
社区
课程
招聘
[原创]2024鹅厂游戏安全技术竞赛决赛题解-PC客户端
发表于: 2024-4-22 02:37 14955

[原创]2024鹅厂游戏安全技术竞赛决赛题解-PC客户端

R0g 活跃值
2
2024-4-22 02:37
14955

虚拟机系统环境:Windows 10 x64 1909 18363.418

调试环境:KDNET network kernel debugging

老规矩查壳

image1.png

很好,什么也看不出来;直接拖IDA看看。

image2.png

导入表有个ExAllocatePoolWithTag,尝试Hook了不过并没有什么卵用,跑起来只会拷贝一个“2024.wo.shi.chu.ti.ren”的字符串上去......直接看Disassembly。

image3.png

一眼VMP,等分析完成后Shift+F12看字符串。

image4.png

“bad array new length”和“vector too long”明显来自stl库,应该是被std::string和std::vector的某个类成员函数所引用的。

image5.png

跑一下Lumina私服能出一些符号,其中std::string成员函数:

image6.png

挨个xref找访问,std::string::~string和std::string::find_last_of能追到同一个地方。

image7.png

word_140675E20数组逐字与0xACE进行了异或,拷贝出代码来跑一下:

image8.png

得到存放key的文件路径

image9.pngimage10.png

联想到key的格式“ACE-4051574845”,可以知道此处正在进行字符串分割。

其次,sub_140AFC7E2通过复制给chatgpt解析能大致得出其为字符串转整数的功能。

image11.png

下断验证:

image12.png

还原大致逻辑,sub_140009CBC是对用户名进行计算,得到一个输出值。算法如下:

image13.png

整体逻辑:

image14.png

用户名匹配时,函数返回1即true,失败返回false。

exp思路:修改用户名输出值与key的比较结果,使函数返回值恒为true即可。

具体方法:注册LoadImage回调,判断加载的映像是否为目标驱动,使判断函数尾部的xor al, al变成mov a1, 1

image15.png

成功加载Loader驱动后,System进程的CPU占有直接飙升至99%。

image16.png

说明Shellcode应当是启动了。而Loader想在内核跑shellcode必然要写到可执行内存并获得执行时机。可执行内存的获取方式一般为:

ExAllocatePool/ExAllocatePoolWithTag/MmAllocateIndenpendentPages/MmAllocateContiguousMemory....

执行时机:PsCreateSystemThread/WorkItem/APC/DPC/Timer/...

延续初赛的解题代码,直接用DetoursX挂钩PsCreateSystemThread、ExAllocatePoolWithTag

image17.png

BSOD,看调用栈是PsCreateSystemThread后的双重错误。而ExAllocatePoolWithTag直接执行到了挂钩后面的int3上去了。

image18.pngimage19.png

应该是程序自己构造函数序言部分,执行完成自行构造的序言部分后jmp到后面的代码验证构造call:

image20.png

直接去挂钩更底层的PsCreateSystemThreadEx和ExAllocateHeapPool一劳永逸,可以成功让目标驱动走我们的钩子。

不过看到跳板push ret有种莫名熟悉的感觉(XXX-BASE),尝试在物理机用CE附加虚拟机进程即vmware-vmx.exe,搜索跳板特征。

68 ?? ?? ?? ?? C7 44 24 04 ?? ?? ?? ?? C3

image21.png

94个结果,估计跳板格式是定死的。

image22.png

image23.png

编写CE lua脚本dump出所有的跳转函数,测试对跳板写入0xCC,windbg中可以接管到断点。

之后把dump出的函数列表去重后依次在windbg里面看符号地址,这样就能得出shellcode的所有导入函数了;依次下断分析,可以知道那些函数是正在被调用的。写个下断脚本一键下断。

image24.pngimage25.png

最终得出正常运行时调用的系统函数大致如下:

image26.png

程序会死循环遍历进程ID,并调用PsLookupProcessByProcessId获取进程对象。

image27.png

Hook更底层的PspReferenceCidTableEnty可以得出最大PID为0x40000找到shellcode调用地址,按4K对齐的方式找到一个大致的shellcode头。

图片1.pngimage28.png

之后dump shellcode到文件,拖到IDA一条龙服务。

image29.pngimage30.png

编写一个简单的脚本去除shellcode中两处影响分析的控制流混淆指令,去掉混淆后只剩一个jmp指令,虽然还有很多混淆,但是基本不影响IDA创建函数分析控制流了。

image31.png

仔细观察被混淆的指令

image32.png

找到规律:

call的传参指令及返回值寄存器操作,非易失寄存器读写,内存读写指令,堆栈操作指令,cmovcc指令,cmp/test+jcc指令,以及某些特定代码块结束的add rdx,[x+y] -> jmp rdx...

混淆的SSE/AVX指令穿插在这些正常指令之间,但是混淆指令的寄存器和算术逻辑运算结果并没有保留或被引用,因此笔者感觉可以使用活跃变量分析去除这些垃圾指令,但奈何比赛时间有限,笔者对以上代码熟练度并不高,故选择手动删除混淆代码(删除之后还有ollvm的控制流平坦化,但是不影响分析)。

去掉混淆之后,代码逻辑清晰可见,参数一传入了保存进程信息的结构体指针。

image33.png

分析用同等方式去掉混淆,总耗时5小时,耗能三个馒头。

5ba87defb19109c8685985ade02bc0c9.png

第一个xref:

image34.png

PsGetProcessExitStatus判断进程存在

获取进程名称:

image35.pngimage36.png

第二个xref:

image37.pngimage38.png

与初赛如出一辙的字符串加密方式,在sub_FFFF8003BD0E543C下个断能拿到解密后的字符串 -> “GameSec.exe”

image39.png

然后随便搞个程序改名成GameSec.exe,丢到测试机里运行。再启动Loader跑起shellcode后直接蓝了。


[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

最后于 2024-4-22 05:45 被R0g编辑 ,原因: 纠错
收藏
免费 9
支持
分享
最新回复 (15)
雪    币: 6166
活跃值: (4937)
能力值: ( LV10,RANK:160 )
在线值:
发帖
回帖
粉丝
2
其实他不是动态混淆,他编译了n份,跑的时候,随便挑一个来跑。
2024-4-22 04:47
1
雪    币: 1282
活跃值: (4555)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
3
淡然他徒弟 [em_19]其实他不是动态混淆,他编译了n份,跑的时候,随便挑一个来跑。[em_19]
单走一个6,我说咋有时候和我dump的一样呢
2024-4-22 04:54
0
雪    币: 10850
活跃值: (5874)
能力值: ( LV15,RANK:533 )
在线值:
发帖
回帖
粉丝
4
tql
2024-4-22 09:54
0
雪    币: 698
活跃值: (4564)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
5
确实6
2024-4-22 10:24
0
雪    币: 446
活跃值: (618)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
这解决方式很有味道,分析过程有点优雅
2024-4-22 13:37
1
雪    币: 1420
活跃值: (2171)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
7
有一说一,你 nmi回调里面用RtlWalkFrameChain  不蓝吗? RtlWalkFrameChain 使用的irql 我记得 是低于dpc的把。
2024-4-22 14:10
0
雪    币: 1282
活跃值: (4555)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
8
青丝梦 有一说一,你 nmi回调里面用RtlWalkFrameChain 不蓝吗? RtlWalkFrameChain 使用的irql 我记得 是低于dpc的把。

RtlCaptureStackBackTrace是可以在DPC_LEVEL上跑的,RtlWalkFrameChain被这个调用,因此也可以在DPC_LEVEL上运行

最后于 2024-4-22 14:26 被R0g编辑 ,原因:
2024-4-22 14:26
0
雪    币: 796
活跃值: (2034)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
DPC_LEVEL及以上,RtlWalkFrameChain回溯到分页代码随缘炸。
2024-4-22 14:30
0
雪    币: 2141
活跃值: (5173)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
10
orz
2024-4-22 16:01
1
雪    币: 1420
活跃值: (2171)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
11
R0g 青丝梦 有一说一,你 nmi回调里面用RtlWalkFrameChain 不蓝吗? RtlWalkFrameChain 使用的irql ...
 nmi 执行回调的时候 irql 等级应该是 HIGH_LEVEL 等级, RtlWalkFrameChain   是用不了的
2024-4-28 14:24
0
雪    币: 1282
活跃值: (4555)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
12
青丝梦 nmi 执行回调的时候 irql 等级应该是 HIGH_LEVEL 等级, RtlWalkFrameChain 是用不了的

是的概率炸,上生产环境还要重新实现下

最后于 2024-4-28 16:05 被R0g编辑 ,原因:
2024-4-28 16:04
0
雪    币: 1420
活跃值: (2171)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
13
R0g 青丝梦 nmi 执行回调的时候 irql 等级应该是 HIGH_LEVEL 等级, RtlWalkFrameChain 是用不了的 ...
我还是选择抄ac的,不过效果比较差而已
2024-4-28 17:41
0
雪    币: 26
活跃值: (321)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
14
所以说为了分析决赛题做了个外挂扫描 很6
2024-8-14 16:14
0
雪    币: 183
活跃值: (2576)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
15
你好强
2024-9-25 15:00
0
雪    币: 40
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
16
学习了,受教
2024-10-5 18:33
0
游客
登录 | 注册 方可回帖
返回
//