假设没有aslr的x86系统我想询问以下内容;
1)理论说当我们执行堆栈溢出攻击时,ebp寄存器指向的值也会被新的返回地址覆盖。
现在,由于我们永远不会回到调用函数,我们并不需要ebp的原始值来恢复先前的堆栈帧,但是,ebp寄存器必须始终指向某处。 eip寄存器开始指向我们的新shellcode后如何设置ebp? 更具体地说,两个汇编指令(leave-ret)中的哪一个引入了另一个微指令,它将ebp恢复到一个值?
2)最后但同样重要的是,我还想问一下,我们如何确保在我们的shellcode需要在堆栈上推送几个值的情况下,这些值不会覆盖shellcode的任何部分?换句话说,我们怎样才能确定任何shellcode生成的变量只会放在shellcode的开头之前,例如介于两者之间?
提前谢谢大家。
答案 0 :(得分:3)
1.当一个函数被调用时,esp
的值被复制到ebp
,然后通过减少esp
的值来分配该特定函数的堆栈帧(通过ENTER
指令或push ebp
; mov ebp,esp
; sub esp, SIZE
;指令序列)。从此时起,esp
的值严格向上增长,因此不会干扰当前函数的堆栈帧。
当函数到达它的末尾时,它通过上述步骤释放堆栈帧,但是向后,即通过LEAVE
指令,或mov esp, ebp
; pop ebp
;指令序列。此时,esp
的值指向返回地址,这是攻击者想要修改的地址。修改此值后,执行RET
指令后,弹出修改后的返回地址,eip
现在指向修改后的地址。
2.由于shellcode上面的任何内容已被释放",您只需通过上述相同步骤为shell代码分配堆栈帧。
答案 1 :(得分:1)
回答问题的第2部分:根据您正在进行的系统调用,您可能必须将值放入esp
(作为arg数组)。如果这是shellcode的结束那么你就没事了。但是,如果shell代码还有更多,并且您碰巧执行了push
和,esp
碰巧指向shellcode的其余部分,则可能会遇到问题(因为那时你会写自己的指示)。一个简单的解决方法是在shellcode的最开始处执行类似sub $0x99, %esp
的操作。
编辑(回应评论)
也许我误解了你的问题。当你说'堆栈溢出'时,我认为你的意思是缓冲区溢出。如果我假设正确,请继续阅读。假设你真的在谈论一个经典的粉碎堆栈漏洞(基于您链接到的图片似乎就是这种情况),那么你正在填充一个带有nop
雪橇的缓冲区,{{1最后覆盖返回指针。 shell代码是“位置无关代码”。这意味着它是一系列指令,无论寄存器,标志等的当前状态如何都可以执行。
通常,(这也是你发布的链接描述它的方式)你用nops填充缓冲区,然后是shellcode,最后是一个返回地址,指向thop nop sled。执行shellcode
指令时,ret
中的地址加速为%esp
,%eip
加4(x86中)。问题是,如果您的shellcode有多个%esp
指令,则会产生递减 push
的副作用。如果你有足够的和你的shellcode一直到最后(即与返回地址相邻),那么你最终可能会用%esp
指令覆盖你的shellcode。
所以,要真正回答你的问题。不,没有“机制”将shellcode与“其堆栈”分开。这是因为shellcode没有堆栈本身。请记住,它是与位置无关的代码。无论机器状态如何,它都必须能够运行。需要发生的任何堆栈管理必须由shellcode本身执行。这就是为什么我在shellcode的前面建议push
如果代码中有很多sub $0x99, %esp
语句。另一个选择是确保返回地址(push
将指向的地址)与您的shellcode之间有足够的空间。