2013-08-27 1 views
1

получить Opcodes автор here делает следующее:Как получить минимальные исполняемые коды операций для c-программы?

[[email protected] testbed8]$ as testshell2.s -o testshell2.o 
[[email protected] testbed8]$ ld testshell2.o -o testshell2 
[[email protected] testbed8]$ objdump -d testshell2 

, а затем он получает три секции (или упоминает только эти 3):

  • < _start>

  • < стартер>

  • < ender>

Я попытался получить шестнадцатеричные коды операций таким же образом, но не может ld правильно. Конечно, я могу производить .o и прог-файл, например, с:

gcc main.o -o prog -g 

однако когда

objdump --prefix-addresses --show-raw-insn -Srl prog 

, чтобы увидеть полный код с аннотациями и символами, I have many additional sections there, например:

  • .init

  • .plt

  • .text (да, я знаю, главное, здесь) [много частей здесь: _start(), call_gmon_start(), __do_global_dtors_aux(), frame_dummy(), основной(), __libc_csu_init(), __libc_csu_fini(), __do_global_ctors_aux()]

  • .fini

Я предполагаю, что эти дополнения, вносимые НКУ ссылаются во время выполнения библиотек. Я думаю, что мне не нужны эти все разделы для вызова кода операции из кода c (автор использует только эти 3 раздела), однако моя проблема заключается в том, что я не знаю, что именно я могу отбросить и которые необходимы. Я хочу, чтобы использовать его как это:

#include <unistd.h> 

char code[] = "\x31\xed\x49\x89\x...x00\x00"; 

int main(int argc, char **argv) 
{ 
/*creating a function pointer*/ 
int (*func)(); 
func = (int (*)()) code; 
(int)(*func)(); 

return 0; 
} 

так я создал это:

#include <unistd.h> 
/* 
* 
*/ 
int main() { 

    char *shell[2]; 

    shell[0] = "/bin/sh"; 
    shell[1] = NULL; 
    execve(shell[0], shell, NULL); 

    return 0; 
} 

и я сделал разборку, как я описал. Я попытался использовать opcode из .text main(), это дало мне ошибку сегментации, затем .text main() + дополнительно .text_start(), с тем же результатом.

Итак, что выбрать из вышеприведенных разделов или как сгенерировать только как минимизированную «прогу», как с тремя разделами?

ответ

1

Вы должны прочитать эту статью: http://www.muppetlabs.com/~breadbox/software/tiny/teensy.html. Это объясняет все, что вам нужно, чтобы создать действительно крошечную программу очень подробно.

+0

спасибо, я думаю, что найду то, что мне там нужно – 4pie0

2

код символа [] = "\ x31 \ xed \ x49 \ x89 \ x ... x00 \ x00";

Это не сработает.

Причина: код определенно содержит адреса. Главным образом адрес функции execve() и адрес строковой константы «/ bin/sh».

Исполняемый файл с использованием подхода "code []" не содержит строковой константы "/ bin/sh" вообще, и адрес функции execve() будет отличаться (если функция будет связана с исполняемым файлом вообще).

Поэтому команда «вызов» функции «execve()» будет перемещаться в любом месте исполняемого файла с использованием подхода «code []».

Немного теории о исполняемых - как раз для вашей информации:

Есть две возможностей для исполняемых файлов:

  • Статический связанно: Эти исполняемые файлы содержат все необходимые символы. Поэтому они не получают доступа к динамическим библиотекам типа «libc.so»
  • Динамически связаны: эти исполняемые файлы не содержат часто используемый код. Такой код хранится в файлах, общих для всех исполняемых файлов: динамические библиотеки (например, «libc.so»)

Когда же код C используется, то статически связаны исполняемые файлы гораздо больше, чем динамически подключаемых исполняемых файлов, так как все Функции C (например, «printf», «execve», ...) должны быть включены в исполняемый файл.

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

Статический связан исполняемое поведение

Статичаская исполняемый загружается в память операционной системы (когда он запускается с помощью execve()). Исполняемый файл содержит адрес точки входа. Этот адрес сохраняется в заголовке файла исполняемого файла. Вы можете увидеть его с помощью «objdump -h ...».

Операционная система выполняет переход к этому адресу, поэтому выполнение программы начинается с этого адреса. Адрес, как правило, является функцией «_start», однако это можно изменить с помощью параметров командной строки при связывании с использованием «ld».

Код в «_start» подготовит исполняемый файл (например, инициализирует переменные, вычислит значения для «argc» и «argv», ...) и вызовет функцию «main()». Когда функция «main()» возвращает функцию «_start», передается значение, возвращаемое функцией «main()» в функцию «_exit()».

Динамически связаны исполняемым поведение

Такие исполняемые файлы содержат два дополнительных секций. Первый раздел содержит имя файла динамического компоновщика (возможно, «/lib/ld-linux.so.1»). Затем операционная система загрузит исполняемый файл и динамический компоновщик и перейдет к точке входа динамического компоновщика (а не к исполняемому файлу).

Динамический компоновщик прочитает второй дополнительный раздел: Он содержит информацию о динамических библиотеках (например, «libc.so»), требуемых исполняемым файлом. Он загрузит все эти библиотеки и инициализирует множество переменных. Затем он вызывает функцию инициализации («_init()») всех библиотек и исполняемого файла.

Обратите внимание, что как операционная система, так и динамический компоновщик игнорируют имена функций и разделов! Адрес точки входа берется из заголовка файла, а адреса функций «_init()» взяты из дополнительного раздела - функции могут быть названы по-разному!

Когда все это будет сделано, динамический компоновщик перейдет в точку входа («_start») исполняемого файла.

О «ПРТ», «PLT», ... Разделы:

Эти разделы содержат информацию об адресах, где динамические библиотеки были загружены линкера. Раздел «PLT» содержит код оболочки, который будет содержать переходы в динамические библиотеки. Это означает: раздел «PLT» будет содержать функцию «printf()», которая фактически ничего не сделает, кроме как перейти к функции «printf()» в «libc.so». Это делается потому, что прямое вызов функции в динамической библиотеке из кода C затрудняло бы соединение, поэтому код C не будет вызывать функции в динамической библиотеке напрямую. Другим преимуществом этой реализации является то, что возможно «ленивое соединение».

Несколько слов о Windows,

Windows, знает только динамически связанные исполняемые файлы. Windows XP даже отказалась загружать исполняемый файл, не требующий DLL. «Динамический компоновщик» интегрирован в операционную систему, а не отдельный файл. Существует также эквивалент раздела «PLT». Однако многие компиляторы поддерживают «прямо» вызов DLL-кода из кода C, не вызывая сначала код в секции PLT (теоретически это также возможно в Linux). Ленивая привязка не поддерживается.

+0

На самом деле есть что-то, что называется [«импорт с задержкой»] (http://msdn.microsoft.com/en-us/library/151kt790), хотя он реализован в компиляторе, а не сам загрузчик ОС. –

+0

@Martin Rosenau спасибо, отличный ответ, однако вы не упомянули о решении моей проблемы: будет ли это нормально, если бы я сделал статическое связывание моей программы оболочки и извлечение опкодов из ее _start? (там не будет никаких прав?) – 4pie0

Смежные вопросы