硬件断点的实现需要依赖于调试寄存器
DR0~DR7 调试寄存器
DR0~DR3-----调试地址寄存器
DR4~DR5-----保留
DR6 -----调试状态寄存器 指示哪个调试寄存器被命中
DR7 -----调试控制寄存器
关于Dr7寄存器每个标志位的解释:
总结如下
DR7调试控制寄存器:
R/W0~R/W3:与DR0~DR3相对应,用来指定监控地址的访问类型,表示意义如下:
00:仅当执行对应的地址时中断
01:仅当写入对应的地址时中断
10:基本不用
11:读取对应的地址时中断,读取指令的指令除外
LEN0~LEN3:与DR0~DR3相对应,用来指定监控地址的长度,意义如下:
00:一个字节长
01:两个字节长
10:未定义或者代表8字节,具体视CPU而定
11:四个字节长
L0~L3:与DR0~DR3相对应,意思表示仅对当前
接下来看看两个Windows提供的两个API函数,GetThreadContext和SetThreadContext来获取或者时设置线程的上下文,什么是线程的上下文,就是线程运行时的各种寄存器的信息,比如调试寄存器,浮点寄存器,控制寄存器等等,在应用层是不能直接操作Drx寄存器的值,但可以调用这两个api来读写线程的上下文,来达到设置硬件断点的目的。
BOOL WINAPI GetThreadContext( __in HANDLE hThread, __inout LPCONTEXT lpContext );
BOOL WINAPI SetThreadContext( __in HANDLE hThread, __in const CONTEXT *lpContext );
在SSDT表中对应的NtGetContextThread和NtSetContextThread
NTSTATUS NtGetContextThread( __in HANDLE ThreadHandle, __inout PCONTEXT ThreadContext )
NTSTATUS NtSetContextThread( __in HANDLE ThreadHandle, __in PCONTEXT ThreadContext )
这两个函数都是调用了PsSet/GetContextThread函数
NTSTATUS PsSetContextThread( __in PETHREAD Thread, __in PCONTEXT ThreadContext, __in KPROCESSOR_MODE Mode ) NTSTATUS PsGetContextThread( __in PETHREAD Thread, __inout PCONTEXT ThreadContext, __in KPROCESSOR_MODE Mode )
我们可以对PsGet/SetContextTread函数Hook来达到对设置硬件断点的一个过滤,对于目标进程获取或者设置线程的Context进行处理。
oid __stdcall FilterSetGetContextThread( PETHREAD Thread, PCONTEXT Context, KPROCESSOR_MODE AccessMode) { __try{ if (AccessMode == UserMode) { //wrk 参数校验 ProbeForReadSmallStructure(Context,sizeof(CONTEXT),PROBE_ALIGNMENT(CONTEXT)); }else{ *Context = *Context; } if (strstr(GetProcessNameByThread(Thread),"test.exe")!=NULL) { if (strstr((char*)PsGetCurrentProcess()+0x16c,"ollydbg") != NULL) { return; } //如果是要获得调试寄存器的值,将Flags 的获得调试寄存器清零, if (Context->ContextFlags | CONTEXT_DEBUG_REGISTERS) { Context->ContextFlags = ~CONTEXT_DEBUG_REGISTERS; } } }__except(EXCEPTION_EXECUTE_HANDLER){ return; } }
typedef NTSTATUS (*PSGETCONTEXTTHREAD)( PETHREAD Thread, PCONTEXT Context, KPROCESSOR_MODE AccessMode); typedef NTSTATUS (*PSSETCONTEXTTHREAD)( PETHREAD Thread, PCONTEXT Context, KPROCESSOR_MODE AccessMode); //global PSGETCONTEXTTHREAD PsGetContextThread; PSSETCONTEXTTHREAD PsSetContextThread; ULONG g_JmpGetContextThread; UCHAR g_cGetContextCode[5]; BOOLEAN g_bHookGetContextSuccess; ULONG g_JmpSetContextThread; UCHAR g_cSetContextCode[5]; BOOLEAN g_bHookSetContextSuccess; char* GetProcessNameByThread(PETHREAD Thread) { ULONG ProcessObj; if (MmIsAddressValid(Thread)) { ProcessObj = *(ULONG*)((ULONG)Thread + 0x150); return (char*)(ProcessObj+0x16C); } return 0; } void PageProtectOn() { __asm{//恢复内存保护 mov eax,cr0 or eax,10000h mov cr0,eax sti } } void PageProtectOff() { __asm{//去掉内存保护 cli mov eax,cr0 and eax,not 10000h mov cr0,eax } } BOOLEAN Jmp_HookFunction( IN ULONG Destination, IN ULONG Source, IN UCHAR *Ori_Code ) { ULONG Jmp_Offest; UCHAR Jmp_Code[5] = {0xE9}; KSPIN_LOCK lock; KIRQL irql; if (Destination==0||Source==0) { DbgPrint("Params error!"); return FALSE; } RtlCopyMemory(Ori_Code,(PVOID)Destination,5); Jmp_Offest = Source - Destination-5; *(ULONG*)&Jmp_Code[1] = Jmp_Offest; KeInitializeSpinLock (&lock ); KeAcquireSpinLock(&lock,&irql); PageProtectOff(); RtlCopyMemory((PVOID)Destination,Jmp_Code,5); PageProtectOn(); KeReleaseSpinLock (&lock,irql); return TRUE; } VOID Res_HookFunction( IN ULONG Destination, IN UCHAR *Ori_Code, IN ULONG Length ) { KSPIN_LOCK lock; KIRQL irql; if (Destination==0||Ori_Code==0){ return; } KeInitializeSpinLock (&lock ); KeAcquireSpinLock(&lock,&irql); PageProtectOff(); RtlCopyMemory((PVOID)Destination,Ori_Code,Length); PageProtectOn(); KeReleaseSpinLock (&lock,irql); } FORCEINLINE VOID ProbeForReadSmallStructure ( IN PVOID Address, IN SIZE_T Size, IN ULONG Alignment ) //wrk源码 { ASSERT((Alignment == 1) || (Alignment == 2) || (Alignment == 4) || (Alignment == 8) || (Alignment == 16)); if ((Size == 0) || (Size >= 0x10000)) { ASSERT(0); ProbeForRead(Address, Size, Alignment); } else { if (((ULONG_PTR)Address & (Alignment - 1)) != 0) { ExRaiseDatatypeMisalignment(); } if ((PUCHAR)Address >= (UCHAR * const)MM_USER_PROBE_ADDRESS) { Address = (UCHAR * const)MM_USER_PROBE_ADDRESS; } _ReadWriteBarrier(); *(volatile UCHAR *)Address; } } void __stdcall FilterSetGetContextThread( PETHREAD Thread, PCONTEXT Context, KPROCESSOR_MODE AccessMode) { __try{ if (AccessMode == UserMode) { //wrk 参数校验 ProbeForReadSmallStructure(Context,sizeof(CONTEXT),PROBE_ALIGNMENT(CONTEXT)); }else{ *Context = *Context; } if (strstr(GetProcessNameByThread(Thread),"test.exe")!=NULL) { if (strstr((char*)PsGetCurrentProcess()+0x16c,"ollydbg") != NULL) { return; } //如果是要获得调试寄存器的值,将Flags 的获得调试寄存器清零, if (Context->ContextFlags | CONTEXT_DEBUG_REGISTERS) { Context->ContextFlags = ~CONTEXT_DEBUG_REGISTERS; } } }__except(EXCEPTION_EXECUTE_HANDLER){ return; } } void __declspec(naked) NewGetContextThread() { __asm{ mov edi,edi push ebp mov ebp,esp push [ebp+0x10] push [ebp+0xc] push [ebp+0x8] call FilterSetGetContextThread mov esp,ebp pop ebp mov edi,edi push ebp mov ebp,esp jmp g_JmpGetContextThread } } void __declspec(naked) NewSetContextThread() { __asm{ mov edi,edi push ebp mov ebp,esp push [ebp+0x10] push [ebp+0xc] push [ebp+0x8] call FilterSetGetContextThread mov esp,ebp pop ebp mov edi,edi push ebp mov ebp,esp jmp g_JmpSetContextThread } } void HookSetGetContextThread() { g_JmpGetContextThread = (ULONG)PsGetContextThread + 0x5; g_bHookGetContextSuccess = Jmp_HookFunction((ULONG)PsGetContextThread,(ULONG)NewGetContextThread,g_cGetContextCode); g_JmpSetContextThread = (ULONG)PsSetContextThread + 0x5; g_bHookSetContextSuccess = Jmp_HookFunction((ULONG)PsSetContextThread,(ULONG)NewSetContextThread,g_cSetContextCode); } void UnHookSetGetContextThread() { if (g_bHookGetContextSuccess) { Res_HookFunction((ULONG)PsGetContextThread,g_cGetContextCode,5); } if (g_bHookSetContextSuccess) { Res_HookFunction((ULONG)PsSetContextThread,g_cSetContextCode,5); } } void DriverUnLoad(PDRIVER_OBJECT pDriverObject) { UnHookSetGetContextThread(); } NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject,PUNICODE_STRING usRegistPath) { UNICODE_STRING usFuncName1,usFuncName2; RtlInitUnicodeString(&usFuncName1,L"PsGetContextThread"); RtlInitUnicodeString(&usFuncName2,L"PsSetContextThread"); PsGetContextThread = (PSGETCONTEXTTHREAD)MmGetSystemRoutineAddress(&usFuncName1); PsSetContextThread = (PSSETCONTEXTTHREAD)MmGetSystemRoutineAddress(&usFuncName2); HookSetGetContextThread(); pDriverObject->DriverUnload = DriverUnLoad; return STATUS_SUCCESS; }
在ring0可以直接改变Drx寄存器的值,设置硬件断点来达到对某个函数的hook,这里以NtOpenProcess为例。我们知道内核层产生的异常都会由RtlDispatchException函数进行分发处理,所以我们首先要InlineHook RtlDispatchException函数,在对异常进行分发时先对异常进行过滤,如果异常地址是我们设置的硬件断点“监控”的地址,则改变EIP,达到对目标函数“hook”的目的。
先InlineHook RtlDispatchException ,RtlDispatchException未导出,在KiDispatchException中被调用,KiDispatchException也未导出,采用的方法是暴力搜索整个内核文件Ntoskrnl.exe来匹配特征码
VOID HookRtlDispatchException() { PLDR_DATA_TABLE_ENTRY Ldr = NULL; //构建RtlDispatchException 的特征码 // nt!KiDispatchException+0x160: // 83eff040 53 push ebx // 83eff041 ff750c push dword ptr [ebp+0Ch] // 83eff044 ff7510 push dword ptr [ebp+10h] // 83eff047 ff15bc49fb83 call dword ptr [nt!KiDebugRoutine (83fb49bc)] // 83eff04d 84c0 test al,al // 83eff04f 0f859d000000 jne nt!KiDispatchException+0x211 (83eff0f2) // 83eff055 57 push edi // 83eff056 53 push ebx // 83eff057 e8 a372ffff call nt!RtlDispatchException (83ef62ff) // kd> u 83ef62ff // nt!RtlDispatchException: // 83ef62ff 8bff mov edi,edi // 83ef6301 55 push ebp // 83ef6302 8bec mov ebp,esp // 83ef6304 83e4f8 and esp,0FFFFFFF8h // 83ef6307 83ec6c sub esp,6Ch // 83ef630a 53 push ebx // 83ef630b 56 push esi // 83ef630c 57 push edi SIGNATURE_INFO SignCode[] = {{0x84,10},{0xc0,9},{0x57,2},{0x53,1},{0xE8,0}}; #ifndef _DEBUG __asm int 3 #endif g_bHookSuccess = FALSE; Ldr = SearchDriver(g_LocalDriverObj,L"ntoskrnl.exe"); if (!Ldr) return; g_RtlDispatchExeceptionAddress = SearchAddressForSignFromPE((ULONG_PTR)(Ldr->DllBase),Ldr->SizeOfImage,SignCode); if (!MmIsAddressValid((PVOID)g_RtlDispatchExeceptionAddress)) return; //利用偏移转成绝对地址 +5 过e8 a372ffff 这五个字节 g_RtlDispatchExeceptionAddress = g_RtlDispatchExeceptionAddress+5 + *(ULONG_PTR*)(g_RtlDispatchExeceptionAddress+1); //过被占的前5个字节,继续执行的代码 DbgPrint("RtlDispatchExceptionAddresss:%x",g_RtlDispatchExeceptionAddress); g_JmpOrigDispatchException = g_RtlDispatchExeceptionAddress + 5; g_bHookSuccess = Jmp_HookFunction(g_RtlDispatchExeceptionAddress,(ULONG_PTR)NewRtlDispatchException,g_cDisExceptionCode); }
然后将要“监控”的目标地址写入Dr0寄存器,当目标地址被执行的时候,触发异常,执行RtlDispatchException函数,
VOID SetMonitor(PVOID Address) { __asm { mov eax , Address mov DR0 , eax mov eax , 0x02 //全局的,仅当执行时产生异常 mov DR7 , eax } } VOID CancelMonitor(PVOID Address) { __asm { xor eax , eax mov DR0 , eax mov DR7 , eax } }
RtlDispatchException的过滤函数,在这里改变Eip的值,异常处理完毕以后,开始执行NewNtOpenProcess
ULONG_PTR _stdcall FilterRtlDispatchException ( IN PEXCEPTION_RECORD ExceptionRecord, IN PCONTEXT ContextRecord ) { //DbgPrint("Address:%x -- ExceptionCode:%x\r\n",ExceptionRecord->ExceptionAddress,ExceptionRecord->ExceptionCode); //如果是NtOpenProcess处的异常 if (ExceptionRecord->ExceptionAddress == (PVOID)KeServiceDescriptorTable.ServiceTableBase[190]) { KdPrint(("<Except addresss>:%X <seh callBack>:%X -- <Except code>:%X", ContextRecord->Eip,ExceptionRecord->ExceptionAddress,ExceptionRecord->ExceptionCode)); //将执行的下一条指令置为NewNtOpenProcess() 函数的地址,CPU接着去执行NewNtOpenProcess ContextRecord->Eip = (ULONG_PTR)NewNtOpenProcess; //返回TRUE,异常不再进行派发 return 1; } return 0; }
NewNtOpenProcess只是简单地调用FilterNtOpenProcess进行简单的调用,打印一些基本的信息。
void __declspec(naked) NewNtOpenProcess() { __asm { pushad pushfd call FilterNtOpenProcess popfd popad mov edi , edi push esp mov ebp , esp //跳过NtOpenProcess的前五个字节, //避免再次触发异常 jmp g_JmpOrigNtOpenProcess } }
完整的工程代码
#ifndef CXX_DRXHOOK_H #define CXX_DRXHOOK_H #include <ntifs.h> #include <devioctl.h> #endif typedef struct _SYSTEM_SERVICE_TABLE32 { ULONG_PTR* ServiceTableBase; ULONG_PTR* ServiceCounterTableBase; ULONG32 NumberOfServices; ULONG_PTR* ParamTableBase; } SYSTEM_SERVICE_TABLE32, *PSYSTEM_SERVICE_TABLE32; typedef struct _SYSTEM_SERVICE_TABLE64{ ULONG_PTR* ServiceTableBase; ULONG_PTR* ServiceCounterTableBase; ULONG64 NumberOfServices; ULONG_PTR* ParamTableBase; } SYSTEM_SERVICE_TABLE64, *PSYSTEM_SERVICE_TABLE64; #ifndef _WIN64 #define _SYSTEM_SERVICE_TABLE _SYSTEM_SERVICE_TABLE64 #define SYSTEM_SERVICE_TABLE SYSTEM_SERVICE_TABLE64 #define PSYSTEM_SERVICE_TABLE PSYSTEM_SERVICE_TABLE64 #else #define _SYSTEM_SERVICE_TABLE _SYSTEM_SERVICE_TABLE32 #define SYSTEM_SERVICE_TABLE SYSTEM_SERVICE_TABLE32 #define PSYSTEM_SERVICE_TABLE PSYSTEM_SERVICE_TABLE32 #endif __declspec(dllimport) SYSTEM_SERVICE_TABLE KeServiceDescriptorTable; //结构声明 typedef struct _SIGNATURE_INFO{ UCHAR cSingature; int Offset; }SIGNATURE_INFO,*PSIGNATURE_INFO; typedef struct _LDR_DATA_TABLE_ENTRY // 24 elements, 0x78 bytes (sizeof) { /*0x000*/ struct _LIST_ENTRY InLoadOrderLinks; // 2 elements, 0x8 bytes (sizeof) /*0x008*/ PVOID ExceptionTable; /*0x00C*/ ULONG ExceptionTableSize; /*0x010*/ struct _LIST_ENTRY InInitializationOrderLinks; // 2 elements, 0x8 bytes (sizeof) /*0x018*/ VOID* DllBase; /*0x01C*/ VOID* EntryPoint; /*0x020*/ ULONG32 SizeOfImage; /*0x024*/ struct _UNICODE_STRING FullDllName; // 3 elements, 0x8 bytes (sizeof) /*0x02C*/ struct _UNICODE_STRING BaseDllName; // 3 elements, 0x8 bytes (sizeof) /*0x034*/ ULONG32 Flags; /*0x038*/ UINT16 LoadCount; /*0x03A*/ UINT16 TlsIndex; union // 2 elements, 0x8 bytes (sizeof) { /*0x03C*/ struct _LIST_ENTRY HashLinks; // 2 elements, 0x8 bytes (sizeof) struct // 2 elements, 0x8 bytes (sizeof) { /*0x03C*/ VOID* SectionPointer; /*0x040*/ ULONG32 CheckSum; }; }; union // 2 elements, 0x4 bytes (sizeof) { /*0x044*/ ULONG32 TimeDateStamp; /*0x044*/ VOID* LoadedImports; }; /*0x048*/ VOID* EntryPointActivationContext; /*0x04C*/ VOID* PatchInformation; /*0x050*/ struct _LIST_ENTRY ForwarderLinks; // 2 elements, 0x8 bytes (sizeof) /*0x058*/ struct _LIST_ENTRY ServiceTagLinks; // 2 elements, 0x8 bytes (sizeof) /*0x060*/ struct _LIST_ENTRY StaticLinks; // 2 elements, 0x8 bytes (sizeof) /*0x068*/ VOID* ContextInformation; /*0x06C*/ ULONG32 OriginalBase; /*0x070*/ union _LARGE_INTEGER LoadTime; // 4 elements, 0x8 bytes (sizeof) }LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY; ULONG_PTR _stdcall FilterRtlDispatchException ( IN PEXCEPTION_RECORD ExceptionRecord, IN PCONTEXT ContextRecord ); VOID HookRtlDispatchException(); VOID UnloadDriver(PDRIVER_OBJECT DriverObject); PLDR_DATA_TABLE_ENTRY SearchDriver(PDRIVER_OBJECT pDriverObject,wchar_t *strDriverName); BOOLEAN Jmp_HookFunction(IN ULONG Destination,IN ULONG Source,IN UCHAR *Ori_Code); VOID ResumeHookFunction(IN ULONG Destination,IN UCHAR *Ori_Code,IN ULONG Length); ULONG_PTR SearchAddressForSignFromPE(ULONG_PTR uStartBase, ULONG_PTR uSearchLength, SIGNATURE_INFO SignatureInfo[5]); VOID WPOFF(); NTSTATUS _stdcall FilterNtOpenProcess (); VOID WPON(); VOID SetMonitor(PVOID Address); VOID CancelMonitor(PVOID Address); #ifndef CXX_DRXHOOK_H # include "DrxHook.h" #endif #include <ntimage.h> KIRQL Irql; PDRIVER_OBJECT g_LocalDriverObj; BOOLEAN g_bHookSuccess; ULONG_PTR g_RtlDispatchExeceptionAddress; ULONG_PTR g_JmpOrigDispatchException; UCHAR g_cDisExceptionCode[5]; ULONG_PTR g_JmpOrigNtOpenProcess; void __declspec(naked) NewNtOpenProcess() { __asm { pushad pushfd call FilterNtOpenProcess popfd popad mov edi , edi push esp mov ebp , esp //跳过NtOpenProcess的前五个字节, //避免再次触发异常 jmp g_JmpOrigNtOpenProcess } } void __declspec(naked) NewRtlDispatchException() { __asm { mov edi,edi push ebp mov ebp , esp pushad //保存所有寄存器 pushfd //保存标志寄存器 push [ebp+0xc] push [ebp+0x8] call FilterRtlDispatchException //检测返回值是否为0 test eax , eax jz __SafeExit // 若eax为0 跳转__SafeExit popfd popad mov esp , ebp pop ebp // 将KiDispatchException中对于RtlDispatchException的返回值进行校验, // 如果为0 则对异常进行重新派发,为1则不再做处理 mov eax ,0x01 retn 0x8 //平衡堆栈,两个参数8字节 __SafeExit: popfd popad mov esp , ebp pop ebp //先执行RtlDispatchException原来的5个字节的内容 mov edi , edi push ebp mov ebp , esp jmp g_JmpOrigDispatchException } } NTSTATUS _stdcall FilterNtOpenProcess () { DbgPrint("FilterNtOpenProcess---%s\r\n",(ULONG_PTR)PsGetCurrentProcess()+0x16c); return STATUS_SUCCESS; } ULONG_PTR _stdcall FilterRtlDispatchException ( IN PEXCEPTION_RECORD ExceptionRecord, IN PCONTEXT ContextRecord ) { //DbgPrint("Address:%x -- ExceptionCode:%x\r\n",ExceptionRecord->ExceptionAddress,ExceptionRecord->ExceptionCode); //如果是NtOpenProcess处的异常 if (ExceptionRecord->ExceptionAddress == (PVOID)KeServiceDescriptorTable.ServiceTableBase[190]) { KdPrint(("<Except addresss>:%X <seh callBack>:%X -- <Except code>:%X", ContextRecord->Eip,ExceptionRecord->ExceptionAddress,ExceptionRecord->ExceptionCode)); //将执行的下一条指令置为NewNtOpenProcess() 函数的地址,CPU接着去执行NewNtOpenProcess ContextRecord->Eip = (ULONG_PTR)NewNtOpenProcess; //返回TRUE,异常不再进行派发 return 1; } return 0; } VOID SetMonitor(PVOID Address) { __asm { mov eax , Address mov DR0 , eax mov eax , 0x02 //全局的,仅当执行时产生异常 mov DR7 , eax } } VOID CancelMonitor(PVOID Address) { __asm { xor eax , eax mov DR0 , eax mov DR7 , eax } } NTSTATUS DriverEntry(IN PDRIVER_OBJECT pDriverObject, IN PUNICODE_STRING RegistryString) { NTSTATUS Status = STATUS_SUCCESS; g_LocalDriverObj = pDriverObject; HookRtlDispatchException(); g_JmpOrigNtOpenProcess = (ULONG_PTR)(KeServiceDescriptorTable.ServiceTableBase[190] + 0x5); //为了方便,这里写死了,NtOpenProcess Win7 x86 SetMonitor((PVOID)KeServiceDescriptorTable.ServiceTableBase[190]); return Status; } VOID HookRtlDispatchException() { PLDR_DATA_TABLE_ENTRY Ldr = NULL; //构建RtlDispatchException 的特征码 // nt!KiDispatchException+0x160: // 83eff040 53 push ebx // 83eff041 ff750c push dword ptr [ebp+0Ch] // 83eff044 ff7510 push dword ptr [ebp+10h] // 83eff047 ff15bc49fb83 call dword ptr [nt!KiDebugRoutine (83fb49bc)] // 83eff04d 84c0 test al,al // 83eff04f 0f859d000000 jne nt!KiDispatchException+0x211 (83eff0f2) // 83eff055 57 push edi // 83eff056 53 push ebx // 83eff057 e8 a372ffff call nt!RtlDispatchException (83ef62ff) // kd> u 83ef62ff // nt!RtlDispatchException: // 83ef62ff 8bff mov edi,edi // 83ef6301 55 push ebp // 83ef6302 8bec mov ebp,esp // 83ef6304 83e4f8 and esp,0FFFFFFF8h // 83ef6307 83ec6c sub esp,6Ch // 83ef630a 53 push ebx // 83ef630b 56 push esi // 83ef630c 57 push edi SIGNATURE_INFO SignCode[] = {{0x84,10},{0xc0,9},{0x57,2},{0x53,1},{0xE8,0}}; #ifndef _DEBUG __asm int 3 #endif g_bHookSuccess = FALSE; Ldr = SearchDriver(g_LocalDriverObj,L"ntoskrnl.exe"); if (!Ldr) return; g_RtlDispatchExeceptionAddress = SearchAddressForSignFromPE((ULONG_PTR)(Ldr->DllBase),Ldr->SizeOfImage,SignCode); if (!MmIsAddressValid((PVOID)g_RtlDispatchExeceptionAddress)) return; //利用偏移转成绝对地址 +5 过e8 a372ffff 这五个字节 g_RtlDispatchExeceptionAddress = g_RtlDispatchExeceptionAddress+5 + *(ULONG_PTR*)(g_RtlDispatchExeceptionAddress+1); //过被占的前5个字节,继续执行的代码 DbgPrint("RtlDispatchExceptionAddresss:%x",g_RtlDispatchExeceptionAddress); g_JmpOrigDispatchException = g_RtlDispatchExeceptionAddress + 5; g_bHookSuccess = Jmp_HookFunction(g_RtlDispatchExeceptionAddress,(ULONG_PTR)NewRtlDispatchException,g_cDisExceptionCode); } //搜索整个PE文件的 ULONG_PTR SearchAddressForSignFromPE(ULONG_PTR uStartBase,ULONG_PTR uSearchLength,SIGNATURE_INFO SignatureInfo[5]) { UCHAR *p; ULONG_PTR u_index1,u_index2; //ULONG uIndex; PIMAGE_DOS_HEADER pimage_dos_header; PIMAGE_NT_HEADERS pimage_nt_header; PIMAGE_SECTION_HEADER pimage_section_header; if(!MmIsAddressValid((PVOID)uStartBase)) { return 0; } pimage_dos_header = (PIMAGE_DOS_HEADER)uStartBase; pimage_nt_header = (PIMAGE_NT_HEADERS)((ULONG)uStartBase+pimage_dos_header->e_lfanew); pimage_section_header = (PIMAGE_SECTION_HEADER)((ULONG)pimage_nt_header+sizeof(IMAGE_NT_HEADERS)); for (u_index1 = 0;u_index1<pimage_nt_header->FileHeader.NumberOfSections;u_index1++) { //#define IMAGE_SCN_MEM_EXECUTE 0x20000000 // Section is executable. //#define IMAGE_SCN_MEM_READ 0x40000000 // Section is readable. //#define IMAGE_SCN_MEM_WRITE 0x80000000 // Section is writeable. //0x60000000 = IMAGE_SCN_MEM_EXECUTE|IMAGE_SCN_MEM_READ if (pimage_section_header[u_index1].Characteristics&0x60000000) { p = (UCHAR*)uStartBase + pimage_section_header[u_index1].VirtualAddress; for (u_index2 = 0;u_index2<pimage_section_header[u_index1].Misc.VirtualSize;u_index2++) { if (!MmIsAddressValid((p-SignatureInfo[0].Offset))|| !MmIsAddressValid((p-SignatureInfo[4].Offset))) { p++; continue; } __try{ if (*(p-SignatureInfo[0].Offset)==SignatureInfo[0].cSingature&& *(p-SignatureInfo[1].Offset)==SignatureInfo[1].cSingature&& *(p-SignatureInfo[2].Offset)==SignatureInfo[2].cSingature&& *(p-SignatureInfo[3].Offset)==SignatureInfo[3].cSingature&& *(p-SignatureInfo[4].Offset)==SignatureInfo[4].cSingature) { return (ULONG_PTR)p; } }__except(EXCEPTION_EXECUTE_HANDLER){ DbgPrint("Search error!"); } p++; } } } return 0; } BOOLEAN Jmp_HookFunction( IN ULONG Destination, IN ULONG Source, IN UCHAR *Ori_Code ) { ULONG jmp_offset; UCHAR jmp_code[5] = {0xE9}; KSPIN_LOCK lock; KIRQL irql; if (Destination==0||Source==0) { DbgPrint("Params error!"); return FALSE; } RtlCopyMemory(Ori_Code,(PVOID)Destination,5); jmp_offset = Source - (Destination+5); *(ULONG*)&jmp_code[1] = jmp_offset; //放入偏移 KeInitializeSpinLock (&lock ); KeAcquireSpinLock(&lock,&irql); WPOFF(); RtlCopyMemory((PVOID)Destination,jmp_code,5); WPON(); KeReleaseSpinLock (&lock,irql); return TRUE; } VOID WPOFF() { ULONG_PTR cr0 = 0; Irql = KeRaiseIrqlToDpcLevel(); cr0 =__readcr0(); cr0 &= 0xfffffffffffeffff; __writecr0(cr0); } VOID WPON() { ULONG_PTR cr0=__readcr0(); cr0 |= 0x10000; __writecr0(cr0); KeLowerIrql(Irql); } //简单的通过链表获得内核模块的基本信息 PLDR_DATA_TABLE_ENTRY SearchDriver(PDRIVER_OBJECT pDriverObject,wchar_t *strDriverName) { LDR_DATA_TABLE_ENTRY *pdata_table_entry,*ptemp_data_table_entry; PLIST_ENTRY plist; UNICODE_STRING str_module_name; RtlInitUnicodeString(&str_module_name,strDriverName); pdata_table_entry = (LDR_DATA_TABLE_ENTRY*)pDriverObject->DriverSection; if (!pdata_table_entry) { return 0; } plist = pdata_table_entry->InLoadOrderLinks.Flink; while(plist!= &pdata_table_entry->InLoadOrderLinks) { ptemp_data_table_entry = (LDR_DATA_TABLE_ENTRY *)plist; //DbgPrint("%wZ",&pTempDataTableEntry->BaseDllName); if (0==RtlCompareUnicodeString(&ptemp_data_table_entry->BaseDllName,&str_module_name,FALSE)) { return ptemp_data_table_entry; } plist = plist->Flink; } return 0; } VOID UnloadDriver(PDRIVER_OBJECT DriverObject) { if (g_bHookSuccess) { ResumeHookFunction(g_RtlDispatchExeceptionAddress,g_cDisExceptionCode,0x5); } } VOID ResumeHookFunction( IN ULONG Destination, IN UCHAR *Ori_Code, IN ULONG Length ) { KSPIN_LOCK lock; KIRQL irql; if (Destination==0||Ori_Code==0) return; KeInitializeSpinLock (&lock ); KeAcquireSpinLock(&lock,&irql); WPOFF(); RtlCopyMemory((PVOID)Destination,Ori_Code,Length); WPON(); KeReleaseSpinLock (&lock,irql); }