您如何直接从 Windows 上的物理内存中读取?

新手上路,请多包涵

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

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

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

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

编辑:添加了有关 os.

原文由 tigrou 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 1.3k
1 个回答

在 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/mem 在 Linux 下的模拟,您也可以直接访问物理内存。顺便说一句,不确定 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);
}

原文由 user707779 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题