#include <ntddk.h>
//如何对函数做inlinehook?
//首先,弄清楚您要inlinehook的函数的定义。
//然后,获得要inline hook的函数的地址:
//如果是未导出的,根据特征码,暴力搜索内存;
//如果是导出的,可以直接使用函数名称做为它的地址或者使用MmGetSystemRoutineAddress
//拿到它的地址。如:
//NTKERNELAPI
//BOOLEAN
//KeInsertQueueApc (
// IN PKAPC Apc,
// IN PVOID SystemArgument1,
// IN PVOID SystemArgument2,
// IN KPRIORITY Increment
// );
//那么KeInsertQueueApc就是该函数的首地址了。注意加上NTKERNELAPI。否则得用MmGetSystemRoutineAddress来拿地址
//
//拿到地址后,就可以做inlineHOOK了。
//将该地址的前五个字节,换成jmp T_MyFunc - Func - 5这个地方
//在T_MyFunc里压栈参数,调用MyFunc。执行完MyFunc之后,再JUMP到Func+5的地方执行。
//在卸载函数里,恢复Func,去掉inline hook
//所以,inlinehook一个Func函数,有如下几个任务:
//1。弄清要hook的函数Func的定义
//2。找到该函数Func的地址
//3。写出T_MyFunc,在里面将参数传给 MyFunc处理,然后跳转到Func后面执行
//4。实现 MyFunc函数,做你自己的处理
//5。inline hook函数,实现inlinehook,将Func函数跳转到T_MyFunc执行。在DriverEntry里调用
//6。inline hook卸载函数,在DriverUnload里调用
//要hook的函数声名
typedef NTSTATUS (*FuncDefine)(
PEPROCESS Process,
NTSTATUS ExitStatus
);
FuncDefine FuncAddress= NULL;
//未导出的函数声名
typedef NTSTATUS (*NTQUERYSYSTEMINFORMATION)(
IN ULONG SystemInformationClass,
OUT PVOID SystemInformation,
IN ULONG SystemInformationLength,
OUT PULONG ReturnLength OPTIONAL);
typedef unsigned long DWORD;
NTQUERYSYSTEMINFORMATION NtQuerySystemInformation;
//系统已加载的模块信息
#define SystemModuleInformation 11
//用于记录模块信息的结构体
typedef struct _SYSTEM_MODULE_INFORMATION
{
ULONG Reserved[2];
PVOID Base;
ULONG Size;
ULONG Flags;
USHORT Index;
USHORT Unknown;
USHORT LoadCount;
USHORT ModuleNameOffset;
CHAR ImageName[256];
} SYSTEM_MODULE_INFORMATION, *PSYSTEM_MODULE_INFORMATION;
PVOID GetFunctionAddressFromKernelMemory(VOID)
{
ULONG size = 0;
ULONG index = 0;
PULONG buf = NULL;
ULONG i = 0;
PSYSTEM_MODULE_INFORMATION module = NULL;
PVOID driverAddress = 0;
ULONG ntosknlBase = 0;
ULONG ntosknlEndAddr = 0;
ULONG curAddr = 0;
NTSTATUS status = 0;
ULONG retAddr = 0;
// 在内存中的函数的特征码
ULONG code1_sp2=0x8b55ff8b,code2_sp2=0xa16456ec,code3_sp2=0x00000124,code4_sp2=0x3b08758b;
//先查询获取大小
NtQuerySystemInformation(SystemModuleInformation,&size, 0, &size);
//再分配内存
if(NULL==(buf = (PULONG)ExAllocatePoolWithTag(PagedPool, size, 'NLNI')))
{
DbgPrint("failed alloc memory failed \n");
return 0;
}
//再查询
status=NtQuerySystemInformation(SystemModuleInformation,buf, size , 0);
if(!NT_SUCCESS( status ))
{
DbgPrint("failed query\n");
return 0;
}
//保存相关信息
module = (PSYSTEM_MODULE_INFORMATION)(( PULONG )buf + 1);
ntosknlEndAddr=(ULONG)module->Base+(ULONG)module->Size;
ntosknlBase=(ULONG)module->Base;
curAddr=ntosknlBase;
//已经保存了信息 释放刚才的缓冲区内存
ExFreePool(buf);
//暴力搜索内存
for (i=curAddr;i<=ntosknlEndAddr;i++)
{
if ((*((ULONG *)i)==code1_sp2)&&
(*((ULONG *)(i+4))==code2_sp2)&&
(*((ULONG *)(i+8))==code3_sp2)&&
(*((ULONG*)(i+12))==code4_sp2))
{
retAddr=i;
DbgPrint("adress is:%x",retAddr);
return (PVOID)retAddr;
}
}
return NULL;
}
ULONG GetFunctionAddr( IN PCWSTR FunctionName)
{
UNICODE_STRING UniCodeFunctionName;
RtlInitUnicodeString( &UniCodeFunctionName,FunctionName );
return (ULONG)MmGetSystemRoutineAddress( &UniCodeFunctionName );
}
NTSTATUS CheckFuncIsHook()
{
int i = 0;
char *addr = (char *)FuncAddress;
char code[] = { 0x8b, 0xff, 0x55, 0x8b, 0xec};
while(i<5)
{
DbgPrint("0x%02X", (unsigned char)addr[i]);
if(addr[i] != code[i])
{
return STATUS_UNSUCCESSFUL;
}
i++;
}
return STATUS_SUCCESS;
}
int MyFunc(PEPROCESS Process,
NTSTATUS ExitStatus
)
{
DbgPrint("MyFunc hello\n");
return 1;
}
_declspec(naked) T_MyFunc(
PEPROCESS Process,
NTSTATUS ExitStatus
)
{
_asm
{
mov edi, edi
push ebp
mov ebp ,esp
//参数压栈,传给MyFunc
push [ebp+0ch]
push [ebp+8]
call MyFunc
cmp eax,1
jz end
mov eax,FuncAddress
add eax,5
jmp eax
end:
//恢复栈
pop ebp
retn 8
}
}
VOID InlineHookFunc()
{
int JmpOffSet = 0;
unsigned char JmpCode[5] = { 0xe9, 0x00, 0x00, 0x00, 0x00 };
KIRQL oldIrql = 0;
if (FuncAddress == 0)
{
DbgPrint("Func NOT FOUND\n");
return;
}
DbgPrint("Func is found at:0x%08x\n", (ULONG)FuncAddress );
DbgPrint("T_MyFunc is:%x\n",T_MyFunc);
JmpOffSet= (char*)T_MyFunc - (char*)FuncAddress - 5;
DbgPrint("JmpOffSet is:%x\n",JmpOffSet);
RtlCopyMemory ( JmpCode+1, &JmpOffSet, 4 );
_asm
{
CLI
MOV EAX, CR0
AND EAX, NOT 10000H
MOV CR0, EAX
}
oldIrql = KeRaiseIrqlToDpcLevel();
RtlCopyMemory ( FuncAddress, JmpCode, 5 );
DbgPrint("FuncAddress is hook now \n");
KeLowerIrql(oldIrql);
_asm
{
MOV EAX, CR0
OR EAX, 10000H
MOV CR0, EAX
STI
}
}
VOID DriverUnload(PDRIVER_OBJECT pDriverObject)
{
// 在win2000上是三字节
// push ebp
// mov ebp, esp
//
// 到了winxp以及后续系统上,则变成了五字节
// mov edi, edi
// push ebp
// mov ebp, esp
// 函数的序言
//恢复HOOK
KIRQL oldIrql = 0;
LARGE_INTEGER Delay = {0};
unsigned char Code[5] = {0x8b,0xff,0x55,0x8b,0xec};
Delay.QuadPart = -5000000;
KeDelayExecutionThread(KernelMode, TRUE, &Delay);
oldIrql = KeRaiseIrqlToDpcLevel();
__asm
{
CLI
MOV eax, CR0
AND eax, NOT 10000H
MOV CR0, eax
}
RtlCopyMemory ( FuncAddress, Code, 5 );
__asm
{
MOV eax, CR0
OR eax, 10000H
MOV CR0, eax
STI
}
KeLowerIrql(oldIrql);
DbgPrint("Goodbye driver\n");
}
NTSTATUS DriverEntry(IN PDRIVER_OBJECT pDriverObject, PUNICODE_STRING pRegPath)
{
//未导出的函数
FuncAddress = GetFunctionAddressFromKernelMemory();
//导出的函数
//FuncAddress = GetFunctionAddr(L"FuncName");
if(STATUS_SUCCESS != CheckFuncIsHook())
{
DbgPrint("Func Match Failed !");
return STATUS_UNSUCCESSFUL;
}
//inline hook它
InlineHookFunc();
pDriverObject->DriverUnload = DriverUnload;
return STATUS_SUCCESS;
}
inlinehook(0环)
原创
©著作权归作者所有:来自51CTO博客作者土匪猿的原创作品,请联系作者获取转载授权,否则将追究法律责任
提问和评论都可以,用心的回复会被更多人看到
评论
发布评论
相关文章
-
【Phaser游戏开发】动画效果-舞动的蝴蝶环
舞动的蝴蝶圆环,蝴蝶群飞舞
Game Phaser 舞动的蝴蝶圆环 蝴蝶群飞舞 -
【Canvas与艺术】三环莫比乌斯圈
在Canvas里用四段嵌合的圆弧绘制三环莫比乌斯圈。
canvas 莫比乌斯