裸函数

裸函数

编译器不会做出保存现场、提升堆栈、恢复现场等功能,在调用函数时只会生成CALL指令

一、普通函数

  • 声明

    int plus(int a, int b)
    {
       return a + b;
    }
    
  • 汇编表示

  1. 函数代码及断点设置

  1. 调用普通函数时编译器的处理

参数处理
CALL调用
外平栈
返回值处理

  1. JMP跳转

  1. 函数内部处理

提升堆栈
保存现场
设置缓冲区
函数功能实现
恢复现场
函数返回

二、裸函数

  • 声明

    void __declspec(naked) plus(int a, int b)
    {
     
    }
    
  • 汇编表示

  1. 函数代码及断点设置

  1. 调用裸函数时编译器的处理

参数处理
CALL调用
堆栈平衡

  1. 执行call时发生错误

并未生成ret指令,导致函数无法返回



  1. 使用__asm{}手动添加汇编代码



  1. 加上返回值与函数功能实现





  • 上方实现功能的汇编代码为简化版本,如按照常规方法因为以下方式
#include "stdafx.h"

int __declspec(naked) plus(int a, int b)
{
	__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 eax,dword ptr ds[ebp+0x8]
        add eax,dword ptr ds[ebp+0xC]
        //恢复现场
        pop edi
        pop esi
        pop ebx
        //降低堆栈
        mov esp,ebp
        pop ebp
        
	ret
	}
}

int main(int argc, char* argv[])
{
	int num = plus(1, 2);
	return 0;
}

三、总结

经过以上实验,不难看出,裸函数可以看作是不交由编译器自动处理的函数,可以说是编译器不管这个函数,其内部功能需要开发者手动编写

posted @ 2021-08-15 15:22  Ybitsec  阅读(154)  评论(0编辑  收藏  举报