在进入Windows之后,Runtime Service 和 ACPI Table之类的仍然存在于内存中,但是Windows没有提供标准的方法进行访问。用户能获得的只有经过包装之后 ACPI Table (实际上是来自注册表) ,或者根本就没有提供(比如:Runtime Service Table)。如果想再次获得这样的信息,只能通过扫描系统保留内存来完成。但是 Windows 没有提供类似 E820 的机制告知用户(应该是因为这种信息对于用户来说是根本无需了解的)。经过一段时间的研究,找到了在 Windows下获得系统保留内存的方法:在注册表 HKLM\HARDWARE\RESOURCEMAP\System Resources\Loader Reserved的位置。以我目前使用的笔记本电脑为例,打开这个位置之后可以看到
此外,Device Manager中也会给出硬件占用的内存地址,但是这个和系统的保留内存是没有任何关系的。
CM_RESOURCE_LIST structure 【参考1】
typedef struct _CM_RESOURCE_LIST { ULONG Count; CM_FULL_RESOURCE_DESCRIPTOR List[1]; } CM_RESOURCE_LIST, *PCM_RESOURCE_LIST;
接下来是下面这个结构体【参考2】
typedef struct _CM_FULL_RESOURCE_DESCRIPTOR { INTERFACE_TYPE InterfaceType; // unused for WDM == 0 ULONG BusNumber; // unused for WDM CM_PARTIAL_RESOURCE_LIST PartialResourceList; } CM_FULL_RESOURCE_DESCRIPTOR, *PCM_FULL_RESOURCE_DESCRIPTOR;
继续解析【参考3】。其中 ULONG 占用 4BYTES;USHORT占用2BYTES;UCHAR占用1BYTES.
typedef struct _CM_PARTIAL_RESOURCE_LIST { USHORT Version; == 00 USHORT Revision; ULONG Count; CM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptors[1]; } CM_PARTIAL_RESOURCE_LIST, *PCM_PARTIAL_RESOURCE_LIST;
接下来就是每一个保留的内存情况
CM_PARTIAL_RESOURCE_DESCRIPTOR structure【参考4】 typedef struct _CM_PARTIAL_RESOURCE_DESCRIPTOR { UCHAR Type; UCHAR ShareDisposition; USHORT Flags; union { ……………… ……………… ……………… }
根据上面的方法即可获得当前系统中 Loader 通知系统的 Reserved Memory
对于 type的定义在【参考5】
Identifies the resource type. The constant value specified for Type indicates which structure within the u union is valid, as indicated in the following table. (These flags are used within both CM_PARTIAL_RESOURCE_DESCRIPTORand IO_RESOURCE_DESCRIPTOR structures, except where noted.)
有了上面的基础就可以编写代码:
// ConsoleApplication3.cpp : Defines the entry point for the console application. // #include "stdafx.h" #include <Windows.h> #include <strsafe.h> #include <tchar.h> HKEY m_hKey; #define OffSet(type, field) ((size_t)&(((type*)0)->field)) #pragma pack(1) // // Physical address. // typedef LARGE_INTEGER PHYSICAL_ADDRESS, *PPHYSICAL_ADDRESS; typedef struct _CM_PARTIAL_RESOURCE_DESCRIPTOR { UCHAR Type; UCHAR ShareDisposition; USHORT Flags; union { // // Range of resources, inclusive. These are physical, bus relative. // It is known that Port and Memory below have the exact same layout // as Generic. // struct { PHYSICAL_ADDRESS Start; ULONG Length; } Generic; // // struct { PHYSICAL_ADDRESS Start; ULONG Length; } Port; // // struct { #if defined(NT_PROCESSOR_GROUPS) USHORT Level; USHORT Group; #else ULONG Level; #endif ULONG Vector; KAFFINITY Affinity; } Interrupt; // // Values for message signaled interrupts are distinct in the // raw and translated cases. // struct { union { struct { #if defined(NT_PROCESSOR_GROUPS) USHORT Group; #else USHORT Reserved; #endif USHORT MessageCount; ULONG Vector; KAFFINITY Affinity; } Raw; struct { #if defined(NT_PROCESSOR_GROUPS) USHORT Level; USHORT Group; #else ULONG Level; #endif ULONG Vector; KAFFINITY Affinity; } Translated; } DUMMYUNIONNAME; } MessageInterrupt; // // Range of memory addresses, inclusive. These are physical, bus // relative. The value should be the same as the one passed to // HalTranslateBusAddress(). // struct { PHYSICAL_ADDRESS Start; // 64 bit physical addresses. ULONG Length; } Memory; // // Physical DMA channel. // struct { ULONG Channel; ULONG Port; ULONG Reserved1; } Dma; struct { ULONG Channel; ULONG RequestLine; UCHAR TransferWidth; UCHAR Reserved1; UCHAR Reserved2; UCHAR Reserved3; } DmaV3; // // Device driver private data, usually used to help it figure // what the resource assignments decisions that were made. // struct { ULONG Data[3]; } DevicePrivate; // // Bus Number information. // struct { ULONG Start; ULONG Length; ULONG Reserved; } BusNumber; // // Device Specific information defined by the driver. // The DataSize field indicates the size of the data in bytes. The // data is located immediately after the DeviceSpecificData field in // the structure. // struct { ULONG DataSize; ULONG Reserved1; ULONG Reserved2; } DeviceSpecificData; // The following structures provide support for memory-mapped // IO resources greater than MAXULONG struct { PHYSICAL_ADDRESS Start; ULONG Length40; } Memory40; struct { PHYSICAL_ADDRESS Start; ULONG Length48; } Memory48; struct { PHYSICAL_ADDRESS Start; ULONG Length64; } Memory64; struct { UCHAR Class; UCHAR Type; UCHAR Reserved1; UCHAR Reserved2; ULONG IdLowPart; ULONG IdHighPart; } Connection; } u; } CM_PARTIAL_RESOURCE_DESCRIPTOR, *PCM_PARTIAL_RESOURCE_DESCRIPTOR; // // A Partial Resource List is what can be found in the ARC firmware // or will be generated by ntdetect.com. // The configuration manager will transform this structure into a Full // resource descriptor when it is about to store it in the regsitry. // // Note: There must a be a convention to the order of fields of same type, // (defined on a device by device basis) so that the fields can make sense // to a driver (i.e. when multiple memory ranges are necessary). // typedef struct _CM_PARTIAL_RESOURCE_LIST { USHORT Version; USHORT Revision; ULONG Count; CM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptors[1]; } CM_PARTIAL_RESOURCE_LIST, *PCM_PARTIAL_RESOURCE_LIST; // // Define the I/O bus interface types. // typedef enum _INTERFACE_TYPE { InterfaceTypeUndefined = -1, Internal, Isa, Eisa, MicroChannel, TurboChannel, PCIBus, VMEBus, NuBus, PCMCIABus, CBus, MPIBus, MPSABus, ProcessorInternal, InternalPowerBus, PNPISABus, PNPBus, Vmcs, ACPIBus, MaximumInterfaceType }INTERFACE_TYPE, *PINTERFACE_TYPE; // // A Full Resource Descriptor is what can be found in the registry. // This is what will be returned to a driver when it queries the registry // to get device information; it will be stored under a key in the hardware // description tree. // // Note: There must a be a convention to the order of fields of same type, // (defined on a device by device basis) so that the fields can make sense // to a driver (i.e. when multiple memory ranges are necessary). // typedef struct _CM_FULL_RESOURCE_DESCRIPTOR { INTERFACE_TYPE InterfaceType; // unused for WDM ULONG BusNumber; // unused for WDM CM_PARTIAL_RESOURCE_LIST PartialResourceList; } CM_FULL_RESOURCE_DESCRIPTOR, *PCM_FULL_RESOURCE_DESCRIPTOR; // // The Resource list is what will be stored by the drivers into the // resource map via the IO API. // typedef struct _CM_RESOURCE_LIST { ULONG Count; CM_FULL_RESOURCE_DESCRIPTOR List[1]; } CM_RESOURCE_LIST, *PCM_RESOURCE_LIST; int main() { DWORD Index; BYTE *v; if (RegOpenKeyEx( HKEY_LOCAL_MACHINE, TEXT("HARDWARE\\RESOURCEMAP\\System Resources\\Loader Reserved"), 0, KEY_READ, &m_hKey) != ERROR_SUCCESS) { printf("RegOpenKeyEx fail \n"); getchar(); exit(0); } BOOL bRet = FALSE; LPSTR lpstrValue; DWORD dwType = REG_SZ; DWORD lpcbData; DWORD r; r = RegQueryValueEx(m_hKey, TEXT(".Raw"), NULL, &dwType, NULL, &lpcbData); if (r != ERROR_SUCCESS) { printf("Can't get data from registry\n"); getchar(); exit(0); } bRet = FALSE; lpstrValue = (LPSTR)malloc(lpcbData); r = RegQueryValueEx(m_hKey, TEXT(".Raw"), NULL, &dwType, (BYTE*)(LPCTSTR)lpstrValue, &lpcbData); if (r != ERROR_SUCCESS) { printf("fail\n"); getchar(); exit(0); } for (Index = 0; Index < lpcbData; Index++) { if (Index % 16 == 0) { printf("\n"); } v = (BYTE*)lpstrValue; printf("%02X ", *(v + Index)); } PCM_RESOURCE_LIST res= (PCM_RESOURCE_LIST)lpstrValue; PCM_PARTIAL_RESOURCE_LIST Partial; DWORD Index1; for (Index = 0; Index < res->Count; Index++) { printf("\nInteface type: %d\n Bus Number: %d\n", res->List[Index].InterfaceType, res->List[Index].BusNumber); Partial = (PCM_PARTIAL_RESOURCE_LIST) &res->List[Index].PartialResourceList; printf(" Version: %d\n Revision: %d\n Counter: %x\n", Partial->Version, Partial->Revision, Partial->Count); for (Index1 = 0; Index1 < Partial->Count; Index1++) { //printf("%d\n", Partial->PartialDescriptors[Index1].Type); if (Partial->PartialDescriptors[Index1].Type == 3) { printf("Start:%016I64x Length:%x \n", Partial->PartialDescriptors[Index1].u.Memory.Start, Partial->PartialDescriptors[Index1].u.Memory.Length ); } } } free(lpstrValue); getchar(); return 0; }
运行结果如下(运行的机器和之前做分析的不同,所以 Counter数量不同)
参考:
1. https://msdn.microsoft.com/en-us/library/windows/hardware/ff541994(v=vs.85).aspx
2. https://msdn.microsoft.com/en-us/library/windows/hardware/ff541954(v=vs.85).aspx
3. https://msdn.microsoft.com/en-us/library/windows/hardware/ff541981(v=vs.85).aspx
4. https://msdn.microsoft.com/en-us/library/windows/hardware/ff541977(v=vs.85).aspx
5. https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/content/wdm/ns-wdm-_cm_partial_resource_descriptor
是这样…
System Reserved Memory Range :
———————————————————————————————————————
Index Start Address Limit Address Size About Flag
1 0x0000000000000000 0x0000000000100000 0x0000000000100000 1024.00KB 0x00000103
2 0x0000000000103000 0x00000000001A7000 0x00000000000A4000 656.00KB 0x00000103
3 0x00000000002E1000 0x00000000002F1000 0x0000000000010000 64.00KB 0x00000103
4 0x000000008DDAB000 0x000000008F40E000 0x0000000001663000 22.39MB 0x00000103
5 0x000000008F40F000 0x0000000090000000 0x0000000000BF1000 11.94MB 0x00000103
6 0x00000000E0000000 0x00000000F0000000 0x0000000010000000 256.00MB 0x00000103
7 0x00000000FE000000 0x00000000FE011000 0x0000000000011000 68.00KB 0x00000103
8 0x00000000FEC00000 0x00000000FEC01000 0x0000000000001000 4.00KB 0x00000103
9 0x00000000FED00000 0x00000000FED04000 0x0000000000004000 16.00KB 0x00000103
10 0x00000000FEE00000 0x00000000FEE01000 0x0000000000001000 4.00KB 0x00000103
11 0x00000000FF000000 0x0000000100000000 0x0000000001000000 16.00MB 0x00000103
———————————————————————————————————————
Total 0x000000001341F000 308.12MB
這篇分析很不錯, 剛好要把自己的工具增加相關的功能, 感謝!
有研究过每一段后面的Flag如何解析?
例如我解析到的Flag 0x00000103, 0x02000107具体代表什么?
貌似没有查到具体代表的意义是什么…
Physical Memory Range :
——————————————————————————————————————
Index Start Address Limit Address Size About Flag
1 0x0000000000001000 0x000000000009F000 0x000000000009E000 632.00KB 0x00000103
2 0x0000000000100000 0x00000000791C3000 0x00000000790C3000 1.89GB 0x00000103
3 0x000000007A2A9000 0x000000007A392000 0x00000000000E9000 932.00KB 0x00000103
4 0x000000007AC0E000 0x000000007AC0F000 0x0000000000001000 4.00KB 0x00000103
5 0x0000000100000000 0x000000047E000000 0x000000037E000000 13.97GB 0x02000107
——————————————————————————————————————
Total 0x00000003F724B000 15.8616GB
uefi 怎么 reseve memory呀,楼主?
楼主,uefi 怎么reserve memory呀?
gBS -> AllocatePool 函数可以分配设置的,你可以参考 https://www.lab-z.com/shellwin/
谢谢站长的回复。
我的问题是这样子的,要想在内核中reserve 一块特定物理内存,不被系统分配使用,而是只由自己使用。
gBS -> AllocatePool 函数只能指定memory type,无法指定具体的地址值吧?
比如, 以内存位置0x22000000为起始地址,reserve 1KB的内存,使得这1KB的内存不被OS使用。
是的,这个函数无法指定内存位置。如果有这样的需求你只能去研究一下扫描 PCI 设备空间分配的内存的函数看看了。具体我没做过,只是猜测。