Используйте mmap для помещения контента в выделенную область памяти - PullRequest
1 голос
/ 31 марта 2020

Я пытался прочитать документацию по 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! и затем завершиться. Я действительно не знаю, как получить этот вывод после карты или как "вызвать / выполнить" mmap.

1 Ответ

0 голосов
/ 01 апреля 2020
  int x = sscanf(read, "%02hhx", assembly_code);

Это преобразует только один байт. Я не думаю, что есть стандартная библиотечная функция для преобразования всей строки шестнадцатеричных байтов; вам придется вызывать sscanf по всем oop, увеличивая указатели внутри входного буфера read и выходного буфера assembly_code, в зависимости от ситуации.

При вызове mmap, если вы не не хотите отображать файл, вы должны использовать флаг MAP_ANONYMOUS вместо MAP_SHARED. Вам также следует проверить его возвращаемое значение (при ошибке возвращается MAP_FAILED) и сообщить о любой ошибке. Кроме того, возвращаемое значение в принципе имеет тип void * вместо int * (хотя это не должно иметь значения в обычных Unix системах).

Вызов mmap (после исправления) будет вернуть указатель на блок памяти, заполненный нулями. Нет смысла в нем содержать ваш assembly_code, поэтому вам придется скопировать его туда, возможно, с memcpy. Или вы можете переместить ваш l oop и проанализировать шестнадцатеричные байты непосредственно в область, выделенную с помощью mmap.

Ваш ((void (*)(void))map)(); для передачи управления на сопоставленный адрес кажется правильным, поэтому, как только вы получите блок правильно сопоставлен и заполнен, он должен выполнять ваш машинный код. Я не пытался разобрать предоставленную вами шестнадцатеричную строку, чтобы посмотреть, действительно ли она будет выполнять то, что вы ожидаете, но, надеюсь, это удастся.

Кроме того, read не очень хорошее имя для переменной, так как есть также стандартная библиотечная функция с этим именем. Ваш код будет работать, поскольку локальная переменная затеняет глобальный объект, но было бы более понятно выбрать другое имя.

О, а char assembly_code[sizeof argv[1]]; не правильно. Тщательно продумайте, что sizeof делает и не делает.

...