c语言 __declspec(naked)裸函数
1、什么是裸函数
就是编译器不会为这个函数生成代码,想用汇编怎么写就怎么写,如果什么都不写,一定会报错,因为没有生成ret
2、裸函数框架
一、裸函数模板
int _declspec(nacked) Function(int x,int y,int z)
{
_asm
{
ret
}
}
二、无参数无返回值框架
void __declspec(naked) Function()
{
__asm
{
push ebp
mov ebp,esp
sub esp,0x40
push ebx
push esi
push edi
lea edi,dword ptr ds:[ebp-0x40]
mov eax,0xCCCCCCCC
mov ecx,0x10
rep stosd
pop edi
pop esi
pop ebx
mov esp,ebp
pop ebp
ret
}
}
三、有参数有返回值的函数框架
int __declspec(naked) Function(int x,int y)
{
__asm
{
push ebp
mov ebp,esp
sub esp,0x40
push ebx
push esi
push edi
lea edi,dword ptr ds:[ebp-0x40]
mov eax,0xCCCCCCCC
mov ecx,0x10
rep stosd
mov eax,dword ptr ds:[ebp+8]
add eax,dword ptr ds:[ebp+0xC]
pop edi
pop esi
pop ebx
mov esp,ebp
pop ebp
ret
}
}
四、带局部变量的函数框架
int __declspec(naked) Function(int x,int y)
{
__asm
{
push ebp
mov ebp,esp
sub esp,0x40
push ebx
push esi
push edi
lea edi,dword ptr ds:[ebp-0x40]
mov eax,0xCCCCCCCC
mov ecx,0x10
rep stosd
mov dword ptr ds:[ebp-4],2
mov dword ptr ds:[ebp-8],3
mov eax,dword ptr ds:[ebp+8]
add eax,dword ptr ds:[ebp+0xC]
pop edi
pop esi
pop ebx
mov esp,ebp
pop ebp
ret
}
}
五、裸函数实例
用__declspec(naked)裸函数实现下面的功能
int plus(int x,int y,int z)
{
int a = 2;
int b = 3;
int c = 4;
return x+y+z+a+b+c;
}
裸函数实现(这里我用的是visual studio2017版生成的)
#include "stdio.h"
int __declspec(naked) plus(int x, int y ,int z) {
//int a = 1;
//int b = 2;
//int c = 3;
//return a + b + c + x + y + z;
__asm
{
//保留调用前堆栈栈底
push ebp
//提升堆栈
mov ebp,esp
sub esp,0E4h
//保护现场
push ebx
push esi
push edi
//往缓冲区填充数据
lea edi,[ebp-0E4h]
mov ecx,39h
mov eax,0CCCCCCCCh
rep stos dword ptr es:[edi]
//函数实现功能
mov dword ptr [a],1
mov dword ptr [b],2
mov dword ptr [c],3
mov eax,dword ptr [a]
add eax,dword ptr [b]
add eax,dword ptr [c]
add eax,dword ptr [x]
add eax,dword ptr [y]
add eax,dword ptr [z]
//恢复现场
pop edi
pop esi
pop ebx
add esp,0E4h
mov esp,ebp
pop ebp
ret
}
}
int main(int argc, char* argu[]) {
int x;
x = plus(4, 5, 6);
printf("%d", x);
}
常见的几种调用约定
调用约定 | 参数压栈顺序 | 平衡堆栈 |
---|---|---|
__cdecl | 从右至左入栈 | 调用者清理栈 |
__stdcall | 从右至左入栈 | 自身清理堆栈 |
__fastcall | ECX/EDX传送前两个,剩下:从右至左入栈 | 自身清理堆栈 |
1、int __cdecl Plus(int a, int b)
{
return a+b;
}
push 2
push 1
call @ILT+15(Plus) (00401014)
add esp,8
2、int __stdcall Plus(int a, int b)
{
return a+b;
}
push 2
push 1
call @ILT+10(Plus) (0040100f)
函数内部:
ret 8
3、int __stdcall Plus(int a, int b)
{
return a+b;
}
push 2
push 1
call @ILT+10(Plus) (0040100f)
函数内部:
ret 8
4、int __fastcall Plus4(int a, int b,int c,int d)
{
return a+b+c+d;
}
push 4
push 3
mov edx,2
mov ecx,1
call @ILT+5(Plus) (0040100a)
函数内部:
ret 8