分析程序1:
C语言代码如下
#include <stdio.h> void fun(int na, int nb) { int nc = na+nb; printf("one\n"); } void fun1() { printf("two\n"); } void main() { fun(55,66); fun1(); }
汇编代码. 详细标出esp的变化情况
void fun(int na, int nb) { esp=0xfa38 ebp=0xfa44 ;call fun (12B1000h)执行后 push ebp esp=0xfa34 ebp=0xfa44 ;esp-=4 mov ebp,esp esp=0xfa34 ebp=0xfa34 push ecx esp=0xfa30 ;esp-=4 int nc = na+nb; mov eax,dword ptr [na] add eax,dword ptr [nb] mov dword ptr [nc],eax printf("one\n"); push 3720F4h ;esp-=4 call dword ptr [3720A0h] add esp,4 ;esp+=4, 重置下栈顶 } void fun1() { push ebp mov ebp,esp printf("two\n"); push offset ___xi_z+3Ch (0CA20FCh) dword ptr [0CA20A0h] add esp,4 } void main() { esp=0xfa48 ebp=0xfa88 push ebp esp=0xfa44 ebp=0xfa88 esp-=4 mov ebp,esp esp=0xfa44 ebp=0xfa44 fun(55,66); push 42h esp=0xfa40 ;esp-=4 push 37h esp=0xfa3c ;esp-=4 call fun (12B1000h) ;esp-=4 add esp,8 ;esp+=8, 重置下栈顶 fun1(); ;esp-=4 call fun1 (12B1020h) } xor eax,eax ;异或 eax=0 pop ebp ;还原ebp ret ;设置eip = 调用main的位置
要点归纳:
1.堆栈初始化代码:
push ebp
mov ebp,esp
..................
pop ebp
ret
2. ESP, EBP指令
ESP就是一直指向栈顶的指针,而EBP只是存取某时刻的栈顶指针,以方便对栈的操作,如获取函数参数、局部变量等,
ESP是栈指针,是CPU机制决定的,push、pop指令会自动调整ESP的值, EBP不是必须的,但有了它可以把过程分开,方便调试。
push 指令 调用后 esp-=4
pop 指令 调用后 esp+=4
call 指令 调用后 esp-=4
函数内部 push后 要 设置esp,保证栈中用不到的内存被覆盖
小程序2:
C代码如下
#include <stdio.h> bool f =false; bool fun(int na) { if (na>100) return true; else return false; } void main() { f = fun(11111); }
汇编代码.
#include <stdio.h> bool f =false; bool fun(int na) { push ebp mov ebp,esp if (na>100) cmp dword ptr [ebp+8], 64h ;[ebp+8] 表示na存放的位置 jle 128100Fh return true; mov al,1 jmp 1281011h ;1281011h编译器计算好的 else jmp 1281011h ;1281011h编译器计算好的 return false; xor al,al ;异或设置eax=0 } pop ebp ret ;改变eip void main() { push ebp mov ebp,esp f = fun(11111); push 2B67h call fun (1281000h) add esp,4 mov byte ptr [f (1283370h)],al ;函数返回值保存在EAX里面, bool 相当于一个8位数据 } xor eax,eax pop ebp ret