//KernelDetours.h #pragma once #include#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 }*/ }
//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();就是实现跳转的功能,即可跳转会原函数执行; 这个功能对绕过某些驱动保护应该足够了.而且用法也很简单.
鱼台论坛http://bbs.370827.org/forum-75-1.html