一直都对游戏保护感兴趣,最近想看一看游戏驱动是怎么写的。于是便尝试逆向分析一下。在这个过程中学到很多。
由于驱动运行在系统内核层,所以对驱动的调试一般采用双机调试。物理机对物理机,或者物理机对虚拟机。因为手上设备限制,就一个笔记本。所以首先想到的是开虚拟机(VMware Workstation Pro)进行双机调试。
一般情况下,游戏都会检测虚拟机运行环境。网上收集一波资料,找到hzqst的一个项目。
hzqst/VmwareHardenedLoader: Vmware Hardened VM detection mitigation loader (anti anti-vm) (github.com)
按照使用说明,卸载vmtools,修改虚拟机配置文件,安装驱动,就能正常运行游戏。
但是卸载vmtools后,虚拟机很卡,而且屏幕显示也很别扭。所以还是希望能在安装了vmtools的情况下运行游戏。经过测试发现是可行的。以下是操作步骤:
1.修改虚拟机配置文件
2.安装vmloader驱动
3.修改vmtools显卡驱动名字(可选)
安装驱动精灵或者驱动人生,备份显卡驱动。用7z或者winrar打开备份的压缩包(不解压),编辑inf文件。
保存文件后。用驱动精灵或者驱动人生还原显卡驱动即可。
完成修改后,成功运行游戏。
在看雪论坛看了一圈发现,游戏驱动基本都对Windbg双机调试进行了检测和处理。目前我并不清楚是怎么检测的,所以放弃VMWare+kdstub+windbg的双机调试方式,另寻他法。经过搜索,发现VMWare+gdbstub+IDA-gdb是个很好的方式。
IDA启动gdb调试器
虚拟机在本地运行,则hostname填localhost,目标系统是64位,则port填8864(32位是8832)在这个窗口等待备用。
去VMware启动虚拟机后,立刻回到IDA单击OK,那就成功附加上了。
IDA-gdb成功附加之后,默认是没有符号。没有符号的情况下,调试内核并不方便。所以得想办法加载上微软的巨硬PDB。内核ntoskrnl.exe的pdb符号文件先下载好备用。IDA在调试时是可以加载pdb文件。
所以只需要得到内核模块ntoskrnl.exe的符号文件和内存加载地址就可以了。而IDA附加之后,断下的位置还在系统启动阶段,并没有加载ntoskrnl.exe。那么可以寻找到载入内核模块,并调用内核入口函数的时机。就能获取到KiSystemStartup函数地址减去函数偏移就能得到ntoskrnl的基址。简单逆向winload.exe(有符号)找到一个关键函数OslArchTransferToKernel。
那么只需要在这个位置下断点,即可跟踪到内核入口。IDA搜索一下OslArchTransferToKernel函数末尾指令对应的字节码:
49 8B CC 56 6A 10 41 55 48 CB
就能确定OslArchTransferToKernel函数位置。
在单步执行跳过去之前需要先映射一下内存区域。
然后单步执行跳到KiSystemStartup函数。
那么当前的KiSystemStartup函数地址为0xFFFFF80006F90010,KiSystemStartup的偏移是0x990010
现在终于获得了基址,配和之前下载备用的pdb,IDA再加载一下,就可以有符号了。
目前为止,我们已经有了可以运行游戏的虚拟机环境和能带微软符号调试内核的调试环境。那么就可以做一些感兴趣且有意思的事情了。前人栽树,后人乘凉。先找一下有没有分析过该游戏保护的,拿过来看一看,找一找思路。hzqst大佬!
[原创]某南极动物厂新版XX分析——系统线程部分(新瓶旧酒)-软件逆向-看雪论坛-安全社区|安全招聘|bbs.pediy.com
看完他的分析,我也想定位一下游戏驱动创建的隐藏了入口的系统线程。那就在启动游戏之前,IDA里在PsCreateSystemThread函数处下断点,看第六个参数StartRoutine是不是SeSetAuditParameter函数内部jmp rcx所在地址。
一共确定了五个线程的地址,再减去游戏驱动的加载地址(IopLoadDriver下断获得)得到函数偏移,就能在IDA里面静态分析了。
当我打开另一个IDA载入游戏驱动文件,跳到线程地址,发现直接就能F5(意外之喜)。
具体分析参考hzqst的帖子,不再多说。看完系统线程部分,自然还想看看其他好功能。再找一波,发现杰克王的帖子。杰克王大佬!
[原创]某企鹅xxx-base分析-软件逆向-看雪论坛-安全社区|安全招聘|bbs.pediy.com
他的帖子里面对回调部分说得比较少,但是我对游戏驱动回调怎么写的确实感兴趣,开始尝试分析找到回调。
首先找一个能用的ark,看看游戏驱动创建的回调函数地址。同样的减去模块基址得到偏移,再去IDA看一看。
LoadImage回调函数地址0xFFFFF8001C0B4190去IDA看看。
好家伙,暗藏只因,趁着双机调试,去那个地址看一看实际的回调函数地址。
同样能直接F5,其他回调函数都是差不多的模式,不再重复。具体功能我也不再分析细说。
分析完回调,我也想看一看游戏驱动的通信函数,学习一下。跳过去一看,不能F5,直呼坏事。那么下一节浅说代码保护。
我对代码保护没什么了解,也没有基础。我只是根据双机动态调试,跟踪一下代码运行过程,做出一些判断和操作。
在调试过程中发现游戏驱动代码具有一些特别的跳转结构。
其中最奇怪的就是 jmp r8会跳转到他的下一句指令pop r8,那么其实这一段代码什么也没做,就是干扰一下。简单对抗一下IDA-F5小子。发现了关键点,那么我们可以写一下去混淆脚本。同样的,网上找一波资料。找到了 逍遥m 发的帖子。逍遥m大佬!
[原创]IDA 驱动vmp变异 去花指令 IDC脚本-软件逆向-看雪论坛-安全社区|安全招聘|bbs.pediy.com
那我也是抄一下代码,针对性的改一改。写好一个IDC脚本开干。脚本这里我就不发了,混淆的原理和如何写idc去混淆脚本都贴出来了。相信大家认真点分析都会写去混淆脚本的。毕竟自己动手丰衣足食。贴一下去混淆之后成功F5的截图。
去混淆之后,大部分功能都能看了。但是还有些是被v了的,跑在虚拟机里面。我能力有限,只是简单分析一下。我拿驱动入口里调用的一个函数举例。
在整个分析过程学到很多东西。从游戏运行环境搭建,到双机调试环境搭建,到动态调试游戏驱动,再到分析代码保护。涉及到的东西确实多,收获也多。
传统功夫,讲究点到为止,此贴到此结束。
hypervisor.cpuid.v0
=
"FALSE"
board
-
id
.reflectHost
=
"TRUE"
hw.model.reflectHost
=
"TRUE"
serialNumber.reflectHost
=
"TRUE"
smbios.reflectHost
=
"TRUE"
SMBIOS.noOEMStrings
=
"TRUE"
ethernet0.address
=
"00:11:22:33:44:55"
/
/
这里随意
hypervisor.cpuid.v0
=
"FALSE"
board
-
id
.reflectHost
=
"TRUE"
hw.model.reflectHost
=
"TRUE"
serialNumber.reflectHost
=
"TRUE"
smbios.reflectHost
=
"TRUE"
SMBIOS.noOEMStrings
=
"TRUE"
ethernet0.address
=
"00:11:22:33:44:55"
/
/
这里随意
/
/
将inf文件以下三行任意修改
DiskID
=
"VMware Tools"
CompanyName
=
"VMware, Inc."
SVGA
=
"VMware SVGA 3D"
/
/
将inf文件以下三行任意修改
DiskID
=
"VMware Tools"
CompanyName
=
"VMware, Inc."
SVGA
=
"VMware SVGA 3D"
debugStub.listen.guest64
=
"TRUE"
debugStub.hideBreakpoints
=
"TRUE"
monitor.debugOnStartGuest64
=
"TRUE"
debugStub.listen.guest64
=
"TRUE"
debugStub.hideBreakpoints
=
"TRUE"
monitor.debugOnStartGuest64
=
"TRUE"
ntoskrnl.base
=
0xFFFFF80006F90010
-
0x990010
=
0xFFFFF80006600000
ntoskrnl.base
=
0xFFFFF80006F90010
-
0x990010
=
0xFFFFF80006600000
1.FFFFF8001C0B5B60
2.FFFFF8001C0
*
*
*
70
3.FFFFF8001C0
*
*
*
80
4.FFFFF8001C0
*
*
*
80
5.FFFFF8001C0
*
*
*
F0
FFFFE20CF9B6ABE0
0000000000000000
MEMORY:unk_0
FFFFE20CF9B6ABE8 FFFFE20CF9B6ACA9 MEMORY:FFFFE20CF9B6ACA9
FFFFE20CF9B6ABF0 FFFFF8001C1965A1 MEMORY:FFFFF8001C1965A1
FFFFE20CF9B6ABF8 FFFFE20C00000000 MEMORY:FFFFE20C00000000
FFFFE20CF9B6AC00 FFFFAD86F81E36F8 MEMORY:FFFFAD86F81E36F8
FFFFE20CF9B6AC08 FFFFF8000693CC31 SeSetAuditParameter
+
41
FFFFE20CF9B6AC10 FFFFF8001C0B5B60 MEMORY:FFFFF8001C0B5B60
FFFFE20CF9B6AC90
0000000000000000
MEMORY:unk_0
FFFFE20CF9B6AC98
0000000000000002
MEMORY:word_2
FFFFE20CF9B6ACA0 FFFFF8001C14B419 MEMORY:FFFFF8001C14B419
FFFFE20CF9B6ACA8 FFFFF80000000000 MEMORY:FFFFF80000000000
FFFFE20CF9B6ACB0 FFFFAD86F81E3238 MEMORY:FFFFAD86F81E3238
FFFFE20CF9B6ACB8 FFFFF8000693CC31 SeSetAuditParameter
+
41
FFFFE20CF9B6ACC0 FFFFF8001C0
*
*
*
70
MEMORY:FFFFF8001C0
*
*
*
70
FFFFE20CF9B6AC10
0000000000000000
MEMORY:unk_0
FFFFE20CF9B6AC18
0000000000000000
MEMORY:unk_0
FFFFE20CF9B6AC20 FFFFF8001C1962F0 MEMORY:FFFFF8001C1962F0
FFFFE20CF9B6AC28
0000000000000000
MEMORY:unk_0
FFFFE20CF9B6AC30 FFFFAD86F8168578 MEMORY:FFFFAD86F8168578
FFFFE20CF9B6AC38 FFFFF8000693CC31 SeSetAuditParameter
+
41
FFFFE20CF9B6AC40 FFFFF8001C0
*
*
*
80
MEMORY:FFFFF8001C0
*
*
*
80
FFFFE20CF9B6AC50
0000000000000000
MEMORY:unk_0
FFFFE20CF9B6AC58
0000000000000002
MEMORY:word_2
FFFFE20CF9B6AC60 FFFFF8001C180C6D MEMORY:FFFFF8001C180C6D
FFFFE20CF9B6AC68
0000000000000000
MEMORY:unk_0
FFFFE20CF9B6AC70 FFFFAD86F8168338 MEMORY:FFFFAD86F8168338
FFFFE20CF9B6AC78 FFFFF8000693CC31 SeSetAuditParameter
+
41
FFFFE20CF9B6AC80 FFFFF8001C0
*
*
*
80
MEMORY:FFFFF8001C0
*
*
*
80
FFFFE20CF9B6AC90
0000000000000000
MEMORY:unk_0
FFFFE20CF9B6AC98
0000000000000002
MEMORY:word_2
FFFFE20CF9B6ACA0 FFFFF8001C1835B0 MEMORY:FFFFF8001C1835B0
FFFFE20CF9B6ACA8
0000000000000000
MEMORY:unk_0
FFFFE20CF9B6ACB0 FFFFAD86F8168378 MEMORY:FFFFAD86F8168378
FFFFE20CF9B6ACB8 FFFFF8000693CC31 SeSetAuditParameter
+
41
FFFFE20CF9B6ACC0 FFFFF8001C0
*
*
*
F0 MEMORY:FFFFF8001C0
*
*
*
F0
1.FFFFF8001C0B5B60
2.FFFFF8001C0
*
*
*
70
3.FFFFF8001C0
*
*
*
80
4.FFFFF8001C0
*
*
*
80
5.FFFFF8001C0
*
*
*
F0
FFFFE20CF9B6ABE0
0000000000000000
MEMORY:unk_0
FFFFE20CF9B6ABE8 FFFFE20CF9B6ACA9 MEMORY:FFFFE20CF9B6ACA9
FFFFE20CF9B6ABF0 FFFFF8001C1965A1 MEMORY:FFFFF8001C1965A1
FFFFE20CF9B6ABF8 FFFFE20C00000000 MEMORY:FFFFE20C00000000
FFFFE20CF9B6AC00 FFFFAD86F81E36F8 MEMORY:FFFFAD86F81E36F8
FFFFE20CF9B6AC08 FFFFF8000693CC31 SeSetAuditParameter
+
41
FFFFE20CF9B6AC10 FFFFF8001C0B5B60 MEMORY:FFFFF8001C0B5B60
FFFFE20CF9B6AC90
0000000000000000
MEMORY:unk_0
FFFFE20CF9B6AC98
0000000000000002
MEMORY:word_2
FFFFE20CF9B6ACA0 FFFFF8001C14B419 MEMORY:FFFFF8001C14B419
FFFFE20CF9B6ACA8 FFFFF80000000000 MEMORY:FFFFF80000000000
FFFFE20CF9B6ACB0 FFFFAD86F81E3238 MEMORY:FFFFAD86F81E3238
FFFFE20CF9B6ACB8 FFFFF8000693CC31 SeSetAuditParameter
+
41
FFFFE20CF9B6ACC0 FFFFF8001C0
*
*
*
70
MEMORY:FFFFF8001C0
*
*
*
70
FFFFE20CF9B6AC10
0000000000000000
MEMORY:unk_0
FFFFE20CF9B6AC18
0000000000000000
MEMORY:unk_0
FFFFE20CF9B6AC20 FFFFF8001C1962F0 MEMORY:FFFFF8001C1962F0
FFFFE20CF9B6AC28
0000000000000000
MEMORY:unk_0
FFFFE20CF9B6AC30 FFFFAD86F8168578 MEMORY:FFFFAD86F8168578
FFFFE20CF9B6AC38 FFFFF8000693CC31 SeSetAuditParameter
+
41
FFFFE20CF9B6AC40 FFFFF8001C0
*
*
*
80
MEMORY:FFFFF8001C0
*
*
*
80
FFFFE20CF9B6AC50
0000000000000000
MEMORY:unk_0
FFFFE20CF9B6AC58
0000000000000002
MEMORY:word_2
FFFFE20CF9B6AC60 FFFFF8001C180C6D MEMORY:FFFFF8001C180C6D
FFFFE20CF9B6AC68
0000000000000000
MEMORY:unk_0
FFFFE20CF9B6AC70 FFFFAD86F8168338 MEMORY:FFFFAD86F8168338
FFFFE20CF9B6AC78 FFFFF8000693CC31 SeSetAuditParameter
+
41
FFFFE20CF9B6AC80 FFFFF8001C0
*
*
*
80
MEMORY:FFFFF8001C0
*
*
*
80
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!