x86对抗栈回溯检测
1.原理 函数调用 CALL 指令可拆分为两步操作: 1)、 将调用者的下一条指令( EIP )的地址压栈 2)、 跳转至将要调用的函数地址中(相对偏移或绝对地址) 那么在执行到子函数首地址位置时,返回地址(即调用函数中调用位置下一条指令的地址)就已经存在于堆栈中了,并且是 ESP 指向地址的值。下面通过栈帧的概念,了解编译器在接下来对堆栈进行的操作。 简言之,栈帧就是利用 EBP (栈帧指针,请注意不是 ESP )寄存器访问栈内部局部变量、参数、函数返回地址等的手段。程序运行中, ESP 寄存器的值随时变化,访问栈中函数的局部变量、参数时,若以 ESP 值为基准编写程序会十分困难,并且也很难使 CPU 引用到正确的地址。 所以,调用某函数时,先要把用作基准点(函数起始地址)的 ESP 值保存到 EBP ,并维持在函数内部。这样,无论 ESP 的值如何变化,以 EBP 的值为基准能够安全访问到相关函数的局部变量、参数、返回地址,这就是 EBP 寄存器作为栈帧指针的作用。 在函数体代码的任何位置,EBP 寄存器指向的地址始终存储属于它的调用函数的 EBP 的值,根据这个原理可逐级向调用函数、调用函数的调用函数进行遍历,向上回溯。 这样有什么用呢? 在将属于调用函数的 EBP 的值压栈之前, ESP 指向的地址存储的是由 CALL 指令压栈的调用函数中调用位置的下一条指令的地址(原