给定指令在 运行 进程中的地址,在可执行文件中查找指令?

Find an instruction in an executable file, given its address in a running process?

我正在修改一个旧的废弃软件游戏以获得无限生命。

包含指令dec ecx的地址与其在被调试的.exe中的位置不一致

记得有一次老朋友告诉我,有一个公式可以通过.exe里面的指令得到"true"地址。作弊引擎给了我内存地址。我记得在数学公式中,我需要得到模块,在 OllyDbg 中我得到了它。但是我不记得公式了。有人知道那个数学公式是怎么来的吗?公式非常简单! 还有另一种获取文件位置永久修改.exe的方法吗?

当然有公式
我们只需要反转 PE 加载器所做的事情:

  1. 找到文件中 PE 部分开始的位置。
    这些数字称为文件偏移量。
  2. 相对于基地址,定位 PE 部分必须加载到内存中的位置。
    这些地址称为 RVA(相对虚拟地址)
  3. 选择1一个可用的基地址并将其添加到 RVA。
    这些地址被称为VAs(Virtual Addresses),是文件偏移量的最终地址。

为了帮助理解以下步骤,请记住每个 PE 部分都具有以下属性:

  • 起始文件偏移量,节在文件中开始的位置。
  • 文件中的长度。
  • 一个起始内存地址,该节应该加载到内存中的位置(相对于基地址)
  • 一旦加载到内存中的长度(这可能与文件长度不同)。

因此对于给定的内存地址 X,您必须:

  1. 减去基地址,对于遗留 Windows 程序,这通常是 40 0000h。
  2. 你现在有一个 RVA,找到第一个 PE 部分,它的起始内存地址低于 RVA,结束内存地址在它之后2
  3. 减去节起始内存地址,您现在有一个节偏移量。
  4. 添加节起始文件偏移量,您现在有一个文件偏移量。

有一个名为 PEEditor 1.7 的工具可以为您执行此操作。
由于某种原因,现在很难找到它,但它应该仍然存在于 Internet 上。请记住:它是免费的。


找到PE编辑器:Here,使用密码tuts4you解压RAR包

加载文件(通过拖入 window 或使用浏览按钮)然后点击 FLC(文件位置计算器)。在新的window中输入地址。


1 多半这实际上意味着使用PE中设置的基地址header,多亏了分页。
2计算为内存起始地址+内存长度-1

有一个 "formula" 但您实际上需要查看可执行文件的内部(尽管可以根据一些假设简化此公式)。

  1. 获取你感兴趣的指令/数据的内存地址(虚拟地址)[VA]
  2. 获取指令/数据所在模块的基址。 [MODBASE]
  3. VA减去MODBASE,得到所谓的相对虚拟地址[RVA]:
    • VA - MODBASE = RVA
  4. 用 PE 文件解析器/编辑器打开二进制文件(例如 *.exe 或 *.dll)并查看 headers.
  5. 部分
  6. 找到您的 RVA 所在的部分。
  7. 找到 RVA 所在的部分后,获取“相对虚拟地址”部分。 [SECRVA].
  8. 从 RVA 中减去 SECRVA,然后得到 [OFFSET]。
    • RVA - SECRVA = OFFSET
  9. 获取您在 5.
  10. 找到的部分的 RawAddress [SECRAWADDR]
  11. 在[SECRAWADDR]中加上[OFFSET],结果就是你要查找的指令/数据在二进制文件。
    • OFFSET + SECRAWADDR = INSDATAOFFSET(指令或数据在磁盘文件中的偏移)。

假设

通常(我坚持通常,有时情况并非如此),第一部分的[SECRVA]将是0x1000——恰好是代码部分——并且它的 [SECRAWADDR] 将是 0x400.

因此,如果您根据指令在内存中的地址搜索指令的偏移量,通常可以假设:

  • SECRVA = 0x1000
  • SECRAWADDR = 0x400

例子

示例基于 cmd.exe。

假设我在 0x1C34B0 处搜索此代码,当程序加载到内存中时:

CPU Disasm
Address   Hex dump          Command                                  Comments
001C34B0  /$  E8 B3040000   CALL 001C3968
001C34B5  \.^ E9 2EFEFFFF   JMP 001C32E8

注意指令操作码(字节)为:0xE8B3040000

  1. VA = 0x1C34B0
  2. 正在内存中搜索模块库(使用调试器或 ProcessExplorer;此处有趣的列在进程资源管理器中简称为 "Base"。):

  • MODBASE = 0x1B0000

    1. VA - MODBASE = RVA ; 0x1C34B0 - 0x1B0000 = 0x134B0; RVA = 0x134B0

    2. 用PE编辑器打开二进制文件(我用的是CFF explorer):

  1. 让我们看看0x134B0在哪个部分:

第一部分是 .text,它的虚拟地址是 0x1000,它的虚拟大小是 0x23E4C(所以该部分的结尾是 0x1000 + 0x23E4C = 0x24E4C)。

0x134B0 在 0x1000 和 0x24E4C 之间吗?

  • 0x1000 >= 0x134B0 < 0x24E4C -> 正确:所以地址位于 .text 部分。

注意:对每个部分重复相同的过程,直到找到正确的部分。

  1. SECRVA = 0x1000(部分虚拟地址)

  2. RVA - SECRVA = OFFSET ; 0x134B0 - 0x1000 = 0x124B0

  3. SECRAWADDR = 0x400(部分原始地址)

  4. OFFSET + SECRAWADDR = INSDATAOFFSET ; 0x124B0 + 0x400 = 0x128B0

如果我们查看文件中的 0x128B0,我们有:

所以我们在文件 (0xE8B3040000) 中发现了与内存中完全相同的字节。