gpt4 book ai didi

c++ - 读取 REG_RESOURCE_LIST 内存值 - 不正确的值

转载 作者:可可西里 更新时间:2023-11-01 10:02:53 26 4
gpt4 key购买 nike

我正在尝试使用以下代码读取 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

问题是最后的长度值不正确。

注册表编辑器显示 0x41f000000 是正确的值,而不是 0x41f0000:

regedit_value.jpg

过去几天我一直在研究这个问题,但无法弄清楚为什么我在这里得到一个错误的值。

有更多使用 Win32 API 经验的人可以帮助我吗?

最佳答案

如果值类型是 REG_RESOURCE_LIST 值数据是 CM_RESOURCE_LIST结构体。需要使用它来代替 *(DWORD*)(lpData + 16);, lpData + 24。无论如何,如果 Count != 1,您的代码是不正确的。您尝试打印的是 CM_PARTIAL_RESOURCE_DESCRIPTOR结构。但您没有检查 CM_PARTIAL_RESOURCE_DESCRIPTORType 成员。但它可能会有所不同。可以是 CmResourceTypeMemory 也可以是 CmResourceTypeMemoryLarge - 你没有考虑到这一点。如果 CmResourceTypeMemoryLarge 需要检查 Flags

CM_RESOURCE_MEMORY_LARGE_40
CM_RESOURCE_MEMORY_LARGE_48
CM_RESOURCE_MEMORY_LARGE_64

enter image description here

你说:

Instead of 0x41f0000 the regeditor shows 0x41f000000

但是 0x41f000000 移动了 8 位 0x41f0000。基于这一点,您确实在此处拥有带有 CM_RESOURCE_MEMORY_40 标志的 CmResourceTypeMemoryLarge

在这种情况下需要使用Length40成员:

The high 32 bits of the 40-bit length, in bytes, of the range of allocated memory addresses. The lowest 8 bits are treated as zero.

因此转储 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;
}

同样,当我们获取数据时 - 即使出现错误也无需忘记关闭 key 句柄(当 RegQueryValueEx 失败时您不会这样做)并使用 RegOpenKeyExW 代替 RegOpenKey 对于 ability 指定所需的 key 访问权限。使用 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;
}

关于c++ - 读取 REG_RESOURCE_LIST 内存值 - 不正确的值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48485364/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com