【IDT】 windows IDT GDT LDT

IDT:

(Interrupt Descrptor Table)中断描述符表,用来处理中断的。

IDT的获取:

  1. 可以通过SIDT指令,它可以在内存中找到IDT,返回一个IDTR结构的地址。
  2. 也可以通过kpcr结构获取

ISR:

中断服务例程

CPU通过查找在中断服务描述表(IDT)中找到的中断服务例程(ISR),知道如何响应以及对新接收到的中断执行哪些内核例程。

IDT的指针存储在每个物理处理器的IDTR寄存器中,每个处理器都有自己的IDTR寄存器,指向自己的中断描述符表。

IDT位置

可以通过读取IDTR寄存器的值来检查中断服务描述表在内核中的位置:

r  idtr

在这里插入图片描述
IDT 结构:
在这里插入图片描述

实模式和保护模式

CPU复位(reset)或加电(power on)的时候以实模式启动,处理器以实模式工作。
在实模式下,内存寻址方式和8086相同,由16位段寄存器的内容乘以16(10H)当
做段基地址,加上16位偏移地址形成20位的物理地址,最大寻址空间1MB,最大分
段64KB。可以使用32位指令。32位的x86 CPU用做高速的8086。在实模式下,所
有的段都是可以读、写和可执行的。
286架构导入保护模式,允许硬件等级的存储器保护。然而要使用这些新的特色,
需要额外先前不需要的软件指令。由于x86微处理机主要的设计规格,是能够完全
地向前兼容于针对先前所有x86芯片所撰写的软件,因此286芯片的开机是处于
’实模式’—也就是关闭新的存储器保护特性的模式,所以可以运行针对旧的微处
理器所设计的软件。到现在为止,即使最新的x86 CPU一开始在电源打开处于实
模式下,也能够运行针对先前任何芯片所撰写的软件.[1]

GDT、LDT与IDT

  1. 在保护模式下,对一个段的描述包括3方面因素:Base Adress, Limit, Access 它们加在一起放在一个64-bit长的数据结构中,被称为段描述符。
    在这里插入图片描述
  2. 段描述符使用数组存储,使用LGDT指令将GDT的入口地址装入GDTr寄存器。
  3. 段选择子,一个16位的数据结构。
    在这里插入图片描述
    三个都是比较重要的系统表
    这三个表都是在内存中由操作系统所建。但并不是固化在那里,所以从理论上是可以被读写的。

这三个表都是描述符表。

GDT: 全局服务描述符表
LDT: 局部描述符表
IDT: 中断服务描述符表

GDT 与IDT表

GDT的理解

    GDT全局服务描述表(Global Descriptor Table)
先理解一下实模式下得编程模型:
        在实模式下,对一个内存地址的访问是通过Segment:Offset的方式来进行的,其中Segment就是一个段的BaseAdress,一个Segment的最大长度是64kb,这是16bit系统所能表示的最大长度。

而offset是相对于此Segment Base Adress的偏移量。 Base Adress + offset就是一个内存绝对地址。由此,我们可以看出,一个段具备两个因素:Base Address 和 Limit (段的最大长度)
对于一个内存地址访问,需要指出: 使用哪个段,及相对于这个段Base Address 的offset 这个offset应该小于此段的limit。 对于16 bit 系统 ,limit不需要指定,默认最大长度为64k,且16bit的offset永远也不会大于此limit。
在保护模式下,内存的管理模式分为两种: 段模式和页模式,其中页模式也是基于段模式的。段模式是必不可少的。页模式是可选的。
对于段模式来讲,访问一个内存地址仍然使用Segment:offset的方式。 由于保护模式运行在32位系统上,那么segment的两个因素: Base Address 和limit 都是32位的。允许将一个段的地址设为32bit所能表示的任何值,而不像实模式下,一个段的Base Address只能是16的倍数。 保护模式,顾名思义,就是又为段模式提供了保护机制。也就是说一个段的描述符需要规定对自身的访问权限(Access)。
所以,在保护模式下,对一个段的描述则包括3方面的因素:【Base Address, limit , Access】,它们加在一起被放在一个64bit长的数据结构中,被称为段描述符。
在这种情况下,如果我们直接通过一个64-bit段描述符来引用一个段的时候,就必须使用一个64-bit长的段寄存器装入这个段描述符。但为了保持向后兼容,将段寄存器仍然规定为16-bit。(虽然
每个段寄存器事实上有一个64-bit长的不可见部分,但对于程序员来说,段寄存器就是16bit的),那么我们无法通过16-bit的长度的段寄存器来直接引用64-bit的段描述符,怎么办?
解决的方法就是把这些长度为64bit的段描述符放入一个数组中,而将段寄存器中的值作为下标索引来间接引用。这个全局的数组就是GDT。事实上,在GDT中存放的不仅仅是段描述符,还有其他描述符。
GDT可以被存放在内存的任何位置,当通过段寄存器引用一个段描述符时,CPU必须知道GDT的入口,也就是基地址放在哪里。所以Intel设计了一个寄存器GDTR用来存放GDT入口地址。
程序员将GDT设定在内存某个位置之后,可以通过:LGDT指令将GDT的入口地装入此寄存器。从此以后,CPU就根据此寄存器中的内容作为GDT的入口来访问GDT了。

在整个系统中,全局服务描述表GDT只有一张(一个处理器对应一个GDT)
GDT可以被放在内存任何位置
系统用GDTR寄存器存放当前GDT表的基地址。
用LDTR寄存器存放LDT表地址

我们知道,在实模式下,CPU是16位的,意思是 寄存器是16位的,数组总线是16位的,但地址总线是20位的。物理内存计算公式:

                物理地址   =  段地址 * 16 + 偏移量

段地址和偏移量都是16位,能寻址的最大内存地址为1M

2的20次方就是1M

若一个内存地址是20:30 最终的内存地址是: 20 * 16 +30

实模式和保护模式

实模式只有20位地址总线, 寻址空间只有1M ,以及8个16位的通用寄存器。4个16位的段寄存器。为了能够通过16位的寄存器去构成20位的主存地址,采取一种特殊的方法,使用下面的地址:

段基址: 段偏移量

物理地址 = 段地址 << 4 + 段内偏移

保护模式下,CPU的32条地址线全部有效,可寻址4G的字节的物理地址空间。但是为了兼容16位。此时计算机中的通用寄存器都成为32位。

在保护模式下存在一些限制。把这些限制信息放在一个全局服务描述表(GDT)中。

GDT的作用是提供段式存储机制。段寄存器提供段值,即描述符在GDT中的索引。

在进入保护模式前、必须准备好GDT、描述符和描述符选择子。

全局服务描述表:

    包含一个段的基址,界限及属性内容。其中段基地址和16
    位的系统中的段地址一样。只是在16位系统中段地址必须
    是16的倍数,但是在32位系统中段地址可以是任意地址。

寻址方式:

段地址(选择子)------在GDT中找到描述符-------
在描述符中找到段地址-----段地址+偏移地址 = 线性地址

IDT结构体:

//idtr指向这个结构体
typedef struct _IDT_INFO{
    UINT16 uIdtLimit;   // IDT范围
    UINT16 uLowIdtBase;   // IDT低基址
    UINT16 uHighIdtBase;   // IDT高基址
}IDT_INFO, *PIDT_INFO;


// IDT表中描述符结构体
//0x8 bytes (sizeof)
typedef struct _IDTENTRY
{
    // USHORT == UINT16
    USHORT uOffsetLow;       //0x0,低地址偏移
    USHORT uSelector;     //0x2,段选择器


    //USHORT uAccess;      //0x4
    UINT8 uReserved;     // 保留
    UINT8 GateType : 4;     // 中断类型
    UINT8 StorageSegment : 1;   // 为0则是中断门
    UINT8 DPL : 2;      // 特权级
    UINT8 Present : 1;      // 如未使用中断可置为0


    USHORT uOffsetHigh; //0x6   // 高地址偏移
}IDTENTRY, *PIDTENTRY;

获取IDTR

__asm sidt stcIDT

遍历IDT:

#include <ntifs.h>
#include <ntddk.h>


#define MAKE_LONG(a,b) ((a) + (b<<16))


typedef struct _IDT_INFO {
    UINT16 uIdtLimit;   // IDT范围
    UINT16 uLowIdtBase;   // IDT低基址
    UINT16 uHighIdtBase;   // IDT高基址
}IDT_INFO, * PIDT_INFO;




//0x8 bytes (sizeof)
typedef struct _IDTENTRY
{
    // USHORT == UINT16
    USHORT uOffsetLow;       //0x0,低地址偏移
    USHORT uSelector;     //0x2,段选择器


    //USHORT uAccess;      //0x4
    UINT8 uReserved;     // 保留
    UINT8 GateType : 4;     // 中断类型
    UINT8 StorageSegment : 1;   // 为0则是中断门
    UINT8 DPL : 2;      // 特权级
    UINT8 Present : 1;      // 如未使用中断可置为0


    USHORT uOffsetHigh; //0x6   // 高地址偏移
}IDTENTRY, *PIDTENTRY;






void OnUnload(DRIVER_OBJECT* pDriver)
{
    pDriver;
}


NTSTATUS DriverEntry(DRIVER_OBJECT* pDriver, UNICODE_STRING* pRegPath)
{
    NTSTATUS status = STATUS_SUCCESS;
    pRegPath;
    pDriver->DriverUnload = OnUnload;


    //KdBreakPoint();


    IDT_INFO stcIDT = { 0 };
    PIDTENTRY pIdtEntry = NULL;
    ULONG uAddr = 0;


    // IDT table
    __asm sidt stcIDT;


    // IDT array
    pIdtEntry = (PIDTENTRY)MAKE_LONG(stcIDT.uLowIdtBase, stcIDT.uHighIdtBase);


    KdPrint(("-------------IDT---------------\n"));
    KdPrint(("IDT Addr: 0x%p\n", pIdtEntry));
    for (ULONG i = 0; i < 0x100; ++i)
    {
        KdPrint(("Interrupted number: %d\n", i));


        uAddr = MAKE_LONG(pIdtEntry[i].uOffsetLow, pIdtEntry[i].uOffsetHigh);
        KdPrint(("Interrupted Addr: 0x%p\n", uAddr));


        KdPrint(("selector: %d\n", pIdtEntry[i].uSelector));


        KdPrint(("GataType: %d\n", pIdtEntry[i].GateType));
        
        KdPrint(("DPL: %d\n\n", pIdtEntry[i].DPL));


    }


    return status;
}

获取IDTR

__asm sidt stcIDT

遍历IDT:

#include <ntifs.h>
#include <ntddk.h>


#define MAKE_LONG(a,b) ((a) + (b<<16))


typedef struct _IDT_INFO {
    UINT16 uIdtLimit;   // IDT范围
    UINT16 uLowIdtBase;   // IDT低基址
    UINT16 uHighIdtBase;   // IDT高基址
}IDT_INFO, * PIDT_INFO;




//0x8 bytes (sizeof)
typedef struct _IDTENTRY
{
    // USHORT == UINT16
    USHORT uOffsetLow;       //0x0,低地址偏移
    USHORT uSelector;     //0x2,段选择器


    //USHORT uAccess;      //0x4
    UINT8 uReserved;     // 保留
    UINT8 GateType : 4;     // 中断类型
    UINT8 StorageSegment : 1;   // 为0则是中断门
    UINT8 DPL : 2;      // 特权级
    UINT8 Present : 1;      // 如未使用中断可置为0


    USHORT uOffsetHigh; //0x6   // 高地址偏移
}IDTENTRY, *PIDTENTRY;






void OnUnload(DRIVER_OBJECT* pDriver)
{
    pDriver;
}


NTSTATUS DriverEntry(DRIVER_OBJECT* pDriver, UNICODE_STRING* pRegPath)
{
    NTSTATUS status = STATUS_SUCCESS;
    pRegPath;
    pDriver->DriverUnload = OnUnload;


    //KdBreakPoint();


    IDT_INFO stcIDT = { 0 };
    PIDTENTRY pIdtEntry = NULL;
    ULONG uAddr = 0;


    // IDT table
    __asm sidt stcIDT;


    // IDT array
    pIdtEntry = (PIDTENTRY)MAKE_LONG(stcIDT.uLowIdtBase, stcIDT.uHighIdtBase);


    KdPrint(("-------------IDT---------------\n"));
    KdPrint(("IDT Addr: 0x%p\n", pIdtEntry));
    for (ULONG i = 0; i < 0x100; ++i)
    {
        KdPrint(("Interrupted number: %d\n", i));


        uAddr = MAKE_LONG(pIdtEntry[i].uOffsetLow, pIdtEntry[i].uOffsetHigh);
        KdPrint(("Interrupted Addr: 0x%p\n", uAddr));


        KdPrint(("selector: %d\n", pIdtEntry[i].uSelector));


        KdPrint(("GataType: %d\n", pIdtEntry[i].GateType));
        
        KdPrint(("DPL: %d\n\n", pIdtEntry[i].DPL));


    }


    return status;
}

遍历GDT:

#include <ntddk.h>


#define MAKE_LONG(a,b) ((LONG)(((UINT16)(((DWORD_PTR)(a)) & 0xffff)) | ((UINT32)((UINT16)(((DWORD_PTR)(b)) & 0xffff))) << 16))


typedef struct _GDT_INFO {
    UINT16 uGdtLimit;
    UINT16 uLowGdtBase;
    UINT16 uHighGdtBase;
}GDT_INFO, *PGDT_INFO;


//0x8 bytes (sizeof)
typedef struct _GDTENTRY
{
    USHORT LimitLow;                                                        //0x0
    USHORT BaseLow;                                                         //0x2
    union
    {
        struct
        {
            UCHAR BaseMid;                                                  //0x4
            UCHAR Flags1;                                                   //0x5
            UCHAR Flags2;                                                   //0x6
            UCHAR BaseHi;                                                   //0x7
        } Bytes;                                                            //0x4
        struct
        {
            ULONG BaseMid : 8;                                           
            ULONG Type : 4;     
            ULONG S : 1;
            ULONG Dpl : 2;                                               
            ULONG Pres : 1;                                              
            ULONG LimitHi : 4;                                           
            ULONG Avl : 1;                                               
            ULONG Reserved_0 : 1;                                        
            ULONG D_B : 1;                                       
            ULONG Granularity : 1;                                       
            ULONG BaseHi : 8;                                            
        } Bits;                                                          
    } HighWord;                                                          
}GDTENTRY, *PGDTENTRY;


void OnUnload(DRIVER_OBJECT* pDriver)
{
    pDriver;
}


NTSTATUS DriverEntry(DRIVER_OBJECT* pDriver, UNICODE_STRING* pRegPath)
{
    NTSTATUS status = STATUS_SUCCESS;
    pRegPath;
    pDriver->DriverUnload = OnUnload;


    //KdBreakPoint();
    
    GDT_INFO stcGDT = { 0 };
    PGDTENTRY pGdtEntry = NULL;
    unsigned int nGdtEntry = 0;
    ULONG uData = 0;


    // IDT table
    __asm sgdt stcGDT;


    // IDT array
    pGdtEntry = (PGDTENTRY)MAKE_LONG(stcGDT.uLowGdtBase, stcGDT.uHighGdtBase);


    KdPrint(("-------------GDT---------------\n"));
    KdPrint(("GDT Addr: 0x%p\n", pGdtEntry));


    nGdtEntry = stcGDT.uGdtLimit / 8;
    for (ULONG i = 0; i < nGdtEntry; ++i)
    {
        if (!(pGdtEntry[i].HighWord.Bits.Pres)) continue;


        uData = (ULONG)pGdtEntry[i].BaseLow
            + ((ULONG)(pGdtEntry[i].HighWord.Bits.BaseMid) << 16)
            + ((ULONG)(pGdtEntry[i].HighWord.Bits.BaseHi) << 24);
        KdPrint(("BaseAddr: 0x%p\n", uData));




        uData = pGdtEntry[i].LimitLow
            + ((ULONG)(pGdtEntry[i].HighWord.Bits.LimitHi) << 16);
        KdPrint(("Segment Limit: 0x%08X ", uData));


        (pGdtEntry[i].HighWord.Bits.Granularity)
            ? KdPrint(("pages\n"))
            : KdPrint(("bytes\n"));




        KdPrint(("DPL: %d\n", pGdtEntry[i].HighWord.Bits.Dpl));




        if ((pGdtEntry[i].HighWord.Bits.S == 0))
        {
            KdPrint(("Type: System segment\t"));
            switch (pGdtEntry[i].HighWord.Bits.Type)
            {
            case 12:
                KdPrint(("Call Gate "));
                break;
            case 14:
                KdPrint(("Interruptting Gate "));
                break;
            case 15:
                KdPrint(("Trap Gate "));
                break;
            case 5:
                KdPrint(("Task Gate "));
                break;
            default:
                KdPrint(("Unknown "));
                break;
            }
            KdPrint(("\n"));
        }
        else
        {
            if (pGdtEntry[i].HighWord.Bits.Type & 0x8)
            {
                KdPrint(("Type: Code Segment\n"));
                KdPrint(("Attr: "));
                KdPrint(("%s", pGdtEntry[i].HighWord.Bits.Type & 0x4 ? "C" : "-"));
                KdPrint(("%s", pGdtEntry[i].HighWord.Bits.Type & 0x2 ? "R" : "-"));
                KdPrint(("%s", pGdtEntry[i].HighWord.Bits.Type & 0x1 ? "A" : "-"));
                KdPrint(("\n"));
            }
            else
            {
                KdPrint(("Type: Data Segment\n"));
                KdPrint(("Attr: "));
                KdPrint(("%s", pGdtEntry[i].HighWord.Bits.Type & 0x4 ? "E" : "-"));
                KdPrint(("%s", pGdtEntry[i].HighWord.Bits.Type & 0x2 ? "W" : "-"));
                KdPrint(("%s", pGdtEntry[i].HighWord.Bits.Type & 0x1 ? "A" : "-"));
                KdPrint(("\n"));
            }
        }




        KdPrint(("\n"));
    }


    return status;
}

REFERENCE

https://www.cnblogs.com/ciyze0101/p/5350613.html windows 下的IDT hook和GDT的学习
https://blog.csdn.net/ggh19/article/details/113705230?spm=1001.2101.3001.6650.1&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7Edefault-1-113705230-blog-50654629.pc_relevant_default&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7Edefault-1-113705230-blog-50654629.pc_relevant_default&utm_relevant_index=2 操作系统中的描述符和GDT

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值