博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
IDT hook KiTrap03
阅读量:4549 次
发布时间:2019-06-08

本文共 15897 字,大约阅读时间需要 52 分钟。

关于idt的基本知识就不进行赘述了,先看一个例子

0x1000:    mov   eax,00x1006:    Int    3            ;------->进入内核,找到中断处理例程KiTrap030x1007:   Mov   eax,1

这段代码执行,触发3号中断,然后开始执行KiTrap03例程,要知道,执行完中断以后还是要回到原来的程序处继续执行的,也就是我们这的Mov eax, 1的指令,显然,发生中断时的寄存器环境就要被保存,便于之后的恢复程序运行,这里,就出现了一个结构_KTRAP_FRAME,陷阱帧。

kd> dt _KTRAP_FRAMEnt!_KTRAP_FRAME   +0x000 DbgEbp           : Uint4B   +0x004 DbgEip           : Uint4B   +0x008 DbgArgMark       : Uint4B   +0x00c DbgArgPointer    : Uint4B   +0x010 TempSegCs        : Uint2B   +0x012 Logging          : UChar   +0x013 Reserved         : UChar   +0x014 TempEsp          : Uint4B   +0x018 Dr0              : Uint4B   +0x01c Dr1              : Uint4B   +0x020 Dr2              : Uint4B   +0x024 Dr3              : Uint4B   +0x028 Dr6              : Uint4B   +0x02c Dr7              : Uint4B   +0x030 SegGs            : Uint4B   +0x034 SegEs            : Uint4B   +0x038 SegDs            : Uint4B   +0x03c Edx              : Uint4B   +0x040 Ecx              : Uint4B   +0x044 Eax              : Uint4B   +0x048 PreviousPreviousMode : Uint4B   +0x04c ExceptionList    : Ptr32 _EXCEPTION_REGISTRATION_RECORD   +0x050 SegFs            : Uint4B   +0x054 Edi              : Uint4B   +0x058 Esi              : Uint4B   +0x05c Ebx              : Uint4B   +0x060 Ebp              : Uint4B   +0x064 ErrCode          : Uint4B +0x068 Eip              : Uint4B   //硬件自动填充   +0x06c SegCs            : Uint4B   //硬件自动填充   +0x070 EFlags           : Uint4B   //硬件自动填充    //后面都是可选的,只有当我们运行的程序处于虚拟86模式异常才会有   +0x074 HardwareEsp      : Uint4B   +0x078 HardwareSegSs    : Uint4B   +0x07c V86Es            : Uint4B   +0x080 V86Ds            : Uint4B   +0x084 V86Fs            : Uint4B   +0x088 V86Gs            : Uint4B

整个陷阱帧结构记录中断发生时的寄存器环境,其中,结构体最后面的几个成员只有运行于虚拟86模式下才会存在,而Eip,SegCs和EFlags三个成员由硬件自动填充,然后剩下的成员才是由KiTrap03自己构建的陷阱帧,我们可以分析下KiTrap03的代码,由于在wrk中只有asm文件,没有C源代码,用ida进行分析

.text:00436C50 _KiTrap03 proc near           ; DATA XREF: INIT:0077317Co.text:00436C50.text:00436C50 var_2= word ptr -2.text:00436C50 arg_4= dword ptr  8.text:00436C50.text:00436C50 push    0                     ; Trap_frame.Errcode.text:00436C52 mov     [esp+4+var_2], 0      ; Trap_frame.Errcode = 0.text:00436C59 push    ebp                   ; Trap_frame.Ebp.text:00436C5A push    ebx                   ; Trap_frame.Ebx.text:00436C5B push    esi                   ; Trap_frame.Esi.text:00436C5C push    edi                   ; Trap_frame.Edi.text:00436C5D push    fs                    ; Trap_frame.SegFs.text:00436C5F mov     ebx, 30h.text:00436C64 mov     fs, bx.text:00436C67 mov     ebx, large fs:0       ; fs对应处理器相关的_KPCR结构,kpcr,那么得到的是.text:00436C67                               ; kpcr.NtTib.ExceptionList.text:00436C6E push    ebx                   ; Trap_frame.ExceptionList.text:00436C6F sub     esp, 4                ; Trap_frame.PreviousPreviousMode,在后面填充.text:00436C72 push    eax                   ; Trap_frame.Eax.text:00436C73 push    ecx                   ; Trap_frame.Ecx.text:00436C74 push    edx                   ; Trap_frame.Edx.text:00436C75 push    ds                    ; Trap_frame.SegDs.text:00436C76 push    es                    ; Trap_frame.SegEs.text:00436C77 push    gs                    ; Trap_frame.SegGs.text:00436C79 mov     ax, 23h               ; ???.text:00436C7D sub     esp, 30h              ; 继续增大栈空间,刚好是整个Trap_Frame的大小.text:00436C80 mov     ds, ax                ; ???.text:00436C83 mov     es, ax.text:00436C86 mov     ebp, esp              ; ebp指向Trap_frame.text:00436C88 test    [esp+68h+arg_4], 20000h ; Trap_frame.EFlags,0x2000代表EFLAGS_V86_MASK,.text:00436C88                               ; 标记虚拟86模式.text:00436C90 jnz     short V86_kit3_a      ; 如果是虚拟86模式跳转.text:00436C92.text:00436C92 loc_436C92:                   ; CODE XREF: V86_kit3_a+25j.text:00436C92 mov     ecx, large fs:124h    ; ecx = CurrentThread.text:00436C92                               ; +0x004 CurrentThread    : Ptr32 _KTHREAD  当前线程 ecx.text:00436C99 cld.text:00436C9A and     dword ptr [ebp+2Ch], 0 ; Trap_frame.Dr7清零.text:00436C9E test    byte ptr [ecx+3], 0DFh.text:00436CA2 jnz     Dr_kit3_a.text:00436CA8.text:00436CA8 loc_436CA8:                   ; CODE XREF: Dr_kit3_a+Dj.text:00436CA8                               ; Dr_kit3_a+79j.text:00436CA8 mov     ebx, [ebp+60h].text:00436CAB mov     edi, [ebp+68h].text:00436CAE mov     [ebp+0Ch], edx        ; Trap_frame.DbgArgPointer = edx.text:00436CB1 mov     dword ptr [ebp+8], 0BADB0D00h ; Trap_frame.DbgArgMark = 0BADB0D00h.text:00436CB8 mov     [ebp+0], ebx          ; Trap_frame.DbgEbp = kTrap_frame.Ebp.text:00436CBB mov     [ebp+4], edi          ; Trap_frame.DbgEip = kTrap_frame.Eip.text:00436CBE cmp     ds:_PoHiberInProgress, 0.text:00436CC5 jnz     short loc_436CCE.text:00436CC7 lock inc ds:_KiHardwareTrigger.text:00436CCE.text:00436CCE loc_436CCE:                   ; CODE XREF: _KiTrap03+75j.text:00436CCE mov     eax, 0.text:00436CD3.text:00436CD3 loc_436CD3:                   ; CODE XREF: _KiDebugService+7Aj.text:00436CD3 test    byte ptr [ebp+72h], 2.text:00436CD7 jnz     short loc_436D08.text:00436CD9 test    byte ptr [ebp+6Ch], 1 ; CS 最后一位,判断是否为UserMode.text:00436CDD jnz     short loc_436CE7      ; 如果是UserMode,跳转.text:00436CDF test    byte ptr [ebp+71h], 2 ; 判断Eflags.IF位是否存在.text:00436CE3 jz      short loc_436CEF.text:00436CE5 jmp     short loc_436CEE.text:00436CE7 ; ---------------------------------------------------------------------------.text:00436CE7.text:00436CE7 loc_436CE7:                   ; CODE XREF: _KiTrap03+8Dj.text:00436CE7 cmp     word ptr [ebp+6Ch], 1Bh.text:00436CEC jnz     short loc_436D08.text:00436CEE.text:00436CEE loc_436CEE:                   ; CODE XREF: _KiTrap03+95j.text:00436CEE                               ; _KiTrap03+C9j.text:00436CEE sti                           ; IF标志位存在.text:00436CEF.text:00436CEF loc_436CEF:                   ; CODE XREF: _KiTrap03+93j.text:00436CEF                               ; _KiTrap03+D6j.text:00436CEF mov     esi, ecx              ; esi=CurrentThread.text:00436CF1 mov     edi, edx.text:00436CF3 mov     edx, eax.text:00436CF5 mov     ebx, [ebp+68h]        ; ebx = kTrap_frame.Eip.text:00436CF8 dec     ebx                   ; "eip-1"是因为int 3本身占一个字节.text:00436CF9 mov     ecx, 3                ; ???在下层函数中会用到,到时候就知道了.text:00436CFE mov     eax, 80000003h        ; 异常类型(STATUS_BREAKPOINT).text:00436D03 call    CommonDispatchException ; 处理异常.text:00436D08.text:00436D08 loc_436D08:                   ; CODE XREF: _KiTrap03+87j.text:00436D08                               ; _KiTrap03+9Cj.text:00436D08 mov     ebx, large fs:124h.text:00436D0F mov     ebx, [ebx+50h].text:00436D12 cmp     dword ptr [ebx+148h], 0.text:00436D19 jz      short loc_436CEE.text:00436D1B push    3.text:00436D1D call    _Ki386VdmReflectException_A@4 ; Ki386VdmReflectException_A(x).text:00436D22 test    ax, 0FFFFh.text:00436D26 jz      short loc_436CEF.text:00436D28 jmp     Kei386EoiHelper@0.text:00436D28 _KiTrap03 endp

很明显,在KiTrap03中没有进行太多的处理,只是判断是否是虚拟86模式来构建了一个不同的陷阱帧结构,之后调用了CommonDispatchException 函数来处理异常。

在虚拟86模式下将会跳转到V86_kit3_a,我们可以看下实现

.text:00436C28 V86_kit3_a proc near          ; CODE XREF: _KiTrap03+40j.text:00436C28 mov     eax, [ebp+84h].text:00436C2E mov     ebx, [ebp+88h].text:00436C34 mov     ecx, [ebp+7Ch].text:00436C37 mov     edx, [ebp+80h].text:00436C3D mov     [ebp+50h], ax         ; Trap_frame.SegFs = Trap_frame.V86Fs.text:00436C41 mov     [ebp+30h], bx         ; Trap_frame.SegGs = Trap_frame.V86Gs.text:00436C45 mov     [ebp+34h], cx         ; Trap_frame.SegEs = Trap_frame.V86Es.text:00436C49 mov     [ebp+38h], dx         ; Trap_frame.SegDs = Trap_frame.V86Ds.text:00436C4D jmp     short loc_436C92.text:00436C4D V86_kit3_a endp

 

 可以看到V86_kit3_a中没有进行处理,只是将陷阱帧中保存的寄存器的值对应为虚拟86模式特有的值。

 然后跟入CommonDispatchException 函数

.text:0043641C CommonDispatchException proc near ; CODE XREF: _KiTrap00-253p.text:0043641C                               ; _KiTrap00-247p _KiTrap00-23Bp.text:0043641C                               ; _KiTrap03+B3p _KiTrap0E+21Ap.text:0043641C                               ; sub_671B78+24p.text:0043641C.text:0043641C var_50= dword ptr -50h.text:0043641C var_4C= dword ptr -4Ch.text:0043641C var_48= dword ptr -48h.text:0043641C var_44= dword ptr -44h.text:0043641C var_40= dword ptr -40h.text:0043641C var_3C= byte ptr -3Ch.text:0043641C.text:0043641C sub     esp, 50h              ; EXCEPTION_RECORD结构空间,ExceptionRecord.text:0043641F mov     [esp+50h+var_50], eax ; eax是上层调用设置的错误码,这里是.text:0043641F                               ; ExceptionRecord->ExceptionCode = eax.text:00436422 xor     eax, eax.text:00436424 mov     [esp+50h+var_4C], eax ; ExceptionRecord->ExceptionFlags = 0.text:00436428 mov     [esp+50h+var_48], eax ; ExceptionRecord->ExceptionRecord = 0.text:0043642C mov     [esp+50h+var_44], ebx ; ebx是上层调用设置的异常发生处地址,.text:0043642C                               ; ExceptionRecord->ExceptionAddress = ebx.text:00436430 mov     [esp+50h+var_40], ecx ; ExceptionRecord->NumberParameters = ecx.text:00436430                               ; 表示ExceptionRecord->ExceptionInformation数组的数量.text:00436434 cmp     ecx, 0                ; ExceptionRecord->NumberParameters为零跳转.text:00436437 jz      short loc_436445.text:00436439 lea     ebx, [esp+50h+var_3C] ; ebx = ExceptionRecord->ExceptionInformation.text:0043643D mov     [ebx], edx            ; 开始填充ExceptionInformation的信息.text:0043643F mov     [ebx+4], esi.text:00436442 mov     [ebx+8], edi.text:00436445.text:00436445 loc_436445:                   ; CODE XREF: CommonDispatchException+1Bj.text:00436445 mov     ecx, esp              ; ecx = ExceptionRecord.text:00436447 test    byte ptr [ebp+72h], 2 ; ebp还是指向TrapFrame,TrapFrame->EFlags,.text:00436447                               ; 这里是EFlags的高2字节,判断是否为虚拟86模式.text:0043644B jz      short loc_436454.text:0043644D mov     eax, 0FFFFh           ; ????.text:00436452 jmp     short loc_436457.text:00436454 ; ---------------------------------------------------------------------------.text:00436454.text:00436454 loc_436454:                   ; CODE XREF: CommonDispatchException+2Fj.text:00436454 mov     eax, [ebp+6Ch]        ; eax = TrapFrame->SegCs.text:00436457.text:00436457 loc_436457:                   ; CODE XREF: CommonDispatchException+36j.text:00436457 and     eax, 1                ; Cs的低两位得到处理器模式.text:0043645A push    1                     ; FirstChance.text:0043645C push    eax                   ; PreviousMode.text:0043645D push    ebp                   ; TrapFrame.text:0043645E push    0                     ; ExceptionFrame.text:00436460 push    ecx                   ; void *.text:00436461 call    _KiDispatchException@20 ; 对异常进行分发处理.text:00436466 mov     esp, ebp              ; 修正esp,然后执行退出操作.text:00436468 jmp     Kei386EoiHelper@0.text:00436468 CommonDispatchException endp

 

可以看到CommonDispatchException也没有进行处理,只是构建了一个ExceptionRecord的结构体,就对异常进行了分发处理,进入了熟悉的KiDispatchException函数。

了解了陷阱帧的构建,再看idt表的基本结构,每个CPU的核心都有自己的idt表,

 

typedef struct _IDTR{  USHORT    limit;   //整个表所占内存大小  ULONG    base;    //IDT表项起始地址}IDTR,*PIDTR;

 

在我的虚拟机上 limit= 0x7ff (包含0)  0x800  = 2048  Entry每项大小8字节,就2048/8 = 256 成员,idt表有256个例程

可以使用kd> !idt -a  命令来查看idt表的详细信息,可以发现就是有256个例程

idt表中的每一项对应一种中断处理例程,结构体如下,我们最关心的是LowOffset和HiOffset这两个成员,他们组成了处理例程地址的高16位和低16位

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;

 

利用MAKELONG 的宏,可以得到处理例程的真正地址

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

 

idt表的获得可以通过sidt指令或者时_KPCR中的成员获得,在内核态fs段寄存器是指向_KPCR结构。

kd> dt _kpcr...... +0x038 IDT              ; Ptr32 _KIDTENTRY......

 

 

 

下面的代码打印了每次触发INT 3断点的地址,可以用OD下普通的断点进行测试,可以打印出断点的地址。

ULONG_PTR g_OrigKiTrap03;KIRQL  Irql;_declspec(naked) void NewKiTrap03(){    __asm    {        //测试        //jmp g_OrigKiTrap03        //构建Trap03的异常帧        //保存现场环境,和原始Trap03一样        push    0   ;ErrorCode        push    ebp        push    ebx        push    esi        push    edi        push    fs        mov     ebx,30h        mov     fs,bx        mov     ebx,dword ptr fs:[0]        push    ebx        sub     esp,4        push    eax        push    ecx        push    edx        push    ds        push    es        push    gs        sub     esp,30h    //esp此时就指向陷阱帧        push    esp         //FilterExceptionInfo自己清理了        call   FilterExceptionInfo   //过滤函数        add     esp , 0x30        pop        gs        pop        es        pop        ds        pop        edx        pop        ecx        pop        eax        add        esp , 4        pop        ebx        pop        fs        pop        edi        pop        esi        pop        ebx        pop        ebp        add     esp , 0x4        jmp     g_OrigKiTrap03    }}VOID __stdcall FilterExceptionInfo(PX86_KTRAP_FRAME pTrapFrame){    //eip的值减一过int3,汇编代码分析中dec,     DbgPrint("Eip:%x\r\n",(pTrapFrame->Eip)-1);}NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryString){    NTSTATUS    Status = STATUS_SUCCESS;    IDTR Idtr;    PIDTENTRY pIdtArray = NULL;    ULONG_PTR Index = 0;    DriverObject->DriverUnload = UnloadDriver;        __asm sidt Idtr    //虚拟机是单核的,只用一个就可以了    if(KeGetIdt(&pIdtArray))    {        DbgPrint("%x---%x\r\n",Idtr.base,Idtr.limit);        for (Index =0;Index<(Idtr.limit+1)/sizeof(IDTENTRY);Index++)                 {            DbgPrint("TrapHandle[%d]:%x\r\n",Index,MAKELONG(pIdtArray[Index].LowOffset,pIdtArray[Index].HiOffset));        }        g_OrigKiTrap03 = MAKELONG(pIdtArray[3].LowOffset,pIdtArray[3].HiOffset);        WPOFF();        pIdtArray[3].LowOffset = (ULONG_PTR)NewKiTrap03 & 0xFFFF;  //低16位        pIdtArray[3].HiOffset =  (ULONG_PTR)NewKiTrap03 >> 16;     //高16位        WPON();    }        //limit 0x7ff (包含0)  0x800  = 2048  Entry每项大小8字节,就2048/8 = 256 成员    //!idt -a   0ff  = 256     //MAKELONG    //#define MAKELONG(a, b)      ((LONG)(((WORD)(((DWORD_PTR)(a)) & 0xffff)) | ((DWORD)((WORD)(((DWORD_PTR)(b)) & 0xffff))) << 16))    return Status;}BOOLEAN KeGetIdt(PIDTENTRY *pIdtArray){    ULONG Index,Affinity,CurrentAffinity;    pfnKESETAFFINITYTHREAD fnpKeSetAffinityThread;    UNICODE_STRING usFuncName;    PIDTENTRY pIdtEntry;    RtlInitUnicodeString(&usFuncName,L"KeSetAffinityThread");    fnpKeSetAffinityThread = (pfnKESETAFFINITYTHREAD)MmGetSystemRoutineAddress(&usFuncName);    if (fnpKeSetAffinityThread==0)    {        return FALSE;    }    Affinity = KeQueryActiveProcessors();                        //KeQueryActiveProcessors获取处理器相关的位图    //(这里的位图可以理解为个数,比如返回1代表一个处理器,返回3表示两个处理器,返回7表示三个处理器,依此类推。    //也就是说从有多少个处理器,那么Affinity的值就会从低位到高位依此填充多少位)    CurrentAffinity = 1;    Index = 0;    while(Affinity)    {        //下面只是个简单的算法,使当前线程运行到不同的处理器上        Affinity &= ~CurrentAffinity;        fnpKeSetAffinityThread(PsGetCurrentThread(),(KAFFINITY)CurrentAffinity);        CurrentAffinity <<= 1;        __asm{            push        eax            mov         eax,fs:[0x38]            mov         pIdtEntry,eax            pop         eax        }        //得到我们要的东西        pIdtArray[Index] = pIdtEntry;        Index++;    }    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);}VOID UnloadDriver(PDRIVER_OBJECT DriverObject){    //恢复    PIDTENTRY pIdtEntry;    if (g_OrigKiTrap03 && KeGetIdt(&pIdtEntry))    {        WPOFF();        pIdtEntry[3].LowOffset = g_OrigKiTrap03 & 0xFFFF;        pIdtEntry[3].HiOffset = g_OrigKiTrap03 >> 16;        WPON();    }}

转载于:https://www.cnblogs.com/lanrenxinxin/p/4360983.html

你可能感兴趣的文章
MySQL firstmatch strategy
查看>>
MS SQL server 2014 创建用户及权限
查看>>
office很抱歉遇到一些临时服务器问题
查看>>
禁止键盘上的刷新键F5等
查看>>
SAP中对于获取订单的状态
查看>>
oracle PL/SQL块
查看>>
CentOS7集群环境Elastic配置
查看>>
【EXCEL】指定の項目の内容一覧を表示
查看>>
Head first java chapter 4 对象的行为
查看>>
luogu_4503【题解】企鹅QQ 哈希
查看>>
linux 面试
查看>>
Linux:Gentoo系统的安装笔记(三)
查看>>
打开IE窗口并最大化显示
查看>>
Windows API SendMessage 和 PostMessage 内部实现
查看>>
服务器发送邮件出现Could not connect to SMTP host错误 解决办法
查看>>
sklearn.preprocessing.LabelBinarizer
查看>>
C teaching
查看>>
分隔指定内容,提取章节数
查看>>
this point
查看>>
leetcode 30 Substring with Concatenation of All Words
查看>>