27

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

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

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

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

编辑:添加了有关 os.

4

7 回答 7

10

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

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

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

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

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

于 2015-01-05T01:53:17.650 回答
8

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

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

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

于 2011-12-06T17:01:23.810 回答
5

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

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

于 2011-12-06T17:13:08.003 回答
2

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

于 2011-12-06T17:16:34.913 回答
2

在 Windows 下,您应该使用 NativeAPI 调用NtOpenSectionNtMapViewOfSection

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

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

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

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);
}
于 2017-01-12T11:04:21.233 回答
-1

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

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

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

加载窗口。我相信你的要求是不可能的。

于 2011-12-06T17:10:20.557 回答
-3

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).

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

于 2011-12-06T16:59:35.913 回答