硬件断点 DrxHook

时间:2021-12-22 11:17:46

硬件断点 DrxHook

硬件断点的实现需要依赖于调试寄存器

DR0~DR7  调试寄存器

DR0~DR3-----调试地址寄存器
DR4~DR5-----保留
DR6 -----调试状态寄存器 指示哪个调试寄存器被命中
DR7 -----调试控制寄存器

硬件断点 DrxHook

关于Dr7寄存器每个标志位的解释:

硬件断点 DrxHook

总结如下

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来读写线程的上下文,来达到设置硬件断点的目的,如果想对某个进程设置硬件断点,就需要对它的每个线程都调用SetThreadContext()函数,设置Drx寄存器的值。

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函数

硬件断点 DrxHook
NTSTATUS
PsSetContextThread(
__in PETHREAD Thread,
__in PCONTEXT ThreadContext,
__in KPROCESSOR_MODE Mode
) NTSTATUS
PsGetContextThread(
__in PETHREAD Thread,
__inout PCONTEXT ThreadContext,
__in KPROCESSOR_MODE Mode
)
硬件断点 DrxHook

我们可以对PsGet/SetContextTread函数Hook来达到对设置硬件断点的一个过滤,对于目标进程获取或者设置线程的Context进行处理。

硬件断点 DrxHook
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;
}
}
硬件断点 DrxHook
硬件断点 DrxHook
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[];
BOOLEAN g_bHookGetContextSuccess;
ULONG g_JmpSetContextThread;
UCHAR g_cSetContextCode[];
BOOLEAN g_bHookSetContextSuccess; char* GetProcessNameByThread(PETHREAD Thread)
{
ULONG ProcessObj;
if (MmIsAddressValid(Thread))
{
ProcessObj = *(ULONG*)((ULONG)Thread + 0x150);
return (char*)(ProcessObj+0x16C);
}
return ;
} 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[] = {0xE9}; KSPIN_LOCK lock;
KIRQL irql; if (Destination==||Source==)
{
DbgPrint("Params error!");
return FALSE;
}
RtlCopyMemory(Ori_Code,(PVOID)Destination,);
Jmp_Offest = Source - Destination-;
*(ULONG*)&Jmp_Code[] = Jmp_Offest; KeInitializeSpinLock (&lock );
KeAcquireSpinLock(&lock,&irql); PageProtectOff();
RtlCopyMemory((PVOID)Destination,Jmp_Code,);
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==||Ori_Code==){ 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 == ) || (Alignment == ) ||
(Alignment == ) || (Alignment == ) ||
(Alignment == )); if ((Size == ) || (Size >= 0x10000)) { ASSERT(); ProbeForRead(Address, Size, Alignment); } else {
if (((ULONG_PTR)Address & (Alignment - )) != ) {
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,);
} if (g_bHookSetContextSuccess)
{
Res_HookFunction((ULONG)PsSetContextThread,g_cSetContextCode,);
}
} 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;
}
硬件断点 DrxHook

在ring0可以直接改变Drx寄存器的值,设置硬件断点来达到对某个函数的hook,这里以NtOpenProcess为例。我们知道内核层产生的异常都会由RtlDispatchException函数进行分发处理,所以我们首先要InlineHook RtlDispatchException函数,在对异常进行分发时先对异常进行过滤,如果异常地址是我们设置的硬件断点“监控”的地址,则改变EIP,达到对目标函数“hook”的目的。

先InlineHook RtlDispatchException ,RtlDispatchException未导出,在KiDispatchException中被调用,KiDispatchException也未导出,采用的方法是暴力搜索整个内核文件Ntoskrnl.exe来匹配特征码

硬件断点 DrxHook
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,},{0xc0,},{0x57,},{0x53,},{0xE8,}};
#ifndef _DEBUG
__asm int
#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+ + *(ULONG_PTR*)(g_RtlDispatchExeceptionAddress+);
//过被占的前5个字节,继续执行的代码
DbgPrint("RtlDispatchExceptionAddresss:%x",g_RtlDispatchExeceptionAddress);
g_JmpOrigDispatchException = g_RtlDispatchExeceptionAddress + ;
g_bHookSuccess = Jmp_HookFunction(g_RtlDispatchExeceptionAddress,(ULONG_PTR)NewRtlDispatchException,g_cDisExceptionCode);
}
硬件断点 DrxHook

然后将要“监控”的目标地址写入Dr0寄存器,当目标地址被执行的时候,触发异常,执行RtlDispatchException函数,

硬件断点 DrxHook
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
}
}
硬件断点 DrxHook

RtlDispatchException的过滤函数,在这里改变Eip的值,异常处理完毕以后,开始执行NewNtOpenProcess

硬件断点 DrxHook
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[])
{
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 ;
}
return ;
}
硬件断点 DrxHook

NewNtOpenProcess只是简单地调用FilterNtOpenProcess进行简单的调用,打印一些基本的信息。

硬件断点 DrxHook
void __declspec(naked)  NewNtOpenProcess()
{ __asm
{
pushad
pushfd call FilterNtOpenProcess popfd
popad mov edi , edi
push esp
mov ebp , esp
//跳过NtOpenProcess的前五个字节,
//避免再次触发异常
jmp g_JmpOrigNtOpenProcess
}
}
硬件断点 DrxHook

完整的工程代码

硬件断点 DrxHook
#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[]);
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[]; 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[])
{
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 ;
}
return ;
}
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[] + 0x5);
//为了方便,这里写死了,NtOpenProcess Win7 x86
SetMonitor((PVOID)KeServiceDescriptorTable.ServiceTableBase[]);
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,},{0xc0,},{0x57,},{0x53,},{0xE8,}};
#ifndef _DEBUG
__asm int
#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+ + *(ULONG_PTR*)(g_RtlDispatchExeceptionAddress+);
//过被占的前5个字节,继续执行的代码
DbgPrint("RtlDispatchExceptionAddresss:%x",g_RtlDispatchExeceptionAddress);
g_JmpOrigDispatchException = g_RtlDispatchExeceptionAddress + ;
g_bHookSuccess = Jmp_HookFunction(g_RtlDispatchExeceptionAddress,(ULONG_PTR)NewRtlDispatchException,g_cDisExceptionCode);
} //搜索整个PE文件的
ULONG_PTR SearchAddressForSignFromPE(ULONG_PTR uStartBase,ULONG_PTR uSearchLength,SIGNATURE_INFO SignatureInfo[])
{
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 ; } 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 = ;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 = ;u_index2<pimage_section_header[u_index1].Misc.VirtualSize;u_index2++)
{
if (!MmIsAddressValid((p-SignatureInfo[].Offset))||
!MmIsAddressValid((p-SignatureInfo[].Offset)))
{
p++;
continue;
}
__try{
if (*(p-SignatureInfo[].Offset)==SignatureInfo[].cSingature&&
*(p-SignatureInfo[].Offset)==SignatureInfo[].cSingature&&
*(p-SignatureInfo[].Offset)==SignatureInfo[].cSingature&&
*(p-SignatureInfo[].Offset)==SignatureInfo[].cSingature&&
*(p-SignatureInfo[].Offset)==SignatureInfo[].cSingature)
{
return (ULONG_PTR)p;
} }__except(EXCEPTION_EXECUTE_HANDLER){
DbgPrint("Search error!");
}
p++;
}
}
} return ;
} BOOLEAN Jmp_HookFunction(
IN ULONG Destination,
IN ULONG Source,
IN UCHAR *Ori_Code
)
{
ULONG jmp_offset;
UCHAR jmp_code[] = {0xE9}; KSPIN_LOCK lock;
KIRQL irql; if (Destination==||Source==)
{
DbgPrint("Params error!");
return FALSE;
} RtlCopyMemory(Ori_Code,(PVOID)Destination,);
jmp_offset = Source - (Destination+); *(ULONG*)&jmp_code[] = jmp_offset; //放入偏移 KeInitializeSpinLock (&lock );
KeAcquireSpinLock(&lock,&irql); WPOFF();
RtlCopyMemory((PVOID)Destination,jmp_code,);
WPON(); KeReleaseSpinLock (&lock,irql); return TRUE;
} VOID WPOFF()
{
ULONG_PTR cr0 = ;
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 ;
}
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 (==RtlCompareUnicodeString(&ptemp_data_table_entry->BaseDllName,&str_module_name,FALSE))
{
return ptemp_data_table_entry;
} plist = plist->Flink;
} return ;
} 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==||Ori_Code==) return; KeInitializeSpinLock (&lock );
KeAcquireSpinLock(&lock,&irql); WPOFF();
RtlCopyMemory((PVOID)Destination,Ori_Code,Length);
WPON(); KeReleaseSpinLock (&lock,irql);
}
硬件断点 DrxHook

jpg改rar

 硬件断点 DrxHook