分析程序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