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

Черная магия для начинающих

0xbeerdrinkz & l1s

Хакер, номер #087, стр. 087-148-2


Программа вышла корректно, а чтобы в этом убедиться, есть специальная и очень

полезная тулза - strace. Этой проге надо указать параметр имени исследуемой

программы:

bash-2.05b# strace ./exit

execve("./exit", ["./exit"], [/* 45 vars */]) = 0

_exit(0) = ?

bash-2.05b#

Мы видим, что произошло все так, как мы и планировали.

Теперь, убедившись, что программа, написанная нами, действует верно, превратим ее в набор байтов кода, то есть в специфический шелл-код. Воспользуемся утилитой objdump с флагом –d:

bash-2.05b# objdump -d exit

exit: формат файла elf32-i386

Дизассемблирование раздела .text:

08048080 <.text>:

8048080: b8 01 00 00 00 mov $0x1,%eax

8048085: cd 80 int $0x80

bash-2.05b#

Вот мы и получили нашу первую магическую последовательность. Но здесь есть одно маленькое "НО". В нашем шелл-коде присутствуют нулевые байты, а их не должно быть, так как в языке Си при копировании символов этот знак (00) означает конец строки. А это привносит огромную вероятность (100%), что наш шелл-код окажется бесполезным, да и размер с 00'ми увеличивается, а размер, как известно, имеет значение. Как же избавиться от нулей?

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

Давай приведем по этому принципу наш exit-шелл-код к нормальному виду:

bash-2.05b# cat exit.asm

xor eax,eax

mov al,1

int 80h

В этом коде мы сначала очистили EAX, а затем засунули номер системного вызова в AL и вызвали прерывание.

bash-2.05b# nasm -felf exit.asm -o exit.o

bash-2.05b# ld exit.o -o exit

ld: warning: cannot find entry symbol _start; defaulting to 0000000008048080

bash-2.05b# ./exit

bash-2.05b#

bash-2.05b# strace ./exit

execve("./exit", ["./exit"], [/* 45 vars */]) = 0

_exit(0) = ?

bash-2.05b#

Проверили, что все прекрасно работает. Теперь сдампим ее код:

bash-2.05b# objdump -d exit

exit: формат файла elf32-i386

Диассемблирование раздела .text:

08048080 <.text>:

8048080: 31 c0 xor %eax,%eax

8048082: b0 01 mov $0x1,%al

8048084: cd 80 int $0x80

bash-2.05b#

И вправду, теперь в нашем байт-коде нет нулей, да и размер уменьшился, что не может не радовать. Кстати, можно вместо некрасивого mov al,1 использовать inc al (на один байт меньше. - Прим. ред), что будет лучше с эстетической точки зрения. Да и вместо xor всегда можно использовать sub, но здесь уже кому как нравится. Экспиримента ради рассмотрим еще один несложный пример шелл-кода:

bash-2.05b# cat pause.asm

xor eax,eax

mov al,29

int 80h

Очищаем EAX, затем кладем в AL номер системного вызова и вызываем прерывание. Компилим, strac’им и получаем байт-код:

STRACE:

execve("./pause", ["./pause"], [/* 45 vars */]) = 0

pause( <unfinished ...>

BCODE:

8048080: 31 c0 xor %eax,%eax

8048082: b0 1d mov $0x1d,%al

8048084: cd 80 int $0x80

Этот шелл-код вызывает системную функцию pause. Которая будет ждать, когда же ты нажмешь <CTRL+C>. Здорово, да? А ведь это могла бы быть и какая-нибудь не такая безобидная функция.

Назад на стр. 087-148-1  Содержание  Вперед на стр. 087-148-3