IDT

中断描述符表寄存器(Interrupt Descriptor Table Register, IDTR)
中断描述符表(Interrupt Descriptor Table, IDT)

中断描述符表寄存器(Interrupt Descriptor Table Register, IDTR)存储了中断描述符表(Interrupt Descriptor Table, IDT)在内存中的基地址.

IDT是一个有256个入口的线形表,每个IDT的入口是个8字节的描述符,所以整个IDT表的大小为256*8=2048 bytes.

每个中断向量关联了一个中断处理过程。所谓的中断向量就是把每个中断或者异常用一个0-255的数字识别。

另外, 每个处理器拥有自己的IDTR寄存器, 所以都拥有自己的中断表, 因此, 在Hook IDT的时候, 要考虑这个问题.

我们可以使用KeGetCurrentProcessorNumber之类的函数来判断代码当前在哪个处理器上运行. 也可以使用KeSetTargetProcessorDpc等函数将代码调度到某个特定处理器上运行.

当中断发生时, 可以从中断指令或可编程中断控制器中获取中断编号, 然后通过IDT寻找要调用的中断服务例程.

IDT有三种不同的描述符或者说是入口,分别是:

  1. 任务门描述符
  2. 中断门描述符
  3. 陷阱门描述符

    其中, 陷阱门和中断门非常相似, 他们区别只在于陷阱门能够被可屏蔽中断所中断, 而中断门不能. 另一方面, 任务门是一个非常过时的处理器特性, 它可以用于强制x86处理器的任务切换. 然而, Windows并不使用该特性, 所以我们也不加过多的研究.

为了获得IDT的内存地址, 必须读取IDTR, 这可以用SIDT指令完成. 当然, 我们也可以用LIDT指令来修改IDTR的内容.

SIDT指令以如下格式存储IDTR的内容:

typedef struct  
{  
    unsigned short IDTLimit; //代表IDT的大小, 为7FFH  
    unsigned short LowIDTbase;  
    unsigned short HiIDTbase;  
}IDTINFO;  

其中的LowIDTbase和HiIDTbase分别指示了IDT地址的低半部分和高半部分.

IDT中每项的结构如下:

#pragma pack(1)  
typedef struct  
{  
    unsigned short LowOffset;  
    unsigned short selector;  
    unsigned char unused_lo;  
    unsigned char segment_type:4;   
    unsigned char system_segment_flag:1;  
    unsigned char DPL:2;  
    unsigned char P:1;  
    unsigned short HiOffect;  
}IDTENTRY;  
#pragma pack()  

下面是一个小程序, 用来打印全部的ISR Interrupt Service Routines(中断服务程序)

#include <ntddk.h>  
#include <stdio.h>  

typedef struct  
{  
    unsigned short IDTLimit; //代表IDT的大小, 为7FFH  
    unsigned short LowIDTbase;  
    unsigned short HiIDTbase;  
}IDTINFO;  

#pragma pack(1)  
typedef struct  
{  
    unsigned short LowOffset;  
    unsigned short selector;  
    unsigned char unused_lo;  
    unsigned char segment_type:4;   
    unsigned char system_segment_flag:1;  
    unsigned char DPL:2;  
    unsigned char P:1;  
    unsigned short HiOffect;  
}IDTENTRY;  
#pragma pack()  

#define MAKELONG(a, b) \  
    ((unsigned long) (((unsigned short) (a)) | ((unsigned long) ((unsigned short) (b))) << 16))   
//IDT中的最大项数是256  
#define MAX_IDT_ENTRIES 0xFF  

VOID  
DriverUnload(IN PDRIVER_OBJECT pDriverObj)  
{      
    KdPrint(("[IDT] Unloading...\r\n"));      
}  

NTSTATUS  
DriverEntry(IN PDRIVER_OBJECT pDriverObj, IN PUNICODE_STRING pRegistryString)  
{  
    NTSTATUS        status = STATUS_SUCCESS;  
    IDTINFO            idt_info;  
    IDTENTRY*        idt_entrys;  
    unsigned long    count;  

    __asm sidt idt_info;  

    idt_entrys = (IDTENTRY*)MAKELONG(idt_info.LowIDTbase, idt_info.HiIDTbase);  

    KdPrint(("IDT Addr: 0x%08X\n", MAKELONG(idt_info.LowIDTbase, idt_info.HiIDTbase)));  
    KdPrint(("IDT Limit: %d\n", idt_info.IDTLimit));  

    for (count = 0; count<=MAX_IDT_ENTRIES; count++)  
    {  
        char _t[255];  
        unsigned long addr;  
        IDTENTRY* i = &idt_entrys[count];  

        addr = MAKELONG(i->LowOffset, i->HiOffect);  
        _snprintf(_t, 253, "Interrupt %3d\tISR 0x%08X", count, addr);  
        KdPrint(("%s", _t));  
    }  

    pDriverObj->DriverUnload = DriverUnload;  
    return STATUS_SUCCESS;  
}  

打印结果如下:

这里写图片描述

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值