首页
社区
课程
招聘
[原创]发一个支持任意地点hook的类(包含驱动hook和应用层hook)
发表于: 2013-3-3 23:58 26394

[原创]发一个支持任意地点hook的类(包含驱动hook和应用层hook)

2013-3-3 23:58
26394

这是以前练习写驱动类的一个产物,  有点早了,很简单.
写这个类也是方便自己绕过某些驱动的保护钩子.  当然这个也只支持x86, 没有做x64的拓展. 因为只是方便自己不需要每次都copy一大堆代码;
如果需要x64的拓展的,可以参考detours 或者是 EasyHook.   比较好的是EasyHook提供了驱动的hook;

貌似关于驱动写类论坛上比较少, 对于驱动,大家更倾向于直接用c写, 而不喜欢用c++写;  其实遇到大的工程,用c++有很多好处,而且微软也是有c++写驱动类的例子的.

废话不多说:  
关于驱动的,啰嗦一句, 不能定义全局的驱动对象, 具体为什么不能大家就自己baidu或者google;

直接上代码,代码里提供了例子;hook NtOpenProcess 和 NtReadVirtualMemory
驱动部分Hook.zip

应用层的:
应用层hook.zip

比较简单, 高手飘过. 这里只是给一个例子

//KernelDetours.h
#pragma once
#include <ntddk.h>
#include "ldasm.h"
//保存5字节代码的结构
#pragma pack(1)
typedef struct _TOP5CODE
{
	UCHAR  instruction;  //指令
	ULONG  address;    //地址
}TOP5CODE,*PTOP5CODE;
#pragma pack()



#ifdef __cplusplus
extern "C" {
#endif
class CKernelDetours
{
public:
	CKernelDetours();
	~CKernelDetours();

	BOOLEAN Hook(ULONG HookAddr,PULONG NakedFunc);
	void UnHook();
	void __stdcall CallJmpBack();

protected:
	VOID WPOFF();
	VOID WPON();

private:
	UCHAR m_Bak[5];
	ULONG m_hookAddr;
	ULONG m_HookCodeLen;//被hook指令的长度

	ULONG m_OldProtect;
	BOOLEAN  m_bHookSuccess;
	KIRQL  Irql;

	PVOID m_detoursFunc;//这个地方呢,是动态生成的. 他是保存hook前的指令, 可以执行到这里然后跳转到原函数下面继续执行

public:
	static void __cdecl operator delete(void* pointer) { ASSERT(NULL != pointer); if (NULL != pointer) ExFreePool(pointer); }
	static void * __cdecl operator new(size_t iSize,POOL_TYPE PoolType,unsigned int tag) {
		KdPrint(("global operator new --  Allocate size :%d \n",iSize));
		PVOID result; // [sp+0h] [bp-4h]@1
		result = ExAllocatePoolWithTag(PoolType, iSize, tag);
		if ( result )
			memset(result, 0, iSize);
		return result;
	}


};



#ifdef __cplusplus
}; // extern "C"
#endif


//KernelDetours.cpp
#include "KernelDetours.h"

#define  TAG 'liuq'


CKernelDetours::CKernelDetours(void)
{
	RtlZeroMemory(m_Bak,0,6);
	m_hookAddr =0;
	m_OldProtect = 0;
	m_bHookSuccess = FALSE;
	m_HookCodeLen = 0;
	m_detoursFunc = NULL;
	m_detoursFunc = ExAllocatePoolWithQuotaTag(NonPagedPool,0x50,TAG);
	memset(m_detoursFunc,0x90,0x50);
	KdPrint(("Enter CKernelDetours::CKernelDetours(void)   m_detoursFunc: %x",(ULONG)m_detoursFunc));
}

CKernelDetours::~CKernelDetours(void)
{
// if (m_bHookSuccess)
// {
// 	UnHook();
// }
KdPrint(("Enter CKernelDetours::~CKernelDetours(void)"));
}

void CKernelDetours::WPOFF()
{		//清除页面保护
	__asm
	{
			cli
			mov eax,cr0
			and eax,not 10000h
			mov cr0,eax
	}
}

void CKernelDetours::WPON()
{	//恢复页面保护
	__asm
	{
			mov eax,cr0
			or eax,10000h
			mov cr0,eax
			sti
	}
}


void CKernelDetours::UnHook()
{
	if (m_bHookSuccess)
	{
		ULONG a = m_hookAddr;
		WPOFF();
		Irql = KeRaiseIrqlToDpcLevel();
		RtlCopyMemory((void*)a,m_Bak,5);
		KeLowerIrql(Irql);
		WPON();

		m_bHookSuccess =FALSE;
	}
	if (m_detoursFunc != NULL)
	{
		KdPrint(("ExFreePoolWithTag(m_detoursFunc,TAG);"));
		ExFreePoolWithTag(m_detoursFunc,TAG);
		m_detoursFunc  =  NULL;
	}
}

BOOLEAN CKernelDetours::Hook(ULONG HookAddr,PULONG NakedFunc)
{
	if(m_bHookSuccess || NakedFunc==NULL || HookAddr == NULL)
	{
		return FALSE;
	}
	m_hookAddr = HookAddr; //保存被hook的地址
	unsigned char jmp[6]  ={0xe9};
	jmp[5] = 0x90;


	PUCHAR pcode = NULL;
	ULONG codelen =0;
	ULONG uSumCodeLen = 0;
	BOOLEAN bFind = FALSE;
	for (int j =0; j<0x30; j+=codelen)
	{
		codelen = 	SizeOfCode((void*)(HookAddr+j),&pcode);
		uSumCodeLen+=codelen;//计算总长度
		if (uSumCodeLen>=5)
		{
			bFind =TRUE; 
			break;
		}
	}

	if (!bFind)
	{
		KdPrint((" I'm sorry, Can Not Find Right Place to Hook\n"));
		return FALSE;
	}
	
	m_HookCodeLen = uSumCodeLen; //保存这个长度

	ULONG  JmpBack= HookAddr + uSumCodeLen;
	ULONG jmpDetoursAddr = ((ULONG)m_detoursFunc + uSumCodeLen);//在detours函数跳转到hook的地方
	ULONG b = JmpBack - jmpDetoursAddr  - 5;
	*(ULONG *)(jmp+1) = b;

	WPOFF();
	Irql = KeRaiseIrqlToDpcLevel();
	RtlCopyMemory((void*)m_detoursFunc,(void*)HookAddr,uSumCodeLen); //把这些数据保存到detours 函数里面,//然后在后面写上 jmp (HookAddr+uSumCodeLen)
	RtlCopyMemory((void*)jmpDetoursAddr,jmp,5);
	KeLowerIrql(Irql);
	WPON();

	ULONG a = HookAddr;  //hook的地址
	 b = (ULONG)NakedFunc - a - 5;
	*(ULONG *)(jmp+1) = b;
	
	
	RtlCopyMemory((void*)m_Bak,(void*)a,5);//保存hook的地方

	WPOFF();
	Irql = KeRaiseIrqlToDpcLevel();
	RtlCopyMemory((void*)a,jmp,5);
	KeLowerIrql(Irql);
	WPON();
	m_bHookSuccess = TRUE;
	return TRUE;
}



void CKernelDetours::CallJmpBack()
{
/*
__asm
{
	push ebp
	mov ebp,esp
	sub,esp,8
}*/

ULONG ebp1 = (ULONG)m_detoursFunc;
__asm
{
	mov eax,ebp1
	mov esp,ebp
	pop ebp
	add esp,8  ;//这里会有一个变量的堆栈空间 + 一个this指针的参数
	jmp eax
}

/*
__asm 
{
	mov esp,ebp
	pop ebp
	retn 4
}*/

}



[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

上传的附件:
收藏
免费 6
支持
分享
最新回复 (23)
雪    币: 822
活跃值: (279)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
2
下来看看 学习学习
2013-3-4 09:55
0
雪    币: 27
活跃值: (127)
能力值: ( LV8,RANK:120 )
在线值:
发帖
回帖
粉丝
3
thanks for share
2013-3-4 09:56
0
雪    币: 1587
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
非常感谢
2013-3-4 10:25
0
雪    币: 284
活跃值: (106)
能力值: ( LV9,RANK:160 )
在线值:
发帖
回帖
粉丝
5
楼主的new不行啊,都没有看到调用构造函数诶
2013-3-4 21:27
0
雪    币: 69
活跃值: (157)
能力值: ( LV8,RANK:130 )
在线值:
发帖
回帖
粉丝
6
没调用?不会吧,应该有打印输出吧!

global operator new --  Allocate size :28
Enter CKernelDetours::CKernelDetours(void)   m_detoursFunc: 814c3040NtOpenProcess Addr 0x805cc3fc
global operator new --  Allocate size :28
Enter CKernelDetours::CKernelDetours(void)   m_detoursFunc: 81730008NtReadVirtualMem Addr 0x805b528a
访问OPenProcess的进程名为 svchost.exe
访问OPenProcess的进程名为 Dbgview.exe
访问OPenProcess的进程名为 InstDrv.exe
访问OPenProcess的进程名为 Dbgview.exe
访问OPenProcess的进程名为 svchost.exe

这部分是卸载的时候析构函数调用打印的调试信息!

ExFreePoolWithTag(m_detoursFunc,TAG);
Enter CKernelDetours::~CKernelDetours(void)
ExFreePoolWithTag(m_detoursFunc,TAG);
Enter CKernelDetours::~CKernelDetours(void)
2013-3-4 22:37
0
雪    币: 12
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
好贴,前排留名,学习了
2013-3-6 14:28
0
雪    币: 270
活跃值: (15)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
谢谢共享,学习学习!
2013-3-6 14:37
0
雪    币: 1689
活跃值: (379)
能力值: ( LV15,RANK:440 )
在线值:
发帖
回帖
粉丝
9
是不是要考虑一下函数头包含相对跳转指令的情况?
2013-3-7 10:37
0
雪    币: 688
活跃值: (3747)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
10
学习下,谢谢分享
2013-3-7 14:41
0
雪    币: 5
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
11
楼主这种inline hook在搞频繁调用的函数,如IoCallDriver,很容易蓝屏的吧~建议利用微软的热补丁做,还是很稳定的,既可做好多核,也可做好多线程的保护,做法如,在待挂钩目标前后1字节寻址范围内搜索5个nop指令~如果是x64,可以在1字节寻址范围内搜索6+8个nop指令,我自己的inlinehook引擎就是这么做的,还是相当稳定的,仅供楼主参考
2013-3-8 17:14
0
雪    币: 69
活跃值: (157)
能力值: ( LV8,RANK:130 )
在线值:
发帖
回帖
粉丝
12
多谢提醒, 其实当时写这个仅仅是方便绕过某些游戏的保护钩子, 纯粹是自用而已,不打算考虑这么多. 就是一句话,简单能用就ok;
2013-3-8 20:18
0
雪    币: 65
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
13
哦,哦,原来如此
2013-3-9 16:26
0
雪    币: 97697
活跃值: (200734)
能力值: (RANK:10 )
在线值:
发帖
回帖
粉丝
14
Thanks for share.
2013-3-10 14:17
0
雪    币: 214
活跃值: (55)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
15
原来的参数怎么取呢?堆栈变了。。
2013-12-30 20:49
0
雪    币: 19
活跃值: (1086)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
16
求代码求代码
2014-1-7 18:14
0
雪    币: 130
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
17
我记得有位高人的INLINEHOOK PUSH_DATA_ARG那才叫爽 完全忽视跳转 如果要跳到其他地方修改返回地址 中间可以HOOK 完全实现代码自管理 遇到跳转也可以HOOK
2014-1-7 19:07
0
雪    币: 110
活跃值: (308)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
18
弱弱地问一下:
刚看了你用户层的hook代码,你是直接把hook程序都放到了测试程序中了。在我们实际分析程序的时候,是不是需要将hook代码写到一个dll中,然后注入到目标程序中? 还是 有其它用法?
2014-1-7 22:37
0
雪    币: 1258
活跃值: (1434)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
19
mark ,收藏下!
2014-1-7 23:03
0
雪    币: 77
活跃值: (48)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
20
mark
2014-1-22 08:18
0
雪    币: 455
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
21
下来学习学习
2014-1-22 16:29
0
雪    币: 294
活跃值: (119)
能力值: ( LV5,RANK:70 )
在线值:
发帖
回帖
粉丝
22
mark
2014-5-2 21:43
0
雪    币: 9
活跃值: (175)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
23
g_p->CallJmpBack中没有恢复原来的寄存器,导致继续执行原函数时候错误
2018-6-8 14:21
0
雪    币: 160
活跃值: (162)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
24
calljmpBack一直出错
2020-9-24 16:54
0
游客
登录 | 注册 方可回帖
返回
//