首页 文章

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

提问于
浏览
6

对于我的学士论文,我想要想象一下内存的数据剩余以及重启系统后它是如何存在的 .

我有一个简单的想法,将图片映射到内存,关闭我的电脑,等待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挂钩或内存分配器黑客攻击 .

大卫先生,谢谢你

6 回答

  • 1

    有一个similar project,其中演示了冷启动攻击 . source code可用,也许你可以在那里得到一些灵感 .

    然而,AFAIR他们首先读取内存而不加载操作系统,因此不必弄乱操作系统内存保护 . 也许您也应该尝试这一点,以避免在启动后被操作系统覆盖或清除内存 .

    (还要查看网站上的视频,这真是令人印象深刻;)

  • 4

    在问题Direct Memory Access in Linux中,我们找出了实现这一目标所需的大部分基础知识 . 注意,mmap()不是这个的答案,正是由于其他人所说明的原因......你需要一个真实的地址,而不是虚拟的,你只能进入内核(或者通过编写驱动程序将一个地址转发给用户空间) ) .

    最简单的方法是编写一个可以读取或写入的字符设备驱动程序,使用ioctl为您提供有效的开始或结束地址 . 同样,如果你想要在内核中使用内存管理函数的指针,请参阅我链接到的问题..大多数问题都是在第一个(和接受的)答案的注释中解决的 .

  • 10

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

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

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

  • 2

    您的测试代码看起来很奇怪

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

    你不能只是将一个整数强制转换为FILE指针,并希望得到一些理智的东西 . 你还把第一个和最后一个参数切换到fwrite吗?最后一个参数应该是要写入的FILE * .

  • 2

    您遇到的一个问题是您正在返回虚拟地址,而不是内存所在的物理地址 . 下次启动时,映射可能不一样 .

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

    如果你有权限(我假设如果你重新启动它可以在这台机器上root),那么你可以查看/ dev / mem以查看实际的phyiscal布局 . 也许您应该尝试采样值,重新启动,并查看其中有多少值持续存在 .

  • 19

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

相关问题