Winapi NtOpenSection(L";\\Device\\PhysicalMemory";)返回状态“未找到对象”“未找到名称”

Winapi NtOpenSection(L";\\Device\\PhysicalMemory";)返回状态“未找到对象”“未找到名称”,winapi,rom,Winapi,Rom,我正在为Windows系统实施SMBIOS读取功能。由于API级别不同,有几种方法可支持: 无故障GetSystemFirmwareTable('RSMB')可在Windows Server 2003及更高版本上使用 硬核NtOpenSection(L“\\Device\\PhysicalMemory”)适用于Windows XP之前和包括Windows XP在内的旧式系统 L“Win32\u ComputerSystemProduct”路径中的基本WMI数据通过繁琐的COM自动化调用作为回退

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

  • 无故障
    GetSystemFirmwareTable('RSMB')
    可在Windows Server 2003及更高版本上使用
  • 硬核
    NtOpenSection(L“\\Device\\PhysicalMemory”)
    适用于Windows XP之前和包括Windows XP在内的旧式系统
  • L“Win32\u ComputerSystemProduct”
    路径中的基本WMI数据通过繁琐的COM自动化调用作为回退
  • 方法1和3已经实现,但我仍然坚持使用\Device\PhysicalMemory,因为
    NtOpenSection
    总是生成0xC0000034(STATUS\u OBJECT\u NAME\u NOT\u FOUND)-肯定不是
    ZwOpenSection
    文档中可能的结果代码之一。当然,我知道从Windows Server 2003sp1开始,可能也从Windows XP-64开始,访问此部分是被禁止的,因此我正在常规的Windows XP-32系统上尝试此操作,例如,结果与Windows 7-64没有什么不同。我还知道,即使在旧系统上也可能需要管理员权限,但面对此问题的Internet用户报告了此类场景的更多相关错误代码,如0xC0000022(状态\访问\拒绝)和0xC0000005(状态\访问\违反)

    我的方法是基于戴尔的库,我认为这是可行的

    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之类的调试器似乎是透明的:一旦syscenter指令接收到控制,执行就会立即返回。所以我不知道为什么Windows找不到这个对象。我还尝试更改节名,因为在线示例中有几个变体,但这总是会产生0xC0000033(STATUS_OBJECT_name_INVALID)。

    最后,我找到了这种奇怪行为的原因,-感谢大家,确认我的代码片段(它是一个实际摘录,不是伪造的示例)确实有效。问题是我最初没有安装Windows DDK(我现在安装了,但仍然无法以Windows SDK自动集成的方式将其与Visual Studio集成),因此需要手动编写定义。特别是,当我意识到
    InitializeObjectAttributes
    实际上是一个预处理器宏而不是Win32函数时,我也将
    RtlInitUnicodeString
    定义为一个宏,因为它的效果更简单。然而,我没有注意到
    UNICODE\u STRING.Length
    MaximumLength
    实际上是指内容大小和缓冲区大小而不是长度。E字节数而非字符数。因此,我的宏将字段设置为其预期值的一半,从而使Windows只能看到
    L“\\Device\\PhysicalMemory”
    字符串的前一半,结果很明显。

    如果要调试到内核模式,则需要内核调试器,例如。或许可以尝试WinObj(可从Microsoft网站获得)要再次检查该节是否存在?并尝试Process Monitor(同上)以查看它是否会捕获NtOpenSection请求,以防它因某种原因被重定向。@HarryJohnston关于系统内部结构的观点很好,但该实用程序实际上什么也不显示:我用
    Sleep(2000)
    包围了
    NtOpenSection()
    ,进程监视器只记录当时发生的4个概要文件事件;不从系统模块中排除事件也没有帮助。适用于我的Windows 7 x64,也就是说,我的访问被拒绝,而不是找不到对象。你能提供吗?在Vista x86上也适用于我(拒绝访问)。我没有XP系统可以试用。这是一个非常危险的建议,将
    RtlInitUnicodeString
    定义为宏。这是一个非常有意的函数,如果您尝试您描述的传递缓冲区而不是文本,它将在您面前爆炸。出于您所描述的目的,有一个非常有用的
    RTL\u CONSTANT\u STRING
    宏,它使用文字来实现您想要的功能(并且还会导致缓冲区出现意外行为)。此外,该对象只能从内核模式打开(
    OBJ\u kernel\u EXCLUSIVE
    )。