如何在Windows上直接从物理内存中读取

How do you read directly from physical memory on Windows?

本文关键字:物理内存 读取 Windows      更新时间:2023-10-16

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

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

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

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

编辑:添加os的信息。

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

在windows 98之后,在大多数情况下不可能从用户模式访问物理内存。正如其他人所说,这就是为什么任何旧程序都不能破坏人们的电脑。您必须编写一个内核驱动程序,只有当它被签名并首先加载到窗口的存储库中时才能安装它。这不是像链接DLL那样简单的过程。

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

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

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

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

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

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

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

但是从Windows Vista开始,即使是WinHex也不能打开物理ram。

在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;
}

devicephysicalmemory是Linux下的/dev/mem的模拟,您也可以直接访问物理内存。顺便说一下,在Windows上不太确定,但在Linux下只有1 Mb的物理地址空间可用,因为它可能包含一些服务底层数据,如BIOS表。访问其他物理内存可能会破坏由操作系统管理的虚拟内存,这就是为什么不允许

UPDATE:提供的代码不能在用户模式下从Windows Vista开始工作。相反,你可以调用GetSystemFirmwareTable()从第1 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);
}

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

扩展craft的答案,而不是编写自己的驱动程序并向Microsoft支付签名费用,您可以加载一个现有的已签名的驱动程序,该驱动程序公开所需的ioctls。它们很常见,KDU列举了一些。这已经在kdmapper中使用包含的英特尔网络驱动blob完成了。该项目在intel_driver::*中公开了用于virt->phy地址查找、映射等的用户模式函数,用于手动映射无符号内核驱动程序。

我认为微软删除用户模式DevicePhysicalMemory是一个很大的错误。当然,物理内存访问可能是危险的,但是考虑到/dev/mem的存在,linux显然认为限制管理员访问是好的,这正是它过去在windows上的工作方式。许多低级用户应用程序需要它来提高性能,这就是为什么这是一个常见的驱动程序漏洞。

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

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

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

加载了windows。我相信你的要求是不可能的。

简短的回答:没有

长答:

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

我想就你们的操作系统/硬件提供的设施重新问这个问题。