搞了下鹅厂的比赛题,跟大佬学到不少,(长见识,继续努力,写篇文来记录下过程。
首先是想办法把hack运行起来,发现是缺一个hack.dat文件。而文件内容需要逆一下。
一个简单的xor,解出hack.dat文件名,接着读取文件的内容,看流程应该是将内容进行解密然后赋值到Proname,Proname为游戏的进程名,从而实现外挂接下来的功能。
从给出的game文件中可以得到Proname,求逆可以写出hack.dat的文件内容。
有了hack.dat之后可以运行hack.exe,游戏中显示自瞄开启成功。
使外挂功能实现的hack.dat文件可以多解,但是get flag是唯一的,后面一段逻辑中有buffer的一段比较,buffer内容是硬编码在里面的。可以写脚本得到hack.dat
flag的内容为可以正确逆出hack.dat使外挂程序正常执行的内容,与buffer运算后相同。
hack的主要功能实现是注入了一段dll,dump出来进行分析,第二部分中进行说明。
游戏是UE4的一个开源的射击游戏项目,能很轻松的从官网下载到源码,但是游戏项目的PDB已经不存在了,当前核心任务是搞清楚 Hack DLL 取得那几个硬偏移的含义,直接刚汇编是极不明智的,因此首先安装UE4环境,在官网上下载这个Demo作为参照。
首先要确认UE引擎的版本号,版本不对会很坑(不要问我怎么知道的)
很容易确认就是引擎版本号是4.22
之后就是折腾个编译环境编译下:
得到一个一模一样的游戏,之后的任务就很简单了,可以利用sigmake做IDA sig文件,有了参照就很容易找出hack DLL拿的硬偏移地址的含义(体力活也不是很容易的
如图所示,得到上述含义,剩下的就是代码分析了,这个也是体力活,没啥好说的。
外挂原理:
Inline Hook了 AHUD::DrawHUD,即界面显示的函数
通过GNames遍历获取对象的名称,这部分代码可以参考开源的吃鸡外挂:
比较获取的对象名,是不是awnC,实际上是判断获取的对象是不是目标对象。
通过GetAsyncKeyState获取鼠标状态,如果右键按下则执行外挂逻辑。
如果是的话,则获取其相当坐标参数。调用引擎APlayerController::ProjectWorldLocationToScreen 函数调整射击者视角,因为准星默认在屏幕中央,因此将视角锁定在目标坐标即实现了自瞄
这种外挂思路是通过修改视角控制HDU来实现,那么另一种外挂思路则是,拿到对象的坐标后,修改开火弹道落点为目标(敌人)坐标,即可实现任意开火命中,分析游戏源码,主要函数实现在AShooterWeapon这个类下,参照Blog https://blog.csdn.net/weixin_30653023/article/details/95798081
因此我们可以Hook GetAdjustedAim来修改弹道,顺便下面的可以修改开火速率。
通过调试分析,函数 AShooterWeapon_Instant::FireWeapon 的RVA是0x51C0A0,
因此我们来Hook GetAdjustedAim 函数即可。
GetAdjustedAim的函数地址为0x523660,剩下的就是代码工作,由于时间关系没有完整调试完。
content
=
[
0x5C
,
0x3D
,
0x23
,
0x23
,
0x1A
,
0x01
,
0x1B
,
0x13
,
0x19
,
0x20
,
0x0C
,
0x35
,
0x1F
,
0x37
,
0x0E
,
0x37
,
0x3D
,
0x2C
,
0xEC
,
0xD5
,
0xEB
,
0xF1
,
0xE1
,
0xFF
,
0xE8
,
0xF5
,
0xFC
,
0xF1
,
0xA4
,
0xE4
,
0xE9
,
0xC1
,
0xF6
,
0xFA
,
0xF5
,
0xF9
,
0xEB
,
0xEA
,
0xD5
,
0xE2
,
0xF4
,
0xE7
,
0xDB
,
0xD6
,
0xC0
,
0xEA
,
0xAC
,
0xE9
,
0xED
,
0xCC
,
0x97
,
0xEC
,
0xF8
,
0xDA
,
0xF2
,
0xC1
,
0xE9
,
0xF2
,
0xC7
,
0xEC
,
0x92
]
temp
=
""
for
i
in
range
(
len
(content)):
temp
+
=
chr
((i
+
110
) ^ content[i])
temp
+
=
"\x00"
tmp
=
""
for
i
in
range
(
len
(temp)):
tmp
+
=
chr
((
ord
(temp[i])
+
19
) ^
0x3f
&
0xff
)
with
open
(
"hack.dat"
,
"w"
) as f:
f.write(tmp)
print
(
"Finish"
)
content
=
[
0x5C
,
0x3D
,
0x23
,
0x23
,
0x1A
,
0x01
,
0x1B
,
0x13
,
0x19
,
0x20
,
0x0C
,
0x35
,
0x1F
,
0x37
,
0x0E
,
0x37
,
0x3D
,
0x2C
,
0xEC
,
0xD5
,
0xEB
,
0xF1
,
0xE1
,
0xFF
,
0xE8
,
0xF5
,
0xFC
,
0xF1
,
0xA4
,
0xE4
,
0xE9
,
0xC1
,
0xF6
,
0xFA
,
0xF5
,
0xF9
,
0xEB
,
0xEA
,
0xD5
,
0xE2
,
0xF4
,
0xE7
,
0xDB
,
0xD6
,
0xC0
,
0xEA
,
0xAC
,
0xE9
,
0xED
,
0xCC
,
0x97
,
0xEC
,
0xF8
,
0xDA
,
0xF2
,
0xC1
,
0xE9
,
0xF2
,
0xC7
,
0xEC
,
0x92
]
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!