- #include <iostream>
- using namespace std;
- void f1(int a,int b)
- {
- }
- int main()
- {
- f1(3,4);
- system("pause");
- }
将上述代码反汇编如下(vs05debug):
- int main()
- {
- 004113D0 push ebp ;/保存栈基址
- 004113D1 mov ebp,esp ;将栈顶指针赋给ebp,重新构造了一个函数栈帧,此函数栈帧属于main函数的。
- 004113D3 sub esp,0C0h ;栈顶指针下移0xc0h,为main函数内局部变量分配空间
- 004113D9 push ebx ;在栈中保存ebx
- 004113DA push esi
- 004113DB push edi
- 004113DC lea edi,[ebp-0C0h] ;将ebp-0c0h值赋给edi
- 004113E2 mov ecx,30h
- 004113E7 mov eax,0CCCCCCCCh
- 004113EC rep stos dword ptr es:[edi];从lea指令到这条指令作用就是把为局部变量分配的内存空间填充CC数据
- f1(3,4);
- 004113EE push 4
- 004113F0 push 3 ;参数入栈
- 004113F2 call f1 (4111D6h) ;call指令实际动作是push eip;mov eip,4111D6h连续两条指令。
- 004113F7 add esp,8 ;c的调用约定,调整栈
- system("pause");
- 004113FA mov esi,esp
- 004113FC push offset string "pause" (415810h)
- 00411401 call dword ptr [__imp__system (4182B4h)]
- 00411407 add esp,4
- 0041140A cmp esi,esp
- 0041140C call @ILT+315(__RTC_CheckEsp) (411140h)
- }
- void f1(int a,int b) //f1函数反汇编代码。
- {
- 004113A0 push ebp
- 004113A1 mov ebp,esp
- 004113A3 sub esp,0C0h
- 004113A9 push ebx
- 004113AA push esi
- 004113AB push edi
- 004113AC lea edi,[ebp-0C0h]
- 004113B2 mov ecx,30h
- 004113B7 mov eax,0CCCCCCCCh
- 004113BC rep stos dword ptr es:[edi] ;上述汇编指令每个函数都有主要用来初始化栈帧和保存一些寄存器的值。
- }
- 004113BE pop edi
- 004113BF pop esi
- 004113C0 pop ebx ;函数调用完毕,回复edi等寄存器的值
- 004113C1 mov esp,ebp
- 004113C3 pop ebp ;回收为f1函数分配的栈帧。
- 004113C4 ret ;此指令实际动作是pop eip;call f1时push eip,那时eip的值是call函数下条指令的值,程序跳转main函数执行
所以通过上述分析,我们得到一下的栈内数据的布局:
eip | ||
高地址 | ebp | main函数 |
CC | ||
CC | ||
… | ||
… | ||
ebx | ||
esi | ||
edi | ||
4 | ||
3 | ||
eip | ||
ebp | f1函数 | |
CC | ||
CC | ||
… | ||
… | ||
ebx | ||
esi | ||
低地址 | edi |
由于eip要存入栈中,所以就有可能被修改,导致程序异常的运行,很多病毒就是利用了这一点。