概述
  _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,跟进去。
   第一次按下F11我们会看到这行代码
1 00401005 jmp Plus1 (00401020)

再按下F11,如下所示
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
在最底层,发现事情都不是明面上看到的那么简单,C语言中一个什么都不写的最简单的一个函数,编译器居然为我们生成了这么多的汇编代码,如果你不懂这段,可以移步我的这一篇博文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 }
   我们在程序调用处,第18行按下F9下一个断点,然后进入反汇编窗口。
 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
   黄色的小箭头,此时指向第16行 00401038   call        @ILT+10(plus) (0040100f),两步F11进去,程序会直接跑没了,跳到一堆int 3的地方去,因此概述中的2,必须自己使用 RET 或 RET n 指令返回 (除非你不返回);这句话就告诉我们该怎么做了
   我们可以自己写一个内敛汇编,加一个ret进去
 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 }
   在C程序中,一个程序有call就必然有ret,否则它就乱了,找不到它回家的路了,加上这一步之后,调用裸函数的时候它就会正常返回了。
无参数无返回值的函数框架
 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 }
 未完,待续补充~~~~~~~~