Вирусы и другой вредоносный код

       

Таблица импорта


Операционные системы семейства Windows поддерживают два основных способа компоновки: статический и динамический. При статической компоновке имена (ординалы) вызываемых API-функций выносятся в специальную таблицу – таблицу импорта, изучение которой дает более или менее полное представление о природе исследуемой программы и круге ее интересов. К потенциально опасным функциям в первую очередь относятся сетевые функции, функции поиска, вызова и удаления файлов, TOOLHELP-функции, используемые для просмотра списка активных процессов и внедрения в них…

Конечно, зловредной программе ничего не стоит загрузить все эти функции и самостоятельно, путем динамической компоновки, в простейшем случае опирающейся на вызов LoadLibrary/GetProcAddress, а то и вовсе на "ручной" поиск API-функций в памяти (адрес системного обработчика структурных исключений дает нам адрес, принадлежащий модулю KERNEL32.DLL, базовый адрес которого определяется сканированием памяти на предмет выявления сигнатур "MZ" и "PE" с последующим разбором PE-заголовка), но в этом случае текстовые строки с именами соответствующих функций должны так или иначе присутствовать в теле программы (если только они не зашифрованы и не импортируются по ординалу).

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

Анализ таблицы импорта позволяет выявить также и ряд вирусных заражений. Собственно, у вируса есть два пути: использовать таблицу импорта файла-жертвы или создавать свою. Если необходимых вирусу API-функций у жертвы нет и она не импортирует функции LoadLibrary/GetProcAddress, вирус должен либо отказаться от ее заражения, либо тем или иным образом импортировать недостающие функции самостоятельно (некоторые вирусы используют вызов по фиксированным адресам, но это делает их крайне нежизнеспособными, ограничивая ареал обитания лишь теми версиями ОС, на которые явно закладывались вирусописатели; другие же определяют адреса функций самостоятельно: по сигнатурному поиску или ручным анализом таблицы импорта; первое – громоздко и ненадежно, второе – слишком сложно в реализации для начинающих).


И вот тут-то и начинается самое интересное. Разберем два варианта: использование готовой таблицы импорта и внедрение своей. На первый взгляд кажется, что отследить "левые" обращения к импорту жертвы просто нереально, так как они ничем не отличаются от "нормальных". Теоретически все так есть. Практически же не все так безнадежно. Большинство сред разработки компилирует программы с инкрементной линковкой и вместо непосредственного вызова всякой импортируемой функции вызывает "переходник" к ней. Таким образом, каждая импортируемая функция вызывается лишь однажды и IDA генерирует лишь одну перекрестную ссылку. При заражении файла картина меняется и к API-функциям, используемым вирусом, теперь ведут две и более перекрестных ссылок.
Это – вернейший признак вирусного заражения! Вернее и быть не может!
BRAT0:00648310 CreateFileAproc near            ; CODE XREF: sub_432A58+C0^p
BRAT0:00648310                                         ; sub_432BC0+C0^p ...
BRAT0:00648310 FF 25 48 44+jmp    ds:__imp_CreateFileA BRAT0:00648310 CreateFileAendp
Листинг 6 "Заглушка", представляющая собой переходник к импортируемой функции и оттягивающая все перекрестные ссылки на себя
.idata:006A4440 extrn __imp_CreateDirectoryA:dword     ; DATA XREF: CreateDirectoryA^r .idata:006A4444 extrn __imp_CreateEventA:dword  ; DATA XREF: CreateEventA^r .idata:006A4448 extrn __imp_CreateFileA:dword   ; DATA XREF: CreateFileA^r .idata:006A4448                                 ; DATA XREF: sub_6A4140^r
.idata:006A444C extrn __imp_CreateProcessA:dword       ; DATA XREF: CreateProcessA^r .idata:006A4450 extrn __imp_CreateThread:dword  ; DATA XREF: CreateThread^r
Листинг 7 таблица импорта исследуемого приложения: наличие "паразитной" ссылки на CreateFileA указывает на факт вирусного заражения
А что, если вирус захочет создать собственную секцию импорта или, как вариант, – попытается расширить уже существующую? Ну, две секции импорта для операционных систем семейства Windows – это слишком! Хотя… Почему, собственно, нет? Вирус создает еще одну секцию импорта, дописывая ее в конец файла, копирует туда содержимое оригинальной таблицы импорта, добавляет недостающие API-функции и затем направляет поле Import Table на "свою" таблицу импорта.


По факту загрузки файла операционной системой вирус проделывает обратную операцию, перетягивая таблицу импорта "назад" (необходимость последней операции объясняется тем, что система находит таблицу импорта по содержимому поля Import Table, а непосредственно сам исполняемый файл работает с ней по фиксированным адресам). Наличие двух таблиц импорта в файле – верный признак его заражения!
Как вариант – вирус может добавить к файлу секцию BOUND IMPORT'а, что очень просто реализуется и, что самое интересное, обнаруживается далеко не всеми дизассемблерами! Откройте исследуемый файл в HIEW'е и посмотрите на 12-й элемент Header'а Data Directories. Если такой элемент действительно присутствует и хранит в себе нечто отличное от нуля, – вероятность присутствия вируса в файле становится весьма велика (хотя некоторые легальные программы, в частности линкер ULINK Юрия Харона, также содержат в себе секцию BOUND IMPORT'а но вирусами очевидно не являются).
Расширение уже существующей таблицы импорта менее наглядно, но при наличии опыта работы с PE-файлами его все-таки можно разоблачить. Так, большинство линкеров упорядочивают импортируемые функции по алфавиту и функции, дописанные вирусом в конец таблицы импорта, сразу же обращают на себя внимание. Даже если импорт и не отсортирован, повышенная концентрация характерных для вируса API-функций все равно не может не броситься в глаза. Действительно, перечисление имен всех импортируемых функций обычно идет сплошным потоком от первой до последней используемой DLL, причем библиотека KERNEL32.DLL (которая вирусу и нужна!) оказывается в конце списка достаточно редко и вирусу ничего не остается, как дописывать импорт из KERNEL32.DLL в хвост другой библиотеки, в результате чего ссылка на модуль KERNEL32.DLL в таблице импорта зараженного файла присутствует дважды!

Содержание раздела