首页 > 解决方案 > 使用 mmap 将内容放入分配的内存区域

问题描述

我试图阅读文档,mmap但我仍然很难理解如何使用它。

我想从命令行获取一个参数,然后将它分配给一个可执行的内存区域。然后我希望能够从该代码执行。

这是我到目前为止所拥有的:

int main(int argc, char const *argv[]) {
  if (argc != 2) {
    printf("Correct input was not provided\n");
    exit(1);
  }

  char assembly_code[sizeof argv[1]];
  const char *in_value = argv[1];

  int x = sscanf(in_value, "%02hhx", assembly_code);
  if (x != 1) {
    printf("sscanf failed, exited\n");
    exit(1);
  }

  void * map;

  size_t ac_size = sizeof(assembly_code) / sizeof(assembly_code[0]);
  map = mmap(NULL, ac_size, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_ANONYMOUS, -1, 0);

  if (map == MAP_FAILED) {
    printf("Mapping failed\n");
    exit(1);
  }

  ((void (*)(void))map)();

  return 0;
}

这是我得到的输出/错误:Mapping failed

我不知道我mmap是否正确使用。如果我是,我不相信我正在正确执行它。

例如,如果这个文件使用一个参数运行,e8200000004889c64831c048ffc04889c74831d2b2040f054831c0b83c0000004831ff0f05e806000000584883c008c3ebf84869210a它应该返回Hi!然后终止。我真的不知道如何在地图之后获得此输出或如何“调用/执行” a mmap.

标签: cmmap

解决方案


  int x = sscanf(read, "%02hhx", assembly_code);

这仅转换单个字节。我认为没有标准库函数可以转换整个十六进制字节字符串;您必须在循环中调用,酌情增加输入缓冲区和输出缓冲区中sscanf的指针。readassembly_code

在您的mmap通话中,如果您不想映射文件,则应使用标志MAP_ANONYMOUS而不是MAP_SHARED. 您还应该检查它的返回值(它返回MAP_FAILED错误)并报告任何错误。此外,返回值原则上是类型void *而不是int *(尽管这在常见的 Unix 系统上应该没有区别)。

mmap调用(在修复后)将返回一个指向填充零的内存块的指针。它没有理由包含您assembly_codememcpy. 或者您可以移动您的循环并将十六进制字节直接解析到使用mmap.

((void (*)(void))map)();将控制权转移到映射地址似乎是正确的,因此一旦您正确映射和填充了块,它应该执行您的机器代码。我没有尝试反汇编您提供的十六进制字符串,以查看它是否真的会达到您的预期,但希望可以。

此外,read这不是一个很好的变量名称,因为该名称还有一个标准库函数。您的代码将起作用,因为局部变量会隐藏全局对象,但选择另一个名称会更清楚。

哦,char assembly_code[sizeof argv[1]];不对。仔细想想做什么sizeof和不做什么。


推荐阅读