栈是一种典型的后进先出的数据结构,其操作主要有压栈 (push) 与出栈 (pop) 两种操作。两种操作都操作栈顶,当然,它也有栈底。
需要注意的是,程序的栈是从进程地址空间的高地址向低地址增长的。
返回导向编程(缩写ROP)是一种高级的内存攻击技术,这类攻击往往利用堆栈调用时的程序漏洞,通常是缓冲溢出。
攻击者通过控制栈堆调用以劫持控制流并执行针对机器语言指令序列(gadgets),每一段gadgets通常以return指令(ret,机器码为c3) 结束,并位于共享库代码中的子程序中。通过执行这些这令序列,就控制了程序的执行。
换个说法来说ret就可以理解为 pop eip也就是出栈,首先读取esp指向的4个字节内容并赋值给eip,然后esp加上4个字节指向栈的下一个位置,如果eip指向的仍旧是以ret指令结束的,这个过程将重复,esp再次增加并且执行下一个指令序列。
在网上看到对gadgets的评价,只要你敢想,它就能做。感觉很牛皮。
将栈顶的数据抛出并保存到寄存器中,然后跳转到新的栈顶地址。所以当返回地址被一个gadgets地址覆盖时,程序将在返回后执行该指令序列。 如:pop eax; ret
将内存地址处的数据保存到寄存器中 如: mov ecx,[eax]; ret
将寄存器地址的值保存到内存地址处 如:mov eax,[ecx]; ret
add , sub , mul ,xor 等 如:add eax,ebx; ret 和xor eax,ebx; ret
执行内核中断 如:int 0x80; ret , call gs:[0x10]; ret
这些gadgets会改变ebp的值,从而影响栈帧,在stack pivot时我们需要这样的指令来转移栈帧。 如:leave; ret , pop ebp; ret