Я пытаюсь прочитать значения физической памяти в 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
чтобы быть правильным значением:
Я исследовал эту проблему в течение последних нескольких дней, но не могу понять, почему я получаю ложное значение здесь.
Может ли кто-нибудь с большим опытом использования Win32 API помочь мне?
если тип значения 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;
}
Других решений пока нет …