C++堆栈分析

it2025-03-12  22

有这样一段代码段:

void fun() { } int mian() {    int a=3;    fun();    printf(“%d\n”,a); }

如何实现fun函数,使得输出的a不等于3?

转到反汇编看这段代码:

00DF1850  push        ebp 

00DF1851  mov         ebp,esp 

00DF1853  sub         esp,0CCh 

这三步是在给函数分配栈空间,大小为CCH。

00DF1859  push        ebx 

00DF185A  push        esi 

00DF185B  push        edi 

这三步是在保存现场,函数调用结束后恢复。

00DF185C  lea         edi,[ebp-0CCh] 

00DF1862  mov         ecx,33h 

00DF1867  mov         eax,0CCCCCCCCh 

00DF186C  rep stos    dword ptr es:[edi] 

这里几步是在初始化堆栈中的数据。

 

rep stos    dword ptr es:[edi]中,rep表示重复,

stos    dword ptr es:[edi]终止条件为ecx=0,每次操作后ecx=ecx-1,

stos:把eax中的内容拷贝到目的地址,这里是edi的值自动增加(这个其实是可变的,它由标准寄存器df的方向来决定,当df=1时,每执行一次stos edi减两个或四个字节;df=0,edi加两个或四个字节)

所以 rep stos    dword ptr es:[edi] 就是填充了ebp到esp中的空间。

 

00DF186E  mov         dword ptr [a],3:给变量a赋值。

00DF1875  call        fun (0DF1221h) 调用函数。

Call分为几种情形:

段内: 保存当前偏移地址  push eips跳转              jump fun 段间: 保存基地址        push cs保存偏移地址      push eip跳转              jump fun

 

看栈顶esp的改变:

就是push与pop的操作:

Push xxx 就会执行 sub esp x

 

再看fun函数内:

        

        ALT+5查看寄存器地址,ALT+6查看内存地址

编译器为32位,所以每次执行push,esp加4字节。接下来就变成数push了。

ESP = 0031F6A8

EBP = 0031F780

 

 

EAX = CCCCCCCC EBX = 7EFDE000 ECX = 00000000 EDX = 6C667018 ESI = 00000000 EDI = 0021F85C EIP = 01021885 ESP = 0021F784 EBP = 0021F85C EFL = 00000206

 

EAX = CCCCCCCC EBX = 7EFDE000 ECX = 00000000 EDX = 6C667018 ESI = 00000000 EDI = 0021F85C EIP = 01021760 ESP = 0021F780 EBP = 0021F85C EFL = 00000206

 

EAX = CCCCCCCC EBX = 7EFDE000 ECX = 00000000 EDX = 6C667018 ESI = 00000000 EDI = 0021F85C EIP = 01021769 ESP = 0021F6B1 EBP = 0021F77C EFL = 00000202

&a=0x0021F854

 

 

0102176C  lea         edi,[ebp-0C0h] 

 

mov  [ebp-0C0h]

所以最终的代码为(vs-32位):

void fun() { __asm { mov[esp + 01A4h], 9 } } int main() { int a = 3; fun(); printf("%d\n",a); return 0; }

 

最新回复(0)