Считать значения памяти REG_RESOURCE_LIST — Неверное значение

Я пытаюсь прочитать значения физической памяти в Hardware\ResourceMap\System Resources\Physical Memory используя следующий код:

#include <iostream>
#include <conio.h>
#include <windows.h>
#include <string>
#include <stdlib.h>

using namespace std;

int main()
{
HKEY hKey = NULL;
LPCTSTR pszSubKey = L"Hardware\\ResourceMap\\System Resources\\Physical Memory";
LPCTSTR pszValueName = L".Translated";

if (! RegOpenKey(HKEY_LOCAL_MACHINE, pszSubKey, &hKey) == ERROR_SUCCESS)
{
cout << "RegOpenKey failed" << endl;
return 0;
}

DWORD dwType = 0;
LPBYTE lpData = NULL;
DWORD dwLength = 0;

if (! RegQueryValueEx(hKey, pszValueName, 0, &dwType, NULL, &dwLength) == ERROR_SUCCESS)
{
cout << "RegOpenKey failed" << endl;
return 0;
}

lpData = new BYTE[dwLength];
RegQueryValueEx(hKey, pszValueName, 0, &dwType, lpData, &dwLength);
RegCloseKey(hKey);

DWORD dwResourceCount = *(DWORD*)(lpData + 16);

auto pmi = lpData + 24;

for (int dwIndex = 0; dwIndex < dwResourceCount; dwIndex++)
{
auto start = *(uint64_t*)(pmi + 0);
cout << "-> 0x" << hex << start;

auto length = *(uint64_t*)(pmi + 8);
cout << "\t + 0x" << hex << length;

auto endaddr = start + length;
cout << "\t0x" << hex << endaddr << endl;

pmi += 20;
}

delete[]lpData;
}

Пример вывода:

-> 0x1000        + 0x57000      0x58000
-> 0x59000       + 0x46000      0x9f000
-> 0x100000      + 0xc855f000   0xc865f000
-> 0xc8666000    + 0xbf3000     0xc9259000
-> 0xc9759000    + 0x13779000   0xdced2000
-> 0xdd0d8000    + 0x3c000      0xdd114000
-> 0xddfff000    + 0x1000       0xde000000
-> 0x100000000   + 0x41f0000    0x1041f0000

Проблема в том, что последнее значение длины неверно.

Вместо 0x41f0000, редактор реестра показывает 0x41f000000 чтобы быть правильным значением:

regedit_value.jpg

Я исследовал эту проблему в течение последних нескольких дней, но не могу понять, почему я получаю ложное значение здесь.

Может ли кто-нибудь с большим опытом использования Win32 API помочь мне?

2

Решение

если тип значения REG_RESOURCE_LIST значение данных CM_RESOURCE_LIST состав. нужно использовать его вместо *(DWORD*)(lpData + 16);, lpData + 24, в любом случае ваш код неверен в случае Count ! = 1. что вы пытаетесь напечатать CM_PARTIAL_RESOURCE_DESCRIPTOR структур. но ты не проверь Type член CM_PARTIAL_RESOURCE_DESCRIPTOR, но это может быть другим. может быть CmResourceTypeMemory но также может быть CmResourceTypeMemoryLarge — Вы не принимаете это во внимание. в случае CmResourceTypeMemoryLarge нужно проверить Flags за

CM_RESOURCE_MEMORY_LARGE_40
CM_RESOURCE_MEMORY_LARGE_48
CM_RESOURCE_MEMORY_LARGE_64

а также

введите описание изображения здесь

ты говоришь:

Вместо 0x41f0000 регулятор показывает 0x41f000000

но 0x41f000000 сдвинут на 8 бит 0x41f0000, основываясь на этом очевидном, что у вас действительно есть здесь CmResourceTypeMemoryLarge с CM_RESOURCE_MEMORY_40 флаг.

в этом случае нужно использовать Length40 член:

Старшие 32 бита 40-битной длины в байтах диапазона
выделенные адреса памяти. Младшие 8 битов рассматриваются как ноль.

так что код для дампа CM_RESOURCE_LIST должно быть следующим:

BOOL Memory(PCM_RESOURCE_LIST pcrl, ULONG size)
{
if (size < FIELD_OFFSET(CM_RESOURCE_LIST, List))
{
return FALSE;
}

size -= FIELD_OFFSET(CM_RESOURCE_LIST, List);

if (ULONG Count = pcrl->Count)
{
PCM_FULL_RESOURCE_DESCRIPTOR List = pcrl->List;

do
{
if (size < FIELD_OFFSET(CM_FULL_RESOURCE_DESCRIPTOR, PartialResourceList.PartialDescriptors))
{
return FALSE;
}

size -= FIELD_OFFSET(CM_FULL_RESOURCE_DESCRIPTOR, PartialResourceList.PartialDescriptors);

DbgPrint("InterfaceType=%x BusNumber=%u\n", List->InterfaceType, List->BusNumber);

if (ULONG n = List->PartialResourceList.Count)
{
PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptors = List->PartialResourceList.PartialDescriptors;

do
{
if (size < sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR))
{
return FALSE;
}

size -= sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR);

ULONG64 Length = PartialDescriptors->u.Memory.Length;

switch (PartialDescriptors->Type)
{
case CmResourceTypeMemoryLarge:

switch (PartialDescriptors->Flags & (CM_RESOURCE_MEMORY_LARGE_40|
CM_RESOURCE_MEMORY_LARGE_48|CM_RESOURCE_MEMORY_LARGE_64))
{
case CM_RESOURCE_MEMORY_LARGE_40:
Length <<= 8;
break;
case CM_RESOURCE_MEMORY_LARGE_48:
Length <<= 16;
break;
case CM_RESOURCE_MEMORY_LARGE_64:
Length <<= 32;
break;
default:
DbgPrint("unknown mamory type\n");
continue;
}
case CmResourceTypeMemory:
DbgPrint("%016I64x %I64x\n",
PartialDescriptors->u.Memory.Start.QuadPart, Length);
break;
}

} while (PartialDescriptors++, --n);
}

} while (List++, --Count);
}

return size == 0;
}

также, когда мы получаем данные — не нужно забывать закрывать дескриптор ключа даже при ошибке (вы не делаете это, когда RegQueryValueEx потерпеть неудачу) и использовать RegOpenKeyExW вместо RegOpenKey Для возможности указать нужные права доступа к ключу. использование 2 последовательных звонков RegQueryValueEx (с 0 буфером и выделенным один раз буфером) тоже не лучший. потому что теоретически размер буфера может изменяться (некоторое значение изменения) между этими 2 вызовами, и вы можете потерпеть неудачу, получив данные при втором вызове RegQueryValueExтоже. также мы можем уже при первом вызове выделить разумное пространство памяти, и только если этого будет недостаточно — перераспределить при следующем вызове. так что лучше называть это в цикле, пока мы не получили ERROR_MORE_DATA и первый раз вызов с уже не пустым буфером:

ULONG Memory()
{
HKEY hKey;

ULONG dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
L"Hardware\\ResourceMap\\System Resources\\Physical Memory",
0, KEY_READ, &hKey);

if (dwError == NOERROR)
{
ULONG cb = 0x100;

do
{
dwError = ERROR_NO_SYSTEM_RESOURCES;

union {
PVOID buf;
PBYTE pb;
PCM_RESOURCE_LIST pcrl;
};

if (buf = LocalAlloc(0, cb))
{
ULONG dwType;

if ((dwError = RegQueryValueExW(hKey, L".Translated",
0, &dwType, pb, &cb)) == NOERROR)
{
if (dwType == REG_RESOURCE_LIST)
{
if (!Memory(pcrl, cb))
{
DbgPrint("error parsing resource list\n");
}
}
else
{
dwError = ERROR_INVALID_DATATYPE;
}
}

LocalFree(buf);
}

} while (dwError == ERROR_MORE_DATA);

RegCloseKey(hKey);
}

return dwError;
}
3

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]