C++ 你如何直接从物理内存中读取?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/8403610/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 18:30:58  来源:igfitidea点击:

How do you read directly from physical memory?

c++cwindowsmemoryreadprocessmemory

提问by tigrou

In C or C++ (windows), how do you read RAM by giving a physical (not virtual) address? That means without going trough virtual memory system (mmu tables), and being specific to one process.

在 C 或 C++(Windows)中,如何通过提供物理(非虚拟)地址来读取 RAM?这意味着无需通过虚拟内存系统(mmu 表),而是特定于一个进程。

I already know the API ReadProcessMemory, which reads from ram (used by most trainers) but it is only for a specific process.

我已经知道 API ReadProcessMemory,它从 ram 读取(大多数培训师使用),但它仅适用于特定进程。

I searched on MSDN and found that Device\PhysicalMemoryseems to give such possibility, but I found no practical example and this feature seems to have been turned off by Windows service packs (to fix some vulnerability).

我在 MSDN 上搜索,发现Device\PhysicalMemory似乎提供了这种可能性,但我没有找到实际示例,而且此功能似乎已被 Windows 服务包关闭(以修复某些漏洞)。

I know it is possible to do because WinHex does it (if you choose "tools" > "open ram" > "physical memory"). It will then display RAM content from 0x00000000 to your_ram_size just like when you open a traditional file. It requires administrator rights, but there is no driver to install (which means WinHex does it from user mode).

我知道这是可能的,因为 WinHex 做到了(如果您选择“工具”>“打开内存”>“物理内存”)。然后它将显示从 0x00000000 到 your_ram_size 的 RAM 内容,就像打开传统文件一样。它需要管理员权限,但不需要安装驱动程序(这意味着 WinHex 是从用户模式完成的)。

EDIT : added information about os.

编辑:添加了有关 os 的信息。

回答by datenwolf

Neither the language C, nor C++ defines the term "memory". Things are defined in abstract terms like "storage" and "storage classifiers". Pointers are abstract things -- their values can be anything, totally unrelated to the physical or virtual addresses.

语言 C 和 C++ 都没有定义术语“内存”。事物是用抽象术语定义的,例如“存储”和“存储分类器”。指针是抽象的东西——它们的值可以是任何东西,与物理或虚拟地址完全无关。

Only in the context of a system and its implementation are terms like memory and address space introduced. And since those are system specific things, one mustuse the methods provided by the OS to access them.

只有在系统及其实现的上下文中才会引入内存和地址空间等术语。由于这些是系统特定的东西,因此必须使用操作系统提供的方法来访问它们。

Even when implementing an OS kernel you have to do access to lowest level stuff not through C (because it simply can't), but through methods specific to implementation and architecture. Usually this is done through a set of low level functions programmed in assembly, which are written in a way that they match the kind of machine code the compiler generates. This allows those functions written in assembly to be called from C as if they were compiled by the compiler.

即使在实现 OS 内核时,您也必须不是通过 C(因为它根本不能)访问最低级别的东西,而是通过特定于实现和体系结构的方法。通常这是通过一组用汇编编程的低级函数来完成的,这些函数的编写方式与编译器生成的机器代码的类型相匹配。这允许从 C 中调用那些用汇编编写的函数,就好像它们是由编译器编译的一样。

回答by marshal craft

You would have to write a kernel mode driver and use memory manager functions to map physical memory range to your kernel driver's system space then export functionality to a user API or driver.

您必须编写内核模式驱动程序并使用内存管理器函数将物理内存范围映射到内核驱动程序的系统空间,然后将功能导出到用户 API 或驱动程序。

After windows 98 it is not possible in most cases to access physical memory from user mode. As others have put it this is so any old program cant just destroy people's computers. You would have to write a kernel driver, which can only be installed if it is signed and first loaded into the window's store. This alone is not a simple process like linking a DLL.

在 Windows 98 之后,大多数情况下无法从用户模式访问物理内存。正如其他人所说的那样,任何旧程序都不能破坏人们的计算机。您必须编写一个内核驱动程序,只有在签名并首先加载到窗口存储区时才能安装该驱动程序。这本身并不是一个简单的过程,比如链接一个 DLL。

In summary MmAllocateContiguousMemory()is a windows kernel mode function which maps contiguous physical memory to system memory and is a part of ntoskrnl.exe.

总之MmAllocateContiguousMemory()是一个 Windows 内核模式函数,它将连续的物理内存映射到系统内存,并且是ntoskrnl.exe.

Also you can not call these API's from user mode applications. Only driver's can use them. User mode applications CANNOT access physical memory with out the help of a driver. The driver can either handle request's from the user API or use IOCTLs and map it's resources to the API's virtual memory. Either way you will need the help of a driver which has to be installed by plug n play manager. PnP has to choose to install the driver on it's own either by hardware activation i.e. hot plug or some other method like a bus driver that is always on.

您也不能从用户模式应用程序调用这些 API。只有司机可以使用它们。没有驱动程序的帮助,用户模式应用程序无法访问物理内存。驱动程序可以处理来自用户 API 的请求,也可以使用 IOCTL 并将其资源映射到 API 的虚拟内存。无论哪种方式,您都需要一个驱动程序的帮助,该驱动程序必须由即插即用管理器安装。PnP 必须选择通过硬件激活(即热插拔)或某些其他方法(如始终打开的总线驱动程序)自行安装驱动程序。

Further windows randomly assign's virtual address so that it is not easily possible to discern any pattern or work out it's physical location.

其他窗口随机分配虚拟地址,因此不容易识别任何模式或计算出它的物理位置。

回答by Shawnone

Check this link: Access Physical Memory, Port and PCI Configuration Space

检查此链接:访问物理内存、端口和 PCI 配置空间

But start from Windows Vista, even WinHex cannot open the physical ram.

但是从Windows Vista 开始,即使是WinHex 也无法打开物理内存。

回答by Shawnone

Under Windows you should use NativeAPI calls NtOpenSectionand NtMapViewOfSection

在 Windows 下你应该使用 NativeAPI 调用NtOpenSectionNtMapViewOfSection

Example from 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\physicalmemoryis an analog of /dev/memunder Linux, where you also have possibility to access physical memory directly. By the way, not sure about Windows, but under Linux only 1 Mb of physical address space is available, because it may contain some service low-level data like BIOS tables. Access to other physical memory may corrupt virtual memory, managed by the OS, and that's why it's not allowed

\device\physicalmemory类似于/dev/mem在 Linux 下,您也可以直接访问物理内存。顺便说一句,不确定 Windows,但在 Linux 下只有 1 Mb 的物理地址空间可用,因为它可能包含一些服务低级数据,如 BIOS 表。访问其他物理内存可能会损坏由操作系统管理的虚拟内存,这就是不允许的原因

UPDATE: Provided code does not work under user-mode starting from Windows Vista. Instead you can call GetSystemFirmwareTable() to get useful information from 1st MB of raw memory without looking for it.

更新:提供的代码在从 Windows Vista 开始的用户模式下不起作用。相反,您可以调用 GetSystemFirmwareTable() 以从 1st MB 的原始内存中获取有用的信息,而无需寻找它。

Bonus: reading physical memory under Linux (Debian 9) using Boost IO memory-mapped file, part of the class:

奖励:使用 Boost IO 内存映射文件在 Linux (Debian 9) 下读取物理内存,该类的一部分:

NativePhysicalMemory::NativePhysicalMemory(size_t base, size_t length)
    : physical_memory_map_(std::make_unique<boost::iostreams::mapped_file_source>())
{
    map_physical_memory(base, length);
}

// ...

void NativePhysicalMemory::map_physical_memory(size_t base, size_t length)
{
#ifdef _SC_PAGESIZE
    size_t mempry_page_offset = base % sysconf(_SC_PAGESIZE);
#else
    size_t mempry_page_offset = base % getpagesize();
#endif /* _SC_PAGESIZE */

    boost_io::mapped_file_params params = {};
    params.path = "/dev/mem";
    params.flags = boost_io::mapped_file::mapmode::readonly;
    params.length = length + mempry_page_offset;
    params.offset = base - mempry_page_offset;
    params.hint = nullptr;
    physical_memory_map_->open(params);
}

回答by Timmah

I would think a device driver must allow physical memory access, since devices such as PCI cards need to be accessed that way. If you can do it from a driver, then write a custom allocator for your "user" ( more like administrator ) mode program to easily link into C++.

我认为设备驱动程序必须允许物理内存访问,因为需要以这种方式访问​​ PCI 卡等设备。如果您可以从驱动程序中做到这一点,那么为您的“用户”(更像是管理员)模式程序编写一个自定义分配器,以轻松链接到 C++。

回答by M S

I guess its not possible to access the physical address directly. Not even with administrative privilege.

我想直接访问物理地址是不可能的。甚至没有管理权限。

Every address accessed by the the application is virtual address which is translated to physical address by hardware MMU.

应用程序访问的每个地址都是虚拟地址,由硬件 MMU 转换为物理地址。

One way is to configure MMU for one to one mapping the virtual address to physical address. This is usually done in embedded systems with no OS or before loading the OS.

一种方法是将 MMU 配置为一对一映射虚拟地址到物理地址。这通常在没有操作系统的嵌入式系统中或在加载操作系统之前完成。

With windows loaded. I believe your requirement is not possible.

随着窗户加载。我相信你的要求是不可能的。

回答by Martin York

Short Answer: No

简短回答:否

Long Answer:

长答案:

The C/C++ standard define a machine in very simple terms. There is no concept of virtual memory (just memory). These concepts are more the domain of the hardware and may be potentially accessed via the OS (if it is aware OS such things).

C/C++ 标准用非常简单的术语定义了一台机器。没有虚拟内存的概念(只是内存)。这些概念更多地属于硬件领域,并且可能通过操作系统进行访问(如果它知道操作系统之类的东西)。

I would re-ask the question in terms of the facilities provided by your OS/Hardware.

我会根据您的操作系统/硬件提供的设施重新提出这个问题。