Черная магия для начинающих 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>. Здорово, да? А ведь это могла бы быть и какая-нибудь не такая безобидная функция. |