您的位置:首页 > 其它

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

2014-02-07 11:36 369 查看
这是以前练习写驱动类的一个产物,  有点早了,很简单.

写这个类也是方便自己绕过某些驱动的保护钩子.  当然这个也只支持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();就是实现跳转的功能,即可跳转会原函数执行; 这个功能对绕过某些驱动保护应该足够了.而且用法也很简单.

鱼台论坛http://bbs.370827.org/forum-75-1.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐