Объединить дополнительный код в исполняемый файл (arm-linux) - PullRequest
2 голосов
/ 22 апреля 2011

Я пытаюсь объединить дополнительный код регистрации в статически связанный исполняемый файл (android arm linux).

(Нормальные методы трассировки, похоже, не работают, так как это процесс-демон, который выполняет clone () перед тем, как делать что-то интересное - указание strace следовать этому просто приводит к его падению).

Hexредактирование существующего кода для вставки инструкций перехода в новый код протестировано и работает, проблема заключается в том, что новый код объединяется с исполняемым файлом таким образом, что он не мешает существующим сегментам и загружается висполняемая страница.

Мне удалось сжать весь дополнительный код в один раздел объектного файла, но я не могу понять, как использовать objcopy (или даже ld), чтобы объединить это таким образом, чтобыон будет загружен должным образом - кажется, мне нужно либо изменить размер и переместить существующие сегменты загрузки, либо добавить дополнительный, который будет учитываться.

Добавление кода в общую библиотеку может быть другим вариантом, если естьспособ добавить необходимые заглушки в уже связанный и в настоящее время статический исполняемый файл (я бы тогда hex-eв инструкциях перехода перейдите к известным местам заглушек, которые компоновщик времени выполнения будет указывать на добавленный код)

1 Ответ

0 голосов
/ 23 апреля 2011

Это не элегантно, так что меня заинтересуют лучшие идеи, но вот краткое изложение того, что мне удалось сделать в основном работой.

Это двухсторонний подход небольшой полезной нагрузки начальной загрузки, вставленной в отступ исходного эльфа, который затем выполняет mmap () произвольно большего двоичного двоичного объекта для выполнения реальной работы.

Часть I: полезная нагрузка начальной загрузки

По сути, я вставляю небольшое количество кода в некоторые отступы между разделом .ARM.exidx (который загружается в верхней части сегмента кода) и разделом .preinit_array. Этот код просто открывает еще один двоичный BLOB-объект и mmap (), которые доступны только для чтения и исполняются по жестко закодированному виртуальному адресу.

Для того, чтобы мой вставленный код загружался как часть основного исполняемого файла, мне пришлось изменить размер сегмента загрузки в файле elf, в данном случае это вторая структура phdr, которая начинается с 0x54. P_filesz в 0x64 (0x54 + 0x20) и p_memsz в 0x68 (0x54 + 0x24) были изменены.

Я также изменил начальный адрес e_entry в заголовке elf со смещением 0x18, чтобы он указывал на мой вставленный код. Мой вставленный код выполняет переход к старому начальному адресу, когда он завершает настройку (на самом деле он сначала переходит на второй этап настройки в большей полезной нагрузке, которая затем переходит к исходному).

Наконец, я изменил статически связанные заглушки системных вызовов для функций, которые я хотел перехватить, чтобы они указывали на мои замены по адресу загрузки большей полезной нагрузки, в которой находится mmap ().

Часть II: большая полезная нагрузка

Это реализует любые изменения, которые вносятся - в моем случае, замена системных вызовов функциями, которые регистрируют, когда выполняются определенные условия. Поскольку основной исполняемый файл статически связан, это должно быть так же - или, проще говоря, он не может использовать библиотеку C. Вместо этого он использует язык ассемблера для выдачи системных вызовов для базового ввода-вывода. Я понял, что, не будучи загруженным в качестве исполняемого файла, у меня нет постоянного хранилища локальных переменных, поэтому при запуске я запускаю mmap () анонимную страницу для хранения локальных переменных - в основном это fd файла, в который я регистрируюсь, и операции драйвера fd устройства который должен быть зарегистрирован.

Компиляция этой части немного не элегантна. Я компилирую в сборку с ключом -S для gcc, затем удаляю все ключевые слова раздела. Затем я передаю его обратно через gcc для сборки и генерации объекта. Я запускаю это через компоновщик, указав имя моей первой функции в качестве точки входа (-e) и используя настройку обычного сценария компоновщика, который удаляет начальное смещение 0x8000. Но есть еще некоторое смещение из-за заголовков, в данном случае 128 байтов. чтобы сохранить исправления, я объявляю содержимое связанного эльфа в двоичный двоичный объект, помещаю 128 байтов из / dev / zero и помещаю это в начало ....

Как я уже говорил ... это не элегантно, поэтому я открыт для лучших идей

...