标签:
我这里学习汇编语言的思路就是逆向C++源码。
先从最简单的一个程序入手:
为什么程序的开头两句总会是
push ebp
mov ebp,esp
?
先来看一个程序:
这个程序调用fun()时,fun的汇编代码也是如此,开头调用这两句汇编:
其实,这里ebp中保存的是你当前的函数(main函数)的栈基址,当你进入一个子函数(func函数)的时候,你要使用这个子函数的栈空间,此时进入子函数的栈空间就要先保存当前函数的栈基址。将此时的 esp 赋予 ebp 以便后面用 ebp 来作为栈基并以此通过 [ebp+??] 来访问函数的参数、以 [ebp-??] 来访问函数的变量。
可以用一个图表示:
ebp其实可以当做是一个fun和main的“分界线”。
sub esp,0C0h,就是开辟了一块栈空间。
push ebx
push esi
push edi
用来保存main函数的“现场环境”。
lea edi,[ebp-0C0h]
mov ecx,30h
mov eax,0CCCCCCCCh
rep stos dword ptr es:[edi]
rep指令的目的是重复其上面的指令.ECX的值是重复的次数.
STOS指令的作用是将eax中的值拷贝到ES:EDI指向的地址.
这样就将这片栈空间中的数据都初始化为“CCCCCC...”
xor eax,eax
这个很简单,就是设置返回值,eax作为返回值。
这几句实现真正的return。
那么问题来了?为什么要将栈空间初始化为“CCCCC...”?
从网上摘录了三句话来解释:
“int 3 的机器码就是 0xcc,对没初始化或变量之间填充这些,一旦程序异常,执行到这些位置来了,就会中断到调试器里面”
“vc debug初始化填充0xCC,为了方便调试查看,防止未初始化的情况发生,要知道release模式是不会自动帮你填任何东西的,也就是所谓初始化,C++不会做任何多余的事”
“这是一种防御式的代码调试方法,CC除了作为无效区域的标记,还是x86指令集中的INT 3单步中断的机器码,可以暂时停止指令的执行。”
看到网友的回答,原以为是因为如果访问未初始化的栈空间就会报错,但事实并非如此。
验证如下,我写了一个测试程序:
#include <iostream> int fun() { int i = 0; int *p = &i - 30; *p = 1; return 0; } int main() { fun(); return 0; }
当初始化栈空间之后,我们可以查看下ebp的值:
在内存中找到这个地址,查看内存:
栈空间的绝大部分已经被“CC”填充。
当单步调试过int *p = &i - 30;时,p就有了值,它所指向的位置就是fun的栈空间
下面我们就用*p = 1;来测试下这个空间是否可以访问
结果,栈空间的位置被改变了。没有报告任何异常。
那么我们只能认为,这段"CC"只是起一个标识作用。如果有更好的解释,也欢迎大家提出。
标签:
原文地址:http://www.cnblogs.com/predator-wang/p/4875883.html