【问题标题】:Addresses in OllyDbg Change on Program reload程序重新加载时 OllyDbg 中的地址更改
【发布时间】:2016-12-23 15:58:25
【问题描述】:

这是我的第一篇文章,我是组装和调试的新手,请多多包涵。

我试图将一些代码(对 MessageBoxA 的一点调用)注入到 Windows 7 记事本可执行文件中。但是,我遇到了地址的问题。首先,我在 OllyDbg 中打开 exe,然后转到包含“notepad.pdb”的 ASCII 文本的行。然后我在其下方放置一个 ASCII 字符串(例如,“INJECTED NOTEPAD”)。接下来,在下面,我输入了这个asm代码:

PUSH 0
PUSH address_of_ASCII_string ; In this case, 00A6B668C
PUSH address_of_ASCII_string ; In this case, 00A6B668C
PUSH 0
CALL MessageBoxA

接下来,我转到程序中的第一行代码(只需右键单击并按 Go to Origin(或只需在数字键盘上按 *))然后我将第一行替换为指向地址的 JMP 指令我注入的代码中的第一个 PUSH 0。 然后,我将替换的指令放在注入代码的末尾。之后,我将 JMP 指令放在我的 JMP 指令之后的代码行中,该指令跳转到我的注入代码(是的,我只是描述了一个 codecave 或类似的东西)。当我运行它时一切正常。但是,当我将修改后的代码保存到一个新的可执行文件并再次使用 OllyDbg 运行它时,它不起作用。当我尝试引用我输入的 ASCII 字符串时,地址完全错误。示例如下图所示:

如您所见,我将字符串压入堆栈,但是当我再次将修改后的程序重新加载到调试器中时,字符串的地址发生了变化,但我的代码没有。因此,当我调用 MessageBoxA 函数时,它会出错,因为我为 Text 和 Caption 参数加载了错误的地址。我该如何解决这个问题?

【问题讨论】:

  • 嗯,是的,当您应该使用相对地址时,您正在尝试使用绝对地址。每次启动进程时,可执行文件的基地址都是随机的,因此固定地址在多次调用中无效。 (另外:欢迎来到 Stack Overflow!感谢您提出的问得好、提出得很好的问题。)
  • 谢谢。那我该如何使用相对地址呢?
  • 我想说你尝试不注入代码而是修补exe。您当然不需要使用相对地址而是绝对地址 - 但所有绝对地址必须在.relocs 部分中描述。你的补丁工作的一种方法 - 在 exe 上禁用 relocs。为此,您需要在 IMAGE_FILE_HEADER.Characteristics 中设置标志 IMAGE_FILE_RELOCS_STRIPPED - 在此 exe 始终将加载到常量地址和可能的硬编码绝对地址之后
  • 我尝试了 RbMm 的建议,它奏效了!我只是在 CFF Explorer 中打开记事本并转到“文件头”部分。然后我通过选中“从文件中剥离的重定位信息”框来编辑“特征”条目。我假设这使可执行文件使用绝对寻址而不是使用基地址对吗?进行此修改会破坏 nor 可执行文件中的任何内容吗?它不会破坏记事本,但我的目标是将一些代码附加到 explorer.exe。我不知道这是否会破坏资源管理器。但是,它适用于记事本。谢谢。
  • 还有其他建议吗?

标签: windows assembly x86 memory-address codecave


【解决方案1】:

你遇到的是ASLR的效果。简而言之,这意味着在操作系统(在此示例中为 Windows)上运行的可执行文件在多次执行时不会具有相同的基地址。

所以有几种方法可以将您的代码注入另一个二进制文件,我将在这里解决 2,并且我还会猜测(在阅读 cmets 之后)您正在尝试修补磁盘上的二进制文件。

  1. 修补磁盘上的二进制文件:

    一个。解决此问题的第一种方法是从PE 中删除重定位表。我绝对不会推荐这种方式,因为它可能会在将来使可执行文件崩溃,以防它没有被加载到它喜欢的基地址 (OptionalHeader.ImageBase),这是所有需要重定位的指令将用作添加基地址的默认值一个偏移量。

    假设您有一个字符串位于映像基址的偏移量0x600,如果可执行文件映射到其首选基地址(通常为0x00400000),则该字符串将保存在地址0x00400000。您的编译器链接文件的方式将使用0x00400000 + 0x600 的地址,因此0x00400600。那么当可执行文件被加载到不同的基地址时会发生什么?在这种情况下,windows 可执行加载程序会将基地址的偏移量(实际上是映射减去首选基地址)添加到每个重定位条目(上面的示例将需要一个)。因此,如果可执行文件将被加载到0x00500000,加载程序会将0x00100000 添加到导致0x00500600 的绝对地址的重定位条目中。

    b.第二种方法是在二进制文件中添加一个重定位条目。这样,与 (a) 中描述的方式相反,您不会损坏二进制文件,只会添加一个重定位条目,在加载可执行文件时,加载器会将地址更改为正确的地址(如果您添加了正确的条目)。

    c。编写与位置无关的代码并使用此代码修补二进制文件。示例:

    sub     esp, 10*4
    mov     byte [esp], 0x68 ; 'h'
    mov     byte [esp + 1], 0x69 ; 'i'
    mov     byte [esp + 2], 0x00 ; null byte
    mov     byte [esp + 3], 0x79 ; 'y'
    mov     byte [esp + 4], 0x6f ; 'o'
    mov     byte [esp + 5], 0x75 ; 'u'
    mov     byte [esp + 6], 0x00 ; null byte
    mov     eax, esp
    push    0
    push    eax
    add     eax, 3
    push    eax
    push    0
    call    [MessageBoxA]  
    

    此代码会将所需的 2 个字符串写入堆栈并将指针推送到堆栈上的字符串,这样代码就不需要任何重定位,因为它是一段与位置无关的代码。

  2. 修补内存中的二进制文件:

    一个。位置无关代码(见上文)

    b.使用VirtualAllocEx,此API 将在调用它后返回一个您可以写入的地址,这样您只需在内存中拥有映射地址并知道在哪里以及如何注入您的代码。

【讨论】:

  • 感谢您的出色回答。我将使用选项 C 或 B。但是,如何将重定位条目添加到二进制文件中?我不知道该怎么做。
  • 我不建议这样做,因为它不是最简单的方法。简而言之,您会找到重定位目录。在重定位目录中,您将找到可执行文件中每个 section/1kb 的重定位表,您会发现一个由条目填充的表,每个条目告诉您从特定 section/1kb 块的开始的偏移量和重定位类型。你可以在这里找到细节:msdn.microsoft.com/en-us/library/ms809762.aspx
猜你喜欢
  • 2013-03-06
  • 2013-03-20
  • 2013-09-28
  • 2016-06-08
  • 1970-01-01
  • 2020-06-20
  • 2021-05-11
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多