685 字
3 分钟
汇编学习__stdcall清理栈的原理及其内联汇编模拟
今天继续学习汇编语言基础。
__stdcall 是一种调用约定(Calling Convention),主要用于 Windows API 和 x86 架构。它规定了函数在调用时,参数如何传递、由谁负责清理栈空间以及函数名如何修饰。
下面让我们看看其特性。
1. 参数传递方向:从右向左
当你调用一个 __stdcall 函数时,参数是按照代码中从右到左的顺序被压入栈(Stack)中的。
代码示例: func(a, b, c)
汇编指令顺序:
push cpush bpush acall func2. 栈清理责任:被调用者(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 字节)。
__stdcall自动清理栈的原理
这次主要学习的是性质2,下面通过代码来演示。
示例1:手动模拟栈的分配和清理
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);}示例2:利用__stdcall漏洞进行内存篡改
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的参数强行修改了,实现了逆向的破解功能}完整测试代码
#include <stdio.h>#include <iostream>#include <iomanip>
int main() { printf("hellword\n"); __asm { push 123 push 1234 call fun1
push 123 push 1234 call fun2 } return 0;}输出结果
hellword123412355554444可以看到,通过内联汇编直接操作栈帧,我们成功地在 fun2 中修改了传入的参数值,从 1234 和 123 变成了 5555 和 4444。这种技术在实际的逆向工程中可以用来破解程序逻辑或修改函数行为。

分享
如果这篇文章对你有帮助,欢迎分享给更多人!
汇编学习__stdcall清理栈的原理及其内联汇编模拟
https://chaojixin.ren/posts/汇编学习__stdcall清理栈的原理及其内联汇编模拟/ 部分信息可能已经过时









