13

在问我的问题之前,我想介绍一些我想确保我得到正确的技术细节:

  • 与位置无关的可执行文件 (PIE) 是一个无论加载到哪个内存地址都能够执行的程序,对吧?

  • ASLR(地址空间布局随机化)几乎指出,为了保持地址静态,我们会以某种方式随机化它们,

我已经读过,特别是在基于 Linux 和 Unix 的系统中,实现 ASLR 是可能的,无论我们的代码是否是 PIE,如果它是 PIE,所有跳转、调用和偏移都是相对的,因此我们没有问题。如果不是,无论代码是可执行文件还是共享对象,代码都会以某种方式被修改并编辑地址。

现在这让我问几个问题

  1. 如果 ASLR 可以在不是 PIE 并且是可执行文件且不是共享/可重定位对象的代码中实现(我知道重定位如何在可重定位对象中工作!!!!),它是如何完成的?ELF 格式不应该包含任何部分来说明代码部分中函数的位置,以便内核加载程序可以修改它,对吗?ASLR 应该是一个内核功能,例如,一个包含例如这些指令的可执行文件。

    伪代码:

     inc_eax:
      add eax, 5
      ret
    
     main:
      mov eax, 5
      mov ebx, 6
      call ABSOLUTE_ADDRES{inc_eax}
    

    如果它们没有存储在 ELF 文件中的某个可重定位表中并且不是相对的以便将可执行文件加载到某个随机地址中,那么内核可执行加载程序如何知道如何更改地址?

  2. 假设我错了,为了实现 ASLR,你必须有一个 PIE 可执行文件。所有段都是相对的。如何编译 C++ OOP 代码并使其工作,例如,如果我有一个类的某个实例使用指向其结构中的虚拟表的指针,并且该虚拟表应该保存绝对地址,因此我不会能够为使用运行时虚拟表的 C++ 程序编译纯 PIE,并且 ASLR 再次是不可能的......我怀疑虚拟表将包含相对地址,并且每次调用都会有一个不同的虚拟表一些虚函数...

  3. 我最后一个也是最不重要的问题是关于 ELF 和 PIE - 是否有一些特殊的方法来检测 ELF 可执行文件是 PIE?我熟悉 ELF 格式,所以我怀疑有没有办法,但我可能错了。无论如何,如果没有办法,内核加载程序如何知道我们的可执行文件是否是 PIE,因此它可以在其上使用 ASLR。

我把这一切都搞砸了,如果有人能在这里帮助我,我会很高兴的。

4

1 回答 1

25

您的问题似乎是混乱和误解的混杂。

与位置无关的可执行文件 (PIE) 是一个无论加载到哪个内存地址都能够执行的程序,对吧?

几乎。二进制文件通常PIE不能在任意地址加载到内存中,因为它的PT_LOAD段会有一些对齐要求(例如 0x400 或 0x10000)。但是如果在满足对齐要求的地址加载到内存中,它可以被加载并正确运行。

ASLR(地址空间布局随机化)几乎指出,为了保持地址静态,我们会以某种方式随机化它们,

我无法以任何有意义的方式解析上述语句。

ASLR 是一种随机化地址空间各个部分的技术,以使“已知地址”攻击更加困难。

请注意,ASLR早于 PIE二进制文件,并且在任何情况下都不需要PIE. 引入 ASLR 时,它随机放置堆栈、堆和共享库。(非PIE)主要可执行文件的位置无法随机化。

ASLR 被认为是成功的,因此扩展为也支持PIE主二进制文件,它实际上是一个特制的共享库(并且具有ET_DYN文件类型)。

  1. call ABSOLUTE_ADDRES{inc_eax} 如果 > 它们没有存储在某个可重定位表中,内核可执行加载程序将如何知道如何更改地址

很简单:在 x86 上,没有关于call ABSOLUTE_ADDRESS-- 所有调用都是相对的指令。

2 ...我无法为使用运行时虚拟表的 C++ 程序编译纯 PIE,而且 ASLR 也是不可能的。

PIEbinary 需要relocation,就像共享库一样。PIE二进制文件中的虚拟表的工作方式与它们在共享库中的工作方式完全相同:在将控制权转移到二进制文件之前ld-linux.so.2更新(全局偏移表)。GOTPIE

3 ...是否有一些特殊的方法来检测ELF可执行文件是PIE

简单:PIE二进制文件的 ELF 文件类型设置为ET_DYN(非PIE二进制文件类型为ET_EXEC)。如果您file a.outPIE可执行文件上运行,您会看到它是一个“共享库”。

于 2016-07-05T19:59:13.983 回答