zoukankan      html  css  js  c++  java
  • 硬件断点 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[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
    ",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
    ",(ULONG_PTR)PsGetCurrentProcess()+0x16c);
        return  STATUS_SUCCESS;
    }
    
    
    
    ULONG_PTR _stdcall
        FilterRtlDispatchException (
        IN PEXCEPTION_RECORD ExceptionRecord,
        IN PCONTEXT ContextRecord
        )
    {
    
        //DbgPrint("Address:%x -- ExceptionCode:%x
    ",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);
    }
  • 相关阅读:
    Combining STDP and binary networks for reinforcement learning from images and sparse rewards
    R-SNN: An Analysis and Design Methodology for Robustifying Spiking Neural Networks against Adversarial Attacks through Noise Filters for Dynamic Vision Sensors
    rust 高阶函数 (high order function)
    Redis从0到精通--三种特殊类型Hyperloglog
    Redis从0到精通--三种特殊类型Geospatial
    Redis从0到精通--三种特殊类型
    Redis从0到精通--Zset
    Redis从0到精通--Set
    Redis从0到精通--Hash
    Redis从0到精通--List
  • 原文地址:https://www.cnblogs.com/lanrenxinxin/p/4680320.html
Copyright © 2011-2022 走看看