IDT系統中斷描述表以及繞過Xurtr檢測的HOOK姿式

 什麼是中斷?數組

 指當出現須要時,CPU暫時中止當前程序的執行轉而執行處理新狀況的程序和執行過程。即在程序運行過程當中,系統出現了一個必須由CPU當即處理的狀況,此時,CPU暫時停止程序的執行轉而處理這個新的狀況的過程就叫作中斷。數據結構

 好比:除零(0號中斷)、斷點(3號中斷)、系統調用(2e號中斷)、以及異常處理等都會引起中斷,因此天然須要相應的中斷例程去進行處理。ide

 這樣操做系統就會用數據結構來維護這些中斷例程,這個數據結構就是IDT(Interrupt Descriptor Table)。函數

 

 中斷描述表佈局

 

 IDT表的長度與地址是由CPU的IDTR寄存器來描述的。IDTR寄存器共有48位,高32位是IDT表的基地址,低16位是IDT的長度。測試

 

typedef struct _IDTR{
    USHORT   IDT_limit;
    USHORT   IDT_LOWbase;
    USHORT   IDT_HIGbase;
}IDTR,*PIDTR;


IDTR        idtr;

__asm    SIDT    idtr;

 能夠經過以上SIDT指令能夠讀取IDTR寄存器。而後經過MAKEWORD宏把高位與地位組合起來就能夠得到IDT表的基地址了。ui

 

 簡單來講,IDT表是一張位於物理內存的線性表,共有256個表項。在32位模式下,每一個IDT表項的長度是8個字節(64 bit),IDT表的總長度是2048字節。編碼

 

kd> r idtr
idtr=8003f400
kd> r idtl
idtl=000007ff

 經過Windbg命令 r idtr、r idtl能夠讀取IDT表的基地址與邊界。spa

 

  如圖能夠清晰的看見每個表項了,但是每個表項8字節都表明什麼意思呢?操作系統

  IDT表中每一項也稱爲「門描述符」,之因此這樣稱呼,是由於IDT表項的基本用途就是引領CPU從一個空間到另外一個空間去執行,每一個表項好像是一個空間到另外一個空間的大門。

  IDT表中能夠包含如下3種門描述符:

  任務門描述符:用於任務切換,裏面包含用於選擇任務狀態段(TSS)的段選擇子。可使用JMP或CALL指令經過任務門來切換到任務門所指向的任務,當CPU由於中斷或異常轉移到任務門時,也會切換到指定任務。

  中斷門描述符:用於描述中斷例程的入口。

  陷阱門描述符:用於描述異常處理例程的入口。

  如下爲三種門描述符的內存佈局:

  

      結構體定義爲

typedef struct _IDTENTRY
{
    unsigned short LowOffset;
    unsigned short selector;
    unsigned char retention:5;
    unsigned char zero1:3;
    unsigned char gate_type:1;
    unsigned char zero2:1;
    unsigned char interrupt_gate_size:1;
    unsigned char zero3:1;
    unsigned char zero4:1;
    unsigned char DPL:2;
    unsigned char P:1;
    unsigned short HiOffset;
} IDTENTRY,*PIDTENTRY;

 

  其中DPL表明描述符優先級,用於優先級控制,P是段存在標誌,段選擇子用來選擇一個段描述符(LDT或GDT)偏移部分用來指定段中偏移。二者共同準確的定義一個內存地址,對於中斷門和陷阱門,他們指定的就是中斷或異常處理例程的地址,對於任務門它們指定的就是任務狀態段地址。

  也就是說段選擇子提供一個所謂的段基地址,那麼處理例程 = 段基址 + 段偏移。

  那麼HOOK方式就有兩種了:更改段偏移或者更改段基址。

  咱們先忽略段選擇子提供的段基址,先簡單的認爲門描述符提供的高16位和低16位的段內偏移就是該中斷的處理例程(其實原本就是,由於32位操做系統中,已經弱化了段基址的概念,運用了平坦模型,也就是說段基址就是0)。

  而後咱們看看HOOK代碼:

  

#ifndef CXX_IDTHOOK_H
#    include "IDTHook.h"
#endif

#define WORD  USHORT
#define DWORD ULONG

ULONG g_InterruptFun = 0;

#define MAKELONG(a, b)      ((LONG)(((WORD)(((DWORD_PTR)(a)) & 0xffff)) \
                            | ((DWORD)((WORD)(((DWORD_PTR)(b)) & 0xffff))) << 16))

NTKERNELAPI VOID KeSetSystemAffinityThread ( KAFFINITY Affinity );  
NTKERNELAPI VOID KeRevertToUserAffinityThread ( VOID );  



PULONG GetKiProcessorBlock()
{
    ULONG* KiProcessorBlock = 0;

    KeSetSystemAffinityThread(1); //使當前線程運行在第一個處理器上  

    _asm
    {
        push eax
        mov  eax,FS:[0x34]
        add  eax,20h
        mov  eax,[eax]
        mov  eax,[eax]
        mov  eax,[eax+218h]
        mov  KiProcessorBlock,eax
        pop  eax
    }

    KeRevertToUserAffinityThread();

    return KiProcessorBlock ; 

}
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
    }
}


void _stdcall FilterInterruptFun()
{
    DbgPrint("CurrentProcess : %s",(char*)PsGetCurrentProcess()+0x174);
}

_declspec(naked)
void Fake_InterruptFun()
{
    _asm{
        pushad
        pushfd

        push fs
        push 0x30
        pop  fs
        
        call FilterInterruptFun;
        pop  fs

        popfd
        popad

        jmp g_InterruptFun
    }
};

NTSTATUS
DriverEntry(IN PDRIVER_OBJECT pDriverObj, IN PUNICODE_STRING pRegistryString)
{
    IDTR        Idtr;
    PIDTENTRY   pIdtEntry;
    ULONG       ulIndex = 0 ;
    ULONG*      KiProcessorBlock;
    
    pDriverObj->DriverUnload = DriverUnload;

    KiProcessorBlock = GetKiProcessorBlock();

    DbgPrint("%X\r\n",KiProcessorBlock);

    while (KiProcessorBlock[ulIndex])
    {
        pIdtEntry = *(PIDTENTRY*)(KiProcessorBlock[ulIndex] - 0x120 + 0x38) ;

        DbgPrint("IDT Base:%X\r\n",pIdtEntry);

        g_InterruptFun = MAKELONG(pIdtEntry[3].LowOffset,pIdtEntry[3].HiOffset);

        DbgPrint("InterruptFun3:%X\r\n",g_InterruptFun);

         PageProtectOff();
        pIdtEntry[3].LowOffset = (unsigned short)((ULONG)Fake_InterruptFun & 0xffff);
         pIdtEntry[3].HiOffset  = (unsigned short)((ULONG)Fake_InterruptFun >> 16);
         PageProtectOn();

        ulIndex++;
    }


    return STATUS_SUCCESS;
}

VOID
DriverUnload(IN PDRIVER_OBJECT pDriverObj)
{    
    
    return;
}

稍微解釋一下,裏面得到IDT表的時候沒有經過寄存器IDTR進行讀取,是由於對於多核CPU來講不必定只有一個IDT表,而經過IDTR來讀取只能讀到一份表,因此HOOK IDT的時候必定要注意多核問題

系統維護了一個全局的處理器數組KiProcessorBlock,其中每一個元素對應於一個處理器的KPRCB 對象。

kd> dt _KPCR
nt!_KPCR
   +0x000 NtTib            : _NT_TIB
   +0x01c SelfPcr          : Ptr32 _KPCR
   +0x020 Prcb             : Ptr32 _KPRCB
   +0x024 Irql             : UChar
   +0x028 IRR              : Uint4B
   +0x02c IrrActive        : Uint4B
   +0x030 IDR              : Uint4B
   +0x034 KdVersionBlock   : Ptr32 Void
   +0x038 IDT              : Ptr32 _KIDTENTRY
   +0x03c GDT              : Ptr32 _KGDTENTRY
   +0x040 TSS              : Ptr32 _KTSS
   +0x044 MajorVersion     : Uint2B
   +0x046 MinorVersion     : Uint2B
   +0x048 SetMember        : Uint4B
   +0x04c StallScaleFactor : Uint4B
   +0x050 DebugActive      : UChar
   +0x051 Number           : UChar
   +0x052 Spare0           : UChar
   +0x053 SecondLevelCacheAssociativity : UChar
   +0x054 VdmAlert         : Uint4B
   +0x058 KernelReserved   : [14] Uint4B
   +0x090 SecondLevelCacheSize : Uint4B
   +0x094 HalReserved      : [16] Uint4B
   +0x0d4 InterruptMode    : Uint4B
   +0x0d8 Spare1           : UChar
   +0x0dc KernelReserved2  : [17] Uint4B
   +0x120 PrcbData         : _KPRCB

在0X120處,有個_KPRCB結構。再來看看這個結構。

kd> dt _KPCR
nt!_KPCR
   +0x000 NtTib            : _NT_TIB
   +0x01c SelfPcr          : Ptr32 _KPCR
   +0x020 Prcb             : Ptr32 _KPRCB
   +0x024 Irql             : UChar
   +0x028 IRR              : Uint4B
   +0x02c IrrActive        : Uint4B
   +0x030 IDR              : Uint4B
   +0x034 KdVersionBlock   : Ptr32 Void
   +0x038 IDT              : Ptr32 _KIDTENTRY
   +0x03c GDT              : Ptr32 _KGDTENTRY
   +0x040 TSS              : Ptr32 _KTSS
   +0x044 MajorVersion     : Uint2B
   +0x046 MinorVersion     : Uint2B
   +0x048 SetMember        : Uint4B
   +0x04c StallScaleFactor : Uint4B
   +0x050 DebugActive      : UChar
   +0x051 Number           : UChar
   +0x052 Spare0           : UChar
   +0x053 SecondLevelCacheAssociativity : UChar
   +0x054 VdmAlert         : Uint4B
   +0x058 KernelReserved   : [14] Uint4B
   +0x090 SecondLevelCacheSize : Uint4B
   +0x094 HalReserved      : [16] Uint4B
   +0x0d4 InterruptMode    : Uint4B
   +0x0d8 Spare1           : UChar
   +0x0dc KernelReserved2  : [17] Uint4B
   +0x120 PrcbData         : _KPRCB
kd> dt _PRCB
Symbol _PRCB not found.
kd> dt _KPRCB
nt!_KPRCB
   +0x000 MinorVersion     : Uint2B
   +0x002 MajorVersion     : Uint2B
   +0x004 CurrentThread    : Ptr32 _KTHREAD
   +0x008 NextThread       : Ptr32 _KTHREAD
   +0x00c IdleThread       : Ptr32 _KTHREAD
   +0x010 Number           : Char
   +0x011 Reserved         : Char
   +0x012 BuildType        : Uint2B
   +0x014 SetMember        : Uint4B
   +0x018 CpuType          : Char
   +0x019 CpuID            : Char
   +0x01a CpuStep          : Uint2B
   +0x01c ProcessorState   : _KPROCESSOR_STATE
   +0x33c KernelReserved   : [16] Uint4B
   +0x37c HalReserved      : [16] Uint4B
   +0x3bc PrcbPad0         : [92] UChar
   +0x418 LockQueue        : [16] _KSPIN_LOCK_QUEUE
   +0x498 PrcbPad1         : [8] UChar
   +0x4a0 NpxThread        : Ptr32 _KTHREAD
   +0x4a4 InterruptCount   : Uint4B
   +0x4a8 KernelTime       : Uint4B
   +0x4ac UserTime         : Uint4B
   +0x4b0 DpcTime          : Uint4B
   +0x4b4 DebugDpcTime     : Uint4B
   +0x4b8 InterruptTime    : Uint4B
   +0x4bc AdjustDpcThreshold : Uint4B
   +0x4c0 PageColor        : Uint4B
   +0x4c4 SkipTick         : Uint4B
   +0x4c8 MultiThreadSetBusy : UChar
   +0x4c9 Spare2           : [3] UChar
   +0x4cc ParentNode       : Ptr32 _KNODE
   +0x4d0 MultiThreadProcessorSet : Uint4B
   +0x4d4 MultiThreadSetMaster : Ptr32 _KPRCB
   +0x4d8 ThreadStartCount : [2] Uint4B
   +0x4e0 CcFastReadNoWait : Uint4B
   +0x4e4 CcFastReadWait   : Uint4B
   +0x4e8 CcFastReadNotPossible : Uint4B
   +0x4ec CcCopyReadNoWait : Uint4B
   +0x4f0 CcCopyReadWait   : Uint4B
   +0x4f4 CcCopyReadNoWaitMiss : Uint4B
   +0x4f8 KeAlignmentFixupCount : Uint4B
   +0x4fc KeContextSwitches : Uint4B
   +0x500 KeDcacheFlushCount : Uint4B
   +0x504 KeExceptionDispatchCount : Uint4B
   +0x508 KeFirstLevelTbFills : Uint4B
   +0x50c KeFloatingEmulationCount : Uint4B
   +0x510 KeIcacheFlushCount : Uint4B
   +0x514 KeSecondLevelTbFills : Uint4B
   +0x518 KeSystemCalls    : Uint4B
   +0x51c SpareCounter0    : [1] Uint4B
   +0x520 PPLookasideList  : [16] _PP_LOOKASIDE_LIST
   +0x5a0 PPNPagedLookasideList : [32] _PP_LOOKASIDE_LIST
   +0x6a0 PPPagedLookasideList : [32] _PP_LOOKASIDE_LIST
   +0x7a0 PacketBarrier    : Uint4B
   +0x7a4 ReverseStall     : Uint4B
   +0x7a8 IpiFrame         : Ptr32 Void
   +0x7ac PrcbPad2         : [52] UChar
   +0x7e0 CurrentPacket    : [3] Ptr32 Void
   +0x7ec TargetSet        : Uint4B
   +0x7f0 WorkerRoutine    : Ptr32     void 
   +0x7f4 IpiFrozen        : Uint4B
   +0x7f8 PrcbPad3         : [40] UChar
   +0x820 RequestSummary   : Uint4B
   +0x824 SignalDone       : Ptr32 _KPRCB
   +0x828 PrcbPad4         : [56] UChar
   +0x860 DpcListHead      : _LIST_ENTRY
   +0x868 DpcStack         : Ptr32 Void
   +0x86c DpcCount         : Uint4B
   +0x870 DpcQueueDepth    : Uint4B
   +0x874 DpcRoutineActive : Uint4B
   +0x878 DpcInterruptRequested : Uint4B
   +0x87c DpcLastCount     : Uint4B
   +0x880 DpcRequestRate   : Uint4B
   +0x884 MaximumDpcQueueDepth : Uint4B
   +0x888 MinimumDpcRate   : Uint4B
   +0x88c QuantumEnd       : Uint4B
   +0x890 PrcbPad5         : [16] UChar
   +0x8a0 DpcLock          : Uint4B
   +0x8a4 PrcbPad6         : [28] UChar
   +0x8c0 CallDpc          : _KDPC
   +0x8e0 ChainedInterruptList : Ptr32 Void
   +0x8e4 LookasideIrpFloat : Int4B
   +0x8e8 SpareFields0     : [6] Uint4B
   +0x900 VendorString     : [13] UChar
   +0x90d InitialApicId    : UChar
   +0x90e LogicalProcessorsPerPhysicalProcessor : UChar
   +0x910 MHz              : Uint4B
   +0x914 FeatureBits      : Uint4B
   +0x918 UpdateSignature  : _LARGE_INTEGER
   +0x920 NpxSaveArea      : _FX_SAVE_AREA
   +0xb30 PowerState       : _PROCESSOR_POWER_STATE

在0x38的地方是否是看到了咱們熟悉的IDT表。

咱們在Windbg下dd KiProcessBlock 

kd> dd KiProcessorBlock
80553e40  ffdff120 00000000 00000000 00000000
80553e50  00000000 00000000 00000000 00000000
80553e60  00000000 00000000 00000000 00000000
80553e70  00000000 00000000 00000000 00000000

 由於是虛擬機裏面作的測試,因此只是單核CPU,那麼問題來了,如何得到KiProcessBlock?

 在Win732位與XP中它是未導出的,那麼能夠用IDA在ntosknl導出表搜索,找到哪一個函數中用了這個變量就能夠用這個函數加硬編碼的方式進行強行定位,上次看到一篇帖子是如何得到系統未導出的全局變量,是經過遍歷未公開的結構體,我就試了試,沒想到還成功了,而後就用了這種方法,其實解決多核問題還有好多種方法,不必定侷限於哪種。

 

 

下面着重講解下,如何修改段基址的方法實現HOOK,而後躲過xuetr的檢測。

 IA-32處理器有三種描述符表:全局描述符表GDT,局部描述符表LDT,中斷描述符表IDT。

 GDT表是全局的,一個系統中一般只有一個GDT表,供系統中全部程序和任務進行使用。LDT與任務相關,每一個任務能夠有一個LDT,也可讓多個任務共享一個LDT。

 咱們用WINDBG觀察下GDT

 

kd> r gdtr
gdtr=8003f000

 得到GDT的基地址以後觀察下它的內存

是否是和IDT表同樣啊,這時候裏面的一項叫作段描述符。

 

 這個圖就是段描述符的內存結構。有點看不清,將就一下,詳情能夠參考張銀奎老師的《軟件調試》。

 

typedef struct _KGDTENTRY {
    USHORT  LimitLow;
    USHORT  BaseLow;
    union {
        struct {
            UCHAR   BaseMid;
            UCHAR   Flags1;     // Declare as bytes to avoid alignment
            UCHAR   Flags2;     // Problems.
            UCHAR   BaseHi;
        } Bytes;
        struct {
            ULONG   BaseMid : 8;
            ULONG   Type : 5;
            ULONG   Dpl : 2;
            ULONG   Pres : 1;

            ULONG   LimitHi : 4;
            ULONG   Sys : 1;
            ULONG   Reserved_0 : 1;
            ULONG   Default_Big : 1;
            ULONG   Granularity : 1;
            ULONG   BaseHi : 8;
        } Bits;
    } HighWord;
} KGDTENTRY, *PKGDTENTRY;

 

 段選擇子:

 還記得門描述符裏的選擇子嗎?選擇子的做用就是選擇一個段描述符,至關於索引。

 

 段選擇子的T1位表明要索引的段描述符表,T1=0表示全局描述符表,T1=1表示局部描述符表。

 段選擇子的高13位是描述符索引,即要選擇的段描述符在T1所表示的段描述符表中的索引號。由於這裏使用的是13位,意味着最多可索引8192個描述符,因此GDT和LDT表的最大表項數都是8192.由於X86CPU最多支持256箇中斷向量,因此IDT 表的最多表項數是256.

 

而後咱們來看看如何修改段基址來實現IDT HOOK。

要是段內偏移不變,那麼必須知足:原始偏移 + newbase = newfuntion

那麼newbase  = newfuntion - 原始偏移  


而後把newbase分解了再填到段描述符中就能夠了嗎?答案是不能夠,由於一個段描述符可能會有不少程序在用,若是無端修改段描述符那麼就會產生不可預料的錯誤,那麼咱們如何修改段基址呢?

咱們能夠變通一下,由於段描述符表裏有不少空的未利用的,咱們能夠把相應的門描述符裏的段選擇子改掉,讓它去選擇一個空的段描述符,咱們把原先段選擇符內容拷貝過來再修改這個段描述符就能夠達到目的了!

 

#include "ntifs.h"

#define WORD    USHORT
#define DWORD    ULONG

#define MAKELONG(a, b)      ((LONG)(((WORD)(((DWORD_PTR)(a)) & 0xffff)) \
    | ((DWORD)((WORD)(((DWORD_PTR)(b)) & 0xffff))) << 16))

typedef struct _IDTR{
    USHORT   IDT_limit;
    USHORT   IDT_LOWbase;
    USHORT   IDT_HIGbase;
}IDTR,*PIDTR;

typedef struct _IDTENTRY
{
    unsigned short LowOffset;
    unsigned short selector;
    unsigned char retention:5;
    unsigned char zero1:3;
    unsigned char gate_type:1;
    unsigned char zero2:1;
    unsigned char interrupt_gate_size:1;
    unsigned char zero3:1;
    unsigned char zero4:1;
    unsigned char DPL:2;
    unsigned char P:1;
    unsigned short HiOffset;
} IDTENTRY,*PIDTENTRY;

typedef struct _KGDTENTRY {
    USHORT  LimitLow;
    USHORT  BaseLow;
    union {
        struct {
            UCHAR   BaseMid;
            UCHAR   Flags1;     // Declare as bytes to avoid alignment
            UCHAR   Flags2;     // Problems.
            UCHAR   BaseHi;
        } Bytes;
        struct {
            ULONG   BaseMid : 8;
            ULONG   Type : 5;
            ULONG   Dpl : 2;
            ULONG   Pres : 1;

            ULONG   LimitHi : 4;
            ULONG   Sys : 1;
            ULONG   Reserved_0 : 1;
            ULONG   Default_Big : 1;
            ULONG   Granularity : 1;
            ULONG   BaseHi : 8;
        } Bits;
    } HighWord;
} KGDTENTRY, *PKGDTENTRY;


//global
USHORT g_FilterJmp[3];
ULONG  g_uOrigInterruptFunc;

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
    }
}

USHORT    g_u_cs;

void __stdcall FilterInterrupt()
{
    KdPrint(("%s---%X",(char*)PsGetCurrentProcess()+0x16c,g_u_cs));
}

__declspec(naked)
void NewInterrupt3OfOrigBase()
{
    __asm{
        pushad
        pushfd

        push    fs
        push    0x30
        pop        fs

        call    FilterInterrupt

        pop        fs

        popfd
        popad

        jmp        g_uOrigInterruptFunc
    }
}



__declspec(naked)
void NewInterrupt3()
{
    __asm{
        mov    g_u_cs,cs
        jmp    fword ptr[g_FilterJmp]
    }
}

ULONG    GetInterruptFuncAddress(ULONG InterruptIndex)
{
    IDTR        idtr;
    IDTENTRY    *pIdtEntry;

    __asm    SIDT    idtr;

    pIdtEntry = (IDTENTRY *)MAKELONG(idtr.IDT_LOWbase,idtr.IDT_HIGbase);

    return MAKELONG(pIdtEntry[InterruptIndex].LowOffset,pIdtEntry[InterruptIndex].HiOffset);
}

ULONG GetNewBase(ULONG NewInterruptFunc,ULONG OrigInterruptOffset)
{
    return (NewInterruptFunc - OrigInterruptOffset);
}


VOID SetInterrupt(ULONG InterruptIndex,ULONG uNewBase,BOOLEAN bIsNew)
{
    ULONG            u_fnKeSetTimeIncrement;
    UNICODE_STRING    usFuncName;
    ULONG            u_index;
    ULONG            *u_KiProcessorBlock;

    IDTENTRY        *pIdtEntry;
    PKGDTENTRY        pGdt;

    RtlInitUnicodeString(&usFuncName,L"KeSetTimeIncrement");

    u_fnKeSetTimeIncrement = (ULONG)MmGetSystemRoutineAddress(&usFuncName);
    if (!MmIsAddressValid((PVOID)u_fnKeSetTimeIncrement))
    {
        return;
    }

    u_KiProcessorBlock = *(ULONG**)(u_fnKeSetTimeIncrement + 44);

    u_index = 0;
    while (u_KiProcessorBlock[u_index])
    {
        pIdtEntry = *(IDTENTRY**)(u_KiProcessorBlock[u_index] - 0xE8);
        pGdt = *(PKGDTENTRY*)(u_KiProcessorBlock[u_index] - 0xE4);
        
        PageProtectOff();

        if (bIsNew)
        {
            pIdtEntry[InterruptIndex].selector = 0xA8;        //10101 000   //低1 2位  RPL用於檢測權限  低 3 位用於選擇 GDT 或者 LDT   高五位用於表明表中索引號  這個索引是21
            RtlCopyMemory(&pGdt[21],&pGdt[1],sizeof(KGDTENTRY));
            pGdt[21].BaseLow = (USHORT)(uNewBase&0xffff);
            pGdt[21].HighWord.Bytes.BaseMid = (UCHAR)((uNewBase>>16)&0xff);
            pGdt[21].HighWord.Bytes.BaseHi = (UCHAR)(uNewBase>>24);         //把原來的段描述符拷過來  修改段描述符的基址
        }else{
            pIdtEntry[InterruptIndex].selector = 0x8;
            memset(&pGdt[21],0,sizeof(KGDTENTRY));
        }

        PageProtectOn();

        u_index++;
    }
}

VOID HookInterruptFunc(ULONG InterruptIndex,ULONG NewInterruptFunc)
{
    ULONG    uNewBase;

    g_uOrigInterruptFunc = GetInterruptFuncAddress(InterruptIndex);
    uNewBase = NewInterruptFunc - g_uOrigInterruptFunc;    //段基地址 + g_uOrigInterruptFunc = NewInterruptFunc
    
    *(ULONG*)g_FilterJmp = (ULONG)NewInterrupt3OfOrigBase;
    g_FilterJmp[2] = 0x8;

    SetInterrupt(InterruptIndex,uNewBase,TRUE);
}

void UnHookInterruptFunc(ULONG InterruptIndex)
{
    SetInterrupt(InterruptIndex,0,FALSE);
}

VOID MyUnload(PDRIVER_OBJECT    pDriverObject)
{
    UnHookInterruptFunc(3);
}

NTSTATUS DriverEntry(PDRIVER_OBJECT    pDriverObject,PUNICODE_STRING Reg_Path)
{
    HookInterruptFunc(3,(ULONG)NewInterrupt3);
    pDriverObject->DriverUnload = MyUnload;
    return STATUS_SUCCESS;
}
相關文章
相關標籤/搜索