Загрузка и выполнение объектного кода ELF-64 - не уверены в последних шагах - PullRequest
3 голосов
/ 01 декабря 2011

Я пишу небольшой инструмент для экспериментов с объектным кодом ELF-64, который предназначен для анализа и загрузки объектного кода ELF-64 для выполнения в родительском процессе.Я верю, что сейчас на правильном пути, но мне нужны некоторые указатели для последних шагов.

Шаг 1: Я анализирую объектный файл и извлекаю всю необходимую информацию.Я подтвердил, что это правильно, используя инструмент readelf.

Шаг 2: Я перебираю все заголовки секций с набором SHF_ALLOC -бит и памятью mmap.

Шаг 3: Этот, казалось бы, простой и бесполезный объект, состоящий только из main -программы и оператора return, не требует перемещения символов, насколько я знаю (я дваждыпроверил с readelf).Я скомпилировал с TinyCC, чтобы избежать выброса .eh_frame и записей о его перемещении.

Но на этом этапе мне нужно загрузить в память разделы с SHF_ALLOC -битами, и вот где яподозреваю, что я делаю не так.

offset = 0

foreach section in sections
    if section.flags & SHF_ALLOC
        memcpy(memory_address + offset, object_code + section.offset, section.size)
        offset += section_size

Шаг 4: Последний шаг, в котором я тоже не уверен.Мне нужно позвонить в выделенную память, которую я пометил как исполняемый.

typedef int (main_t)(int argc, char* argv[]);

((main_t)object->address)(0, NULL);

Я был бы очень признателен за некоторую информацию по этому вопросу.Я считаю, что это сводится к отсутствию понимания, что именно содержит .text -сегмент и как они предназначены для хранения в памяти.

Некоторые мысли:

  • - это mainрасположены по смещению 0x0 в .text -сегменте?
  • - это выделенные сегменты, предназначенные для последовательного сохранения с правильными выравниваниями?

Что-нибудь, чтобы указать мне правильное направлениепоможет безмерно!Спасибо!

PS.Я собираюсь узнать о перемещении символов в ближайшее время.Один шаг за раз.: -)

Ответы [ 2 ]

1 голос
/ 01 декабря 2011

Для этого вы должны использовать заголовки программ, а не заголовки разделов.Заголовки разделов предназначены для компоновщика, программные заголовки предназначены для загрузчика.

Выделенные сегменты предназначены для перехода к их предпочтительному VirtAddr, если они есть (библиотеки без предварительной ссылки могут иметь базовый виртуальный адрес 0, что означает, что загрузчик назначит им случайные адреса).

Заголовок ELF имеет поле точки входа.Это не main, обычно это какой-то код инициализации libc, который ... выполняет инициализацию ... и затем вызывает main.Вы должны настроить все, что соответствует ELF ABI, прежде чем передавать управление точке входа (поместите argc, argv, envp, auxv в стек, очистите некоторые регистры, я думаю, что это так).

0 голосов
/ 01 декабря 2011

Мне удалось это осуществить после хорошего сна.

Сначала я разобрал объектный файл, используя objdump, который вывел:

/tmp/test.o:     file format elf64-x86-64


Disassembly of section .text:

0000000000000000 <main>:
   0:   55                      push   %rbp
   1:   48 89 e5                mov    %rsp,%rbp
   4:   48 81 ec 10 00 00 00    sub    $0x10,%rsp
   b:   48 89 7d f8             mov    %rdi,-0x8(%rbp)
   f:   48 89 75 f0             mov    %rsi,-0x10(%rbp)
  13:   b8 c8 00 00 00          mov    $0xc8,%eax
  18:   e9 00 00 00 00          jmpq   1d <main+0x1d>
  1d:   c9                      leaveq 
  1e:   c3                      retq 

Этот вывод обеспечил мне местоположениеmain должно быть на 0x0, что означает, что если я правильно скопирую сегмент .text в память по адресу, возвращенному mmap, я смогу вызвать его с помощью фрагмента, найденного в вопросе (которым я былне уверен насчет).Он будет использовать стек вызывающего потока.

Затем я обнаружил небольшую ошибку при копировании разделов в память, где section.offset было смещением от начала файла , чтоЯ ошибочно предположил, что это смещение от начала заголовка раздела.

Будет гораздо проще экспериментировать, когда я знаю основы работы.: -)

...