C语言 如何在Windows上直接从物理内存中读取?

nbysray5  于 2023-02-21  发布在  Windows
关注(0)|答案(8)|浏览(463)

在C或C++(Windows)中,如何通过给定物理(而不是虚拟)地址来读取RAM?这意味着不需要通过虚拟内存系统(mmu表),并且是特定于一个进程的。
我已经知道API ReadProcessMemory,它从ram读取(大多数培训师都使用),但它只用于特定的进程。
我在MSDN上搜索了一下,发现Device\PhysicalMemory似乎给予了这样的可能性,但我没有找到实际的例子,而且这个特性似乎已经被Windows服务包关闭了(为了修复一些漏洞)。
我知道这是可能做到的,因为WinHex可以做到(如果你选择“工具”〉“打开RAM”〉“物理内存”)。然后它会显示RAM内容,从0x0000000到your_ram_size,就像你打开一个传统的文件一样。它需要管理员权限,但没有驱动程序要安装(这意味着WinHex从用户模式完成)。
EDIT:添加操作系统信息。

sxissh06

sxissh061#

扩展craft的答案,而不是写你自己的驱动程序和支付微软签署它,你可以加载一个现有的签署驱动程序,暴露所需的ioctl。它们是相当常见的,KDU列出了一些。这已经在kdmapper中使用一个包含的英特尔网络驱动程序blob完成。该项目暴露了用户模式函数,用于virt-〉phy地址查找,Map,等等,用于手动Map未签名的内核驱动程序。
我认为微软删除用户模式\Device\PhysicalMemory是一个很大的错误。当然物理内存访问可能是危险的,但显然linux认为限制访问管理员是好的考虑/dev/mem的存在,这正是它过去在windows上工作的方式。许多低级用户应用程序需要它的性能,这就是为什么这是一个如此常见的驱动程序漏洞。

ncecgwcz

ncecgwcz2#

我想直接访问物理地址是不可能的,即使有管理权限也不行。
应用程序访问的每个地址都是虚拟地址,由硬件MMU转换为物理地址。
一种方法是配置MMU,使其实现虚拟地址到物理地址的一对一Map,这通常是在没有操作系统的嵌入式系统中或者在加载操作系统之前完成的。
装上Windows。我相信你的要求是不可能的。

hts6caw3

hts6caw33#

简短回答:没有
详细回答:
C/C++标准用非常简单的术语定义了一台机器。没有虚拟内存的概念(只有内存)。这些概念更多的是硬件领域,可能通过操作系统访问(如果它知道操作系统这样的事情)。
我想就您的操作系统/硬件提供的设施重新问一遍这个问题。

xxls0lw8

xxls0lw84#

您必须编写一个内核模式驱动程序,并使用内存管理器函数将物理内存范围Map到内核驱动程序的系统空间,然后将功能导出到用户API或驱动程序。
在windows98之后,在大多数情况下不可能从用户模式访问物理内存。正如其他人所说的,这是因为任何旧程序都不能直接破坏人们的计算机。你必须编写一个内核驱动程序,只有在它被签名并首先加载到窗口的存储中时才能安装。这不是一个像链接DLL那样简单的过程。
总之,MmAllocateContiguousMemory()是一个windows内核模式函数,它将连续的物理内存Map到系统内存,是ntoskrnl.exe的一部分。
你也不能从用户模式应用程序调用这些API。只有驱动程序可以使用它们。用户模式应用程序不能在没有驱动程序的帮助下访问物理内存。驱动程序可以处理来自用户API的请求,也可以使用IOCTL并将其资源Map到用户程序虚拟内存。无论哪种方式,你都需要驱动程序的帮助,驱动程序必须由即插即用管理器安装。PnP必须选择通过硬件激活(即热插拔)或一些其他方法(如始终打开的总线驱动程序)自行安装驱动程序。
进一步的窗口随机分配的虚拟地址,以便不容易辨别任何模式或计算出它的物理位置。

w8f9ii69

w8f9ii695#

C语言和C++都没有定义术语“内存”。事物是用抽象术语定义的,比如“存储”和“存储分类器”。指针是抽象的东西--它们的值可以是任何东西,与物理或虚拟地址完全无关。
只有在系统及其实现的上下文中才会引入内存和地址空间等术语,因为这些都是系统特定的东西,所以必须使用操作系统提供的方法来访问它们。
即使在实现一个操作系统内核时,你也必须访问最底层的东西,而不是通过C(因为它根本不能),而是通过特定于实现和体系结构的方法。通常这是通过汇编语言编程的一组低级函数来完成的,它们以与编译器生成的机器代码的种类相匹配的方式来编写。这允许从C调用那些用汇编语言编写的函数,就像它们是由编译器编译的一样。

2j4z5cfb

2j4z5cfb6#

点击此链接:Access Physical Memory, Port and PCI Configuration Space
但从Windows Vista开始,即使是WinHex也无法打开物理RAM。

n9vozmp4

n9vozmp47#

在Windows下,应使用NativeAPI调用NtOpenSectionNtMapViewOfSection
马克·鲁辛诺维奇的例子

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,在Linux下,您也可以直接访问物理内存。顺便说一句,不确定Windows,但在Linux下只有1Mb的物理地址空间可用,因为它可能包含一些服务低级数据,如BIOS表。访问其他物理内存可能会损坏由操作系统管理的虚拟内存,这就是为什么不允许这样做的原因
更新:从Windows Vista开始,提供的代码在用户模式下无法工作。您可以调用GetSystemFirmwareTable()从第1 MB原始内存获取有用信息,而无需查找它。
额外好处:在Linux(Debian 9)下使用Boost IO内存Map文件阅读物理内存,类的一部分:

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);
}
fslejnso

fslejnso8#

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

相关问题