反作弊游戏如何破解,看看《黑色沙漠》逆向分析过程:使用 IDAPython 和 FLIRT 签名恢复 IAT

来源:岁月联盟 编辑:猪蛋儿 时间:2020-01-29

《黑色沙漠》是PearlAbyss Corp开发的一款 MMOARPG 网络游戏,是款在电玩游戏中的动作和战斗的基础上添加大规模攻城战,不动产使用、交易和雇佣等模拟要素的MMORPG。于2013年10月17开启第一次测试。
在这篇文章开始之前,你有必要先看一下如何使用Scylla和x64dbg转储黑色沙漠(BlackDesert64.exe)的过程。我们将在这篇文章中看到我为了简化静态逆向分析而转储过程时所做的一些事情。
黑色沙漠二进制文件的开发者很早就预料到了,会有人对他们的游戏进行逆向分析,因此早已经使用了Themida进行了预防。Themida是一个强劲的保护系统, 专为了那些想保护自己的软件不被先进的逆向工程和黑客软件破解的软件开发者而开发的。开发者不需要更改任何的原代码,和不需要程式编制的经验使用WinLicense。通常,当你从内存中转储一个进程时,特别是如果该进程已封装,则有很多事情会被破坏或正确地说,不会像预期的那样转储。

RDB Packer检测器的输出结果
其中之一就是IAT(我们将要了解IAT是什么以及如何识别它们),如果我们转储一个进程,并且由于某种原因而没有IAT表,则逆向分析将会非常困难,并且将看到调用诸如qword_1419FB008之类的函数而不是GetProcAddress的函数。如果我们能够看到IAT表,逆向分析会变得容易得多。
另一个有趣的事情是应用来自IDA的FLIRT签名,这些签名是IDA附带的,你可以在互联网上找到许多公共集合,将这些公共集合装入二进制文件后,它们将尝试从多个库中识别出众所周知的函数。
导入地址表(IAT)
通常,来自dll的函数地址不是静态的,因此,导入地址表用于存储进程使用的已加载dll中的所有函数指针。基本上,它是内存的一部分,你可以在其中找到指向程序所使用的每个函数的指针列表。每当进程需要访问来自kernel32.dll的WriteFile时,程序便会指向IAT表以获取所加载dll中函数的真实地址。

在该图中,我们可以看到IAT从正在运行的进程中转储出来的数据。可以理解为两个主要的列:第一个列属于内存中每个IAT条目的地址;第二个是从加载的dll指向每个函数的真实地址的指针。这样,每当程序要从dll访问任何函数时,它将指向该表以检索该函数的动态地址。
第三列是x64dbg添加的注释,它根据调试器在内存中加载的符号从每个指针解析函数的名称。当我们从内存中转储进程时,由于所有指针将不再存在于静态转储中,因此我们将无法看到最后的信息,而且我们使用的任何工具都不能像这里的x64dbg那样解析这些指针。
有没有一种方法可以还原此信息以进行静态分析?
当然有,如果我们使用Scylla转储进程,则此工具将自动尝试识别内存中的IAT,但是封装程序很讨厌,通常它们会在解压缩实际二进制文件后删除原始IAT并在内存中分配一个新表。此工具可能无法识别内存中的实际IAT,实际上,如果我们尝试这样做,Sylla会告诉我们IAT表的大小为8字节(一个条目),这是不可能的。
IAT通常是一组指针组成的数组,用一个空指针将每个DLL与另一个DLL分开。在内存中识别它们对于两种情况(静态地使用IDA和动态地使用x64dbg)都是非常简单的。对于x64dbg,你可以简单地寻找任何一块程序集,使调用一个函数从一个dll和遵循的IAT指针:

调用GetModuleHandleW
为了识别转储中的IAT,我们需要寻找一个指针数组,就像我们之前解释的那样。一种可能是寻找对这种格式为qword_1419FB008的函数的调用,这类似于调用cs:qword_1419FB008。如果我们在IDA中遵循此变量,我们将发现看起来像这样的IAT:

IAT与IDA
在上图中,我们可以看到IAT的多个条目,并且在右侧,可以看到IDA标识的所有xref。 Black Desert Online IAT表包含大约1000个条目,你可以想象这将如何简化静态反向过程。

没有符号的反作弊初始化进程
恢复IAT
现在,我们已经在运行的进程以及静态转储中标识了IAT表,我们可以知道尝试将所有符号从进程迁移到IDA。由于x64dbg为我们解决了这些符号,我们可以尝试从运行的进程中复制IAT并在IDA上重命名功能,以便我们在逆向分析时可以使用它们。
我认为有一个更好的方法来执行此操作,但是我决定手动执行第一部分,然后使用IDAPython编写一个小脚本。首先,我们将以x64xdb转到IAT的开头,并在表的第一个条目上执行“右键单击->跟进转储”。这将设置转储1,如下所示:

x64dbg中的IAT
现在,我们将选择从表的第一个地址开始直到表的最后一个条目的所有值。最后,我们要做的是“右键单击->复制->选定行”。如果我们将其存储在新的txt文件中,则将得到以下内容:
00000001419FB000  00007FFC8F3C38F0  advapi32.SetServiceStatusStub
00000001419FB008  00007FFC8F3C3910  advapi32.CryptGenRandomStub
00000001419FB010  00007FFC8F3C3390  advapi32.CryptReleaseContextStub

[1] [2]  下一页