【原创】rootkit ring3进ring0之门系列[二] -- 中断门

标 题:  【原创】rootkit ring3进ring0之门系列[二] -- 中断门
作 者: combojiang
时 间: 2008-04-01,16:31:08
链 接: http://bbs.pediy.com/showthread.php?t=62336

接上篇续,我们继续谈谈386保护模式中的门,今天一起学习下中断门。

386实模式下的中断和异常的转移方法与8086相同。这里介绍的中断和异常的转移方法是指 80386在保护模式下响应中断和处理异常时所采用的转移方法。 
1.中断描述符表IDT
    象全局描述符表GDT一样,在整个系统中,中断描述符表IDT只有一个。中断描述符表寄存器IDTR指示IDT在内存中的位置。由于80386只识别256个中断向量号,所以IDT最大长度是2K。 
    中断描述符表IDT所含的描述符只能是中断门、陷阱门和任务门。也就是说,在保护模式下,80386只有通过中断门、陷阱门或任务门才能转移到对应的中断或异常处理程序。 

我们直观的看看IDT的内存位置,在本机 IDT: 8003f400
lkd> !pcr
KPCR for Processor 0 at ffdff000:
    Major 1 Minor 1
  NtTib.ExceptionList: b2c3fc7c
      NtTib.StackBase: b2c3fdf0
     NtTib.StackLimit: b2c3c000
   NtTib.SubSystemTib: 00000000
        NtTib.Version: 00000000
    NtTib.UserPointer: 00000000
        NtTib.SelfTib: 7ffde000

              SelfPcr: ffdff000
                 Prcb: ffdff120
                 Irql: 00000000
                  IRR: 00000000
                  IDR: ffffffff
        InterruptMode: 00000000
                  IDT: 8003f400
                  GDT: 8003f000
                  TSS: 80042000

        CurrentThread: 873dd1e8
           NextThread: 00000000
           IdleThread: 80552d20
前面我们讲过80386只识别256个中断向量号,每个中断向量号占8个字节,对应着一个描述符。因此,中断描述表IDT共占 256 * 8 = 2048字节。
下面是中断描述符的结构。
名称:  1.JPG查看次数: 2340文件大小:  14.0 KB
名称:  2.JPG查看次数: 2344文件大小:  13.8 KB
在IDT中,并不是这256个中断向量都被系统占用了,系统紧紧占用了一小部分,大部分是空闲的,因此用户可以在其中添加自己的中断描述符,即中断门。

2.中断响应和异常处理的步骤
    由硬件自动实现的中断响应和异常处理的步骤如下: 
    首先,判断中断向量号要索引的门描述符是否超出IDT的界限。若超出界限,就引起通用保护故障,出错码为中断向量号乘8再加2。 
    其次,从IDT中取得对应的门描述符,分解出选择子、偏移量和描述符属性类型,并进 行有关检查。描述符只能是任务门、286中断门、286陷阱门、386中断门或386陷阱门,否则就引起通用保护故障,出错码是中断向量号乘8再加2。如果是由INT n指令或INTO指令引起转移,还要检查中断门、陷阱门或任务门描述符中的DPL是否满足CPL<=DPL(对于其它的异常或中断,门中的DPL被 忽略)。这种检查可以避免应用程序执行INT n指令时,使用分配给各种设备用的中断向量号。如果检查不通过,就引起通用保护故障,出错码是中断向量号乘8再加2。门描述符中的P位必须是1,表示门描述符是一个有效项,否则就引起段不存在故障,出错码是中断向量号乘8再加2。 
    最后,根据门描述符类型,分情况转入中断或异常处理程序。 如下图:
名称:  3.JPG查看次数: 2345文件大小:  25.6 KB
   
3.通过中断门的转移
     如果中断向量号所指示的门描述符是386中断门,那么控制转移到当前任务的一个处理程序过程,并且可以变换特权级。与其它调用门的CALL指令一样,从中断门中获取指向处理程序的48位全指针。其中16位 选择子是对应处理程序或代码段的选择子,它指示全局描述符表GDT或局部描述符表LDT中的代码段描述符;32位偏移指示处理程序入口点在代码段内的偏移量。 
    通过中断门的转移过程如下所示,该过程由硬件自动进行,简单了解下。
    (1)若选择子为空,则产生通用保护故障;
    (2)取对应的描述符;
    (3)若非存储段描述符,则产生通用保护故障;
    (4)若非一致代码段且DPL且段存在,则切换到内层堆栈;
    (5)调整RPL=0;
    (6)把描述符装入CS;
    (7)若入口偏移越界,则产生通用保护故障;
    (8)EFLAGS压入堆栈;
    (9)CS压入堆栈;
    (10)EIP压入堆栈;
    (11)使TF=0,NT=0;
    (12)若为中断门,则使IF=0;
    (13)若有出错码,则把出错码压入堆栈;
    (14)转入处理程序。
    由上述转移过程可见,中断门中指示处理程序的选择子必须指向描述一个可执行的代码段的描述符。如果选择子为空,就引起通用保护故障,出错码是0。如果描述符不是代码段描述符,就引起通用保护故障,出错码含选择子。 
    中断或异常可以转移到同一特权级或内层特权级。上述指定处理程序代码段的描述符中的类型及DPL字段,决定了这种同一任务内的转移是否要发生特权级变换。如果是一个非一致代码段,并且DPL<CPL则产生通用保护异常。 
    上述转移过程中的第六步,也就是“把描述符装入CS”,是指把上述指定处理 程序段的描述符装入CS的高速缓冲寄存器中,在这一步骤中要对描述符进行类似通过调用门进行转移的其它检查,包括是否代码段描述符和代码段描述符是否存在 等,因此可能再发生异常。在对该描述符进行检查时,通过调整门中选择子的RPL=0(在处理器内部调整,而不影响存储器中的选择子的RPL字段)的方法, 实现只考虑代码段的DPL,而不考虑门中选择子的RPL。把描述符装入CS之后,还要检查门描述符中给出的表示处理程序代码段入口的偏移是否越界,即是否 超出段界限。如果越界,就引起出错码为0的通用保护故障。
    把TF置成0,表示不允许处理程序单步执行。把NT置成0,表示处理程序在利用中断返回指令IRET返回时,返回到同一任务而不是一个嵌套任务。
    通过中断门的转移和通过陷阱门的转移之间的差别只是对IF标志的处理。对于中断门,在转移过程中把IF置为0,使得在处理程序执行期间屏蔽掉INTR中断。

4.中断或异常处理后的返回
     中断返回指令IRET用于从中断处理程序的返回。该指令的执行根据任务嵌套标志NT位是否为1分为两种情形。 该过程由硬件自动进行,简单了解下。
    NT位为1,表示是嵌套任务的返回。
    NT位为0,表示当前任务内的返回。

后面跟上我们的代码:
.386
.model flat, stdcall
option casemap:none

include myIntGate.inc
.const
CCOUNTED_UNICODE_STRING "\\Device\\MyIntGate",g_usDeviceName,4
CCOUNTED_UNICODE_STRING "\\??\\MyIntGate",g_usSymbolicLinkName,4
IDT_LIMIT = 256 * 8
GATE_TYPE = 0eeh

.data?
g_myInt dd ?
g_myIntoffset dd ?
g_IsAddMyGate dd ?

.code
;中断执行函数
MyIntGateFunction proc
   invoke DbgPrint,$CTA0("MyIntGate calling...\n")
   iretd
MyIntGateFunction endp

;在IDT中添加中断门,返回中断号
AddMyIntGate proc FuncAddr:DWORD
    push ebx
  push ecx
  sidt [esp-2]
  pop ecx
  
  mov eax,0
  .while eax < IDT_LIMIT
       lea edx,[ecx+eax]
       assume edx:ptr GATE
       test [edx].GTYPE,80h
      .if ZERO?
         cli
         mov ebx,FuncAddr
         mov [edx].OFFSETL,bx
         mov [edx].SELECTOR,08h
         mov [edx].DCOUNT,0
         mov [edx].GTYPE,GATE_TYPE
         shr ebx,16
         mov [edx].OFFSETH,bx   
         sti  
          .break
     .endif   
      assume edx:nothing
     add eax,8
  .endw
  pop ebx
  mov g_myInt,eax
  ret
AddMyIntGate endp

;去掉添加的中断门
RemoveMyIntGate proc
  push ebx
  push ecx
  sidt [esp-2]
  pop ecx
  mov eax,g_myIntoffset
  lea edx,[ecx+eax]
  assume edx:ptr GATE
  cli
  mov [edx].OFFSETL,0
  mov [edx].SELECTOR,08h
  mov [edx].DCOUNT,0
  mov [edx].GTYPE,0
  mov [edx].OFFSETH,0 
  sti 
  assume edx:nothing
  pop ebx
  ret

RemoveMyIntGate endp

DispatchControl proc uses esi edi pDeviceObject:PDEVICE_OBJECT,pIrp:PIRP
  mov esi,pIrp
  assume esi:ptr _IRP
  mov [esi].IoStatus.Status,STATUS_UNSUCCESSFUL
  and [esi].IoStatus.Information,0
  
  IoGetCurrentIrpStackLocation esi
  mov edi,eax
  assume edi:ptr IO_STACK_LOCATION
  .if [edi].Parameters.DeviceIoControl.IoControlCode == IOCTL_MYINTGATE && !g_IsAddMyGate
    invoke AddMyIntGate,offset MyIntGateFunction
    mov g_myIntoffset,eax
    xor edx,edx
    cdq
    mov ecx,8
    div ecx
    mov g_myInt,eax
    mov edx,[esi].AssociatedIrp.SystemBuffer
    mov [edx],eax
    
    mov [esi].IoStatus.Status, STATUS_SUCCESS
    mov [esi].IoStatus.Information,4
    mov g_IsAddMyGate,1
  .else
    mov [esi].IoStatus.Status,STATUS_INVALID_DEVICE_REQUEST
  .endif
  
  push [esi].IoStatus.Status
  assume edi:nothing
  assume esi:nothing
  invoke IoCompleteRequest,esi,IO_NO_INCREMENT
  pop eax
  
  ret

DispatchControl endp
DispatchCreateClose proc pDeviceObject:PDEVICE_OBJECT,pIrp:PIRP
   mov eax,pIrp
   assume eax:ptr _IRP
   mov [eax].IoStatus.Status,STATUS_SUCCESS
   and [eax].IoStatus.Information,0
   fastcall IofCompleteRequest,pIrp,IO_NO_INCREMENT
   assume eax:nothing
   mov eax,STATUS_SUCCESS
   ret
DispatchCreateClose endp
DriverUnload proc pDriverObject:PDRIVER_OBJECT
    .if g_IsAddMyGate
     invoke RemoveMyIntGate
  .endif
  invoke IoDeleteSymbolicLink,addr g_usSymbolicLinkName
  mov eax,pDriverObject
  invoke IoDeleteDevice,(DRIVER_OBJECT PTR[eax]).DeviceObject
  ret

DriverUnload endp


DriverEntry proc pDriverObject:PDRIVER_OBJECT,pusRegistryPath:PUNICODE_STRING
    LOCAL pDeviceObject:PDEVICE_OBJECT
    LOCAL status:NTSTATUS
    
    mov status,STATUS_DEVICE_CONFIGURATION_ERROR
    invoke IoCreateDevice,pDriverObject,0,addr g_usDeviceName,FILE_DEVICE_UNKNOWN,0,FALSE,addr pDeviceObject
    .if eax == STATUS_SUCCESS
        invoke IoCreateSymbolicLink,addr g_usSymbolicLinkName,addr g_usDeviceName
        .if eax == STATUS_SUCCESS
            mov eax,pDriverObject
            assume eax:ptr DRIVER_OBJECT
            mov [eax].MajorFunction[IRP_MJ_CREATE * (sizeof PVOID)],offset DispatchCreateClose
            mov [eax].MajorFunction[IRP_MJ_CLOSE * (sizeof PVOID)],offset DispatchCreateClose
            mov [eax].MajorFunction[IRP_MJ_DEVICE_CONTROL *(sizeof PVOID)],offset DispatchControl
            mov [eax].DriverUnload,offset DriverUnload
            assume eax:nothing
            mov g_IsAddMyGate,0
            mov status,STATUS_SUCCESS
        .else
          invoke IoDeleteDevice,pDeviceObject
        .endif
    .endif
    mov eax,status
    ret

DriverEntry endp

end DriverEntry

最后友情提示:
在我的本机返回添加的中断向量是0x20, 调用方法是:
         __asm int 0x20;
    
当然,如果你有参数传递的话,可以使用寄存器进行传递,在MyIntGateFunction中断响应函数中可以得到这个参数。例如:
        _asm
        {
              mov eax, 100
              int 0x20
        }

上传的附件
文件类型: rar myIntGate.rar (11.3 KB, 691 次下载)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值