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

第四章 探索 Windows 2000 的内存管理机制
翻译: Kendiv( fcczj@263.net)
更新: Sunday, February 17, 2005
声明:转载请注明出处,并保证文章的完整性,本人保留译文的所有权利 。
IOCTL 函数 SPY_IO_INTERRUPT
SPY_IO_INTERRUP 类似于 SPY_IO_SEGEMT,不过该函数仅影响存储在系统中断描述符表( IDT )的中断描述符,不会涉及 LDT 或 GDT 描述符 。IDT 最多可容纳 256 个描述符,这些描述符可用来描述任务门、中断门或陷阱门(参见 Intel 1999c, pp. 5-11ff ) 。顺便说一下,中断和陷阱在本质上十分相似,二者只存在微小的差异:在进入一个中断处理例程后,总是会屏蔽其他中断;而进入陷阱处理例程却不会修改中断标志 。SPY_IO_INTERRUPT 的调用者提供一个 0 到 255 之间的中断号,该中断号将位于输入缓冲区中,而一个 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

推荐阅读