在进入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