Издательский дом ООО "Гейм Лэнд"СПЕЦВЫПУСК ЖУРНАЛА ХАКЕР #48, НОЯБРЬ 2004 г.

Like a Virus

Дмитрий Коваленко aka Ingrem

Спецвыпуск: Хакер, номер #048, стр. 048-064-1


(ingrem@list.ru)

Вирусные технологии в троянах

Уже привыкли, что троян - это отдельный файл, который стартует из автозагрузки. Мало кому известно, что загрузчик трояна (или весь троян) может быть оформлен в виде адресно-независимого кода. Переносимый код прописывается в чужой EXE или DLL - заражает точно так же, как это делают вирусы.

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

Две проблемы адресно-независимого кода

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

Проблема первая. Неизвестно, где окажется код трояна, заразив EXE. Поэтому, как только код получит управление, он должен будет узнать адрес своего начала. Чаще всего используется бородатый (но стопроцентно рабочий) прием, который был популярен еще во времена DOS:

_trojan_code_start: ; начало кода трояна

call $5 ; call на следующую инструкцию

pop ebp ; вытолкнем из стека адрес инструкции pop ebp

sub ebp, 5 ; теперь в ebp адрес _trojan_code_start

Проблема вторая. Нужно научиться вызывать API. У обычного приложения трудностей с этим не возникает - нормальный EXE-файл имеет таблицу импорта. В ней, кроме всего прочего, указано, какие API требуются программе и куда нужно записать их адреса (система это делает еще при загрузке).

Поскольку адресно-независимый код трояна не имеет таблицы импорта, ему нужно как-то узнать эти адреса самому. Вирусописатели знают несколько способов нахождения API. Самый надежный из них - анализ таблицы экспорта kernel32.dll. Не будем приводить полный исходник процедуры, которая это делает, а упомянем лишь общие принципы и некоторые сведения о формате Portable EXE (PE).

Как добраться до таблицы экспорта?

Большинство EXE и DLL - это PE-файлы (kernel32.dll - не исключение). Все они имеют следующую структуру. PE-файл начинается со stub'a. Stub - это EXE-программа, работающая под MS DOS. Начинается с сигнатуры - двух байт 'MZ' или (что бывает очень редко) 'ZM'. Stub получает управление, если EXE запущен под DOS'ом. Обычно он имеет небольшой размер и выводит "This program requres Microsoft Windows", после чего завершает работу. В DLL stub просто для красоты. В своем заголовке по смещению 3Ch stub содержит dword - RVA PE-заголовка.

После stub'а идет, собственно, Windows-программа. Она начинается с заголовка PE. Первые четыре байта заголовка образуют сигнатуру 'P','E',0,0 или (почти не встречается) 'E','P',0,0. Заголовок имеет довольно сложную структуру, из которой нас интересуют лишь некоторые элементы. В частности, RVA таблицы экспорта находится по смещению 78h от сигнатуры PE (если считать, что сама сигнатура имеет смещение 0).

В таблице экспорта интересны следующие элементы. По смещению 20h от начала таблицы экспорта лежит dword - RVA массива указателей на 0-терминирующие строки с именами экспортируемых API. По смещению 24h лежит еще один интересный dword - RVA массива ординалов. Ординал - это обычное двухбайтовое слово (зачем нужны ординалы, смотри ниже). И по смещению 1Ch лежит RVA массива адресов API.

Содержание  Вперед на стр. 048-064-2