【问题标题】:Why does inserting characters into an executable binary file cause it to "break"?为什么将字符插入可执行二进制文件会导致它“中断”?
【发布时间】:2013-12-31 01:08:48
【问题描述】:

为什么将字符插入可执行二进制文件会导致它“中断”?

还有,有什么方法可以在不破坏编译程序的情况下添加字符?

背景

我早就知道可以使用十六进制编辑器更改已编译的可执行文件中的代码,并且仍然可以正常运行...

示例

以下面应用程序为例,Facebook 可以更改为Lacebook,程序仍然可以正常执行:

但它会因新角色而中断

我也知道,如果添加新字符,它会破坏程序并且它不会运行,或者它会立即崩溃。例如,在Facebook 前面添加My 可以实现:

我知道的

我不知道的事

  • 我不太明白操作系统和可执行文件的关系。我猜当您输入程序名称并按回车键时,您基本上是在指示操作系统“执行”该文件,这基本上意味着将文件加载到内存中,将处理器的指针设置为它,并告诉它“走吧!”
  • 我明白为什么二进制文件的文本字符串中有多余的字符会导致问题

我想知道的

  1. 为什么多余的字符会导致程序中断?
  2. 是什么决定了程序坏了?操作系统?操作系统是否也将此程序保持为沙盒状态,以免现在整个系统崩溃?
  3. 有什么方法可以通过十六进制编辑器在编译程序的文本字符串中添加额外的字符,而不会使应用程序中断?

【问题讨论】:

  • 程序计数器通常是绝对的,所以如果你移动东西,一切都会中断。
  • 非常好的问题,但它需要一个很大的答案。如果还在的话,我会在稍后尝试完整地回答。现在,把函数想象成在内存中。每次调用函数时,您都在告诉代码 跳转 到特定位置。如果您之前添加了额外的字节,您会将函数的代码 shift X 个字节,因此指令将不再有效,并且函数调用肯定不会按照您的想法执行。所有函数调用都是硬编码的指针。
  • 在 Q3:否。假设您在字符串“Facebook”之前插入“hello”。然后 every 之后的字符串向上移动 5 个位置。您需要在更改后找到指向字符串的每个字符串 pointer 并将其递增。 (而且“数据”不仅是易于识别的文本字符串!)如果运气不好,您可能还必须在不同的点增加“数据部分”的大小。
  • 如果您查看 F (46) 和 L (4C) 的位模式,您会注意到它们具有相同的位数,因此看起来某处有一个校验和适用于位.如果您尝试使用 34($)、43 (C) 或 64 (d),它也可能会起作用。其他任何事情都会破坏校验和

标签: c linux compiler-construction linker hex-editors


【解决方案1】:

我不太明白操作系统和可执行文件之间的关系。我猜当您输入程序名称并按回车键时,您基本上是在指示操作系统“执行”该文件,这基本上意味着将文件加载到内存中,将处理器的指针设置为它,并告诉它“走吧!”

现代操作系统只是将文件映射到内存中。在需要之前,他们不会费心加载它的页面。

为什么多余的字符会导致程序中断?

因为他们将文件中的所有其他信息都放在了错误的位置,所以加载器最终加载了错误的东西。此外,代码中的跳转最终会转到错误的位置,可能是在一条指令的中间。

是什么决定了程序坏了?操作系统?操作系统是否也将这个程序保持在沙盒中,这样它现在就不会导致整个系统崩溃?

这取决于到底是什么搞砸了。可能是你移动了一个头部,加载器注意到头部的某些参数有无效数据。

有没有办法通过十六进制编辑器在编译程序的文本字符串中添加额外的字符,而不会使应用程序中断?

可能不可靠。至少,您需要可靠地识别需要调整的代码部分。这可能会非常困难,特别是如果有人故意这样做的话。

【讨论】:

    【解决方案2】:

    当一个程序被编译成机器代码时,它包括许多对程序存储器中指令和数据地址的引用。编译器确定程序所有内存的布局,并将这些地址放入程序中。可执行文件也被组织成多个部分,开头有一个目录,其中包含每个部分的字节数。

    如果你在程序中插入一些东西,之后所有东西的地址都会上移。但是包含对程序和数据位置的引用的程序部分没有更新,它们继续指向原始地址。此外,包含所有部分大小的表不再正确,因为您增加了修改的任何部分的大小。

    【讨论】:

      【解决方案3】:

      机器语言可执行文件的格式基于硬偏移,而不是解析字节流(如文本程序源代码)。当您在某处插入一个字节时,文件格式会继续引用原始偏移处插入点之后的信息。

      偏移量可能出现在文件格式本身中,例如告诉加载器文件在什么位置以及它们有多大的标题。

      硬偏移也出现在机器语言本身中,例如在引用程序数据的指令中或在分支指令中。

      假设一条指令说“从我们现在的位置向下分支 200 个字节”,并且您在这 200 个字节中插入一个字节(因为您想要更改的字符串恰好在那里)。哎呀;分支仍然覆盖 200 个字节。

      在某些机器上,即使你修复了分支,它甚至不能是 201 字节,因为它会错位并导致 CPU 异常;例如,您必须添加四个字节才能将其修补为 204(以及使文件健全所需的无数其他东西)。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-09-03
        • 1970-01-01
        • 2014-06-05
        相关资源
        最近更新 更多