冬冬 发表于 2012-3-26 11:44:38

C/C++函数传参,汇编分析

本帖最后由 冬冬 于 2012-3-26 21:33 编辑

   函数传参介绍:_cdecl这是C/C++采用的默认的传参方式,即参数按从右到左依次入栈。且有调用者负责清理堆栈.
1、EBP寄存器,栈基址寄存器。

这本是一个通用寄存器,但在长期的编程习惯中,人们给了它一个默认的约定,通常用来堆栈传参后,执行call后的栈指针值。
2、我利用内联汇编分析了:
#include <iostream>
using namespace std;
int Add(int a,int b)
{
int tmp_A,tmp_B;
int tmp_EBP;
__asm
{
push eax
mov eax,
mov tmp_A,eax
mov eax,
mov tmp_B,eax
mov tmp_EBP,ebp
pop eax
}
cout<<"EBP+0:\t\t"<<hex<<uppercase<<tmp_EBP<<endl;
cout<<"EBP+4\t\t"<<hex<<*(int*)(tmp_EBP+4)<<endl;
cout<<"EBP+8\t\t"<<hex<<*(int*)(tmp_EBP+8)<<endl;
cout<<"EBP+12\t\t"<<hex<<*(int*)(tmp_EBP+12)<<endl<<endl;
cout<<"第一个参数\t"<<hex<<tmp_A<<endl;
cout<<"第二个参数\t"<<hex<<tmp_B<<endl;
return tmp_A+tmp_B;
}

int main()
{
Add(123,456);
return 0;
}

//输出结果:
EBP:             2DFD40      //那么这几个值是啥呢???
EBP+0:          2DFE1C            //那么这几个值是啥呢???
EBP+4            131193A    //那么这几个值是啥呢???
EBP+8         7B                  //毫无疑问,这是我要传递的参数
EBP+12          1C8               //毫无疑问,这是我要传递的参数
第一个参数      7B
第二个参数      1C8
请按任意键继续. . .



我们在VC++中进入调试模式,查看反汇编代码(ALT+8)
先来看下Main函数内:

int main()
{
01311910push      ebp
01311911mov         ebp,esp
01311913sub         esp,0C0h
01311919push      ebx
0131191Apush      esi
0131191Bpush      edi
0131191Clea         edi,
01311922mov         ecx,30h
01311927mov         eax,0CCCCCCCCh
0131192Crep stos    dword ptr es:
Add(123,456);
0131192Epush      1C8h
01311933push      7Bh
01311935call      Add (13110B4h)
0131193Aadd         esp,8    //注意下他的指令地址与 输出EBP+4            131193A
system("Pause");
0131193Dmov         esi,esp
0131193Fpush      offset string "Pause" (13178B8h)
01311944call      dword ptr
0131194Aadd         esp,4
0131194Dcmp         esi,esp
0131194Fcall      @ILT+445(__RTC_CheckEsp) (13111C2h)
return 0;
01311954xor         eax,eax
}

//看看他们的指令地址:
01311935call      Add (13110B4h)
0131193Aadd         esp,8    //注意下他的指令地址与 输出EBP+4            131193A

知道ESP+4是啥了不?

4、EBP和EBP+4的值什么。
EBP:             2DFD40      //那么这几个值是啥呢???
EBP+0:          2DFE1C            //那么这几个值是啥呢???

介绍下OEP即入口地址:
C语言每个函数的开头均已
push ebp                     // EBP寄存器保护
mov ebp,esp
而函数结束
mov esp,ebp               //回复ESP寄存器,以保持对战平衡
pop ebp                     //函数入口时的esp寄存器既然回复了,我们利用esp寄存器,就可以回复ebp寄存器了。

至于我在函数中,输出的EBP和EBP+0 值我想聪明的你应该知道是啥了。
呵呵至此,分析完毕......
我至于初学者,许多地方也是凭着才想去实验的.....      

遗留的几个问题解答:


push ebp                     // EBP寄存器保护
mov ebp,esp
那么EBP的值自然是 进入call之后的ESP值。
第二个问题:【EBP+0】
是进入call执
pushebp
那么 EBP+0就是 上次EBP的值,入栈一边保护寄存器用










libocdf 发表于 2012-3-26 14:03:57

本帖最后由 libocdf 于 2012-3-26 14:04 编辑

难得的好帖。楼主,这个应该置顶加精。。不过问题的关键点是EBP和EBP+0的值,但仔细看源程序中,只有对EBP+0的输出,而没有EBP的输出

libocdf 发表于 2012-3-26 14:06:58

本来想加分的。。结果我没有贡献值。。擦擦擦!!

libocdf 发表于 2012-3-26 14:19:40

文章还有其他一些问题。比如楼主提出的问题“知道ESP+4是啥了不?”应该是想问“EBP+4”或“ESP-0ch”吧。。就是call压入的返回地址。还有“4、EBP和EBP+4的值什么。”应该是“4、EBP和EBP+0的值什么。”吧。。这里我确实没看懂。。。望楼主解答一下。

冬冬 发表于 2012-3-26 21:32:20

libocdf 发表于 2012-3-26 14:19 static/image/common/back.gif
文章还有其他一些问题。比如楼主提出的问题“知道ESP+4是啥了不?”应该是想问“EBP+4”或“ESP-0ch”吧。。 ...

push ebp                     // EBP寄存器保护
mov ebp,esp
那么EBP的值自然是 进入call之后的ESP值。
第二个问题:【EBP+0】
是进入call执
pushebp
那么 EBP+0就是 上次EBP的值,入栈一边保护寄存器用

心静如死水 发表于 2012-3-28 06:36:56

完全不明白,小菜呀,努力学习,超越楼主

bananazzl 发表于 2012-3-28 23:22:36

不懂得汇编,看不明白

ylo523 发表于 2013-4-6 21:31:41

真是难得给力的帖子啊。

feitianqu 发表于 2013-4-8 20:45:04

强烈支持楼主ing……

374457634 发表于 2013-4-11 22:33:05

好贴,只不过看着头晕啊啊
肿么办!!!~?

☆小韦QQ 发表于 2013-5-5 10:54:43

真是难得给力的帖子啊。

蓝弹 发表于 2013-5-25 23:30:17

C语言,C++,真没易语言好学

yuan71058 发表于 2013-5-26 07:57:31

楼主加油,鱼C加油!我们都看好你哦!

海豚c 发表于 2013-8-1 17:49:15

好,谢谢分享

快乐阳光 发表于 2013-8-2 12:09:05

给力!!!!!!!!!!!!!!!!

朕要破外挂 发表于 2013-8-2 12:38:36

楼主,函数的传递不保证从右至左,每个c++编绎器不一样

loveyaqin1990 发表于 2013-12-2 11:03:57

不错的啊:lol:

宇宙浪人 发表于 2013-12-9 22:03:01

表示不是很懂

爬虫121 发表于 2024-9-3 17:30:07

看不懂{:10_277:},难受啊
页: [1]
查看完整版本: C/C++函数传参,汇编分析