Enterprise Just Builder

Solution for Enterprise Software Architecture

win32

将 Win32 枚举型 APIs 转换为 STL 迭代器

原文1

操作系统都有许多 API 用于存取实体集合的,比方说 Unix 的 opendir()/readdir() 函数。Win32 API 也提供了许多函数用来枚举集合内的元素,通常采用的模型无外乎下面几种:回调函数 (如 EnumChildWindows), get-first/get-next (取第一个/取下一个 比如FindFirst/NextFile), 或 get-nth (取第n个 如 RegEnumValue) — 其语义和前二者完全不同。

现在 C++ 社区正在逐步朝着符合 STL 的通用编码格式迈进,如使用容器 (序列和关联)、迭代器、泛函 (或函子或函数对象)、算法和适配器等等。这一做法的最大好处是可以采用一种通用的方法操纵不同的实体, 大大减少开发者的工作量, 同时提高健壮性、可维护性和重用。

STL 技术未被广泛运用的原因之一是除了标准库所提供的类和函数 (list, vector, for_each 等) 之外, 缺少可用的 STL 兼容库, 特别对于操作系统 API。原因之一是这涉及编程模型之间迁移转换的复杂性, 特别是对于集合和序列。本文通过将两种 Win32 枚举模型实际转换 STL 序列, 创建封装了 Win32 API 的轻量级序列类, 并提供了可按 STL 标准算法来操纵枚举实体的迭代器。

本文所演示的类是 WinSTL 库的一部分,WinSTL 则是 STLSoft 的子项目。STLSoft 是个开源组织,一直致力于将 STL 概念运用到多种技术和操作系统中去。

>>> 阅读全文

 

, , , ,

为 Windows NT 内核扩展 API

与 Unix 基于中断的系统调用接口类似, Windows NT 提供了大量未经文档化的基础系统服务,即原生 API (Native API)。这些内核模式的系统服务被 Win32、 Posix 和 OS2 等环境子系统用于在 NT 微内核(Windows NT 是个修改过的微内核体系结构的操作系统)之上实现其运行环境。在 Win32 下,原生 API 通过 NTDLL.DLL 的导出函数提供给其他 API 和程序使用,如 KERNEL32.DLL 中的许多函数只是简单地重定向到 NTDLL.DLL 中。

事实上 NTDLL.DLL 那些调用系统服务的函数不过是个存根函数,它们只是对 SysEnter/SysCall(早些版本使用 INT 2EH)1等系统调用接口的简单包装。以 NtCreateFile 函数为例:(Windows 7 SP1 64位):2 ,它的具体实现如下:

mov     r10,rcx ;保存 rcx 的值,rcx 将被置为 rip(返回值)
mov     eax,52h ;系统调用号
syscall
ret
nop     dword ptr [rax+rax]

存根函数负责在 EAX 中填入系统调用号,随后执行本机调用接口实现从用户态向内核态的跳转。EAX 中的调用号将用以查找并调用系统服务以完成 API 的最终功能。每个原生 API 的调用号各不同,例子中 NTCreateFile 的调用号是 0x52h,且随着 Windows 的版本和架构不尽相同,有兴趣的话可以查询 Windows X86 系统调用表Windows X86-64 系统调用表

执行 SYSCALL 或 SYSENTER 时,CPU 并不会象执行 CALL一样保存返回地址和状态信息,所以需要存根函数来保存返回信息。3

当从原生 API 进入内核态以后,后续则交由 NCI 派发器 (NCI Dispatcher)处理。 NCI 派发器在微内核中(NTOSKRNL.EXE) 实现的, NCI 派发器( _KiSystemService ) 本质上就是 INT 2EH 的处理函数(handler)。NCI 派发器通过系统服务描述符表 (System Service Descriptor Table — SSDT) 来查找并调用某个服务的相应处理函数,函数参数则通过 NCI 传递。(一些内核调试器比如 IMHO 或者 NuMega Soft-ICE 可以通过 NTCALL 命令来显示 SSDT)。 微软并未提供文档来说明如何扩展原生 API,并通过 NCI 来调用自己的内核服务。所以本文试图通过变通的办法来解决这一问题。不过在此之前,我们还是大致看一下来如何通过 NCI 来调用原生 API 服务,或者其他 NCI 服务。

>>> 阅读全文

 

, , , ,