用户名: 密码: 免费注册 忘记密码? 网站地图 | 加入收藏 | 设为首页
首页 | 新闻 | 工具 | 系统 | 办公 | 聊天 | 多媒体 | 网页 | 运营 | 平面 | 欣赏 | 数据库 | 程序 | 服务器 | 组网
网页 | 3dmax | Ghost | Windows Xp| Dreamweaver | photoshop | Flash | office | Alexa | Css | QQ | Asp | PHP | Jsp | Access
Flash MX 2004入门 | 网站推广策略 | CorelDRAW入门 | ASP学习 | 网站建设大师功 | Word入门
  iTbulo.com > 学院 > 操作系统教程 > Windows2000教程 > 文章正文
《Undocumented Windows 2000 Secrets》翻译 --- 第四章(4)
iTbulo.COM 2005-8-3 ccxunmeng()

typedef struct _SPY_VERSION_INFO

{

DWORD dVersion;

WORD awName [SPY_NAME];

}

SPY_VERSION_INFO, *PSPY_VERSION_INFO, **PPSPY_VERSION_INFO;

#define SPY_VERSION_INFO_ sizeof (SPY_VERSION_INFO)

NTSTATUS SpyOutputVersionInfo (PVOID pOutput,

DWORD dOutput,

PDWORD pdInfo)

{

SPY_VERSION_INFO svi;

svi.dVersion = SPY_VERSION;

wcscpyn (svi.awName, USTRING (CSTRING (DRV_NAME)), SPY_NAME);

return SpyOutputBinary (&svi, SPY_VERSION_INFO_,

pOutput, dOutput, pdInfo);

}

列表 4-12. 获取 Spy 驱动程序的版本信息

IOCTL 函数 SPY_IO_OS_INFO

该函数比上一个有趣的多。它是另一个只有输出的函数,不需要输入参数,使用几个操作系统的内部参数来填充调用者提供的 SPY_OS_INFO 结构。 列表 4-13 列出了该结构的定义,和 Dispatcher 调用的 SpyOutputOsInfo() 帮助函数。有些结构体成员只是被简单的设为定义于 DDK 头文件和 w2k_spy.h 中的常量;其他的将被设为从几个内部的内核变量和结构体中读取的当前值。在第二章中,你已经了解了变量 NtBuildNumber 和 NtGlobalFlag (由 ntoskrnl.exe 导出,参见 附录 B 中的 B-1 )。和其他的 Nt* 符号不同,这两个符号不指向 API 函数,而是指向位于内核的 .data section 中的变量。在 Win32 世界里,导出变量是十分罕见的。不过, Windows 2000 的几个内核模块都使用了这一技术。 Ntoskrnl.exe 导出了至少 55 个变量, ntdll.dll 提供了 4 个, hal.dll 提供了 1 个。 SpyOutputOsInfo() 将从 ntoskrnl.exe 导出的变量中复制 MmHighestUserAddress 、 MmUserProbeAddress 、 MmSystemRangeStart 、 NtGlobalFlag 、 KeI386MachineType 、 KeNumberProcessors 和 NtBuildNumber 到输出缓冲区中。

当一个模块从另一个模块中导入数据时,它需要使用 extern 关键字来通知编译器和链接器。这会使链接器生成一个进入模块导出节的入口,并会解析符号名以确定其地址。有些 extern 声明已经包含在 ntddk.h 。 列表 4-13 给出了缺失的那些 extern 声明。

extern PWORD NlsAnsiCodePage;

extern PWORD NlsOemCodePage;

extern PWORD NtBuildNumber;

extern PDWORD NtGlobalFlag;

extern PDWORD KeI386MachineType;

typedef struct _SPY_OS_INFO

{

DWORD dPageSize;

DWORD dPageShift;

DWORD dPtiShift;

DWORD dPdiShift;

DWORD dPageMask;

DWORD dPtiMask;

DWORD dPdiMask;

PX86_PE PteArray;

PX86_PE PdeArray;

PVOID pLowestUserAddress;

PVOID pThreadEnvironmentBlock;

PVOID pHighestUserAddress;

PVOID pUserProbeAddress;

PVOID pSystemRangeStart;

PVOID pLowestSystemAddress;

PVOID pSharedUserData;

PVOID pProcessorControlRegion;

PVOID pProcessorControlBlock;

DWORD dGlobalFlag;

DWORD dI386MachineType;

DWORD dNumberProcessors;

DWORD dProductType;

DWORD dBuildNumber;

DWORD dNtMajorVersion;

DWORD dNtMinorVersion;

WORD awNtSystemRoot [MAX_PATH];

}

SPY_OS_INFO, *PSPY_OS_INFO, **PPSPY_OS_INFO;

#define SPY_OS_INFO_ sizeof (SPY_OS_INFO)

NTSTATUS SpyOutputOsInfo (PVOID pOutput,

DWORD dOutput,

PDWORD pdInfo)

{

SPY_SEGMENT ss;

SPY_OS_INFO soi;

NT_PRODUCT_TYPE NtProductType;

PKPCR pkpcr;

NtProductType = (SharedUserData->ProductTypeIsValid

? SharedUserData->NtProductType

: 0);

SpySegment (X86_SEGMENT_FS, 0, &ss);

pkpcr = ss.pBase;

soi.dPageSize = PAGE_SIZE;

soi.dPageShift = PAGE_SHIFT;

soi.dPtiShift = PTI_SHIFT;

soi.dPdiShift = PDI_SHIFT;

soi.dPageMask = X86_PAGE_MASK;

soi.dPtiMask = X86_PTI_MASK;

soi.dPdiMask = X86_PDI_MASK;

soi.PteArray = X86_PTE_ARRAY;

soi.PdeArray = X86_PDE_ARRAY;

soi.pLowestUserAddress = MM_LOWEST_USER_ADDRESS;

soi.pThreadEnvironmentBlock = pkpcr->NtTib.Self;

soi.pHighestUserAddress = *MmHighestUserAddress;

soi.pUserProbeAddress = (PVOID) *MmUserProbeAddress;

soi.pSystemRangeStart = *MmSystemRangeStart;

soi.pLowestSystemAddress = MM_LOWEST_SYSTEM_ADDRESS;

soi.pSharedUserData = SharedUserData;

soi.pProcessorControlRegion = pkpcr;

soi.pProcessorControlBlock = pkpcr->Prcb;

soi.dGlobalFlag = *NtGlobalFlag;

soi.dI386MachineType = *KeI386MachineType;

soi.dNumberProcessors = *KeNumberProcessors;

soi.dProductType = NtProductType;

soi.dBuildNumber = *NtBuildNumber;

soi.dNtMajorVersion = SharedUserData->NtMajorVersion;

soi.dNtMinorVersion = SharedUserData->NtMinorVersion;

wcscpyn (soi.awNtSystemRoot, SharedUserData->NtSystemRoot,

MAX_PATH);

return SpyOutputBinary (&soi, SPY_OS_INFO_,

pOutput, dOutput, pdInfo);

}

列表 4-13. 获取有关操作系统的信息

SPY_OS_INFO 结构的剩余成员会由位于内存中的系统数据结构填充。例如, SpyOutputOsInfo() 将内核的进程控制区域( Kernel's Processor Control Region, KPCR )的基地址赋值给 pProcessorControlRegion 成员。 KPCR 是一个非常重要的数据结构,该结构包含很多线程相关的数据项,因此,它位于自己的内存段中,该内存段的地址由 CPU 的 FS 寄存器给出。 Windows NT 4.0 和 Windows 2000 都将 FS 指向处于内核模式的线性地址 0xFFDFF000 。 SpyOutputOsInfo() 调用 SpySegment() 函数(稍后讨论它)来查询 FS 段在线性地址空间中的基地址。这个段中还包含内核的进程控制块( Kernel's Processor Control Block, KPRCB ), KPCR 结构的 Prcb 成员指向 KPRCB 结构的首地址,紧随其后的是一个 CONTEXT 结构,该结构包含当前线程的底层 CPU 信息。 KPCR 、 KPRCB 和 CONTEXT 结构定义在 ntddk.h 头文件中。

列表 4-13 中引用的另一个内部数据结构是 SharedUserData 。该结构实际上是一个由一个“众所周知的地址”通过类型转化( TypeCast )得来的结构体指针。 列表 4-14 给出了它在 ntddk.h 中的定义。那个“众所周知的地址”位于线性地址空间中,它会在编译时被设置,因此不需要花费额外的时间或进行配置。显然, SharedUserData 是一个指向 KUSER_SHARED_DATA 结构的指针,该结构的基地址在 0xFFDF0000 (这是一个线性地址)。这个内存区域由系统和用户模式的应用程序共享,它包含像操作系统版本号这样的数据, SpyOutputOsInfo() 将该版本数据复制到 SPY_OS_INFO 结构(由调用者提供)的 dNtMajorVersion 和 dNtMinorVersion 成员。就像我稍后要展示的那样, KUSER_SHARED_DATA 结构将被映射到 0x7FFE0000 ,这样用户模式的代码就可以访问它了。

在对 Spy 设备的 IOCTL 函数的讲解之后还将提供了一个示例程序,该示例程序会把返回的数据显示在屏幕上。

#define KI_USER_SHARED_DATA 0xFFDF0000

#define SharedUserData ((KUSER_SHARED_DATA *const)KI_USER_SHARED_DATA)

列表 4-14. SharedUserData 结构定义

IOCTL 函数 SPY_IO_SEGMENT

到现在讨论以变得更加有趣了。 SPY_IO_SEGMENT 函数通过一些更底层的操作来查询指定段的属性,调用者需要首先给出一个选择器( selector )。 SpyDispatcher() 首先调用 SpyInputDword() 来获取由调用程序传入的选择器的值。你可能还记得选择器( selector )是一个 16 位的数。不过,只要可能,我就会尝试避免使用 16 位的数据类型,这是因为原生的 WORD 在 i386 CPU 的 32 位模式下是 32 位的 DWORD 类型。因此,我将选择器参数扩展为 DWORD ,不过其高 16 位总是 0 。如果 SpyInputDword() 报告操作成功,接下来就会调用 SpyOutputSegemnt() 函数( 列表 4-15 给出了此函数)。不管 SpySegment() 帮助函数如何, SpyOutputSegemnt() 总是返回到调用者。基本上来说, SpySegment() 将填充 SPY_SEGMENT 结构,该结构定义于 列表 4-15 的顶部。它以 X86_SELECTOR 结构(参见 列表 4-2 )的形式给出选择器的值,紧随其后的是 64 位的 X86_DESCRIPTOR ,以及相应的段基址,段的大小限制以及一个名为 fOk 的标志,该标志用来指出 SPY_SEGMENT 结构是否有效。在稍后的一些函数中需要一次返回多个段的属性,利用 fOk 成员,调用者就可以将无效的段信息从输出数据中筛选出来。

上一页  [1] [2] [3] 下一页

文章搜索
相关资讯
相关文章 相关下载
没有相关文章
焦点信息