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


1. DeviceType 这是一个 16 位的设备类型 ID。ntddk.h 列出了一对预定义的类型,由符号常量 FILE_DEVICE_* 表示 。0x0000 到 0x7FFF 保留给微软内部使用,开发人员可使用 0x8000 到 0xFFFF。Spy 驱动程序定义了它自己的设备 ID : FILE_DEVICE_SPY,其值为 0x8000。
2. 2 位的访问检查值用来确定 IOCTL 操作所需的访问权限 。可能的值有: FILE_ANY_ACCESS (0),FILE_READ_ACCESS (1),FILE_WRITE_ACCESS (2) 和最后两个的组合: FILE_READ_ACCESS | FILE_WRITE_ACCESS (3)。详见 ntddk.h。
3. 12 个位的 ID 表示所选择的操作函数,所选操作将由设备来执行 。0x0000 到 0x7FFF 保留给微软内部使用,开发人员可使用 0x8000 到 0xFFFF。Spy 设备采用的 IOCTL 函数 ID 位于 0x8000 到 0xFFFF。
4. 传输模式占用 2 个位,可在四个可用 I/O 传输模式中选择一个,这四个模式为: METHOD_BUFFERED (0),METHOD_IN_DIRECT (1),METHOD_OUT_DIRECT (2) 和 METHOD_NETTHER (3),可在 ntddk.h 中找到这些定义 。Spy 设备针对所有请求使用 METHOD_BUFFERED,这是一个非常安全但有些慢的模式,因为数据需要在客户端和系统缓冲区之间进行复制 。因为 Memory Spy 对 I/O 的处理速度并不敏感,所以选择安全是一个不错的注意 。如果你希望知道其他模式的细节,请参考我在 Windows Developer"s Journal(Schreiber 1997) 发表的文章“ A Spy Filter Driver for Windows NT ”
表 4-2 列出了 w2k_spy.sys 支持的所有 IOCTL 函数 。0 到 10 的函数 ID 为最基本的内存探测函数,绝大部分的任务都会用到它们;本章稍候将讨论它们 。剩余的函数 ID 从 11 到 23 分属于不同的 IOCTL 组,在下一章我们将讨论它们,在下一章,我们将讨论 Native API hook 和在用户模式下调用内核 。注意某些 IOCTL 编码需要写入权限,由第 15 号位表示(参见 图 4-6 ) 。确切的说,所有形如 0x80006nnn 的 IOCTL 命令只需读权限,而形如 0x8000Ennn 的命令需要读 / 写权限 。典型的要求读权限的例子是 CreateFile(),它通过指定 dwDesiredAccess 参数为 GENERIC_READ 和 GENERIC_WRITE 的组合来打开设备 。
表 4-2 最左面的函数名称同样出现在 SpyDispatcher() (见 列表 4-7 )中那个庞大的 switch/case 语句中 。这些函数首先获取设备的 dispatcher mutex,这样就能保证,如果一个以上的客户端或一个多线程的程序和设备通讯时,在同一时间只有一个请求被执行 。MUTEX_WAIT() 是 KeWaitForMutexObject() 的外包宏( wrapper marco ),KeWaitForMutexObject() 至少需要 5 个参数 。KeWaitForMutexObject() 本身也是一个宏,它将传入的参数向前传递给 KeWaitForSingleObject()。列表 4-9 给出了 MUTEX_WAIT() 以及它的伙伴 MUTEX_RELEASE() 和 MUTEX_INITIALIZE()。在 mutex 对象变为有信号( signaled )状态后,根据接收到的 IOCTL 编码,SpyDispatcher() 会转向不同的分支,每个分支都包含多种简单的代码序列 。
表 4-2. w2k_spy.sys 支持的 IOCTL 函数
函数名称
ID
IOCTL 编码
描 述
SPY_IO_VERSION_INFO
0
0x80006000
返回 Spy 的版本信息
SPY_IO_OS_INFO
1
0x80006004
返回操作系统的版本信息
SPY_IO_SEGMENT
2
0x80006008
返回一个段的属性
SPY_IO_INTERRUPT
3
0x8000600C
返回一个中断门的属性
SPY_IO_PHYSICAL
4
0x80006010
线性地址转换为物理地址
SPY_IO_CPU_INFO
5
0x80006014
返回特殊 CPU 寄存器的值
SPY_IO_PDE_ARRAY
6
0x80006018
返回位于 0xC0300000 的 PDE 数组
SPY_IO_PAGE_ENTRY
7
0x8000601C
Return the PDE or PTE of a linear address
SPY_IO_MEMORY_DATA
8
0x80006020
返回内存块中的内容
SPY_IO_MEMORY_BLOCK
9
0x80006024