2

假设一个没有 aslr 的 x86 系统我想问以下问题;

1) 理论上说,当我们执行堆栈溢出攻击时,ebp 寄存器指向的值也会被新的返回地址覆盖。

现在,由于我们从不返回调用者函数,我们实际上并不需要 ebp 的原始值来恢复先前的堆栈帧,但是,ebp 寄存器必须始终指向某个地方。在 eip 寄存器开始指向我们的新 shellcode 之后,ebp 是如何设置的?更具体地说,两条汇编指令(leave-ret)中的哪一条会引发进一步的微指令,将 ebp 恢复为一个值?

2)最后但同样重要的是,我还想问一下,我们如何确保在我们的 shellcode 需要将几个值压入堆栈的情况下,这些值不会覆盖 shellcode 的任何部分?换句话说,我们如何确定任何 shellcode 生成的变量只会放在 shellcode 开始之前,而不是介于两者之间?

谢谢大家。

4

2 回答 2

3

1.当一个函数被调用时, 的值esp被复制到ebp,然后通过减少esp(通过ENTER指令或push ebp; mov ebp,esp;sub esp, SIZE指令序列)的值来分配该特定函数的堆栈帧。从这一点开始, 的值esp严格向上增长,因此不会干扰当前函数的堆栈帧。

当函数到达其末尾时,它通过上述步骤释放堆栈帧,但向后,即通过LEAVE指令,或mov esp, ebppop ebp; 指令序列。此时, 的值esp指向了返回地址,这就是攻击者要修改的地址。一旦这个值被修改,在RET指令执行时,修改后的返回地址被弹出,eip现在指向修改后的地址。

2. 由于您的 shellcode 之上的任何内容都已“释放”,您只需通过上述相同步骤为您的 shell 代码分配堆栈帧。

于 2013-02-17T20:12:51.480 回答
1

回答您问题的第 2 部分:根据您正在制作的系统调用,您可能必须将一个值放入esp(作为 arg 数组)。如果这是 shellcode 的结尾,那么你很好。但是,如果 shell 代码还有更多内容,而您碰巧做了 apush 并且碰巧指向了其余 shellcode 中的esp某个地方,那么您可能会遇到麻烦(因为此时您将编写自己的指令)。sub $0x99, %esp一个简单的解决方法是在 shellcode 的开头做一些事情。

编辑(回应评论)

也许我误解了你的问题。当您说“堆栈溢出”时,我认为您的意思是缓冲区溢出。如果我假设正确,请继续阅读。假设您确实在谈论经典的破坏堆栈类型的利用(根据您链接到的图片似乎就是这种情况),那么您正在用nop雪橇填充缓冲区,shellcode最后覆盖返回指针。外壳代码是“位置无关代码”。这意味着它是一系列指令,无论寄存器、标志等的当前状态如何,都可以执行。

通常,(这也是您发布的链接描述它的方式)您用 nop 填充缓冲区,然后是 shellcode,最后是指向 nop 雪橇中某处的返回地址。执行指令时ret,地址 in%esp被弹出%eip%esp增加 4(在 x86 中)。问题是,如果你的 shellcode 有多个指令,这会产生递减push的副作用。如果你有足够的它们并且你的shellcode一直在最后(即与返回地址相邻),那么你最终可能会用指令覆盖你的shellcode。 %esppush

所以,要真正回答你的问题。不,没有“机制”可以将你的 shellcode 与“它的堆栈”分开。这是因为您的 shellcode 本身没有堆栈。请记住,它是与位置无关的代码。无论机器状态如何,它都必须能够运行。任何需要进行的堆栈管理都必须由 shellcode 本身执行。这就是为什么如果代码中有很多语句,我建议sub $0x99, %esp在 shellcode 的开头使用a。push另一种选择是确保返回地址(%esp-4将指向)和您的 shellcode 之间有足够的空间。

于 2013-02-19T03:42:58.323 回答