Обходим все популярные антивирусы, или лажовая защита в действии

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

Итак, я потратил около часа на то, чтобы написать программу, скачивающую из интернета exe-файл и сразу запускающую ее. Удалось обойти антивирусы Kaspersky Internet Security 2011, NOD32, Dr. Web, Microsoft Security Essentials и Avast. Скорее всего, и другие бы ничего не заметили, просто не проверял. А антивирусы из списка выше даже не пикнули, когда запускался файл, скачанный только что из интернета.

Сразу скажу - я приведу не только тот способ, которым воспользовался в своей программе, но и некоторые идеи по обходу, которые я не проверял, но которые вполне могут быть на руку (и это не шифрование строк простым xor'ом со статическим ключом).

Я выбрал язык assembler и компилятор MASM32. На ассемблере удобно можно творить беспредел, в отличие от других языков. Итак, сначала моя программа приняла такой вид:

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

Первое, что мне пришло в голову - скрыть имена этих функций из таблицы импорта и искать их адреса хитрым образом через PEB (это недокументированная структура Windows, которая выдается каждому процессу системы и содержит массу полезной информации, я когда-нибудь напишу про нее статью, а пока что можете поискать описание на ntinternals). Мне ничто не мешало это сделать, тем более, я и макросы для вызова функций без использования таблицы импорта не так давно писал. Что ж, воспользуемся ими:

Вкратце: через PEB мы ищем адрес ядра (kernel32.dll), парсим его таблицу экспорта до тех пор, пока не найдем функцию GetProcAddress, а с ее помощью получаем адрес функции LoadLibraryA. Этих двух функций нам вполне достаточно для получения адресов всех необходимых нам функций в любых библиотеках. Теперь у программы всего один импорт - ExitProcess, его я вызвал явно, как и в первом варианте. После этого NOD32 сразу посчитал файл легальной программой и даже дал ему исполниться! Но вот Dr.Web продолжал определять программу как Trojan.Downloader. "Неужели они умеют эмулировать PEB?", - подумал я. Но не тут-то было, они, по всей видимости, просто считали, что если в программе есть строки URLDownloadToFileA и ShellExecuteA, то это вирус!

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

А теперь по порядку. Добавилась процедура string_coder, принимающая единственный параметр - указатель на строку, которую необходимо расшифровать или зашифровать. Так как я использую операцию xor для шифрования, функция обратима: прогнали ей один раз строку - получили зашифрованную, прогнали второй - расшифровали. Но я не использую статический ключ шифрования, я, как уже и сказал, воспользовался функцией QueryDosDevice, которая позволяет получить некоторую информацию о желаемом диске. Вся фишка тут в том, что я передал ей вполне легальные параметры, но вот размер буфера очень ограничил (последний параметр функции - 5 байтов, а этого явно мало для записи целой длинной строки с информацией). А это значит, что функция вернет ошибку (0), и дальше я проверяю это. Но и это еще не все - после такого обращения к функции последняя ошибка будет выставлена в ERROR_INSUFFICIENT_BUFFER, о чем антивирус вообще едва ли знает, и именно это значение (после некоторых преобразований, чтобы зашифрованный вариант был текстовым, как и оригинальная строка) я и использую для шифрования строк. В остальной части программы ничего не поменялось, за исключением того, что теперь я сначала расшифровываю зашифрованные строки и только после этого вызываю сами функции. Теперь у меня и импорты менее приметные стали - используются штатные функции SetLastError, GetlastError, QueryDosDevice и ExitProcess.

Теперь программа не то что не определяется, но и даже спокойно выполняется под контролем всех антивирусов, которые я перечислил в начале статьи - Kaspersky Internet Security 2011, NOD32, Dr. Web, Microsoft Security Essentials и Avast. Такими результатами вполне можно гордиться. Как мы только что выяснили, ни один из этих антивирусов не эмулирует PEB и ядро kernel32, подгруженное всегда в любой процесс Windows (или просто не знает ничего о функции QueryDosDevice, или вообще и то и то одновременно).

Скорее всего, после написания этой статьи такой способ быстро будет обнаруживаться по сигнатурам, но это ведь не мешает немного изменить код и добиться прежнего результата?

А теперь еще несколько мыслей по обходу, которые могут сработать (и точно работают со многими антивирусами). Эти способы совершенно не новы, но это не делает их устаревшими и неактуальными.

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

2. Использование сообщений Windows. В принципе, все как и в первом пункте, просто следует слать себе некое сообщение (либо пользоваться стандартными сообщениями Windows) и использовать в обработчике полученное сообщение как ключ шифрования либо как маркер для выбора дальнейшего пути исполнения.

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

4. Запись собственного кода в некое место штатной API-функции в памяти (это, естественно, затронет только наш процесс, т.к. DLL с API-функциями грузятся в каждый процесс отдельно), а затем ее вызов.

5. Для вирусов типа "скачай из интернета плохой exe-файл - запусти его" можно вместо URLDownloadToFile использовать, например, сокеты либо еще какие-то сетевые API Windows - и количество антивирусов, определяющих такую малварь, сразу уменьшится раза в полтора-два.

Если немного подумать, можно и другие способы привести и реализовать, но этих пока хватит.

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

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *