这应该是一个非常简单,非常快速的qustion。这些是C编写的程序的前3行:
Dump of assembler code for function main:
0x0804844d <+0>: push ebp
0x0804844e <+1>: mov ebp,esp
0x08048450 <+3>: and esp,0xfffffff0
... ... ... ... ... ... ...
什么是0x0804844d
和0x0804844e
以及0x08048450
?它不受ASLR的影响。它仍然是内存地址,还是文件的相对点?
答案 0 :(得分:4)
如果您查看Intel Developer Manual instruction-set reference,可以看到0x0804846d <+32>: eb 15 jmp 0x8048484
对相对地址进行编码。即它是jmp rel8
短编码。这甚至可以在与位置无关的代码中工作,即在任何地址映射/加载时都可以运行的代码。
ASLR意味着每次将文件加载到内存时,可执行文件中的堆栈地址(以及可选的代码+数据)都会发生变化。 显然,一旦程序加载,地址将不再更改,直到再次加载。因此,如果您在运行时知道地址,则可以将其作为目标,但是假设固定地址,则无法编写漏洞。
在任何ASLR之后,GDB会向您显示进程虚拟内存空间中的代码地址。 (顺便说一下,GDB默认禁用ASLR:set disable-randomization on|off
来切换。)
对于可执行文件,通常只有堆栈指针是ASLRed,而代码是位置相关的并且加载在固定地址,因此代码和静态数据地址是链接时常量,因此代码如{ {1}} / push OFFSET .LC0
可以工作,将字符串常量的地址硬编码为call puts
。
无论如何,库通常需要与位置无关,因此ASLR可以在随机地址加载它们。
但可执行文件的ASLR是可能的,并且变得更加常见,可以通过making position-independent executables(Linux),也可以让操作系统修复每个硬编码的地址,当它在不同的地址加载可执行文件时编译为(Windows)。
地址仅与相同段内的相对意义上的文件中的位置具有1:1的关系。即代码的下一个字节是文件的下一个字节。可执行文件的标题描述了文件的哪些区域是什么(以及它们应该由OS的程序加载器映射到何处)。
答案 1 :(得分:3)
所示地址的含义在三种情况下有所不同:
对于可执行文件:
可执行文件通常无法加载到内存中的任何地址。在Windows中,可以向可执行文件添加“重定位表”(非常旧的Windows版本需要);如果不存在(通常是使用GCC时的情况),则无法将文件加载到另一个内存位置。在Linux中,永远不可能将可执行文件加载到另一个位置。
您可以尝试这样的事情:
static int a;
printf("%X\n", &a);
执行程序100次时,您会看到a的地址始终相同,因此不会对可执行文件本身进行ASLR。
objdump转储的地址是绝对地址。
对于DLLs / .so文件:
地址是相对于DLL的基地址(在Linux下)或它们是绝对地址(在Windows下),当DLL加载到另一个内存区域时它们会发生变化。
对于目标文件:
转储目标文件时,地址与当前显示的部分相关。如果文件中有多个“.text”部分,则每个部分的地址将从0开始。