4

I am implementing SMBIOS reading functionality for Windows systems. As API levels vary, there are several methods to support:

  1. trouble-free GetSystemFirmwareTable('RSMB') available on Windows Server 2003 and later;
  2. hardcore NtOpenSection(L"\\Device\\PhysicalMemory") for legacy systems prior to and including Windows XP;
  3. essential WMI data in L"Win32_ComputerSystemProduct" path through cumbersome COM automation calls as a fallback.

Methods 1 and 3 are already implemented, but I am stuck with \Device\PhysicalMemory, as NtOpenSection always yields 0xC0000034 (STATUS_OBJECT_NAME_NOT_FOUND) — definitely not one of the possible result codes in the ZwOpenSection documentation. Of course, I am aware that accessing this section is prohibited starting from Windows Server 2003sp1 and perhaps Windows XP-64 as well, so I am trying this on a regular Windows XP-32 system — and the outcome is no different to that of a Windows 7-64, for example. I am also aware that administrator rights may be required even on legacy systems, but people on the internets having faced this issue reported more relevant error codes for such scenario, like 0xC0000022 (STATUS_ACCESS_DENIED) and 0xC0000005 (STATUS_ACCESS_VIOLATION).

My approach is based on the Libsmbios library by Dell, which I assume to be working.

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;

I thought it could be possible to debug this, but native API seems to be transparent to debuggers like OllyDbg: the execution immediately returns once SYSENTER instruction receives control. So I have no idea why Windows cannot find this object. I also tried changing the section name, as there are several variants in examples available online, but that always yields 0xC0000033 (STATUS_OBJECT_NAME_INVALID).

Anton Samsonov
  • 1,380
  • 17
  • 34
  • 1
    If you want to debug into kernel mode, you'll need a kernel debugger, like [WinDbg or kd](https://msdn.microsoft.com/en-us/library/windows/hardware/ff551063.aspx). – IInspectable Apr 16 '15 at 19:12
  • 1
    Perhaps try WinObj (available from the Microsoft web site) to double-check that the section does exist? And try Process Monitor (ditto) to see if it will capture the NtOpenSection request, in case it is being redirected for some reason. – Harry Johnston Apr 17 '15 at 02:22
  • @HarryJohnston Good point about Sysinternals, but this utility actually displays nothing: I surrounded `NtOpenSection()` with `Sleep(2000)`, and Process Monitor only logs 4 profile events happening at that time; not excluding events from the *System* module does not help either. – Anton Samsonov Apr 17 '15 at 18:32
  • 1
    Works for me on Windows 7 x64, that is, I get access denied rather than object not found. Can you provide [an MCVE](http://stackoverflow.com/help/mcve)? – Harry Johnston Apr 18 '15 at 02:15
  • 1
    Also works for me (access denied) on Vista x86. I don't have an XP system to try it on. – Harry Johnston Apr 18 '15 at 02:21

1 Answers1

0

Finally, I found the cause of such a strange behavior, — thanks to you, people, confirming that my code snippet (it was an actual excerpt, not a forged example) really works. The problem was that I did not have Windows DDK installed initially (I do have now, but still cannot integrate it with Visual Studio in a way that Windows SDK integrates automatically), so there was a need to write definitions by hand. Particularly, when I realized that InitializeObjectAttributes is actually a preprocessor macro rather than a Win32 function, I defined RtlInitUnicodeString as a macro, too, since its effect is even simpler. However, I was not careful enough to notice that UNICODE_STRING.Length and .MaximumLength are in fact meant for content size and buffer size instead of length, i. e. number of bytes rather than number of characters. Consequently, my macro was setting the fields to a half of their expected value, thus making Windows see only the first half of the L"\\Device\\PhysicalMemory" string, — with obvious outcome.

Anton Samsonov
  • 1,380
  • 17
  • 34
  • This is a very dangerous suggestion to define `RtlInitUnicodeString` as a macro. It is quite intentionally a function and if you try what you describe passing a buffer instead of a literal, it'll blow up in your face. For the purpose you describe there is the very useful `RTL_CONSTANT_STRING` macro, which does exactly what you want using literals (and will also cause unintended behavior with buffers). Also, the object can only be opened from kernel mode (`OBJ_KERNEL_EXCLUSIVE`). – 0xC0000022L Mar 29 '16 at 19:03