Как выполнить mmaped двоичный/код справа от выделенной памяти

62
7

У меня есть несколько двоичных файлов, я использую mmap() для записи в память. Затем я пытаюсь выполнить его прямо из выделенной памяти, но до сих пор это не результаты. Может ли кто-нибудь помочь? Примеры приветствуются) Я на Ubuntu, любой двоичный (c hello world), его размер file_size, его дескриптор fd и затем:

addr = mmap(NULL, file_size, PROT_READ | PROT_EXEC, MAP_PRIVATE, fd, pa_offset);
if (addr == MAP_FAILED)
handle_error("mmap");

поэтому я не знаю, как это выполнить

спросил(а) 2016-11-23T16:48:00+03:00 4 года, 4 месяца назад
1
Решение
87

Хотя ваш вопрос остается запутанным даже после редактирования, я думаю, вы сказали достаточно, чтобы определить, что вы делаете неправильно.

любой бинарный (c hello world)

Вы не можете выполнить двоичный файл mmap ed так же, как ОС выполняет его. Вы работаете в Linux, поэтому ваш мир приветствия, скорее всего, является двоичным в формате ELF. Linux знает, как читать и выполнять ELF файлы, в вашей программе нет. ELF начинается с заголовка, поэтому ваши данные с отображением памяти также начинаются с заголовка. Который не является исполняемым кодом. Заголовок начинается с 0x7F, что соответствует команде jg на x86, поэтому попытка "выполнить" заголовок ELF в качестве исполняемого кода, возможно (в зависимости от состояния ваших флагов) сразу же перейдет на адрес мусора, построенный из следующих байтов заголовка.

Если вы хотите запустить такой код, вам нужно проанализировать файл ELF, найти его точку входа (или, скорее всего, секцию .init) и начать выполнять код оттуда. Вы, безусловно, должны делать это как упражнение для учебных целей, но это не обычный способ выполнения другой программы. Типичным подходом было бы вместо этого использовать вызовы fork и exec. Это позволяет Linux обрабатывать технические возможности запуска программы.

ответил(а) 2016-11-23T17:26:00+03:00 4 года, 4 месяца назад
62

Это практически невозможно выполнить в произвольный образ памяти. Файлы ELF должны быть помечены определенным образом в адресном пространстве процесса, почти никогда не являясь непрерывным изображением базового файла.

Самый близкий рабочий подход, о котором я могу думать, заключается в том, чтобы сохранить изображение в (возможно, безымянный) файл и выполнить этот файл с помощью execveat(fd, "",...). Проверьте execveat (2), где они говорят о пустом пути, и откройте (2) в O_TMPFILE.


Именованный файл temp и обычный execve (2) также будут работать, если разрыв между close/munmap и execve, когда файл может быть изменен, не является проблемой.

Другая идея заключалась бы в полной загрузке ELF в пользовательском пространстве, настройке правильного адресного пространства для нового процесса, вызове LD и т.д. Определенно не легко. Не требует вызова execve (2), только для fork и работы оттуда. Поскольку execve (2) не будет использоваться, некоторые вещи, такие как обработка O_CLOEXEC и ненужная дополнительная память, потребуют нетривиальных обходных решений.

ответил(а) 2016-11-23T17:29:00+03:00 4 года, 4 месяца назад
Ваш ответ
Введите минимум 50 символов
Чтобы , пожалуйста,
Выберите тему жалобы:

Другая проблема