当前位置:早雪网网络学院编程文档其他语言 → 《Undocumented Windows 2000 Secrets》翻译 --- 第四章(5)

《Undocumented Windows 2000 Secrets》翻译 --- 第四章(5)

减小字体 增大字体 作者:未知  来源:supcode.com收集整理  发布时间:2005-7-1 14:39:16

第四章  探索Windows 2000的内存管理机制

翻译:Kendiv( fcczj@263.net )

更新:Sunday, February 17, 2005

 

声明:转载请注明出处,并保证文章的完整性,本人保留译文的所有权利。

 

IOCTL函数SPY_IO_INTERRUPT

SPY_IO_INTERRUP类似于SPY_IO_SEGEMT,不过该函数仅影响存储在系统中断描述符表(IDT)的中断描述符,不会涉及LDTGDT描述符。IDT最多可容纳256个描述符,这些描述符可用来描述任务门、中断门或陷阱门(参见Intel 1999c, pp. 5-11ff)。顺便说一下,中断和陷阱在本质上十分相似,二者只存在微小的差异:在进入一个中断处理例程后,总是会屏蔽其他中断;而进入陷阱处理例程却不会修改中断标志。SPY_IO_INTERRUPT的调用者提供一个0255之间的中断号,该中断号将位于输入缓冲区中,而一个SPY_INTERRUPT结构将作为输出数据被存放到输出缓冲区中,如果成功返回,该结构中将包含对应的中断处理例程的属性。由Dispatcher调用的帮助函数SpyOutputInterrupt()只是一个简单的外包函数,它实际上调用SpyInterrupt()函数并且将需要返回的数据复制到输出缓冲区中。列表4-18给出了这两个函数,以及它们操作的SPY_INTERRUPT结构。稍后一些,SpyInterrupt()函数将填充如下项目:

l         Selector  用来指定一个任务状态段(Task-State Segment, TSS)或代码段(Code Segment)的选择器。代码段选择器用来确定中断或陷阱处理例程所在的段。

 

l         Gate  用来表示一个64位的任务门、中断门或陷阱门描述符,由Selector确定其地址。

 

l         Segment  包含段的属性,该段的地址由前面的Gate给出。

 

l         pOffset  指定中断或陷阱处理例程的入口地址相对基地址的偏移量。这里的基地址是指中断或陷阱处理例程所在代码段的起始地址。因为任务门不包含偏移量,所以,如果输入的选择器指向一个TSS,则忽略该成员。

 

l         fOk  一个标志变量,用来指示SPY_INTERRUPT结构中的数据是否有效。

 

通常情况下,TSS被用来保证一个错误情况可以被一个有效的任务处理。这是一个特殊的系统段类型(system segment type),它可以保存104个字节的进程状态信息,该信息在任务切换时,用来进行任务的恢复,如4-3所示。当与任务相关的中断发生时,CPU总是强制切换该任务,并将所有的CPU寄存器保存到TSS中。Windows 2000在中断位置0x02(非屏蔽中断[NMI]0x08[Double Fault]0x12[堆栈段故障])处保存任务门。剩余的位置指向中断处理例程。不使用的中断由一个哑元例程---KiUnexpectedInterruptNNN()处理,这里的NNN为一个十进制数。这些哑元例程最后都汇集到内部函数KiEndUnexpectedRange(),在这里,这些例程将依次进入KiUnexpectedInterruptTail()

 

typedef struct _SPY_INTERRUPT

    {

    X86_SELECTOR Selector;

    X86_GATE     Gate;

    SPY_SEGMENT  Segment;

    PVOID        pOffset;

    BOOL         fOk;

    }

    SPY_INTERRUPT, *PSPY_INTERRUPT, **PPSPY_INTERRUPT;

 

#define SPY_INTERRUPT_ sizeof (SPY_INTERRUPT)

 

// -----------------------------------------------------------------

NTSTATUS SpyOutputInterrupt (DWORD  dInterrupt,

                             PVOID  pOutput,

                             DWORD  dOutput,

                             PDWORD pdInfo)

    {

    SPY_INTERRUPT si;

 

    SpyInterrupt (dInterrupt, &si);

 

    return SpyOutputBinary (&si, SPY_INTERRUPT_,

                            pOutput, dOutput, pdInfo);

    }

 

// -----------------------------------------------------------------

BOOL SpyInterrupt (DWORD          dInterrupt,

                   PSPY_INTERRUPT pInterrupt)

    {

    BOOL fOk = FALSE;

 

    if (pInterrupt != NULL)

        {

        if (dInterrupt <= X86_SELECTOR_LIMIT)

            {

            fOk = TRUE;

 

            if (!SpySelector (X86_SEGMENT_OTHER,

                              dInterrupt << X86_SELECTOR_SHIFT,

                              &pInterrupt->Selector))

                {

                fOk = FALSE;

                }

            if (!SpyIdtGate  (&pInterrupt->Selector,

                              &pInterrupt->Gate))

                {

                fOk = FALSE;

                }

            if (!SpySegment  (X86_SEGMENT_OTHER,

                              pInterrupt->Gate.Selector,

                              &pInterrupt->Segment))

                {

                fOk = FALSE;

                }

            pInterrupt->pOffset = SpyGateOffset (&pInterrupt->Gate);

            }

        else

            {

            RtlZeroMemory (pInterrupt, SPY_INTERRUPT_);

            }

        pInterrupt->fOk = fOk;

        }

    return fOk;

    }

 

// -----------------------------------------------------------------

PVOID SpyGateOffset (PX86_GATE pGate)

    {

    return (PVOID) (pGate->Offset1 | (pGate->Offset2 << 16));

    }

列表4-18.  查询中断属性

 

4-3.    任务状态段(TSS)中的CPU状态域

偏移量

位数

ID

     

0x00

16

 

前一个任务的链接

0x04

32

ESP0

Ring0级的堆栈指针寄存器

0x08

16

SS0

Ring0级的堆栈段寄存器

0x0C

32

ESP1

Ring1级的堆栈指针寄存器

0x10

16

SS1

Ring1级的堆栈段寄存器

0x14

32

ESP2

Ring2级的堆栈指针寄存器

0x18

16

SS2

Ring2级的堆栈段寄存器

0x1C

32

CR3

页目录基址寄存器(PDBR

0x20

32

EIP

指令指针寄存器

0x24

32

EFLAGS

处理器标志寄存器

0x28

32

EAX

通用寄存器

0x2C

32

ECX

通用寄存器

0x30

32

EDX

通用寄存器

0x34

32

EBX

通用寄存器

0x38

32

ESP

堆栈指针寄存器

0x3C

32

EBP

基地址指针寄存器

0x40

32

ESI

源索引寄存器

0x44

32

EDI

目标索引寄存器

0x48

16

ES

扩展段寄存器

0x4C

16

CS

代码段寄存器

0x50

16

SS

堆栈段寄存器

0x54

16

DS

数据段寄存器

0x58

16

FS

附加的数据段寄存器#1

0x5C

16

GS

附加的数据段寄存器#2

0x60

16

LDT

本地描述符标的段选择器

0x64

1

1

调试陷阱标志

0x66

16

 

I/O Map的基地址

0x68

-

 

CPU状态信息结束

 

SpyInterrupt()调用的SpySegment()SpySelector()函数已经在列表4-5列表4-16中给出。SpyGateOffset()位于列表4-18的末尾,它的工作和SpyDescriptorBase()SpyDescriptorLimit()类似,从X86_GATE结构中取出Offset1Offset2位域,并适当的组织它们以构成一个32位地址。SpyIdtGaet()定义于列表4-19。它与SpyDescriptor()十分类似。汇编指令SIDT存储一个48位的值,该值就是CPUIDT寄存器的内容,它由一个16位的表大小限制值和IDT32位线性基地址构成。列表4-19中的剩余代码将选择器的描述符索引和IDT的大小限制值进行比较,如果OK,则对应的中断描述符将被复制到调用者提供的X86_GATE结构中。否则,门结构的所有成员都将被设置为0

 

BOOL SpyIdtGate (PX86_SELECTOR pSelector,

                 PX86_GATE     pGate)

    {

    X86_TABLE idt;

    PX86_GATE pGates = NULL;

    BOOL      fOk    = FALSE;

 

    if (pGate != NULL)

        {

        if (pSelector != NULL)

            {

            __asm

                {