- 注册时间
- 2011-3-6
- 最后登录
- 1970-1-1
该用户从未签到
|
这是以前练习写驱动类的一个产物, 有点早了,很简单.
写这个类也是方便自己绕过某些驱动的保护钩子. 当然这个也只支持x86, 没有做x64的拓展. 因为只是方便自己不需要每次都copy一大堆代码;
如果需要x64的拓展的,可以参考detours 或者是 EasyHook. 比较好的是EasyHook提供了驱动的hook;
貌似关于驱动写类论坛上比较少, 对于驱动,大家更倾向于直接用c写, 而不喜欢用c++写; 其实遇到大的工程,用c++有很多好处,而且微软也是有c++写驱动类的例子的.
废话不多说:
关于驱动的,啰嗦一句, 不能定义全局的驱动对象, 具体为什么不能大家就自己baidu或者google;
直接上代码,代码里提供了例子;hook NtOpenProcess 和 NtReadVirtualMemory
比较简单, 高手飘过. 这里只是给一个例子
代码:
//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();就是实现跳转的功能,即可跳转会原函数执行; 这个功能对绕过某些驱动保护应该足够了.而且用法也很简单. |
|