阅读目录
函数调用约定实现分析
发布于:2015-11-24 17:17 | 194598次阅读 作者: 管理员 | 原作者: TP
在开始之前,还是以代码说话,一般函数调用说明有如下几种方式,值需要参照源码函数声明和汇编层实现就可以很好的理解函数调用约定: 图3.1 图3.2 1.1 __cdecl调用约定 图3.3 从函数调用约定的声明上来看,int __cdecl TestFunctionC(int a, int b, int c, int d, int e, int f)的调用约定我们声明为__cdecl调用方式。从汇编层实现,我们可以看到该方式具有以下特征:1、参数传递都通过堆栈传递;2、函数入栈顺序从右到左;3、堆栈平衡由调用者平衡,add esp, 18h这行命令就是用来平衡堆栈的。另外在IDA中我们看到int TestFunctionA(int a, int b, int c, int d, int e, int f)的调用方式也符合该原则,这说明在c\c++写的函数中如果不是类的成员函数,没做特殊调用声明,那么默认采用 __cdecl调用约定。 1.2 __stdcall调用约定 图3.4 图3.5 从函数调用约定的声明上来看,int __stdcall TestFunctionB(int a, int b, int c, int d, int e, int f)的调用约定我们声明为__stdcall 调用方式。从汇编层实现,我们可以看到该方式具有以下特征:1、参数传递都通过堆栈传递;2、函数入栈顺序从右到左;3、堆栈平衡由被调用者平衡,被调用函数内部函数结尾处retn 18h这行命令就是用来平衡堆栈的。 1.3 __fastcall 调用约定
图3.6
图3.7 从函数调用约定的声明上来看,int __fastcall TestFunctionD(int a, int b, int c, int d, int e, int f)的调用约定我们声明为__fastcall 调用方式。从汇编层实现,我们可以看到该方式具有以下特征:1、参数传递上第一个参数ecx传递,第二个参数edx传递,大于2个的部分都通过堆栈传递;2、函数入栈顺序从右到左;3、堆栈平衡由被调用者平衡,被调用函数内部函数结尾处retn 10h这行命令就是用来平衡堆栈的。由于前两个参数通过寄存器传递所以不需要堆栈平衡,函数内堆栈平衡值需要考虑大于2个参数的部分即可。 1.4 thiscall 调用约定 Thiscall 调用约定是唯一一个不需要特殊声明也无法人为指定的调用方式,它是指类的普通成员函数调用方式。该调用方式具有以下特点:1、ecx被使用,用作this指针的传递;2、其它参数一律通过堆栈传递,入栈顺序从右到左;3、堆栈平衡有被调用者平衡。 2.1 函数参数个数的确定技巧 基于堆栈传递的部分,要确定参数个数比较简单,通过堆栈平衡部分就可以快速确定参数个数。不过如果有参数是通过寄存器传递的,那么就需要一定技巧来确定寄存器里是否有参数传递进来。如下截图所示: 图3.8 图3.9 确定一个寄存器是否有被当成参数传递,那么最简单的方式就是看该寄存器在使用之前有没有进行数据保存和赋值。如图3.8所示,在对edi进行使用和赋值之前有进行push edi保存操作,所以edi就没有作为参数传递寄存器。如图3.9所示,edx没有进行赋值和保存数据,直接把edx里面的值复制给ebp+b参数了,所以edx是作为参数传递寄存器了。在分析游戏利用游戏函数实现功能的过程中edx就需要特别处理。
*转载请注明来自游戏安全实验室(https://gslab.qq.com) |
最新评论
发表评论