2021腾讯游戏安全技术竞赛 决赛PC客户端writeup
前言
最近忙了一些琐碎的事情,这两天又有闲功夫了,发现2021安全技术竞赛决赛赛题出来了,而且比赛都结束了....
虽然赛事已经结束,但题目还是能做。既然闲下来就继续做做,写个writeup吧。
赛题
说明:
- shootgame是一个游戏,hack.exe是游戏shootergame的一个外挂程序。
- 运行shootgame游戏,运行hack.exe,成功执行外挂功能并分析外挂实现过程。
目标:
- 成功执行hack功能,给出外挂执行成功的flag
- 实现与hack.exe外挂功能相同,但原理不同的程序
很有意思的游戏外挂方向,算是我比较擅长的领域
先打开游戏试试,跑一下hack.exe,发现一闪而过,并没有执行外挂功能 看了一下无壳,所以直接拖入IDA分析
分析hack.exe
main函数里就是整个外挂程序的执行流程,先大体看一下流程
程序运行流程
一. 程序先解密了字符串,得到文件名hack.dat,并读取了这个文件

1 | data = [0x06, 0x0E, 0x13, 0x1A, 0x5C, 0x17, 0x15, 0x1] |
这也解释了,直接打开外挂为什么会一闪而过
二. 程序从hack.dat里解密出游戏进程名,并打开游戏进程

decrypt函数解密出hack.dat的明文,通过下标构造出进程名,然后用CreateToolhelp32Snapshot
和Process32First
遍历进程,找到后打开进程。
代码中有一个for循环目前不太清楚是干嘛的、decrypt函数的解密算法也先放放。先继续往下看
三. 程序开始构造flag,并检查hack.dat的内容

- 第一个循环用于构造flag,脚本如下(与解密FileName的算法一致)
1 | data = [92, 61, 35, 35, 26, 1, 27, 19, 25, 32, |
- 第二个循环用于检查flag与hack.dat明文是否一致
- 如果一致,就解密出
flag%s
(此处省略解密脚本,与解密FileName的算法一致),调用printf
输出flag
四. 注入DLL

- 解密DLL数据
- 远程申请内存,用于放DLL
- 解密ntdll.dll,以及各种DLL注入需要用到的函数(解密算法还是和上文一样,函数很多,不一一展示了)

- 使用
WriteProcessMemory
远程写入DLL内容、执行dll的执行器
到这里,就能解释上文步骤二中的for是用来干嘛的了,是用来计算dll执行器的shellcode的长度
- 使用
CreateRemoteThreadEx
创建远程线程执行DLL,实现外挂功能
decrypt函数分析
hack.exe中有两处调用了decrypt函数,分别是: 1. hack.dat文件的解密 2. DLL数据的解密
由于上文已经知道了hack.dat解密出来的明文会与flag做对比。所以我们只需要分析decrypt函数的加密算法就可以得到hack.dat文件,也就能正常启动外挂了,顺便也可以dump出DLL文件

decrypt函数是经过SSE指令集优化后的解密函数。
利用SSE指令集,可以实现一个CPU指令操作16byte的数据,所以此函数SSE部分每次循环解密64byte的数据。 当解密到不足64byte时候(或本身就不足64byte),就使用常规,一byte一byte的解密 解密算法如图已经分析的很清楚了,下面上解密脚本,将flag反向输出成hack.dat
1 | flag = '2RSRhrofoWtLeLrJCSlTireznrtx.oeLxuehyyAwbpCOZq0tsS7MZyVdOUoE8' |
把输出的hack.dat放在hack.exe目录下,运行hack.exe

成功输出flag

成功执行外挂功能,试了一下,鼠标右键可以自瞄
Dump外挂DLL
由于已经搞懂了decrypt函数的算法,将DLL给dump出来就很简单了,既可以动态调试、也可以静态的使用IDAPython脚本解密后输出
我这次使用脚本
1 | start_addr = 0x14001DA40 |
小总结
dump出来后,下面就可以分析外挂功能的具体实现
分析dump.dll
无壳,直接拖入IDA分析
程序运行流程
DllMain创建了一个线程,线程里放着主流程
一. 程序先获取游戏主模块,初始化各种全局变量

根据主模块+基址偏移,获得World指针、三维xyz转屏幕xy的函数地址、以及游戏tick函数地址等等
二. 然后Hooking游戏tick函数,将自瞄功能实现在Hook函数里
64位inline Hook,这里应该用了某Hook库,比较复杂。原理是修改原函数入口,JMP到Hook函数里,也实现了蹦床,这里就不具体分析了,看一下Hook修改原函数入口的核心代码就行,如下图

三. 最后实现自瞄功能
这里是本DLL的重点,自瞄功能的实现又分为以下几个步骤
- 根据基址偏移获取
player_controller
对象

- 判断鼠标右键是否按下,如果按下就调用
get_target
函数尝试匹配一个敌人
get_target
函数分析如下

遍历对象数组,并排除自己。获取每个对象名字,并排除物品、武器等对象

计算每个敌人与准心的距离,取距离准心最近的一个敌人返回
- 获取自己和敌人的坐标

- 计算相对距离,求俯仰角和偏航角,然后将数据写入到玩家Carm里,实现自瞄

小总结
自此大概就明白了此DLL是如何实现自瞄的了,属于传统的内部攻击
实现与hack.exe外挂功能相同的程序
等有时间了再写...