裸函数

匿名 (未验证) 提交于 2019-12-03 00:11:01

概述

  _declspec(naked)修饰可以生成一个“裸”函数, 使用后C编译器将生成不含函数框架的纯汇编代码,裸函数中什么都没有,所以也不能使用局部变量,只能全部用内嵌汇编实现。

裸函数的定义

1 void __declspec(naked) Function()   2  3 { 4         ... 5 }
  _declspec(naked) 的介绍:
  _declspec(naked),就是告诉编译器,在编译的时候,不要优化代码,通俗的说就是,没代码,完全要自己写
  比如:
1 #define NAKED __declspec(naked) 2  3 void NAKED code(void) 4 { 5     __asm 6     { 7         ret 8     } 9 }
  使用__declspec(naked)关键字定义函数:
  1,使用 naked 关键字必须自己构建 EBP 指针 (如果用到了的话);
  2,必须自己使用 RET 或 RET n 指令返回 (除非你不返回);
  _delcspec(naked)用在驱动编写,C语言内嵌汇编完成一些特定功能。

实例

  我们先通过一个C语言中最简单函数,然后观察反汇编代码,看看编译器为我们做了些什么
  编译环境:VmWare Workstation 15 Pro、windows 7、VC++ 6.0 英文版
 1 // xiaoyu1.cpp : Defines the entry point for the console application.  2 //  3   4 #include "stdafx.h"  5   6 void Plus1()  7 {  8       9 } 10  11 int main(int argc, char* argv[]) 12 { 13     Plus1(); 14     return 0; 15 }
  Plus1()很显然是我们C语言中最简单的一个函数,但是它真的有这么简单吗?我们来看看它的反汇编代码,看看编译器都为这个函数做了些什么。我们在第13行代码处按下F9下一个断点。
  按下F7,F5,进入如下窗口:

在这个窗口处,右键选择Go To Disassembly,进入我们的反汇编窗口

1 00401068   call        @ILT+0(Plus1) (00401005)
  还记得我在前面博文中讲过call吗?https://www.cnblogs.com/Reverse-xiaoyu/p/11470633.html(JMP、CALL、RET指令),call做了两件事情,将下一行地址压栈,并修改EIP的值,我们按下F11,跟进去。
1 00401005   jmp         Plus1 (00401020)

 1 00401020   push        ebp  2 00401021   mov         ebp,esp  3 00401023   sub         esp,40h  4 00401026   push        ebx  5 00401027   push        esi  6 00401028   push        edi  7 00401029   lea         edi,[ebp-40h]  8 0040102C   mov         ecx,10h  9 00401031   mov         eax,0CCCCCCCCh 10 00401036   rep stos    dword ptr [edi] 11 00401038   pop         edi 12 00401039   pop         esi 13 0040103A   pop         ebx 14 0040103B   mov         esp,ebp 15 0040103D   pop         ebp 16 0040103E   ret

https://www.cnblogs.com/Reverse-xiaoyu/p/11489082.html

 看完了正常的函数之后,我们再去看看裸函数,看看最底层,编译器为它做了些什么,在概要里也说过,编译器什么都不会为它做,自己自生自灭去。
  可能你在反汇编窗口不知道如何退回到编辑界面,按下shift + F5就退回去了
 1 // xiaoyu1.cpp : Defines the entry point for the console application.  2 //  3   4 #include "stdafx.h"  5   6 void __declspec(naked) plus()  7 {  8       9 } 10  11 void Plus1() 12 { 13      14 } 15  16 int main(int argc, char* argv[]) 17 { 18     plus(); 19     return 0; 20 }

 1 --- D:\Project\xiaoyu1\xiaoyu1.cpp  ---------------------------------------------------------------------------------------------------------------------------  2 15:  3 16:   int main(int argc, char* argv[])  4 17:   {  5 00401020   push        ebp  6 00401021   mov         ebp,esp  7 00401023   sub         esp,40h  8 00401026   push        ebx  9 00401027   push        esi 10 00401028   push        edi 11 00401029   lea         edi,[ebp-40h] 12 0040102C   mov         ecx,10h 13 00401031   mov         eax,0CCCCCCCCh 14 00401036   rep stos    dword ptr [edi] 15 18:       plus(); 16 00401038   call        @ILT+10(plus) (0040100f) 17 19:       return 0; 18 0040103D   xor         eax,eax 19 20:   } 20 0040103F   pop         edi 21 00401040   pop         esi 22 00401041   pop         ebx 23 00401042   add         esp,40h 24 00401045   cmp         ebp,esp 25 00401047   call        __chkesp (0040d430) 26 0040104C   mov         esp,ebp 27 0040104E   pop         ebp 28 0040104F   ret

2,必须自己使用 RET 或 RET n 指令返回 (除非你不返回);这句话就告诉我们该怎么做了
 1 // xiaoyu1.cpp : Defines the entry point for the console application.  2 //  3   4 #include "stdafx.h"  5   6 void __declspec(naked) plus()  7 {  8     __asm  9     { 10         ret 11     } 12 } 13  14 void Plus1() 15 { 16      17 } 18  19 int main(int argc, char* argv[]) 20 { 21     plus(); 22     return 0; 23 }

 1 void __declspec(naked) plus()  2 {  3     __asm  4     {  5         //提升堆栈  6         push ebp  7         mov ebp,esp  8         sub ebp,0x40  9         //保护现场 10         push ebx 11         push esi 12         push edi 13         //向缓冲区填充数据 14         lea edi,dword ptr ds:[ebp-0x40] 15         mov eax,0xCCCCCCCC 16         mov ecx,0x10 17         rep stosd  ;rep stos dword ptr es:[edi] 18         //恢复现场 19         pop edi 20         pop esi 21         pop ebx 22         //降低堆栈 23         mov esp,ebp 24         pop ebp 25         //返回函数调用前的下一行地址 26         ret 27     } 28 }

 1 int __declspec(naked) plus(int x, int y)  2 {  3     __asm  4     {  5         //提升堆栈  6         push ebp  7         mov ebp,esp  8         sub esp,0x40  9         //保护现场 10         push ebx 11         push esi 12         push edi 13         //向缓冲区填充数据 14         lea edi,dword ptr ds:[ebp-0x40] 15         mov eax,0xCCCCCCCC 16         mov ecx,0x10 17         rep stos dword ptr es:[edi] 18  19         //函数核心功能块 20         mov eax,dword ptr ds:[ebp+0x8] 21         add eax,dword ptr ds:[ebp+0xC] 22  23         //恢复现场 24         pop edi 25         pop esi 26         pop ebx 27  28         //降低堆栈 29         mov esp,ebp 30         pop ebp 31         //返回函数调用前的下一行地址 32         ret 33     } 34 }

 1 int __declspec(naked) plus(int x, int y)  2 {  3     __asm  4     {  5         //提升堆栈  6         push ebp  7         mov ebp,esp  8         sub esp,0x40  9         //保护现场 10         push ebx 11         push esi 12         push edi 13         //向缓冲区填充数据 14         lea edi,dword ptr ds:[ebp-0x40] 15         mov eax,0xCCCCCCCC 16         mov ecx,0x10 17         rep stos dword ptr es:[edi] 18  19         //局部变量入栈 20         mov dword ptr ds:[ebp-0x4] 21         mov dword ptr ds:[ebp-0x8] 22  23         //函数核心功能块 24         mov eax,dword ptr ds:[ebp+0x8] 25         add eax,dword ptr ds:[ebp+0xC] 26  27         //恢复现场 28         pop edi 29         pop esi 30         pop ebx 31         //降低堆栈 32         mov esp,ebp 33         pop ebp 34         //返回函数调用前的下一行地址 35         ret 36     } 37 }

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!