Внедрение кода в исполняемый файл во время выполнения - PullRequest
13 голосов
/ 03 июня 2011

Я работаю над приложением (написанным на C ++), которое генерирует некоторый машинный код во время выполнения (Linux, x86-64 сейчас, но я планирую перейти на ARM). Затем он сохраняет сгенерированный код в памяти и выполняет его, перепрыгивая в область памяти. В течение долгого времени у меня была проблема с выделением исполняемой памяти, но я наконец решил ее с помощью:

uint8_t *memory = mmap (NULL, length, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);

Пока это работает, но я не уверен, что это элегантный способ делать такие вещи. Интересно, как исполняемый загрузчик это делает?

Ответы [ 2 ]

13 голосов
/ 11 июня 2011

Ваше решение в основном то, что должно быть сделано: пусть ОС считает страницы исполняемыми.Однако некоторые операционные системы будут применять так называемую политику W ^ X , в которой страница может быть либо записываемой, либо исполняемой, но не одновременно обеими.Для таких систем (а именно OpenBSD, но есть модифицированные версии Linux, которые тоже это делают), ваш mmap() выше не удастся.Таким образом, полное решение предполагает сначала выделение некоторых страниц с mmap() и PROT_READ | PROT_WRITE, а затем с помощью mprotect() переключите страницы на PROT_READ | PROT_EXEC после генерации кода.

Даже если ОС делает этоне применять W ^ X, вызов mprotect() настоятельно рекомендуется из-за эффектов кэширования (доступ к данным и их выполнение довольно сильно отличаются друг от друга в ЦП; вы хотите быть уверены, что ЦП будет использовать только что написанные вами коды операций, а нето, что было в оперативной памяти непосредственно перед этим; mprotect() содержит необходимую магию для этого).

13 голосов
/ 03 июня 2011

Это, по сути, как исполняемые загрузчики делают вещи; в их случае они выполняют mmap файла, а не анонимное сопоставление, но, кроме того, это по сути то же самое.

Обратите внимание, что не рекомендуется одновременно иметь доступ как для записи, так и для выполнения, поскольку это облегчает использование некоторых типов уязвимостей. Вы можете использовать mprotect для настройки флагов защиты после первоначального сопоставления.

...