汇编学习__stdcall清理栈的原理及其内联汇编模拟

chaoji_xinren 发布于 11 小时前 14 次阅读


今天继续学习汇编语言基础

__stdcall 是一种调用约定(Calling Convention),主要用于 Windows API 和 x86 架构。它规定了函数在调用时,参数如何传递、由谁负责清理栈空间以及函数名如何修饰。

下面让我们看看其特性

1. 参数传递方向:从右向左

当你调用一个 __stdcall 函数时,参数是按照代码中从右到左的顺序被压入栈(Stack)中的。

  • 代码示例func(a, b, c)
  • 汇编指令顺序
    1. push c
    2. push b
    3. push a
    4. call func

2. 栈清理责任:被调用者(Callee)清理

这是 __stdcall 与 C 语言默认约定(__cdecl)最大的区别。

  • __cdecl 中:调用者(Caller)在函数返回后,需要手动把栈指针移回去(例如执行 add esp, 12)。
  • __stdcall 中:被调用函数在内部执行 ret n 指令(n 是参数总字节数)。这意味着函数执行完后,自己就把占用的参数空间“退还”给系统了。

3. 函数名修饰(Name Mangling)

在编译器底层,为了区分不同的调用约定,__stdcall 会对函数名进行特殊的处理。 通常规则是:_函数名@参数字节数

例子:如果函数是 void __stdcall test(int a, int b),编译后的符号名可能是 _test@8(因为两个 int 占 8 字节)。

这次主要学习的是性质2,__stdcall自动清理栈的原理

#include <stdio.h>
#include<iostream>
#include<iomanip>
//__stdcall为被调用者清理栈
//如这个函数用了两个参数,需要push两个参数
//stdcall则在出call时自动add esp,8
void __stdcall fun1(int a, int b) {   //用汇编手动模拟编译器分配局部变量的过程
	__asm {
		sub esp, 8   //开辟8空间
		mov[esp], 0x23  //放入临时值
		mov[esp + 4], 0x34 
		push eax 
		push ebx
		pop ebx
		pop eax
		add esp, 8  //释放

                           //实际上这些指令其实没对程序有任何影响
	}
	printf("%d%d\n", a, b); 


}

void __stdcall fun2(int a, int b) {  //演示如何利用__stdcall漏洞进行内存篡改
	__asm {
	
		mov eax, 5555  //5555放进ebp + 8
		mov[ebp + 8], eax
		push eax
		mov eax, 4444  //4444放进ebp + 12
		mov[ebp + 12], eax
		pop eax


	}
	printf("%d%d\n", a, b);   //这里已经把a,b的参数强行修改了,实现了逆向的破解功能
                                  

}
int main() {     
	printf("hellword\n");
	__asm {
		push 123
		push 1234
		call fun1
		push 123
		push 1234
		call fun2
		
	}

	return 0;
}

最后输出为

hellword
1234123 
55554444
此作者没有提供个人介绍。
最后更新于 2025-12-17