如何使用C获取特定的内存地址C

问题描述:

对于我的学士论文,我希望可视化内存的数据剩余量以及在重新引导系统后它如何持续存在。如何使用C获取特定的内存地址C

我有一个简单的想法将一张照片mmap到内存,关闭我的电脑,等待x秒钟,启动电脑,看看照片是否仍然存在。

 
int mmap_lena(void) 
{ 
    FILE *fd = NULL; 
    size_t lena_size; 
    void *addr = NULL; 

    fd = fopen("lena.png", "r"); 

    fseek(fd, 0, SEEK_END); 
    lena_size = ftell(fd); 

    addr = mmap((void *) 0x12345678, (size_t) lena_size, (int) PROT_READ, (int) MAP_SHARED, (int) fileno(fd), (off_t) 0); 
    fprintf(stdout, "Addr = %p\n", addr); 
    munmap((void *) addr, (size_t) lena_size); 
    fclose(fd); 
    fclose(fd_log); 
    return EXIT_SUCCESS; 
} 

我忽略了检查返回值的缘故。

所以在mmap后,我试图以某种方式获取地址,但通常最终会出现分段错误,因为我了解内存受操作系统保护。

 
int fetch_lena(void) 
{ 
    FILE *fd = NULL; 
    FILE *fd_out = NULL; 
    size_t lenna_size; 
    FILE *addr = (FILE *) 0x12346000; 

    fd = fopen("lena.png", "r"); 
    fd_out = fopen("lena_out.png", "rw"); 

    fseek(fd, 0, SEEK_END); 
    lenna_size = ftell(fd); 

    // Segfault 
    fwrite((FILE *) addr, (size_t) 1, (size_t) lenna_size, (FILE *) fd_out); 

    fclose(fd); 
    fclose(fd_out); 

    return 0; 

} 

还请注意,我硬编码的不会忽略在这个例子中,所以只要您运行mmap_lena我在fetch_lena使用该值可以作为操作系统采用的第一个参数只是针对mmap作为一个提示是错误的(上我的系统总是默认为0x12346000)。

如果有任何微不足道的编码错误,我很抱歉,因为我的C技能还没有完全开发。

我想现在如果有任何方法可以获得我想要的数据而不实现任何malloc挂钩或内存分配器黑客。

由于提前, 大卫你有

+2

首先,一个标准的Linux进程无法访问原始(物理)内存,因此您可以轻松地从进程中查看给定的物理内存地址(查看MMU,虚拟内存)。此外,Linux内核在将内存交给进程之前将内存清零(如在memset 0中)。 – ysdx 2015-09-30 11:14:05

的一个问题是,你取回一个虚拟地址,不要在那里驻留内存的物理地址。下次启动时,映射可能不会相同。

这可以definitly在Linux的内核模块中完成,但我不认为这是在用户空间中任何类型的API,你可以使用。

如果您有权限(我假设你可能是这台机器,如果你重新启动它的根),那么你就可以从/ dev/MEM偷看看到实际phyiscal布局。也许你应该尝试抽样值,重新启动,并看看有多少这些值持续存在。

+0

谢谢,我不记得虚拟内存映射也是一个问题。 我在某种程度上不确定如何使用/ dev/mem来获取我想要的信息,所以我想我将不得不编写一个内核模块。 – tr9sh 2009-06-07 17:24:45

+1

也许尝试mmap/dev/mem然后寻找你想要查看的位置? – 2009-06-07 17:37:30

+4

我会同意克里斯:你将需要使用某种操作系统(或者根本不需要操作系统),它可以直接访问内存。如果您重新启动到Linux或其他具有受保护虚拟内存的操作系统,则无法保证您可以访问相同的内存页面。如果你想要一些易于使用的东西,那么重新引导到旧版本的DOS中怎么样? – 2009-06-07 18:16:14

有一个similar project显示冷启动攻击。 source code可用,也许你可以在那里得到一些启发。

然而,AFAIR他们读出存储器中,而第一,因此加载操作系统不必与操作系统内存保护一塌糊涂。也许你也应该尝试这样做,以避免启动后内存被操作系统覆盖或清除。

(同时检查网站上的视频,这是非常令人印象深刻;)

我不熟悉Linux,但你可能需要写一个设备驱动程序。出于DMA目的,设备驱动程序必须有一些方法将虚拟内存地址转换为物理内存地址(DMA控制器仅处理物理内存地址)。您应该能够使用这些接口直接处理物理内存。

测试代码看起来很奇怪

FILE * ADDR =(FILE *)0x12346000; ((FILE *)fd_out,(size_t)1, (size_t)lenna_size,(FILE *)addr);

你不能只是将一个整数转换为一个FILE指针,并期望得到一个健全的东西。 您是否也将第一个和最后一个参数切换到fwrite?最后一个参数应该是要写入的FILE *。

Direct Memory Access in Linux的问题中,我们找出了实现这一目标所需的大部分基本原理。请注意,mmap()并不是其他人所说的原因。你需要一个真正的地址,而不是虚拟的,你只能在内核中获得地址(或者通过编写一个驱动程序将一个地址传递给用户空间)。

最简单的方法是编写一个可以读取或写入的字符设备驱动程序,使用ioctl为您提供有效的开始或结束地址。同样,如果你想让内存管理函数的指针在内核中使用,请参阅我已经链接到的问题。大部分内容是在第一个(并且被接受的)答案的评论中得出的。

您可能希望尽可能少的操作系统为此目的;您加载的软件越多,覆盖您想要检查的内容的机会就越多。

DOS可能是一个不错的选择;它使用< 640k的内存。如果你不加载HIMEM,而是编写你自己的(需要程序集)例程来跳转到pmode,将一块高内存复制到低内存中,然后跳回到实模式,你可以编写一个主要是实模式的程序,可以转储出物理内存(不包括BIOS,DOS和您的应用程序)。它可以将其转储到闪存盘或其他东西。

当然,真正的问题可能是BIOS在POST期间清除内存。