《逆向工程核心原理》--- 函数调用约定

函数的约定:

对函数调用时如何传递参数的一种约定,我们知道调用函数前需要将参数压入栈然后再传递给函数,栈就是定义在进程中的一段内存,向下扩展,大小记录在PE头中,运行时确定栈的大小

函数执行完毕后,ESP的值如何变化?

ESP的值恢复到函数调用之前,这样可引用的栈大小不会缩减

函数:

int function(int a, int b)
{
     return a + b;
}
void main()
{
     function(10, 20);
}

主要函数约定如下:

 __cdecl约定

__cdecl函数调用约定是我们最长见的一种约定,我们平时在写程序的时候默认会使用该种约定,其特点如下:

  • 参数从右向左依次传递,存放在堆栈中。
  • 堆栈平衡由调用函数来维护。
  • C语言编译时的函数命名规则为下划线加名称:__functionName
_function
                 push    ebp
                 mov     ebp, esp
                 mov     eax, [ebp+8]       ;参数1
                 add     eax, [ebp+C]       ;加上参数2
                 pop     ebp
                 retn
_main
                 push    ebp
                 mov     ebp, esp
                 push    14h                ;参数 2入栈
                 push    0Ah                ;参数 1入栈
                 call    _function          ;调用函数
                 add     esp, 8             ;修正栈
                 xor     eax, eax
                 pop     ebp
                 retn

 __stdcall约定

__stdcall约定是我们在写WinAPI的时候经常用的约定,很多windows下面的API都是该种调用约定,其特点如下:

  • 参数从右向左依次传递,存放在堆栈中。
  • 堆栈平衡由被调用函数来维护
  • C语言编译时的函数命名规则为下划线加名称加@加参数字节大小:
8
                 push    ebp
                 mov     ebp, esp
                 mov     eax, [ebp]             ;参数 1
                 add     eax, [ebp+C]           ;加上参数 2
                 pop     ebp
                 retn    8                     ;修复栈
 _main
                 push    ebp
                 mov     ebp, esp
                 push    14h                ;参数 2入栈
                 push    0Ah                ;参数 1入栈
                call    8       ;函数调用
                 xor     eax, eax
                 pop     ebp
                 retn

__fastcall约定

从名称上可以看出是速度快,因为其参数是可以放在寄存器中传递的,通常需要在要求高效率的函数中使用此约定,其特点如下:

  • 最右侧两个参数由ecx和edx两个寄存器来传递,剩余参数从右往左依次存放在堆栈中。
  • 堆栈平衡由被调用函数来维护
  • C语言编译时的函数命名规则为@加函数名加@加参数大小:@

该约定是高效率的调用约定,和另外两种约定最大的区别就是参数的传递方式,利用了寄存器来快速的传递

@8
                 push    ebp
                 mov     ebp, esp           ;保存栈指针
                 sub     esp, 8             ;多了两个局部变量
                 mov     [ebp-8], edx       ;保存参数 2
                 mov     [ebp-4], ecx       ;保存参数 1
                 mov     eax, [ebp-4]       ;参数 1
                 add     eax, [ebp-8]       ;加上参数 2
                 mov     esp, ebp           ;修正栈
                 pop     ebp
                 retn
 _main
                 push    ebp
                 mov     ebp, esp
                 mov     edx, 14h           ;参数 2给EDX
                 mov     ecx, 0Ah           ;参数 1给ECX
                 call    @8        ;调用函数
                 xor     eax, eax
                 pop     ebp
                 retn

相关推荐