分享
 
 
 

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

王朝system·作者佚名  2006-01-09
窄屏简体版  字體: |||超大  

第四章 探索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 << 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结构中取出Offset1和Offset2位域,并适当的组织它们以构成一个32位地址。SpyIdtGaet()定义于列表4-19。它与SpyDescriptor()十分类似。汇编指令SIDT存储一个48位的值,该值就是CPU的IDT寄存器的内容,它由一个16位的表大小限制值和IDT的32位线性基地址构成。列表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

{

sidt idt.wLimit

}

if ((pSelector->wValue & X86_SELECTOR_INDEX)

<= idt.wLimit)

{

pGates = idt.pGates;

}

}

if (pGates != NULL)

{

RtlCopyMemory (pGate,

pGates + pSelector->Index,

X86_GATE_);

fOk = TRUE;

}

else

{

RtlZeroMemory (pGate, X86_GATE_);

}

}

return fOk;

}

列表4-19. 获取IDT门的值

IOCTL函数SPY_IO_PHYSICAL

SPY_IO_PHYSICAL函数很简单,它完全依赖于ntoskrnl.exe导出的MmGetPhysicalAddress()函数。该IOCTL函数通过简单的调用SpyInputPointer()(参见列表4-10)来获取需要转换的线性地址,然后让MmGetPhysicalAddress()查找对应的物理地址,最后将结果作为PHYSICAL_ADDRESS结构返回给调用者。注意,PHYSICAL_ADDRESS是一个64位的LARGE_INTEGER。在大多数i386系统上,其高32位总是为0。不过,若系统启用了物理地址扩展(Physical Address Extension, PAE),并且安装的内存大于4GB,这些位可能就是非0值了。

MmGetPhysicalAddress()使用起始于线性地址0xC0000000的PTE数组,来进行物理地址的查找。其基本的工作机制如下:

l 如果线性地址位于:0x80000000----0x9FFFFFFF,则其高3位将被设为零,最后产生的物理地址位于:0x00000000-----0x1FFFFFFF。

l 否则,线性地址的高20位将作为PTE数组(起始于0xC0000000)的索引。

l 如果目标PTE的P位已被设置,这表示其对应得数据页存在于物理内存中。除了20位的PFN外,所有的PTE位都可以被剥离出来,线性地址最低的12位将作为在数据页中的偏移量被加到最后的32位物理地址上去。

l 如果数据页没有存在于物理内存中,MmGetPhysicalAddress()返回0。

MmGetPhysicalAddress()假设内核内存范围:0x80000000----0x9FFFFFF之外的所有线性地址都使用4KB的页。而其他函数,如MmIsAddressValid(),会首先加载线性地址的PDE,并且检查该PDE的PS位,以检查页大小是4KB还是4MB。这是一个非常通用的方法,可以处理任意的内存配置。不过上述两个函数都会返回正确的结果,这是因为Windows 2000仅针对内存范围:0x80000000-----0x9FFFFFFF,使用4MB页。不过某些内核API函数,显然设计的比其它的灵活许多。

IOCTL函数SPY_IO_CPU_INFO

个别的CPU指令仅对运行于Ring 0级的代码有效,Ring 0是五个特权级(Intel系列的CPU只支持两个特权级:Ring0和Ring3)中级别最高的一个。用Windows术语来说,Ring 0意味着内核模式(Kernel-mode)。这些被禁止的指令有:读取控制寄存器CR0、CR2和CR3的内容。因为这些寄存器中保存着非常有趣的信息,应用程序可能想要找到一个办法来访问它们,解决方案就是SPY_IO_CPU_INFO函数。如列表4-20所示,IOCTL处理例程调用的SpyOutputCpuInfo()函数使用了一些嵌入式汇编来读取控制寄存器,以及其他一些有价值的信息,比如IDT的内容,GDT和LDT寄存器以及存储在寄存器CS、DS、ES、FS、GS、SS和TR中的段选择器。任务寄存器(Task Register, TR)还包含一个涉及当前任务的TSS的选择器。

typedef struct _SPY_CPU_INFO

{

X86_REGISTER cr0;

X86_REGISTER cr2;

X86_REGISTER cr3;

SPY_SEGMENT cs;

SPY_SEGMENT ds;

SPY_SEGMENT es;

SPY_SEGMENT fs;

SPY_SEGMENT gs;

SPY_SEGMENT ss;

SPY_SEGMENT tss;

X86_TABLE idt;

X86_TABLE gdt;

X86_SELECTOR ldt;

}

SPY_CPU_INFO, *PSPY_CPU_INFO, **PPSPY_CPU_INFO;

#define SPY_CPU_INFO_ sizeof (SPY_CPU_INFO)

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

NTSTATUS SpyOutputCpuInfo (PVOID pOutput,

DWORD dOutput,

PDWORD pdInfo)

{

SPY_CPU_INFO sci;

PSPY_CPU_INFO psci = &sci;

__asm

{

push eax

push ebx

mov ebx, psci

mov eax, cr0

mov [ebx.cr0], eax

mov eax, cr2

mov [ebx.cr2], eax

mov eax, cr3

mov [ebx.cr3], eax

sidt [ebx.idt.wLimit]

mov [ebx.idt.wReserved], 0

sgdt [ebx.gdt.wLimit]

mov [ebx.gdt.wReserved], 0

sldt [ebx.ldt.wValue]

mov [ebx.ldt.wReserved], 0

pop ebx

pop eax

}

SpySegment (X86_SEGMENT_CS, 0, &sci.cs);

SpySegment (X86_SEGMENT_DS, 0, &sci.ds);

SpySegment (X86_SEGMENT_ES, 0, &sci.es);

SpySegment (X86_SEGMENT_FS, 0, &sci.fs);

SpySegment (X86_SEGMENT_GS, 0, &sci.gs);

SpySegment (X86_SEGMENT_SS, 0, &sci.ss);

SpySegment (X86_SEGMENT_TSS, 0, &sci.tss);

return SpyOutputBinary (&sci, SPY_CPU_INFO_,

pOutput, dOutput, pdInfo);

}

列表4-20. 查询CPU状态信息

可使用帮助函数SpySegement()获取段选择器,在前面,我们已讨论过该函数。参见列表4-15。

………………待续…………………

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有