欢迎来到 嗅灵易学

零基础也能上手的脚本技术课,一对一答疑带你入门

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

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

这是以前练习写驱动类的一个产物,  有点早了,很简单.
写这个类也是方便自己绕过某些驱动的保护钩子.  当然这个也只支持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

}*/

}


至于用法就比较简单了;
CKernelDetours *g_p= NULL; //hook NtOpenProcess 定义一个全局的指针,是为了方便还原, 不需要还原hook的可以直接在函数内部定义对象

//NtOpenProcess的中继函数

__declspec(naked) void MyOpenProcess()

{

	__asm

	{

			pushad

			pushfd

	}

	ANSI_STRING  p_str1;

	RtlInitAnsiString(&p_str1,(PSTR)((ULONG)IoGetCurrentProcess()+0x174));

	//将我们要比对的进程名放入str2

	KdPrint(("访问OPenProcess的进程名为 %s\n", p_str1.Buffer));

	__asm

	{

			popfd

			popad

	}

	// call detours

	g_p->CallJmpBack();

}

CKernelDetours* Hook_NtOpenProcess()

{

	CKernelDetours *p =  new(NonPagedPool, 'RysI') CKernelDetours;

	ULONG addr= GetSsdtFuncAddr(0x7A) ;

	KdPrint(("NtOpenProcess Addr 0x%x\n",addr));

	p->Hook(addr,(PULONG)MyOpenProcess);//这里只需要填入要hook的地址,和中继函数的地址即可.很简单; 在函数头,函数尾都行;有了这个功能,大家就可以专心写中继函数了.不必考虑其他的事情;

	return p;

}

void UnHookNtOpenProcess(CKernelDetours* p)

{

	CKernelDetours *pthis = p;

	if (pthis != NULL)

	{

		pthis->UnHook();

		delete pthis;

	}

}


这里就是演示其用法. 作用就是可以在任意函数内部进行Hook, 专心写中继函数,也不需要你人为的去调用被覆盖的代码. 你只需要在中继函数的最后面调用一下        g_p->CallJmpBack();就是实现跳转的功能,即可跳转会原函数执行; 这个功能对绕过某些驱动保护应该足够了.而且用法也很简单.

上传的附件 驱动部分Hook.zip
应用层hook.zip

注意:上传附件及图片大小不得大于30M。

⚠️ 版权声明:
本博客所有内容(含教程、源码、工具)仅供个人技术学习与研究交流使用,严禁商用、倒卖、二次分发及非法用途。
未经作者书面授权,任何组织或个人不得转载、复制或用于其他平台,违者将追究相关责任。

0 0 0 举报
复制成功