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


}
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

推荐阅读