硬件断点 DrxHook

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

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

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[];
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;
}

在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,},{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);
}

然后将要“监控”的目标地址写入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[])
{
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 ;
}

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[]);
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);
}

jpg改rar

 
 
 

硬件断点 DrxHook的更多相关文章

  1. ring3硬件断点

    4个断点寄存器DR0~DR3用来设置断点的线性地址. DR6为状态寄存器,DR7为控制寄存器. DR4和DR5保留.当CR4.DE==1时,访问DR4和DR5产生#UD异常:IF CR4.DE==0, ...

  2. windbg-bp、 bm、 bu、 bl、 bc、 ba(断点、硬件断点)

    bp bp 命令是在某个地址下断点, 可以 bp 0x7783FEB 也可以 bp MyApp!SomeFunction . 对于后者,WinDBG 会自动找到MyApp!SomeFunction 对 ...

  3. Xcode中使用数据(硬件)断点调试

    大熊猫猪·侯佩原创或翻译作品.欢迎转载,转载请注明出处. 如果觉得写的不好请多提意见,如果觉得不错请多多支持点赞.谢谢! hopy ;) 在Xcode的GUI界面中只能添加软断点,而无法增加硬断点.但 ...

  4. Ollydbg中的内存断点和硬件断点的区别

    转载自: https://www.zhihu.com/question/52625624 旅人的回复 作者:旅人链接:https://www.zhihu.com/question/52625624/a ...

  5. Jlink 软件断点和硬件断点

    调试2440 RAM拷贝至SDRAM遇到的问题 汇编代码主要是初始化一些寄存器,关狗,初始化时钟,初始化存储管理器以便访问内存,然后将SoC上4k RAM数据拷贝至SDRAM,然后在SRAM里面运行, ...

  6. 为什么NtReadVirtualMemory 硬件断点无法下断

    win7 x64为例 nt!NtReadVirtualMemory ----- nt!MmCopyVirtualMemory NTSTATUS NTAPI MmCopyVirtualMemory(IN ...

  7. X86逆向10:学会使用硬件断点

    本节课我们将学习硬件断点的使用技巧,硬件断点是由硬件提供给我们的一组寄存器,我们可以对这些硬件寄存器设置相应的值,然后让硬件帮我们断在需要下断点的地址上面,这就是硬件断点,硬件断点依赖于寄存器,这些寄 ...

  8. Windows硬件断点-实现单步异常

    触犯单步异常 改变的是当前Eflags 而不是触发异常的Eflags 也就是 PUSHF MOV EAX, DWORD PTR[ESP]       OR EAX, 0x100       MOV D ...

  9. 认识OD的两种断点

    OllyDBG从原理上来区分,有两种不同的断点:软件断点和硬件断点. 也许会有朋友说那不是还有内存断点吗? 内存断点严格来说是属于一种特殊的软件断点. 内存断点: 内存断点每次只能设置一个,假如你设置 ...

随机推荐

  1. MySQL Plugin 'InnoDB' init function returned error

    . . 在MySQL的配置文件中,设定default-table-type=InnoDB,发现MySQL无法正常的启动,错误日志中给出了如下的信息: 150210 18:11:19 mysqld_sa ...

  2. DataTemplate应用

    在WPF中,决定数据外观的是DataTemplate,即DataTemplate是数据内容的表现形式,一条数据显示成什么样子,是简单的文本还是直观的图形,就是由DataTemplate决定的.下面通过 ...

  3. ACM/ICPC 之 SPFA范例两道(POJ3268-POJ3259)

    两道以SPFA算法求解的最短路问题,比较水,第二题需要掌握如何判断负权值回路. POJ3268-Silver Cow Party //计算正逆最短路径之和的最大值 //Time:32Ms Memory ...

  4. Effective C++ -----条款38:通过复合塑模出has-a或“根据某物实现出”

    复合(composition)的意义和public继承完全不同. 在应用域(application domain),复合意味has-a(有一个).在实现域(implementation domain) ...

  5. nyoj133_子序列_离散化_尺取法

    子序列 时间限制:3000 ms  |  内存限制:65535 KB 难度:5   描述 给定一个序列,请你求出该序列的一个连续的子序列,使原串中出现的所有元素皆在该子序列中出现过至少1次. 如2 8 ...

  6. 微信video标签全屏无法退出bug 本文系转载

    安卓(android)微信里面video播放视频,会被强制全屏,播放完毕后还有腾讯推荐的视频,非常讨厌..强制被全屏无法解决,但是视频播放完毕后退出播放器可以解决.方法就是视频播放完毕后,用音频aud ...

  7. (转)JAVA AJAX教程第三章—AJAX详细讲解

    现在开始深入AJAX,这里还是按老思路,理论和实践相结合.这章的内容主要是讲解AJAX步骤详解,下一张将会用一个AJAX技术实现页面提示效果的实例来说明AJAX的实现. 一.AJAX步骤详解 AJAX ...

  8. IIS 4.0配置

    neHandler”   今天安装了windows7 开发web项目需要安装IIS,当安装完以后,web程序已经映射到了本地IIS上,运行出现如下错误提示 处理程序“PageHandlerFactor ...

  9. 【leetcode】Best Time to Buy and Sell 2(too easy)

    Say you have an array for which the ith element is the price of a given stock on day i. Design an al ...

  10. 用css解决iframe的自适应问题(跨域下同样有用)

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xht ...