逆向:x86,x64从汇编分析函数调用约定详解

前言

网上大多教程都是对x86汇编进行分析,少有x64的,因此,本次对x86和x64的函数调用的参数传递以及函数的调用约定进行详细的分析对比和总结。

(cdecl,fastcall,stdcall,vectorcall,thiscall)
注意本次实验中(环境):x86的cdecl, fastcall, stdcall代码以debug模式编译,x86的thiscall,以及x64代码均以relase模式下编译并关闭性能优化

x86 汇编分析 (cdecl, fastcall, stdcall,thiscall)

分析汇编的源码:

c 复制代码
#include <iostream>

int __cdecl cdecl_test(int a, int b, int c, int d, int e, int f, int g) {
	char p[] = "Hello, World!";
	int result = 0;
	result += a + b + c + d + e + f + g;
	return result;
}

int __fastcall fastcall_test(int a, int b, int c, int d, int e, int f, int g) {
	char p[] = "Hello, World!";
	int result = 0;
	result += a + b + c + d + e + f + g;
	return result;
}

int __stdcall stdcall_test(int a, int b, int c, int d, int e, int f, int g) {
	char p[] = "Hello, World!";
	int result = 0;
	result += a + b + c + d + e + f + g;
	return result;
}

int main(){
	int a = 1, b = 2, c = 3, d = 4, e = 5, f = 6, g = 7;
	int result = 0;
	result = cdecl_test(a, b, c, d, e, f, g);
	printf("cdecl_test result: %d\n", result);
	result = fastcall_test(a, b, c, d, e, f, g);
	printf("fastcall_test result: %d\n", result);
	result = stdcall_test(a, b, c, d, e, f, g);
	printf("stdcall_test result: %d\n", result);
	return 0;
}
c 复制代码
#include <iostream>

class Test {
public:
	int func(int a, int b, int c, int d, int e, int f, int g) {
		int result = 0;
		result += a + b + c + d + e + f + g;
		printf("Result: %d\n", result);
		return result;
	}
};

int main() {
	int a = 1, b = 2, c = 3, d = 4, e = 5, f = 6, g = 7;
	int result = 0;
	Test test;
	result = test.func(a, b, c, d, e, f, g);
	printf("Result: %d\n", result);
	return 0;
}

cdecl


传递参数

开辟栈空间,保存栈环境

恢复环境,恢复栈空间,返回

平栈,保存返回值

fastcall


传递参数

开辟栈空间,保存环境

恢复环境,恢复栈空间,平栈

stdcall


传递参数

开辟栈空间,保存环境

恢复环境,恢复栈空间,平栈

thiscall


传递参数

开辟栈空间,保存环境

恢复环境,恢复栈空间,平栈

总结

函数调用约定 参数传递方式 平栈方式
cdecl(默认) push(从右到左) 函数外平栈
fastcall ecx(参数1),edx(参数2),push(从右到左) 函数内平栈
stdcall push(从右到左) 函数内平栈
thiscall ecx(this指针),push(从右到左) 函数内平栈

值得注意的是:在winapi中大多是用stdcall

x64 汇编分析(vectorcall, thiscall)

分析汇编的源码

c 复制代码
#include <iostream>

int __vectorcall test(int a, int b, int c, int d, int e, int f, int g) {
	int result = 0;
	result += a + b + c + d + e + f + g;
	printf("Result: %d\n", result);
	return result;
}

int main() {
	int a = 1, b = 2, c = 3, d = 4, e = 5, f = 6, g = 7;
	int result = 0;
	result = test(a, b, c, d, e, f, g);
	printf("Result: %d\n", result);
	return 0;
}

vectorcall


传递参数

保存参数,开辟栈空间,(保存环境)

恢复栈空间

总结

函数调用约定 参数1 参数2 参数3 参数4 参数5以上 平栈方式
vectorcall rcx rdx r8 r9 堆栈传递 函数内平栈
vectorcall(浮点参数) xmm0 xmm1 xmm2 xmm3 堆栈传递 函数内平栈
thiscall rcx(this) rdx r8 r9 堆栈传递 函数内平栈

我这里给出thiscall,vectorcall的浮点表现形式,thiscall,因为在底层默认函数第一个参数传递this指针,这两种函数调用约定在x64中本质是一样的

以上出现错误可评论区提醒!