为什么在 PE 映射到内存后写入 ModuleBase.exe+0x100 以及可能的其他标头偏移是“安全的”?

逆向工程 聚乙烯 抵消 游戏黑客
2021-06-22 09:50:50

通常,当我在反转游戏后编写游戏黑客可执行文件时,我会进行代码挖掘以找到可以根据需要注入代码的位置。好吧,虽然从其他人那里反转了一些这样的可执行文件,但我注意到他们选择总是在 Game.exe+100 中注入他们的代码。这让我想知道开始这样做并称之为完成是否更容易。

然而,我在这里的问题是针对那些比我现在更熟悉 PE 格式的人(说实话,我的大脑此刻正在游弋,试图将我的脑袋围绕在我在 Google 上搜索到的资源上) ):

为什么从模块基地址偏移 0x100?一旦 PE 被映射到内存中,是否有文档和/或众所周知的来自图像库的偏移量,这些偏移量几乎总是可以安全地覆盖/写入?如果是这样,它们可能是哪些偏移量?从那里,我将了解这些部分中的每一个代表什么,以及每个偏移量可以使用多少字节。

无论如何,不​​要费力地回答,请随时为我指出正确的图表或详细说明特定偏移量的信息。我现在对信息不知所措,并且对我正在查看的所有内容感到有些困惑(例如看到用于各个部分的相同偏移量等)。谢谢!

2个回答

在 PE 文件中,节通常映射到 4kb 倍数的地址(这是默认值,尽管它可以被覆盖)。这意味着即使是单个物理字节长的部分也将为它分配整个 4kb 的内存。第一部分被映射到文件头之后的内存中,因此它将距离文件头4kb。很少有文件头需要使用那么多空间,现在绑定导入表已被弃用,因此有很多可用空间。0x100 是一个很好的整数,它超出了记录的标准标头大小,这就是使用它的原因。

简短回答:因为您的普通程序永远不会访问这些值。

长答案:Peter ferrie 的回答指出,该偏移处通常没有任何东西。那不是真的。Portable Executable 的最短可能有效标头长度为 0xc8。但这是针对具有单个部分、没有导入(或任何其他需要数据目录的东西)、没有 DOS 存根和富标头的程序(在不修补链接器的情况下使用 Visual Studio 是不可能的)。具有导入和两个部分(实际程序通常有 4-7 个部分)的实际(但仍然主要是学术)程序的最短标题至少为 0x160 长。添加默认的 DOS 存根,您将位于 0x1a0。添加富标头,这通常是另一个 0x30-0x80 字节。事实上,您很少会看到头部适合前 512 个字节的 PE。所以在 0x100 你覆盖数据,但是,一旦加载程序完成将图像加载到内存中,操作系统就不再使用该数据,因此只要程序不使用该数据(例如加载资源),就可以了。

可能值得注意的是,0x40 之后的所有偏移量都是可变的,因此如果不先检查目标二进制文件,您甚至不知道在 0x100 处覆盖的是什么。由于无论如何您都必须调用 VirtualProtectEx(无论是使数据部分可执行还是代码部分可写),您不妨调用 VirtualAllocEx 并且根本不用费心寻找代码洞。如果我不得不猜测为什么另一个人总是注入 0x100,我会说这是因为他从一个已知地址运行(除非启用了 ASLR 并且目标二进制文件是可重定位的)所以他不必重新定位他的注入/使其位置独立之前的代码。它是懒惰的、草率的、不安全的。