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

问题描述 投票:22回答:7

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

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

我在MSDN上搜索并发现Device\PhysicalMemory似乎给出了这样的可能性,但我发现没有实际的例子,这个功能似乎已被Windows服务包关闭(以修复一些漏洞)。

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

编辑:添加有关操作系统的信息。

c++ c windows memory readprocessmemory
7个回答
6
投票

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

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

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

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

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


5
投票

检查此链接:Access Physical Memory, Port and PCI Configuration Space

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


5
投票

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

仅在系统及其实现的上下文中引入了诸如存储器和地址空间之类的术语。由于这些是特定于系统的东西,因此必须使用操作系统提供的方法来访问它们。

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


0
投票

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


0
投票

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

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

奖励:使用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);
}

-2
投票

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

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

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

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


-3
投票

简答:不

答案很长:

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

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

© www.soinside.com 2019 - 2024. All rights reserved.