原理
内联钩子的原理在R3和R0下是相同的,就是不改变SSDT表项,而是改变函数内部前几条指令。
内联钩子的典型伪函数为:
- 恢复原指令
- 执行目标操作,或改写参数
- 执行原函数
- 返回时重新挂钩
demo
#include "stdafx.h"
#ifdef __cplusplus
extern "C" NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath);
#endif
typedef NTSTATUS (*NtCreateProcess)(
OUT PHANDLE ProcessHandle,
IN ACCESS_MASK DesiredAccess,
IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
IN HANDLE ParentProcess,
IN BOOLEAN InheritObjectTable,
IN HANDLE SectionHandle OPTIONAL,
IN HANDLE DebugPort OPTIONAL,
IN HANDLE ExceptionPort OPTIONAL ,
IN ULONG JobMemberLevel );
typedef struct _SERVICE_DESCRIPTOR_TABLE
{
PULONG ServiceTableBase;
PULONG ServiceCounterTableBase;
ULONG NumberOfService;
PUCHAR ParamTableBase;
}SERVICE_DESCRIPTOR_TABLE,*PSERVICE_DESCRIPTOR_TALBE;
NtCreateProcess real_func_addr = NULL;
unsigned char bOldBytes[5];
unsigned char bNewBytes[5];
extern "C" PSERVICE_DESCRIPTOR_TALBE KeServiceDescriptorTable;//name can‘t change. import member must be global variable.
/*
cr0 -16th bit = 0 means page can write
*/
bool REMOVE_ONLYREAD()
{
__asm
{
push eax
mov eax,CR0
and eax, not 10000h
mov CR0,eax
pop eax
}
return TRUE;
}
/*
cr0 -16th bit(WP) = 1,reset to the attribute of ONLY READ
*/
bool RESET_ONLYREAD()
{
__asm
{
push eax
mov eax,CR0
or eax,10000h
mov CR0,eax
pop eax
}
return TRUE;
}
VOID RelineHookCreateProcess()
{
REMOVE_ONLYREAD();
//writememory with "jmp xxxxxxxx";
RtlCopyMemory((PVOID)real_func_addr,(CONST PVOID)bNewBytes,5);
RESET_ONLYREAD();
}
VOID UnHookCreateProcess()
{
REMOVE_ONLYREAD();
//__asm int 3
RtlCopyMemory((PVOID)real_func_addr,(const PVOID)bOldBytes,5);
RESET_ONLYREAD();
}
void InlineSSDTHookUnload(PDRIVER_OBJECT pDriverObject) //no return ,with return compiler error
{
UnHookCreateProcess();
DbgPrint("GoodBye from InlineHook!\n");
}
NTSTATUS MyNtCreateProcessEx(
OUT PHANDLE ProcessHandle,
IN ACCESS_MASK DesiredAccess,
IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
IN HANDLE ParentProcess,
IN BOOLEAN InheritObjectTable,
IN HANDLE SectionHandle OPTIONAL,
IN HANDLE DebugPort OPTIONAL,
IN HANDLE ExceptionPort OPTIONAL ,
IN ULONG JobMemberLevel
)
{
NTSTATUS Status = STATUS_SUCCESS;
UnHookCreateProcess();
Status = real_func_addr(
ProcessHandle,
DesiredAccess,
ObjectAttributes,
ParentProcess,
InheritObjectTable,
SectionHandle ,
DebugPort ,
ExceptionPort ,
JobMemberLevel
);
RelineHookCreateProcess();
DbgPrint("have hook CreateProcess!\r\n");
return Status;
}
NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath)
{
unsigned i;
DbgPrint("Hello from InlineSSDTHook!\n");
DriverObject->DriverUnload = InlineSSDTHookUnload;
//hook
PULONG PSsdt = (PULONG)KeServiceDescriptorTable->ServiceTableBase;
PULONG p_real_func_addr =PSsdt+0x30; //(unsigned char *) pssdt+0x30*4;
DbgPrint("%08x,%08x",p_real_func_addr,PSsdt+0x30); //diff compared with ssdt hook
real_func_addr = (NtCreateProcess)(*p_real_func_addr);
//__asm int 3
RtlCopyMemory((PVOID)bOldBytes,(CONST PVOID)real_func_addr,5);
bNewBytes[0] =‘\xe9‘;
*(PULONG)&bNewBytes[1]=(ULONG)MyNtCreateProcessEx-(ULONG)real_func_addr-5;
//__asm int 3
RtlCopyMemory((PVOID)real_func_addr,(CONST PVOID)bNewBytes,5);
return STATUS_SUCCESS;
}
今天在做实验的时候,老是出错,无语了。在本地加载了程序的符号文件后调试出现各种奇葩问题,比如说函数入口指令的第一个字节总是没有改回来,后来也不知道怎么解决的。
挂钩后不能打开程序,提示文件错误
,但是停止服务后恢复正常,所以怀疑是伪函数执行时候有错误,查了半天也没有错误。最后发现是少了一个参数,我函数指针定义成nt!NtCreatProcess
的参数了,nt!NtCreateProcessEx
比nt!ntCreateProces
多了一个参数JobMemeberLevel
。
typedef NTSTATUS (*NtCreateProcessEx)(
OUT PHANDLE ProcessHandle,
IN ACCESS_MASK DesiredAccess,
IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
IN HANDLE ParentProcess,
IN BOOLEAN InheritObjectTable,
IN HANDLE SectionHandle OPTIONAL,
IN HANDLE DebugPort OPTIONAL,
IN HANDLE ExceptionPort OPTIONAL ,
/*************/ IN ULONG JobMemberLevel );
可是非常奇怪,参数错误函数执行肯定出错,昨天的SSDT HOOK却也是少了这个参数,挂钩函数也是nt!ntCreateProcessEx
,按理说应该出错啊,为什么昨天的又是正确的呢???参数不一致也可以?仔细研究一下。
时间: 2024-11-08 05:57:57