在C或C ++(窗口)中,如何通过给物理(而不是虚拟)地址来读取RAM? 这意味着不需要通过虚拟内存系统(mmu表),而是针对一个进程。
我已经知道API ReadProcessMemory
(从大多数培训人员使用的ram读取),但它只适用于特定的进程。
我在MSDNsearch,发现设备\ PhysicalMemory似乎给这种可能性,但我没有find实际的例子,这个function似乎已经被Windows服务包closures(以解决一些漏洞)。
我知道这是可能的,因为WinHex可以做到这一点(如果你select“工具”>“打开内存”>“物理内存”)。 然后,它将显示RAM内容从0x00000000到your_ram_size,就像打开传统文件时一样。 它需要pipe理员权限,但没有驱动程序安装(这意味着WinHex从用户模式)。
编辑:添加有关操作系统的信息。
语言C和C ++都没有定义术语“内存”。 用“存储”和“存储分类器”等抽象术语来定义事物。 指针是抽象的东西 – 它们的值可以是任何东西,完全与物理或虚拟地址无关。
只有在系统及其实现的情况下才会引入像内存和地址空间这样的术语。 而且由于这些是系统特定的事情,所以必须使用OS提供的方法来访问它们。
即使在实现OS内核时,也必须通过C(而不是通过C)访问最低级别的内容,而是通过特定于实现和体系结构的方法来访问。 通常这是通过在汇编中编程的一组低级函数完成的,这些函数的编写方式与编译器生成的机器代码的类型相匹配。 这允许用汇编语言编写的这些函数可以从C中调用,就好像它们是由编译器编译的一样。
您必须编写内核模式驱动程序,并使用内存管理器功能将物理内存范围映射到内核驱动程序的系统空间,然后将功能导出到用户API或驱动程序。
在Windows 98之后,大多数情况下不可能从用户模式访问物理内存。 正如其他人所说的那样,任何旧的程序都不能摧毁人们的电脑。 你将不得不编写一个内核驱动程序,只有当它被签名并首次加载到窗口的存储区时才能被安装。 这本身并不是像链接DLL那样简单的过程。
总而言之, MmAllocateContiguousMemory()
是一个Windows核心模式函数,它将连续的物理内存映射到系统内存,并且是ntoskrnl.exe
的一部分。
您也不能从用户模式应用程序调用这些API。 只有司机可以使用它们。 用户模式应用程序无法通过驱动程序的帮助访问物理内存。 驱动程序可以处理来自用户API的请求,也可以使用IOCTL并将其资源映射到API的虚拟内存。 无论哪种方式,你将需要一个驱动程序的帮助,必须由插件管理器安装。 即插即用必须选择通过硬件激活(即热插拔)或其他方法(如总是处于开启状态的总线驱动程序)来自行安装驱动程序。
更多的窗口随机分配的虚拟地址,以便不容易辨别任何模式或找出它的物理位置。
检查此链接: 访问物理内存,端口和PCI配置空间
但从Windows Vista开始,即使WinHex也无法打开物理内存。
我认为设备驱动程序必须允许物理内存访问,因为像PCI卡这样的设备需要这样访问。 如果你可以从驱动程序中完成,那么为你的“用户”(更像管理员)模式程序写一个自定义分配器,以便轻松链接到C ++。
在Windows下,您应该使用NativeAPI调用NtOpenSection和NtMapViewOfSection
Mark Russinovich的例子
static BOOLEAN MapPhysicalMemory( HANDLE PhysicalMemory, PDWORD Address, PDWORD Length, PDWORD VirtualAddress ) { NTSTATUS ntStatus; PHYSICAL_ADDRESS viewBase; char error[256]; *VirtualAddress = 0; viewBase.QuadPart = (ULONGLONG) (*Address); ntStatus = NtMapViewOfSection (PhysicalMemory, (HANDLE) -1, (PVOID) VirtualAddress, 0L, *Length, &viewBase, Length, ViewShare, 0, PAGE_READONLY ); if( !NT_SUCCESS( ntStatus )) { sprintf_s( error, "Could not map view of %X length %X", *Address, *Length ); PrintError( error, ntStatus ); return FALSE; } *Address = viewBase.LowPart; return TRUE; } static HANDLE OpenPhysicalMemory() { NTSTATUS status; HANDLE physmem; UNICODE_STRING physmemString; OBJECT_ATTRIBUTES attributes; WCHAR physmemName[] = L"\\device\\physicalmemory"; RtlInitUnicodeString( &physmemString, physmemName ); InitializeObjectAttributes( &attributes, &physmemString, OBJ_CASE_INSENSITIVE, NULL, NULL ); status = NtOpenSection( &physmem, SECTION_MAP_READ, &attributes ); if( !NT_SUCCESS( status )) { PrintError( "Could not open \\device\\physicalmemory", status ); return NULL; } return physmem; }
\device\physicalmemory
是Linux下的/dev/mem
一个模拟,你也可以直接访问物理内存。 顺便说一下,不确定Windows,但在Linux下,只有1 Mb的物理地址空间可用,因为它可能包含一些服务底层数据,如BIOS表。 访问其他物理内存可能会破坏由操作系统管理的虚拟内存,这就是为什么它不被允许
我想不可能直接访问物理地址。 甚至没有管理权限。
每个由应用程序访问的地址都是由硬件MMU转换为物理地址的虚拟地址。
一种方法是将MMU配置为一对一映射虚拟地址到物理地址。 这通常在没有操作系统或加载操作系统之前的嵌入式系统中完成。
随着窗户加载。 我相信你的要求是不可能的。
简答:不
长答案:
C / C ++标准以非常简单的术语定义了一台机器。 没有虚拟内存的概念(只是内存)。 这些概念更多的是硬件的领域,可能通过操作系统(如果它知道操作系统这样的东西)潜在的访问。
我会重新问你的操作系统/硬件提供的设施的问题。