NtOpenSection(L"\\Device\\PhysicalMemory") returns STATUS_OBJECT_NAME_NOT_FOUND

NtOpenSection(L"\\Device\\PhysicalMemory") returns STATUS_OBJECT_NAME_NOT_FOUND

我正在为 Windows 系统实现 SMBIOS 读取功能。由于API级别不同,有几种支持方法:

  1. 无故障 GetSystemFirmwareTable('RSMB') 在 Windows Server 2003 及更高版本上可用;
  2. hardcore NtOpenSection(L"\Device\PhysicalMemory") 适用于 Windows XP 之前的遗留系统;
  3. L"Win32_ComputerSystemProduct" 路径中的基本 WMI 数据通过繁琐的 COM 自动化调用作为后备。

方法 1 和 3 已经实现,但我坚持使用 \Device\PhysicalMemory,因为 NtOpenSection 总是产生 0xC0000034 (STATUS_OBJECT_NAME_NOT_FOUND) — 绝对不是可能的结果代码之一ZwOpenSection 文档。当然,我知道从 Windows Server 2003sp1 和 Windows XP-64 开始禁止访问此部分,所以我在常规 Windows XP-32 上尝试此操作系统 - 结果与 Windows 7-64 的结果没有什么不同,例如。我也知道即使在遗留系统上也可能需要管理员权限,但互联网上遇到此问题的人报告了此类情况的更多相关错误代码,例如 0xC0000022 (STATUS_ACCESS_DENIED) 和 0xC0000005 (STATUS_ACCESS_VIOLATION ).

我的方法基于戴尔的 Libsmbios 库,我认为它可以工作。

UNICODE_STRING wsMemoryDevice;
OBJECT_ATTRIBUTES oObjAttrs;
HANDLE hMemory;
NTSTATUS ordStatus;

RtlInitUnicodeString(&wsMemoryDevice, L"\Device\PhysicalMemory");
InitializeObjectAttributes(&oObjAttrs, &wsMemoryDevice,
    OBJ_CASE_INSENSITIVE, NULL, NULL);

ordStatus = NtOpenSection(&hMemory, SECTION_MAP_READ, &oObjAttrs);
if (!NT_SUCCESS(ordStatus)) goto Finish;

我认为可以调试它,但是本机 API 似乎对像 OllyDbg 这样的调试器是透明的:一旦 SYSENTER 指令接收到控制权,立即 returns 执行。所以我不知道为什么 Windows 找不到这个对象。我还尝试更改部分名称,因为在线示例中有多种变体,但始终会产生 0xC0000033 (STATUS_OBJECT_NAME_INVALID).

终于,我找到了这种奇怪行为的原因,- 感谢大家,确认我的代码片段(这是一个实际的摘录,而不是伪造的例子)确实有效。问题是我最初没有安装 Windows DDK(我现在已经安装了,但仍然无法以 Windows SDK 自动集成的方式将其与 Visual Studio 集成),所以有需要手写定义。特别是,当我意识到 InitializeObjectAttributes 实际上是一个预处理器宏而不是 Win32 函数时,我也将 RtlInitUnicodeString 定义为一个宏,因为它的效果更简单。但是,我不够仔细,没有注意到 UNICODE_STRING.Length.MaximumLength 实际上是针对 content sizebuffer size 而不是 length, i. e. 字节数 而不是 字符数 。因此,我的宏将字段设置为预期值的一半,从而使 Windows 只能看到 L"\Device\PhysicalMemory" 字符串的前半部分,结果很明显。