裸函数
C源码(.c) →【预处理】→【编译】→【汇编】→【链接】→可执行程序
- 预处理 (cpp):展开头文件、宏替换、删掉注释,生成
.i文件(还是 C 语言文本) - 编译 (cc1):C → 汇编 (.s)
- 汇编 (as):汇编 (.s) → 机器码目标文件 (.o/.obj)
- 链接 (ld):多个.o + 库 → exe/elf 可执行文件
因此在我们的程序成为可执行文件之前,先转化为汇编语言,我们看到的函数里面的那些代码都死编译器自己生成的,push ebp等等,裸函数是编译器完全不生成函数 prologue (序言) /epilogue (尾声),你必须手写全部汇编。
需要注意的是 裸函数不能为空 而且不能出现C格式的代码
void __declspec(naked) Function()
{
_asm
}
{
汇编内容
}
列举三个常用的裸函数框架
无参数无返回值的框架
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
}
}
裸函数作业
练习:
1、用__declspec(naked)裸函数实现下面的功能
练习目的:
(1) 熟悉堆栈结构
(2) 参数、局部变量的位置
(3) 返回值存储的位置
int plus(int x,int y,int z) 010101010
{
int a = 2;
int b = 3;
int c = 4;
return x+y+z+a+b+c;
}
下面是作业内容
#include<stdio.h>
int plus1(int x, int y, int z)
{
int a = 2;
int b = 3;
int c = 4;
return a + b + c + x + y + z;
}
int _declspec(naked) plus(int x, int y, int z)//转换的裸函数
{
_asm
{
push ebp;
mov ebp,esp
sub esp,0x40
push ebx
push esi
push edi
mov eax,0xcccccccc
mov ecx,0x10
lea edi,dword ptr ds:[ebp-0x40]
rep stosd
mov dword ptr ds:[ebp-4],2
mov dword ptr ds : [ebp - 8] , 3
mov dword ptr ds : [ebp - 0Xc] , 4
// 核心计算功能
mov eax,dword ptr ds:[ebp-4]//第一个变量赋值给eax
add eax,dword ptr ds:[ebp - 8]//第一个变量赋值给eax
add eax,dword ptr ds:[ebp - 0XC]//第一个变量赋值给eax
add eax,dword ptr ds:[ebp+8]//第一个参数赋值给eax
add eax,dword ptr ds:[ebp+0xC]//第一个参数赋值给
add eax,dword ptr ds:[ebp+0x10]//第一个参数赋值给
pop edi
pop esi
pop ebx
mov esp,ebp
pop ebp
ret
}
}
extern "C" void test()
{
}
int main()
{
int res = plus(1, 2, 3);
printf("%d", res);
}