// 将本文完整拷贝, 然后在VC6 下建立控制台程序, 可直接运行~ 看到结果后再来阅读此文
// 文章出处甚多, 已不能列出所有连接
#include "stdafx.h"
#include <stdio.h>
/*
>>>>>> _declspec(naked) 使用 <<<<<<<<
最近学习驱动开发,在写绕过inline hook的代码时,有个问题困扰了我一天,
最后发现原来是在内嵌汇编时,没有使用_declspec(naked)导致的,
看来是偶的基础知识掌握的不牢固啊(得补一下了,磨刀不误砍柴功),在此给记录一下,给自己一个警示。
对于jmp类型的hook, 如果自己的过程没有使用_declspec(naked),那么系统会自动给添加一些额外的代码,控制堆栈平衡,
但是这些额外的代码会破坏被hook函数的堆栈。
对于call类型的hook,如果使用_declspec(naked)修饰的话,要注意自己恢复堆栈平衡..
下面是网上对_declspec(naked) 的介绍:
_declspec(naked)
就是告诉编译器,在编译的时候,不要优化代码,通俗的说就是
没代码,完全要自己写
比如
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
#define NAKED __declspec(naked)
void NAKED code(void)
{
__asm
{
ret
}
}
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
使用__declspec(naked)关键字定义函数:
1,使用 naked 关键字必须自己构建 EBP 指针 (如果用到了的话);
2,必须自己使用 RET 或 RET n 指令返回 (除非你不返回);
// >> __declspec(naked) 是且仅是不产生 prolog 和 epilog 代码
// >> {保存并恢复使用过的寄存器和分配局部变量、平衡堆栈、返回值}。
_delcspec(naked)用在驱动编写,C语言内嵌汇编完成一些特定功能。
*/
#pragma warning (disable: 4700)
unsigned int retAddress;
void Test2();
void NormalFunc();
void NormalFunc()
{
// data[1] : ebp的值, data[2] : 函数返回地址
unsigned int data[1] = { 0 };
// 保存 返回地址
retAddress = data[2];
data[2] = (unsigned int)Test2;
return ;
}
// naped 函数 (手工指定 prolog 和 epilog)
// >> 一下四种形式皆可
// __declspec(naked) void Test2()
// void __declspec(naked) Test2()
// void _declspec(naked) Test2()
_declspec(naked) void Test2()
{
printf("Naked : hello world!\r\n");
// 跳回main函数体重!
__asm
{
jmp [retAddress]
}
}
int main()
{
NormalFunc();
printf(" before exit\r\n");
return 0;
}