C/C++逆向:函数逆向分析-调用约定分析

admin 2024年10月6日23:28:15评论17 views字数 3047阅读10分9秒阅读模式

在进行函数逆向分析时,分析其函数调用约定具有非常重要的作用,因为调用约定直接影响了函数的参数传递、返回值、栈管理、寄存器使用等多个方面,不同的编译器和平台可能有不同的默认调用约定,识别调用约定可以帮助判断代码是由哪种编译器生成的。例如:

①Windows API 函数通常使用 stdcall 调用约定。
②在 x64 平台,Windows 使用的调用约定与 Linux 的 System V 调用约定有所不同。
③通过调用约定,可以更好地识别代码的上下文,甚至推断出目标程序使用的编译器和编译选项。

调用约定描述了函数调用和参数传递的方式,掌握这些约定是正确分析函数的基础,常见的调用约定如下:

cdecl:参数通过栈从右向左传递,调用者负责清理栈。
stdcall:参数通过栈从右向左传递,函数本身负责清理栈。
fastcall:部分参数通过寄存器传递,通常第一个和第二个参数通过 ecx 和 edx 寄存器传递(在windows x86 平台上),剩余参数从右到左压入栈中。 (在 Windows x64 平台上,前四个参数使用 rcx, rdx, r8, r9 寄存器传递。)函数可能负责栈的清理,具体情况与实现相关。

下面是一个 C 代码的示例,通过使用 cdeclstdcallfastcall 三种调用约定来演示它们的区别。在代码中,我们使用 Microsoft 编译器提供的关键字来指定不同的调用约定:

#include <stdio.h>

// 使用 cdecl 调用约定
int __cdecl add_cdecl(int a, int b) {
   return a + b;
}

// 使用 stdcall 调用约定
int __stdcall add_stdcall(int a, int b) {
   return a + b;
}

// 使用 fastcall 调用约定
int __fastcall add_fastcall(int a, int b) {
   return a + b;
}

int main() {
   int x = 3;
   int y = 4;

   // 调用 cdecl 函数
   int result_cdecl = add_cdecl(x, y);
   printf("cdecl result: %dn", result_cdecl);

   // 调用 stdcall 函数
   int result_stdcall = add_stdcall(x, y);
   printf("stdcall result: %dn", result_stdcall);

   // 调用 fastcall 函数
   int result_fastcall = add_fastcall(x, y);
   printf("fastcall result: %dn", result_fastcall);

   return 0;
}

接下去我们将代码进行编译,生成exe文件后放入x32dbg中进行动态调试,去具体分析这三种调用约定的区别。

C/C++逆向:函数逆向分析-调用约定分析

在文件载入完毕后,我们需要先进行main函数的定位(定位main函数的方法请看笔者前面C/C++逆向:定位main函数文章);此时我们需要重点关注的是红线以下代码。

C/C++逆向:函数逆向分析-调用约定分析

mov dword ptr ss:[ebp-8],3
mov dword ptr ss:[ebp-14],4

代码中首先初始化了两个四字节(dword ptr)的局部变量ebp-8ebp-14;这两个局部变量就对应上述C代码中的两个int型变量x(ebp-8)y(ebp-14)

①cdecl调用约定

相关代码如下:

mov eax,dword ptr ss:[ebp-14]
push eax
mov ecx,dword ptr ss:[ebp-8]
push ecx
call function_x86.281050
add esp,8

这串代码首先将局部变量ebp-14(y)的值加载到eax中,接着将 eax 寄存器中的值压入栈中,这是即将调用函数的第一个参数。然后将另一个局部变量ebp-8(x)的值加载到 ecx 寄存器中;将 ecx 寄存器中的值压入栈中,作为调用函数的第二个参数,接着通过call指令调用名为 function_x86.281050 的函数。通过对比上述的函数调用C代码;

int result_cdecl = add_cdecl(x, y);

cdecl调用约定在进行参数传递时,调用函数所使用的参数是从右到左推入栈中,正如这个例子所展现的,我们调用函数add_cdecl(x, y)时,反汇编代码中先压入栈中的参数是ebp-14(y),接着才是x。并且在调用函数完毕后需要由调用者来恢复栈指针;add esp,8调用函数后,恢复栈指针。因为调用之前压入了两个参数,每个 4 字节,共计 8 字节,所以通过 add esp, 8 来调整栈指针,清理掉这些参数。

②stdcall调用约定

相关代码:

C/C++逆向:函数逆向分析-调用约定分析

mov eax,dword ptr ss:[ebp-14]
push eax
mov ecx,dword ptr ss:[ebp-8]
push ecx
call function_x86.281235

可以看到stdcallcdecl调用约定一样,都是从右往左依次将参数压入栈中,但是与cdecl不一样的是,stdcall的平栈操作是在函数内完成的。这个时候我们进入函数function_x86.281235进行查看:

C/C++逆向:函数逆向分析-调用约定分析

我们可以看到在函数结尾有一个ret 8指令;该指令在 x86 汇编中表示返回到调用函数的地址,并在返回之前从栈中移除 8 个字节,这是一种同时进行函数返回和栈清理的指令。

③fastcall调用约定

相关代码:

C/C++逆向:函数逆向分析-调用约定分析

mov edx,dword ptr ss:[ebp-14]
mov ecx,dword ptr ss:[ebp-8]
call function_x86.2810F5

fastcall 调用约定中,部分参数通过寄存器传递,而不是全部通过栈来传递。在该程序的函数调用中,第一个ebp-8(x)和第二个参数ebp-14(y)分别通过 ecxedx 寄存器传递,接着使用call指令调用函数即可。若有更多参数,超出寄存器能够处理的范围,这些额外的参数会被压入栈中;对于通过栈传递的额外参数,栈的清理方式可以与 stdcall 类似,即由被调用者来负责清理栈上的参数。为了验证这个结论,我们在这边举个例子;现有如下C代码,在VS中进行编译生成exe。

#include <stdio.h>

int __fastcall add(int a, int b, int c) {
   return a + b + c;
}

int main() {
   int result = add(1, 2, 3);
   printf("Result: %dn", result);
   return 0;
}

接着放入x32dbg中进行进行动态调试,这个例子中的add函数在定义时指定了其调用约定为fastcall,并且该函数的参数为3个,那么这个时候就表示其中一个参数在传递需要被压入栈中。具体的代码如下:

C/C++逆向:函数逆向分析-调用约定分析

push 3
mov edx,2
mov ecx,1
call function_x86.6B11BD

接着我们进入function_x86.6B11BD中进行查看,发现栈清理已在函数内完成。

C/C++逆向:函数逆向分析-调用约定分析

相关代码就是ret 4

在逆向工程中,了解不同的函数调用约定对于准确分析程序的行为至关重要。不同平台和编译器选项会导致汇编代码的细微差异,这些差异往往是解密代码逻辑和理解函数调用机制的关键。通过对调用约定的深入理解,我们不仅能更有效地还原源代码逻辑,还能提升逆向分析的效率和准确性。希望这篇文章能够帮助你更好地掌握函数调用约定,为后续的逆向工程工作打下坚实的基础。

原文始发于微信公众号(风铃Sec):C/C++逆向:函数逆向分析-调用约定分析

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2024年10月6日23:28:15
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   C/C++逆向:函数逆向分析-调用约定分析https://cn-sec.com/archives/3232719.html
                  免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉.

发表评论

匿名网友 填写信息