Как загрузить и выполнить двоичный исполняемый файл ELF вручную?

Допустим, бинарник — это PIC, как его загрузить в память и выполнить точку входа? Я делаю это, чтобы познакомиться с ELF, поэтому execve не разрешено.


c elf
person Je Rog    schedule 02.07.2011    source источник
comment
Это очень важная задача, требующая знаний не только об ELF. Возможно, вы захотите создать парсер файлов ELF, а не полноценный загрузчик, чтобы ознакомиться с форматом. В любом случае вам понадобится парсер, чтобы получить адрес функции main.   -  person zneak    schedule 02.07.2011
comment
Интересный вопрос, но я не решаюсь поставить +1, потому что он очень краткий и не дает много информации о вашем прошлом, о том, что вы уже читали или пробовали, и т. д.   -  person R.. GitHub STOP HELPING ICE    schedule 02.07.2011
comment
Прочтите исходный код ядра, там всё ясно: stackoverflow.com/questions/8352535/   -  person Ciro Santilli 新疆再教育营六四事件ۍ    schedule 14.07.2015


Ответы (1)


Вот основные шаги:

  1. Прочтите заголовки программы, чтобы найти директивы LOAD и определить общую длину отображений, которые вам понадобятся, в страницах.
  2. Сопоставьте директиву LOAD с наименьшим адресом с общей длиной (которая может быть больше, чем длина файла), позволяя mmap назначить вам адрес. Это позволит зарезервировать непрерывное виртуальное адресное пространство.
  3. Сопоставьте директивы remining LOAD поверх частей этого сопоставления, используя MAP_FIXED.
  4. Используйте заголовки программы, чтобы найти вектор DYNAMIC, который, в свою очередь, даст вам адрес вектора(ов) перемещения.
  5. Примените переезды. Предполагая, что ваш двоичный файл был двоичным файлом PIE со статической привязкой, он должен полностью состоять из RELATIVE перемещений (просто добавляя адрес базовой загрузки), что означает, что вам не нужно выполнять поиск символов или что-то необычное.
  6. Создайте стек записи программы ELF, состоящий из следующей последовательности значений размером системного слова в массиве в стеке:

    ARGC ARGV[0] ARGV[1] ... ARGV[ARGC-1] 0 ENVIRON[0] ENVIRON[1] ... ENVIRON[N] 0 0
    
  7. (Для этого шага требуется ASM!) Наведите указатель стека на начало этого массива и перейдите к адресу точки входа загруженной программы (который можно найти в заголовках программы).

person R.. GitHub STOP HELPING ICE    schedule 02.07.2011
comment
Э-э, я думал, что смысл кода, не зависящего от позиции, в том, что он не имеет перемещений - у него есть глобальная таблица смещений или что-то в этом роде. - person Random832; 02.07.2011
comment
@ Random832, смогу ли я реализовать загрузчик и выполнить двоичный файл, если это не PIC? - person Je Rog; 02.07.2011
comment
@ Random832: У вас всегда есть вероятность перемещения данных. Как еще может работать static int x, *y=&x;? И, конечно же, в ПТ полно переездов. Единственный способ избежать каких-либо перемещений — избежать каких-либо глобальных данных. - person R.. GitHub STOP HELPING ICE; 02.07.2011
comment
@R..: Я не думаю, что статически связанный исполняемый файл, отличный от PIE, нуждается в каком-либо перемещении. - person ninjalj; 02.07.2011
comment
@R..: вы также должны передать массив auxv в программу. - person ninjalj; 02.07.2011
comment
@ninjalj, когда auxv полезен? - person Je Rog; 02.07.2011
comment
@Je Rog: как правило, почти никогда. - person ninjalj; 02.07.2011
comment
Я говорил о позиционно-независимом коде. Очевидно, что статическая связанная программа с фиксированным адресом не нуждается в перемещении. - person R.. GitHub STOP HELPING ICE; 02.07.2011
comment
И что касается auxv: последний 0 в моем примере стека был нулевой длины auxv. Передача нетривиального auxv может быть хорошей идеей, но вы не можете просто скопировать тот, который дал вам ядро; вы должны изменить его, чтобы он соответствовал адресу загрузки, адресу заголовка программы и т. д. для новой программы. - person R.. GitHub STOP HELPING ICE; 03.07.2011
comment
@R.., я не понимаю одну из спецификаций: почему loadable process segments must have congruent values for p_vaddr and p_offset, modulo the page size? - person Je Rog; 07.07.2011
comment
Отображение виртуальной памяти осуществляется на уровне страниц (на самом деле это определение страницы). Таким образом, если бы p_vaddr и p_offset не были конгруэнтны по модулю размера страницы, не было бы никакого способа удовлетворить LOAD с помощью mmap. Сегмент придется полностью скопировать на новые анонимные страницы. - person R.. GitHub STOP HELPING ICE; 07.07.2011
comment
@R.., Как соотносятся ч/б сегменты и участки, пересекаются ли они? - person Je Rog; 13.07.2011