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

Вторник, 22. Ноябрь 2011
Раздел: Assembler, Windows, Это интересно, автор:

На днях лень было заниматься чем-то сложным, поэтому решил заняться трендовым нынче направлением - обманом антивирусов. Сейчас статей типа "апходим мегакрутой онтевирус" в том же журнале "Хакер" развелось немеряно, причем способы обхода антивирусов авторы выбирают наиприметивнейшие: банальное шифрование строк статическим ключом, добавление формальных задержек (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 - и количество антивирусов, определяющих такую малварь, сразу уменьшится раза в полтора-два.

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

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

 Обсудить на форуме


Получать обновления на почту:     

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


  1. UserXP :

    Да мне нужна не сама цель взломать определенный антивирь, а я хотел бы НАУЧИТСЯ это делать. Из языков я знаю паскаль и С++.

    [Ответить]

    flisk:

    Если вы действительно знаете С++, то купите/скачайте книгу Джефри Рихтера "Windows via C++", прочитав которую будете иметь глубокие знания по винапи и работе винды. И сможете накодить на Си макросы, аналогичные тем, что в данной статье по Масм.

    [Ответить]

    dx:

    Имхо, человек, знакомый с программированием, не будет спрашивать, запуститься ли программа, если ее сорс переименовать в exe :)
    Разве что, веб-программист, и то вряд ли.

    [Ответить]

    flisk:

    Меня это тоже удивило, но с другой стороны, как же он написал те два трояна (для отсылки куки на FTP; для администрирования удалённого компьютера через клиент.)?
    разве что на компонентах + не особо вникая в тему, что такое компиляция.
    Или он нас так толсто троллит? :)

    [Ответить]

    UserXP:

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

    dx:

    Хорошо, распишу ответ поподробнее.
    Данный обход можно в принципе применить, только зная языки программирования. Либо писать полностью на MASM32, а потом компилировать, либо собирать с помощью MASM32 lib-файл с нужными вызовами функций через PEB (как в статье описано), а потом линковаться с этой либой из других языков, например, C++. Применить данный материал к готовому exe-файлу, скорее всего, не получится.
    Можно посидеть-подумать и реализовать похожие макросы для языка C или C++ вполне. Но это опять-таки придется писать, готовое не применишь.

    flisk:

    Может [b]dx[/b] что-то скажет иное, но я бы советовал учить матчасть. Системный кодинг это не веб, где можно скачать скрипт, что-то там поправить и вставить в цмс. Тут надо знать систему, понимать что и куда, тем более в таких вопросах, как обход аверов (обычно тут используются какие-то нестандартные извраты).


  2. 123 :

    Да вы что, издеваетесь? Ну блин, ну dx! Что ему объяснять? Что он накодил?
    Научился "конструировать" - скачал билдер троя типа пинча.
    Видно же, что человек очень и очень далек от какого-либо кодинга (если конечно не считать кодингом "язык хтмл" и вывод на экран "хэлоу ворлд" в паскале.

    Чувак, а ближайшие пару лет своей жизни ты проблему крипта решить не сможешь точно. В твоем случае - врятли когда-либо решишь своими силами.
    Так что закажи сие удовольствие у криптовальщиков, стоит 15-20 уе. Живет крипт от 1 до 7 дней примерно.

    [Ответить]


  3. alias6969 :

    >Как мы только что выяснили, ни один из этих антивирусов не эмулирует PEB и ядро kernel32
    В большинстве случаев, их эмуляция вообще ограничивается конкретным набором действий вместо попытки сэмулировать весь код. Приведу забавный пример.

    Пусть LoadLibrary и GetProcAddress используются "в открытую" и с их помощью получаем адреса URLDownloadToFileA и ShellExecuteA. Строки с именами упрятаны как в статье. Такой код палится KIS.

    Теперь тупо возьмем адрес функции GetProcAddress (такого вида: 0х76d51222) и используем в коде. То есть вызовем GetProcAddress так:
    mov eax, 76d51222h
    push offset buf1
    push h1
    call DWORD PTR eax
    Такой код уже не палится, хотя, казалось бы, никакого труда сэмулировать это. Даже OllyDbg, если сделать брейк на call'е, покажет имя ф-ии, на которую прыгаем. А ведь KIS считается одним из наиболее продвинутых аверов.

    [Ответить]

    dx:

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

    [Ответить]

    alias6969:

    Да это ясно. С другой стороны, kernel32 не выгружается из памяти, поэтому не перемещается по крайней мере после загрузки ОС. Все сводится к получению его адреса - можно помимо PEB ковырять стек вниз, смотреть на адреса в SEH или топорно забрать адрес возврата, помещенный в стек при запуске программы.
    Есть еще извращенный вариант. Нужно найти процесс в ring3 с правами PROCESS_VM_READ и прочитать его IAT, найти там элемент для kernel32, сходить туда и найти хэдер дллки. Все процессы используют ExitProcess (ну, тут я не совсем уверен), поэтому kernel32 всегда импортируется, однако процесс с доступном для чтения VM теоретически может не найтись. В таком случае его можно запустить самому, то есть добиться того, что стандартный загрузчик импортирует kernel32, а потом нестандартно его выкусить из IAT. Минус в сложности. Плюс в базонезависимости и в том, что это вообще никто не проэмулирует еще сто лет.
    Всем добра.

    [Ответить]


  4. dedushka :

    Пытаюсь уже который день просто тупо закодировать строку и вывести её MessageBox-ом на экран, ничего не получаеться. Может напишешь код? Делов-то 5 минут!

    [Ответить]

    dx:

    Делов 5 минут, а делаешь ты несколько дней. Отсюда вопрос: оно тебе вообще надо?
    Все материалы по программированию и сборке сорсов на MASM32 на блоге есть, было бы желание разобраться.

    [Ответить]


  5. dedushka :

    .386
    .model flat, stdcall
    option casemap :none

    include \masm32\include\windows.inc
    include \masm32\macros\macros.asm
    uselib kernel32, user32

    String_coder PROTO :DWORD

    .data
    fname db "URLDownloadToFileA",0
    buffer db 128 dup(?)
    .data?
    funcname dd ?
    .code
    start:

    mov funcname,FUNC(String_coder, offset fname)

    invoke wsprintf, offset buffer, chr$("Закодированное имя API-функции- %u "), funcname
    invoke MessageBox, NULL, offset buffer, chr$("Info"), 0

    invoke ExitProcess, 0

    String_coder PROC strok:DWORD
    LOCAL buf[16]:BYTE

    invoke lstrlen, strok
    mov esi, strok
    mov edi, eax

    next_sym:
    .if edi>0
    invoke SetLastError, 0
    invoke QueryDosDevice, chr$("C:"), addr buf, 5
    .if eax==0
    invoke GetLastError
    and al,0Fh
    dec al
    xor byte ptr[esi],al
    inc esi
    dec edi

    jmp next_sym
    .endif
    .endif

    mov eax, strok
    ret
    String_coder ENDP

    end start

    Да подскажи-же почему у меня строка в цифру кодируется, или зачем тогда вообще тему выставлял? Не все же такие молодцы, а все хотят равнятся на тебя!

    [Ответить]

    dx:

    Строка в цифру? Я не понял, что не так. И у тебя в коде нет ни одной закодированной строки.

    [Ответить]

    dx:

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

    [Ответить]


  6. dedushka :

    Я и спрашиваю по этому. Не могу сам разобраться как ты имя апишки закодил в квазикозябрины, и потом всё работает зэргут? У меня какое-то гамно и получается!

    [Ответить]

    dx:

    А ты пробовал сначала выучить немного синтаксис ассемблера интеловского, потом внимательно прочитать статью, а потом уже городить что-то? Я не могу тебе помочь, потому что ты не знаешь вообще ничего, зацепиться не за что.

    [Ответить]


  7. dedushka :

    Ну зачем ты так dx? Я рад за тебя, что ты умный чувак и знаешь в совершенстве "синтаксис ассемблера интеловского"!Тут таких как я 95% ,а то и больше.И не поленился мне целую тераду написать, мог обойтись тремя словами-"посмотри дамп OllyDebuger" я бы понял.Уже и сам разобрался и сложил твой "ребус" в кучу. Не ошибается тот, кто ничего не делает, а ты если статью выкладываешь в паблик ,то потрудись её таким как я разжевывать, или не выкладывай вообще и радуйся сам -какой ты молодец!Ну а вообще спасибо, потрудился ты знатно, у меня всё скомпилировалось, правда не проверил работает ли, надо вбросить что-то на хост и посмотреть!Буду тебе очень признателен если напишешь какой-нибудь скрипт на PHP, чтобы при нажатии на ссылку в файле HTML с моего хоста грузился и устанавливался .exe файл.

    [Ответить]

    dx:

    А ты знаешь такое понятие, как "уровень сложности статьи"? Так вот, уровень этой статьи явно выше, чем "для полных нулей". И разжевывать я ничего не буду, я пишу так, как считаю нужным, и отвечаю на адекватные вопросы. А когда мне пишут "а сделай все за меня", это несерьезно, извините.

    "Грузился и устанавливался exe-файл" - вообще эпично, ты предлагаешь мне для тебя сделать сплоит, который будет пробивать защиту браузеров. Молодец.

    [Ответить]

    незнающий:

    Уважаемый, КРАЙНЕ интересует даже не сам брутфорс RDP, а посылка логина и пароля. Ну то есть как брутфорс посылает на сервер логин и пароль, API-функция есть какая или что? У вас тут есть сканер IP адресов но это не то, как вы сами понимаете.
    Из надыбанногго: вот такой списочек API-функций

    http://msdn.microsoft.com/en-us/library/windows/desktop/aa383464%28v=vs.85%29.aspx

    но в том-то и дело, что во-первых во всём инете шаром покати, ни одного примера, а во-вторых, некотоые функции просто-напросто отсутствуют, (например у меня в XP) и отстутсвует главная WTSConnectSession

    Как в таких осбтоятельствах работает брут у меня на компе- загадка (но его палит антирвиь)

    А уж с многопоточностью и перебором я справлюсь сам! СПасибо!

    [Ответить]

    flisk:

    Поищите на васме, вроде видел там где-то работу с RDP.


  8. dedushka :

    Dx я немного уточню, "не для меня лично", а для многих сотен людей которые заходят к тебе!!!! на сайт, читают твои !!!! статьи и может быть всё-таки не совсем "полные нули"!Ты же эту статью не для меня писал!?

    [Ответить]


  9. dedushka :

    К слову DX! Уже всё палится АВ, попробовал зашифровать строку статическим ключом- всё тоже самое.Выход оказался до боли прост, разбил выводы функций на две программы, потом при помощи простенького bat файла сложил их вместе и прогой Bat To converter собрал в один ехе, не палится и главное пашит и без всяких извратов!

    [Ответить]

    flisk:

    Учитывая сколько "начинающих малваре кодеров" со времени написания стотьи скомпилили и прогрузили эту идею, ничего удивительного что палится.

    А многие вопросы отпадут, если изучить матчасть.

    [Ответить]


  10. rogue :

    Поменял ф-ию на ключ. Пискнуло только при включенном анти-Ха-ре в К6fWW.

    [Ответить]


  11. xsolla :

    Это правда что эту статью не вы написали, а некий data777?
    Это ваша статья?

    [Ответить]

    dx:

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

    [Ответить]


Оставьте ваш комментарий