Издательский дом ООО "Гейм Лэнд"ЖУРНАЛ ХАКЕР #90, ИЮНЬ 2006 г.

Самый маленький эльф

Крис Касперски ака мыщъх

Хакер, номер #090, стр. 090-110-5


xorl %ebx,%ebx ; // код возврата

int $0x80 ; // exit(0);

.data

msg: .ascii "hello,elf\n"

len = . - msg

Пара замечаний к программе. Инструкция "MOVL $1,%EBX" занимает пять байт, но при желании ее можно ужать до трех: "XORL %EBX,%EBX", "INCL %EBX", однако, учитывая размер служебных полей elf-файла, выигрыш не составит и доли процента, так что над оптимизацией кода можно не напрягаться.

Сборка для всех систем осуществляется следующим образом:

$ as -о elf_80h.o elf_80h.S

$ ld -s -o elf_80h elf_80h.o

Под Linux'ом размер файла составляет всего 388 байт, под FreeBSD слегка отстает — 452 байта (сказываются разные версии трансляторов и линкеров). Под Linux файл запускается сразу же и без вопросов, а вот под FreeBSD требует предварительной эмуляции:

$ brandelf -t Linux elf_80h

$ ./elf_80h

hello,elf

Кстати, под Linux'ом существует альтернативный вариант автоматической сборки при помощи все того же gcc, запущенного с ключом "-nostartfiles", но в этом случае размер полученного файла (даже после стрипа) будет составлять 928 байт, а это плохо (тем не менее, все равно меньше, чем с использованием libc).

Конструирование elf'а

Программирование без libc значительно сокращает размер программ, однако полученные файлы все равно остаются большими и толстыми. Самый крошечный эльф, который нам только удалось получить, весит целых 388 байт, и это притом, что он не насчитывает и десятка ассемблерных команд. Что же в нем такое содержится? Возьмем любой hex-редактор и посмотрим.

Нашему взору представится одна вода, то есть нули, "заботливо" вставленные тупым линкером. А что если отказаться от услуг линкера и попробовать соорудить elf-файл голыми руками? Для этого нам, во-первых, потребуется подробное описание всех служебных структур elf'а (последний draft лежит здесь www.caldera.com/developers/gabi/), а во-вторых, транслятор, умеющий генерировать двоичные файлы, например NASM, входящий в большинство Linux-дистрибутивов, но, к сожалению, не в BSD. Во всяком случае, его всегда можно скачать с "родной" страницы проекта: nasm.sf.net.

Исполняемый elf-файл нуждается в двух структурах: elf-header'e, описывающим основные параметры файла (платформа, адрес точки входа и т.д.) и program header table, перечисляющего все сегменты. Как минимум, должен быть один сегмент с правами на чтение, запись и исполнение. Наконец, чтобы elf заработал, требуется добавить "боевую начинку", то есть непосредственно сам ассемблерный код. Минимальный адрес, с которого в UNIX-системах может загружаться elf, равен 8048000h, поэтому нам понадобится директива ORG, задающая начальное смещение в файле.

Остается только изучить документацию и заполнить все служебные структуры соответствующим образом:

Ассемблерный файл elf_tiny.asm, сконструированный голыми руками

BITS 32

org 8048000h

...

_start:

mov eax,4 ; // системный вызов #4 "write"

xor ebx,ebx

inc ebx ; // 1 - STDOUT

push ebx

mov ecx,msg ; // смещение выводимой строки

mov edx,msg_end-msg ; // длина строки

int 80h ; // write(stdout, msg, len);

pop eax ; // системный вызов #1 "exit"

Назад на стр. 090-110-4  Содержание  Вперед на стр. 090-110-6