【问题标题】:Find an instruction in an executable file, given its address in a running process?给定正在运行的进程中的地址,在可执行文件中查找指令?
【发布时间】:2016-03-09 18:23:11
【问题描述】:

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

指令dec ecx的地址与被调试的.exe中的位置不一样。

我记得我的一位老朋友曾经告诉我,有一个公式可以通过 .exe 中的指令获取“真实”地址。作弊引擎给了我内存地址。我记得在数学公式中,我需要得到模块,在 OllyDbg 中我得到了它。但我不记得公式。有人知道这个数学公式是怎么回事吗?公式很简单! 还有另一种方法可以让文件位置永久修改.exe吗?

【问题讨论】:

  • 尝试搜索 dec ecx 周围的字节模式。

标签: assembly reverse-engineering memory-address portable-executable cheat-engine


【解决方案1】:

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

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

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

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

所以对于给定的内存地址 X,你必须:

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

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


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

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


1 大部分情况下这实际上意味着使用PE头中设置的基地址,这要归功于分页。
2 计算为内存起始地址+内存长度-1

【讨论】:

  • base address ... is often 40 000h. - 甚至 400 000h。
【解决方案2】:

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

  1. 获取您感兴趣的指令/数据的内存地址(虚拟地址)。[VA]
  2. 获取指令/数据所在模块的基地址。 [MODBASE]
  3. 从 VA 中减去 MODBASE,得到所谓的相对虚拟地址 [RVA]:
    • VA - MODBASE = RVA
  4. 使用 PE 文件解析器/编辑器打开二进制文件(例如 *.exe 或 *.dll)并查看节标题。
  5. 找出您的 RVA 位于哪个部分。
  6. 找到 RVA 所在的部分后,获取相对虚拟地址部分。 [SECRVA]。
  7. 从 RVA 中减去 SECRVA,然后得到 [OFFSET]。
    • RVA - SECRVA = OFFSET
  8. 获取您在 5 找到的部分的 RawAddress [SECRAWADDR]。
  9. 将[OFFSET]添加到[SECRAWADDR],结果是您在二进制文件中搜索的指令/数据的偏移量。
    • 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 资源管理器):

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

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

0x134B0 是否介于 0x1000 和 0x24E4C 之间?

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

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

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

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

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

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

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

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

【讨论】:

  • +1 you can usually assume that: SECVA = 0x1000 SECRAWADDR = 0x400 - 你不必假设 - 这两个对齐值都记录在 PE 图像的“可选”标题中,分别作为节对齐和文件对齐。虽然节对齐通常是一个虚拟内存页 (0x1000),但文件对齐有时会与此处的不同。
猜你喜欢
  • 1970-01-01
  • 2018-09-17
  • 1970-01-01
  • 2023-03-26
  • 1970-01-01
  • 2015-10-10
  • 1970-01-01
  • 1970-01-01
  • 2016-06-30
相关资源
最近更新 更多