Борьба с вирусами. Опыт контртеррористических операций

не рой яму другому, чтобы он не использовал ее как окоп!
солдатская мудрость

...червю LoveSan, разрушительной силой своей эпидемии побудившего меня написать эту статью, посвящается...
автор

…знайте: когда вы читаете эти строки, какой-то парень на планете отлаживает очередной вирус, который не сегодня-завтра нанесет удар, и одной из жертв вирусного террора окажетесь вы. Не пытайтесь отмахнуться от проблемы и не надейтесь, что на этот раз вас "пронесет"! Вирусные атаки стали слишком интенсивными и никто не может чувствовать себя в безопасности. Использование антивирусов ничего не меняет, - если вы администрируете локальную сеть крупной организации, персонально для вас может быть написан специальный вирус (троянская программа, шпион), проходящий сквозь антивирусные заслоны, как нож сквозь масло. Причем, если до недавнего времени вирусы были нетехнической проблемой "грязных рук", которая решалась элементарным выламыванием дисководов и раздачей по ушам всем любителей левого "софта", то основная масса современных вирусов проникает в целевые компьютеры самостоятельно, не требует никаких действий со стороны пользователя.
Всякий, уважающий себя администратор, должен уметь находить и нейтрализовать имеющие его вирусы самостоятельно. Тому, как именно это сделать, и посвящена настоящая статья….

Крис Касперски

1. Расплата за бездумность


Ущерб, приносимый вирусами, троянскими конями и прочими зловредными программами, трудно переоценить. И дело здесь не только в разрушенной информации (при своевременном резервировании данных их всегда можно восстановить). Гораздо большие убытки приносит панический страх перед самой возможностью заражения, выливающийся в настоящую вирусную истерию. Точно такой же страх вызывает вирус СПИДа, хотя чтобы заразиться им при половом контакте следует очень сильно стараться!

А всякий страх зиждется на незнании. После изобретения громоотвода, молнии по прежнему продолжают убивать людей, однако, сейчас их (молний) уже не так боятся и, оказались застигнутыми молнией один на один, всякий грамотный человек знает, как свести риск поражения к минимуму. Напротив, поддавшись панике и действия наобум, вы идете прямой тропой к своему кладбищу. И плачевные результаты попыток противостояния вирусным атакам - лучшее тому подтверждение. Лихорадочные переустановки операционной системы, чередующиеся с форматированием винчестера и отрубанием себя от сети- ничуть не эффективнее омовения сервера святой водой или накачиванием его антибиотиками.
Использование антивирусов также не решает проблемы. Чтобы там ни говорила реклама, а качество антивирусных программ все еще оставляет желать лучшего. Зачастую вирусы не распознаются совсем или распознаются, но не удаляются. Мягкая переустановка системы (т.е. переустановка "поверх" ранее установленной версии) не гарантирует удаления заразы и многие зловредные программы ее вполне благополучно переживают! Форматирование диска- вообще безумный способ лечения, сродни сжиганию больных на костре- жестокий и крайне неэффективный. До тех пор, пока не будут перекрыты все каналы проникновения вируса в систему, повторные заражения будут происходить вновь и вновь!

Основной недостаток подавляющего большинства антивирусов как раз и состоит в том, что удаляя вирус из системы, они даже и не пытаются заткнуть те дыры, которые вирус использует для своего распространения. Как следствие, "лечение" компьютера подключенного к сети, превращается в перегон тараканов из одной казармы в другую, а потом обратно. Ладно, заражение локальной сети это еще полбеды ("останавливаем" сеть, лечим все машины, "запускаем" сеть), но вот проникновение вирусов в Интернет представляет собой весьма нетривиальную проблему. Вылечить все машины глобальной сети за раз просто нереально… Можно (и нужно!) установить очередное обновление от Microsoft, заткнув брешь в системе безопасности, но… кто даст голову на отсечение, что этот способ действительно сработает? Ряд обнаруженных дыр парням из Microsoft удалось заткнуть лишь с второго-третьего раза, а некоторые дыры остались не заткнутыми и по сих пор (или заплатки были выпущены не для всех ОС). Причем, наблюдается ярко выраженная тенденция в ухудшении поддержки четвертой версии Windows NT. Хоть и древней - но до сих пор работающей.

В идеале - каждый администратор должен быть готов к самостоятельному отражению вирусной атаки, не надеясь на помощь извне. Существование подобных отрядов самообороны, рассредоточенных по всей Сети, сделало бы развитие глобальных эпидемий практически невозможным и снизило убытки от хакерских атак к разумному минимуму. В свое время существовала прекрасная книга "Компьютерные вирусы в MS-DOS" Евгения Касперского, доходчиво объясняющая методики рукопашной борьбы с вирусами, доступные для освоения всякому специалисту средней руки. Однако, с появлением Windows и развитием глобальных сетей, стратегия заражения файлов существенно изменилась, и старые рецепты перестали работать, а новых книг по этой тематике с тех пор так не выходило.

Данная статья рассказывает о наиболее типичных способах инфицирования исполняемых файлов и методах их выявления. Материал ориентирован на системных администраторов и прикладных программистов с минимальным уровнем подготовки.

2. Что нам потребуется?


Анализ вирусного кода требует обширных значений из различных областей программирования, а так же специализированного инструментария, без которого исследовательская работа рискует превратиться в орудие средневековой пытки. По этому поводу вспоминается один анекдот: "Наташа, вас по точке схождения двух прямых веслом не били? Ну, тогда вы нас навряд ли поймете". Все это отпугивает новичков, которые порой даже и не пытаются взять в руки дизассемблерный меч, считая, что борьба с вирусами слишком сложна дня них. Однако, это предположение неверно. Бесспорно, наивно надеяться на то, что искусству дизассемблирования можно научиться за одну ночь, но вот пары недель упорного труда для достижения поставленной цели должно оказаться достаточно.

Знание языка ассемблера - древнейшего языка программирования - обязательно. И одних лишь учебников в стиле "ASSEMBLER" Юрова и "Программируем на языке ассемблера IBM PC" Рудакова для его освоения катастрофически недостаточно, поскольку всякий язык познается лишь при общении в "живую". Сходите на любой системно-ориентированный сайт (например, http://www.wasm.ru) и попытайтесь ухватить суть ассемблера извне, а не изнутри. На форумах, где дикие люди произносят непонятные слова, ругаются матом и обсуждают репродуктивные рецепторы вирусов, витает особый системный дух, делающий все сложное таким простым и понятым.

В конечном счете, ассемблер - это всего лишь язык, причем очень и очень простой. Некоторые даже сравнивают его с эсперанто - десяток команд и вы уже можете сносно говорить. Единственная сложность состоит в том, что вирусы в отличие от нормальных программ содержат множество ассемблерных "извращений", смысл которых понятен только посвященным. Для непосвященных же это - интеллектуальный вызов! Это увлекательные логические (и психологические!) головоломки; это бессонные ночи, горы распечаток, яркие озарения и ни с чем не сравнимые радости найденных вами решений! Хотя, если говорить честно... все уже украдено до нас, тьфу, все головоломки давным-давно разгаданы, а задачки - решены. Ресурсы глобальной сети к вашим услугам! Посетите сайт удивительного человека и исследователя программ Марка Русиновича - http://www.sysinternals.com, а так же отыщите его книгу "Внутреннее устройство Windows 2000". Еще вам пригодится знаменитый Interrupt List Ральфа Брауна, - хорошо структурированный справочник по портам, ячейкам памяти и прерываниям (включая недокументированные). Последние версии Platform SDK и DDK от Microsoft и Basic Architecture/Instruction Set Reference/System Programming Guide от Intel иметь обязательно. Русские переводы технической документации, которые заполонили книжные магазины, годятся разве что для студентов, работающих над очередным рефератом, который все равно никто не читает, а для реальной работы они не пригодны.

Из инструментария вам в первую очередь понадобится хороший отладчик и дизассемблер. Конечно, свой выбор каждый волен делать сам, но ничего лучше soft-ice от NuMega (www.numega.com) и IDA PRO от Ильфака Гильфанова (http://www.idapro.com) еще никто не видел. Оба этих продукта относятся к классу тяжелой артиллерии и по сложности своего управления ничуть не уступают таким софтверным монстрам как, например, PhotoShop или CorelDRAW! Равно как изучение интерфейса PhotoShop'а не заменяет собой освоение техники рисования, так и искусство владения отладчиком/дизассемблером не ограничивается чтением штатной документации. Ищите в магазинах "Отладка Windows-приложений" Джона Роббинса, "Отладчик soft-ice" Романа Айрапетяна, "Образ мышления - дизассемблер IDA" Криса Касперски и "Фундаментальные основы хакерства - искусство дизассемблирования" его же.

По данным сайта VX.NETLUX.ORG на начало сентября 2003 года рейтинг "популярности" вирусов и троянских коней выглядел так:

TOP-20 вирусной гонки на выживание

I-Worm.Sobig.f
Worm.Win32.Lovesan
Worm.Win32.Welchia
I-Worm.Sobig.a
Worm.Win32.Ladex
Win32.Parite
I-Worm.FireBurn
Trojan.Win32.Filecoder
I-Worm.Mimail
I-Worm.Klez.a-h
33.525
Worm.P2P.Harex.a
I-Worm.Tanatos.a
TrojanProxy.Win32.Webber
MBA.First
AJ family
Worm.P2P.Tanked
Andrey.932
Worm.Win32.Opasoft
Worm.Win32.Autorooter

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

Если, работая под Windows 2000/Windows XP, вы поймаете сообщение о критической ошибке приложения в модуле SVCHOST.EXE и эта критическая ошибка с завидной регулярностью станет повторяться вновь и вновь, - не торопитесь переустанавливать систему, не сносите ваш компьютер в ремонт! Источник ошибки сидит отнюдь не в нем, а приходит к вам по сети своим шагом и имя ему - DCOM RPC bug.
Небрежное тестирование операционной системы вкупе с использованием потенциально опасных языков программирования привело к тому, что всякий нехороший человек получил возможность выполнять на вашей машине свой зловредный машинный код, управление которому передается путем нехитрого переполнения буфера. Однако, современные хакеры в своей массе настолько тупы, что даже переполнить буфер, не уронив при этом машину, оказываются не в состоянии!

Немедленно кликните мышкой по Windows Update и скачайте все критические обновления, которые вы по своей лени не скачали до сих пор! Поймите же, наконец, что антивирусы против этой беды вам все равно не помогут, поскольку осуществляют лечение пост-фактум, когда зачастую лечить уже нечего... На худой конец, закройте 135 порт - тогда вирусы и троянские кони не смогут распространяться.


Это не признак нестабильности системы. Это - признак вирусной атаки! если нажать на "ОК" - перестанет работать буфер обмена и некоторые другие функции системы, если нажать на "Отмену" - запустится отладчик (если он у вас есть) и система полностью встанет. Если же не делать ни того, ни другого - система успешно продолжит свою работу...


3. Места наиболее вероятного внедрения вирусов


Объектом вирусного поражения могут выступать как исполняемые файлы (динамические библиотеки, компоненты ActiveX, плагины), драйверы, командные файлы операционной системы (bat, cmd), загрузочные сектора (MBR и BOOT), оперативная память, файлы сценариев (Visual Basic Script, Java Script), файлы документов (Microsoft Word, Microsoft Excel) и... И это - далеко не все! Фантазия создателей вирусов поистине безгранична, и потому угрозы следует ожидать со всех сторон.

Поскольку охватить все вышеперечисленные типы объектов в рамках одной-единственной статьи не представляется сколько-нибудь разрешимой задачей, автор остановил свой выбор на самых интересных вирусоносителях из всех - на исполняемых файлах. Во-первых, вирусы, поражающие исполняемые файлы (а так же троянские программы, распространяющиеся через них же), лидируют по численности среди всех остальных типов вирусов вообще. Во-вторых, методология анализа new-EXE файлов на предмет их заражения не в пример скудно освещена. В-третьих, тема дизассемблирования достаточно интересна и сама по себе. Для многих она служит источником творческого вдохновения, да и просто хорошим средством времяпрепровождения. Так что, не будем мешкать и совершим наш решительный марш-бросок, снося всех вирусов, встретившихся на нашем пути!

4. Основные признаки вирусного внедрения


Единственным гарантированным способом выяснения: является ли данный файл "плохим" файлом или нет - является его полное дизассемблирование. Не скорою, дизассемблирование - крайне кропотливая работа и на глубокую реконструкцию программы размером в пять - десять мегабайт могут уйти годы, если не десятки человеко-лет! Чудовищные трудозатраты делают такой способ анализа чрезвычайно непривлекательным и бесперспективным. Давайте лучше отталкиваться от того, что подавляющее большинство вирусов и троянских коней имеют ряд характерных черт, своеобразных "родимых пятен", отличающих их от всякой "нормальной" программы. Надежность таких "индикаторов" зараженности существенно ниже и определенный процент зловредных программ при этом останется незамечен, но... Как говорится, на безрыбье и слона из мухи сделаешь!

Количество всевозможных "родимых пятен", прямо или косвенно указывающих на зараженность файла, весьма велико и ниже перечислены лишь наиболее характерные из них. Но даже они позволяют обнаружить до 4/5 всех существующих вирусов, а по некоторым оценкам и более того (по крайней мере, все "лауреаты" вирусного TOP-20 - обнаруживаются).

4.1 Текстовые строки

Прежде, чем приступать к тотальному дизассемблированию исследуемого файла, нелишне пролистать его дамп на предмет выявления потенциально небезопасных текстовых строк, к которым, в частности, относятся команды SMTP-сервера и командного интерпретатора операционной системы ("HELO/MAIL FROM/MAIL TO/RCPT TO, DEL/COPY/RD/RMDIR соответственно), ветвей автозапуска реестра (RunServices, Run, RunOnce), агрессивные лозунги и высказывания ("легализуем марихуану", "сам дурак") и т.д.

Конечно, все это еще не свидетельство наличия вируса (троянской программы), а отсутствие компрометирующих программу текстовых строк - не гарант ее лояльности, но… Просто поразительно, какое количество современных вирусов ловится таким элементарным способом. Не иначе как снижение культуры программирования дает о себе знать? Действительно, подавляющее большинство программ (и зловредных программ в том числе) сегодня разрабатывается на языках высокого уровня и программисты не дают себе труда хоть как-то скрыть "уши", торчащие из секции данных (не знают, как это сделать?). Откомпилированная программа просто шифруется статическими упаковщиками, которые легко поддаются автоматической/полуавтоматической распаковке, выдавая исследователю исходный дамп со всеми текстовыми строками на поверхности (см. "Идентификация упаковщика и автоматическая распаковка").

Ниже в качестве примера приведен фрагмент вируса I-Worm.Klez.e, на малую известность которого жаловаться не приходится (как трудно взглянуть на дамп того, что вы запускаете!):


Фрагмент вируса I-Worm.Klez.e, которого выдают с головой содержащиеся в теле текстовые строки - агрессивные намерения


4.2 Идентификация упаковщика и автоматическая распаковка

Упаковка исполняемых файлов "навесными" упаковщиками была широко распространена еще во времена господства MS-DOS и преследовала собой следующие цели:

а) уменьшение размеров программы на диске;
б) сокрытие текстовых строк от посторонних глаз;
в) затруднение анализа программы;
г) "ослепление" сигнатурного поиска.

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

С переходом на Windows многое изменилось. Количество упаковщиков резко возросло, но ни одного универсального распаковщика до сих пор так и не появилось, а потому анализ упакованных файлов представляет собой одну из актуальнейших проблем современной антивирусной индустрии.

Если при дизассемблировании исследуемого файла большую часть исполняемого кода дизассемблер представил в виде дампа или выдал на выходе бессмысленный мусор (неверные опкоды команд, обращения к портам ввода/вывода, привилегированные команды, несуществующие смещения и т.д.), то файл, скорее всего, упакован и/или зашифрован.

Зачастую расшифровщик крайне примитивен и состоит из десятка-другого машинных команд, смысл которых понятен с первого взгляда. В таком случае распаковать файл можно и самостоятельно. Вам даже не придется выходить из дизассемблера, - всю работу можно выполнить и на встроенном языке (если, конечно, ваш дизассемблер поддерживает такой язык). Для расшифровки простейших "ксорок" хорошо подходит HIEW, а задачи посложнее решаются с помощью IDA. Подробное изложение методики расшифровки исполняемых файлов вы найдете в книге "Образ мышления - дизассемблер IDA" Криса Касперски.


Пример типичного "ксорного" расшифровщика с комментариями

Если же код расшифровщика по своей дремучести напоминает непроходимый таежный лес, - у исследования есть все основания считать, что исследуемая программа упакована одним из навесных упаковщиков, к которым, в частности, принадлежат ASPack, UPX, NeoLite и другие. Отождествить конкретный упаковщик при наличии достаточного опыта можно и самостоятельно (даже полиморфные упаковщики легко распознаются визуально, стоит только столкнуться с ними три-пять раз кряду), а во всех остальных случаях вам помогут специальные сканеры, самым известным (и мощным!) из которых является бесплатно распространяемый PE SCAN (http://k-line.cjb.net/tools/pe-scan.zip). Давайте возьмем файл с вирусом Worm.Win32.Lovesan (также известный под именем MSBlast) и натравим на него PE-SCAN. Сканер тут же сообщит, что вирус упакован упаковщиком UPX, который можно скачать с сервера upx.sourceforge.net, а при нажатии на кнопку "OEP" определит и адрес оригинальной точки входа в файл (в данном случае она равна 0x00011CB). Ну, коль скоро мы знаем имя упаковщика, найти готовый распаковщик не составит больших проблем ("UPX" + "unpack" в любом поисковике). Кстати, упаковщик UNPX так же содержит в себе и распаковщик, хотя это скорее исключение, чем правило. С другой стороны, знание оригинальной точки входа в файл позволяет установить на этот адрес точку останова и тогда в момент передачи управления только что распакованному файлу, отладчик немедленно всплывет.

Внимание! установка программной точки останова с кодом CCh в подавляющем большинстве случаев приводит к краху распаковщика, для предотвращения которого следует воспользоваться аппаратными точками останова; за подробностями обращайтесь к руководству пользователя вашего отладчика, в частности, в soft-ice установка аппаратной точки останова осуществляется командой BPM адрес X).


PE-SCAN в действии

А как быть, если PE-SCAN не сможет определить оригинальную точку входа или ни один из найденных вами распаковщиков не справляется с данным файлом? Если исследуемый файл хотя бы однократно запускался (то есть, ваша машина уже потенциально заражена), можно взять ProcDump (http://ProcDump32.cjb.net) и, запустив распаковываемый файл еще раз, снять с него полный дамп памяти (Task -> имя процесса -> Dump Fill). Конечно, чтобы полученный дамп превратился в полноценный PE-файл, над ним придется как следует поработать "руками", но для дизассемблирования сойдет и так. Шансы распаковать файл без его запуска средствами ProcDump относительно невелики, да и качество распаковки оставляет желать лучшего. Зачастую распакованный файл не пригоден даже для дизассемблирования, не то, что запуска!

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

Итак, вызываем soft-ice и устанавливаем точки останова на все потенциально опасные функции, а так же все те функции, которые обычно присутствуют в стартовом коде (см. "Стартовый код"). Если вирус написан на языке высокого уровня, мы захватим выполнение еще до начала выполнения функции main. В противном случае, отладчик всплывет при первой попытке выполнения потенциально опасной функции.

Отладчики, устанавливающие глобальные точки останова (и soft-ice в их числе), всплывают независимо от того, какое приложение их вызывает, поэтому всегда обращайте внимание на правый нижний угол экрана, в котором soft-ice выводит имя процесса, "потревожившего" отладчик и, если это - не исследуемый вами процесс, а что-то еще, вы можете смело покинуть отладчик, не дожидаясь его очередного всплытия.

Таблица 1
 Основные функции стартового кода Основные потенциально опасные функции
 GetVersion CreateFileA
 GetVersionExA RegOpenKeyA
 GetCommandLineA RegOpenKeyExA
 GetModuleHandleA LoadLibraryA
 GetStartupInfoA FindFirstFileA
 SetUnhandledExceptionFilter FindFirstFileExA

Функции, помогающие перехватить управление у распакованного вирусного кода, получившего управление

Давайте продемонстрируем технику ручной распаковки на примере анализа вируса I Worm.Sobig.f. PE-SCAN показывает, что он упакован полиморфным упаковщиком TeLock 0.98 (http://egoiste.cjb.net/), однако, найти готовый распаковщик в Интернет для этой версии не удается (те, что есть - не распаковывают файл совсем или распаковывают его неправильно). Пошаговая трассировка распаковщика (равно как и попытки анализа алгоритма распаковки) заводят нас в никуда, ибо код оказывается, слишком сложен для начинающих (а вот опытные программисты получают от его реконструкции настоящее удовольствие, ибо упаковщик весьма неплох). Просмотр дампа в HEX-редакторе так же не показывает ничего подозрительного. Тупик...

А теперь на сцену выходит наш прием с контрольными точками: и исследуемая программа тотчас ловится на GetModuleHandleA и CreateFileA. На момент вызова последний весь код и все данные зараженного файла уже полностью распакованы, и просмотр содержимого сегмента данных немедленно разоблачает вирус по агрессивным текстовым строкам:


Распакованный вручную I-Worm.Sobig.f сразу же выдает агрессивность своих намерений характерными текстовыми строками


4.3 Стартовый код

В девяностых годах двадцатого века, когда вирусы создавались преимущество на ассемблере и писались преимущественно профессионалами, а коммерческие программисты в своем подавляющем большинстве полностью отказались от ассемблера и перешли на языки высокого уровня, для разработчиков антивирусов наступили золотые дни, ибо распознать зараженный файл зачастую удавалось с одного взгляда. Действительно, любая нормально откомпилированная программа начинается с так называемого стартового кода (Start Up code), который легко отождествить визуально (как правило, он начинается с вызова функций GetVersion, GetModuleHandleA и т. д.), а дизассемблер IDA и вовсе идентифицирует стартовый код по обширной библиотеке сигнатур, выдавая тип и версию компилятора. Ассемблерные же программы стартового кода лишены и потому, когда ассемблерный вирус внедряется в программу, написанную на языке высокого уровня, стартовый код отодвигается как бы "вглубь" файла, демаскируя тем самым факт своего заражения.

Сегодня, когда ассемблерные вирусы становятся музейной редкостью, такой способ отождествления мало-помалу перестает работать, однако до полного списывания в утиль дело еще далеко.

Строго говоря, никаких формальных признаков "нормального" start-up'a не существует и всяк разработчик волен реализовывать его по-своему. Однако редкий разработчик цепляет к программе свой собственный start-up и все чаще для этих целей используется библиотечный стартовый код, поставляемый вместе с компилятором. Несмотря на то, что даже в рамках одного-единственного компилятора существует множество разновидностей стартового кода, все они легко узнаваемы и факт отсутствия стартового кода надежно обнаруживается даже самыми начинающими из исследователей!

Приблизительная структура типичного стартового кода такова: сначала идет пролог, затем настройка обработчика структурных исключений (для Си++ программ), обнаруживающая себя по обращению к сегментному регистру FS. Далее следует вызов функций GetVersion (GetVersionEx), GetModuleHandleA и GetStartupInfoA. Подробнее об идентификации стартового кода можно прочитать в книге "Фундаментальные основы хакерства" Криса Касперски или в "Hacker Disassembling Uncovered" его же.

Здесь же мы не можем позволить себе подробно останавливаться на этом обширном вопросе и просто сравним start-up код нормальной программы с кодом вируса Win2K.Inta.1676:


Так выглядит нормальный start-up от Microsoft Visual C++ 6.0…



...А так выглядят окрестности точки входа вируса Win2K.Inta.1676

Смотрите! В то время как "хорошая" программа лениво опрашивает текущую версию операционной системы и иже с ней, зловредный вирус сломя голову несется в объятья драйвера inf.sys. Правильные программы так себя не ведут, и коварность вирусных планов разоблачается с первого взгляда!

Разумеется, отсутствие стартового кода еще не есть свидетельство вируса! Быть может, исследуемый файл был упакован или разработчик применил нестандартный компилятор или набор библиотек. Ну, с упаковкой мы уже разобрались, а с идентификацией компилятора поможет справиться IDA и наш личный опыт (замечание: текущие версии IDA PRO определяют версию компилятора непосредственно по стартовому коду и если он отсутствует или был изменен, механизм распознавания дезактивируется и поиском подходящей библиотеки сигнатур нам приходится заниматься вручную, через меню File -> Load file -> FLIRT signature file). И если обнаружится, что нормальный start-up у файла все-таки есть, но выполнение программы начинается не с него, - шансы на присутствие вируса значительно возрастут!

Троянские программы, в большинстве своем написанные на языках высокого уровня, имеют вполне стандартный Start-Up и потому на такую наживку не обнаруживаются. Взять, например того же Kilez'a, стартовый код которого выглядит так:


Червь I-Worm.Kilez.h имеет стандартный стартовый код

Даже "невооруженным" глазом видно, что стартовый код червя идентичен стартовому коду Microsoft Visual C++ 6.0, что и не удивительно, - именно на нем червь и написан.

4.4 Точка входа

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

И, если "нормальные" точки входа практически всегда находятся в кодовой секции исполняемого файла (".text"), точнее - в гуще библиотечных функций (Навигатор IDA PRO по умолчанию выделяет их голубым цветом), непосредственно предшествуя секции данных, то точка входа зараженного файла традиционно располагается между секцией инициализированных и неинициализированных данных, практически у самого конца исполняемого файла.

Так происходит потому, что дописывая свое тело в конец файла, "вирусная" секция оказывается самой последней секцией инициализированных ячеек памяти за которой простирается обширный регион неинициализированных данных, без которого не обходится ни одна программа. Это-то его (вируса) и демаскирует!

Ни один из известных автору упаковщиков исполняемых файлов так себя не ведет и потому, ненормальное расположение точки входа с высокой степенью вероятности свидетельствует о заражении файла вирусом!


Так выглядит дизассемблерный листинг нормального файла. Точка входа расположена внутри секции .text в гуще библиотечных функций приходясь приблизительно на середину файла



Так выглядит дизассемблерный листинг файла, зараженного вирусом WinNT.Infis.4608: точка входа расположена в секции .reloc, помещенной непосредственно за концом инициализированных данных у самой "кромки" исполняемого файла


4.5 Нестандартные секции

При заражении исполняемого файла методом дозаписи своего тела в его конец, у вируса есть две альтернативы: либо увеличить размер последней секции файла (а это, как правило, секция .data), присвоив ей атрибут Executable (впрочем, под Windows 9x/NT этого можно и не делать, так как она разрешает выполнение кода в секции данных), либо создать свою собственную секцию. Оба этих способа легко распознаются визуально.

Код, расположенный в конце секции данных, - весьма характерный признак вируса, равно как и секция .text, замыкающая собой файл и после недолгих мытарств передающая управление "вперед" - на нормальную точку входа. То же самое относится и к секциям с нестандартными именами, зачастую совпадающими с именем самого вируса или маскирующиеся под секции, создаваемые упаковщиками исполняемых файлов (но сам файл при этом остается неупакован!).

Достаточно часто вирусы внедряются в создаваемую ими секцию .reloc, штатно предназначенную для хранения перемещаемых элементов. Быть может, вирусописатели думают, что разработчики антивирусов все сплошь круглые идиоты, и не знают для чего это секция предназначена? Но, так, или иначе, встретив в исследуемом файле секцию .reloc, содержащую исполняемый код, знайте, с вероятностью близкой к единице вы имеете дело с вирусом.


Так выглядит дизассемблерный листинг файла, зараженного вирусом WinNT.Chatter: исполняемый код, расположенный в секции .reloc, предназначенной для хранения перемещаемых данных, сигнализирует о ненормальности ситуации


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

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

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

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

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

И вот тут-то и начинается самое интересное. Разберем два варианта: использование готовой таблицы импорта и внедрение своей. На первый взгляд кажется, что отследить "левые" обращения к импорту жертвы просто нереально, так как они ничем не отличаются от "нормальных". Теоретически все так есть. Практически же - не все так безнадежно. Большинство сред разработки компилирует программы с инкрементной линковкой и вместо непосредственного вызова всякой импортируемой функции, вызывает "переходник" к ней. Таким образом, каждая импортируемая функция вызывается лишь однажды и IDA генерирует лишь одну перекрестную ссылку. При заражении файла картина меняется и к API-функциям, используемым вирусом, теперь ведут две и более перекрестных ссылок.

Это - вернейший признак вирусного заражения! Вернее и быть не может!


"Заглушка", представляющая собой переходник к импортируемой функции и оттягивающая все перекрестные ссылки на себя



Таблица импорта исследуемого приложения: наличие "паразитной" ссылки на 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 в таблице импорта зараженного файла присутствует дважды!

Заключение


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