Вирусы или программное управление. Часть 2

Вирусы или программное управление. Часть 2


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

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

Вспоминаем и немного дополняем первую статью

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

По итогам первой статьи у нас есть вирус, умеющий корректно заражать исполняемый файл (т.е. умеет при запуске файла отработать сам и корректно выполнить код самого файла) и антивирусный детектор, который знает, что вирус размещается в строго определённых местах файла, и что на некотором расстоянии от характерной точки (от точки входа, от начала секции, от конца заголовка) существует фиксированный набор байт, который характеризует данный вирус. Также, чтобы статья не съезжала в обсуждение тем «что плохого делает вирус», давайте договоримся, что payload вирусa ничего не делает. Так можно отсеять все обсуждения касательно характера действий рассматриваемого кода и сосредоточиться на методах детектирования и сокрытия.

Продолжаем вспоминать и дополнять первую статью. Схему противостояния вируса и антивируса можно по аналогии рассмотреть с точки зрения взлома коммерческой программы. Вместо инфектора здесь работает собственно программа, «навешивающая» защиту на исполняемый файл. Она «портит» код самой программы, информацию, необходимую для его восстановления прячет в свое тело, и таким же хитрым способом, как и вирус, скрывая алгоритм своей работы, первым исполняет код защиты, который проверяет валидность серийного номера или время действия trial, и, затем, «починив» основную программу, передаёт ей управление. Крэкер в свою очередь исполняет роль антивируса, пытаясь добраться до внутреннего кода защиты и узнать его алгоритм. Получается, что он занимается тем же самым, что и авер, пытаясь найти (и сохранить) характерную часть кода. Разница лишь в том, что крэкер заберет весь оригинальный код и изготовит из него работоспособный файл, а авер найдет в нем характерный кусок и создаст сигнатуру.

Самым популярным способом снять такую защиту является dump образа программы в памяти на диск. Крэкер ищет момент, когда защита отработала, расшифровала и «починила» основную программу, и в памяти находится работоспособный образ кода этой основной программы. Фактически он ищет возможность остановить программу на так называемой OEP (Original Entry Point) — «старой» точке входа защищаемой программы. В этот момент образ в памяти можно сохранить на диск. Он, конечно, будет неработоспособен, но его можно починить, «перенастроив» Entry Point исполняемого файла так, чтобы он указывал на OEP, и, если программа в этот момент работоспособна, такой образ будет работать просто пропуская защиту (там есть еще много манипуляций с восстановлением вызовов внешних функций, многократным дампом на случай, если программа расшифровывается не полностью, и вообще, это тема для десятка статей, но главный принцип именно такой). Другим популярным способом является найти кусок кода, генерирующий серийный номер и, если это возможно, «выкусить» его, и сделать маленький исполняемый файл, генерирующий валидные серийные номера (keygen). Как мы увидим ниже, похожий образ действий не чужд и антивирусному детектору.

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

Дизассемблер и отладчик

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

Дизассемблер принимает на вход либо исполняемый файл, либо абстрактный буфер с кодом и, что довольно важно, первый адрес, с которого нужно начать дизассемблирование. В случае исполняемого файла это, например, точка входа. Поставив указатель на первую инструкцию, дизассемблер, определяет, что это за инструкция, её длину в байтах, является ли она инструкцией перехода, какие регистры использует, на какие адреса в памяти ссылается и т.п. Если инструкция не является инструкцией перехода, дизассемблер переходит к следующей инструкции, переместив указатель вперед на длину инструкции. Если это безусловный JMP или CALL, дизассемблер перемещает указатель следующей инструкции туда, куда указывает адрес перехода. Если это условный переход (JZ, JNA и т.п.) то дизассемблер помечает следующими к рассмотрению сразу два адреса — адрес следующей инструкции и адрес, на который возможен переход. Если комбинация байт не распознается, процесс дизассемблирования данной ветви останавливается. Также необходимо упомянуть о том, что дизассемблер сохраняет информацию о том, какие инструкции ссылаются на данную(!), что позволяет определять вызовы функций, и, самое главное, кто их вызывает.

Дизассемблер превращает последовательность байт в последовательность многосвязных структур, в которых хранится информация о каждом байте инструкции: является ли конкретный байт частью опкода (кода операции), данными, адресом, на который откуда-то совершается переход и т.п. Каждая структура может содержать ссылки на одну или две следующих структуры и при этом являться объектом, на который ссылается произвольное число других структур (например первая инструкция функции, которая вызывается множество раз). Также, умные дизассемблеры могут следить за указателем стека, или уметь распознавать и корректно помечать для дизассемблирования такие конструкции, как: mov eax, 0x20056789; call eax; Плюс распознавать характерные функции по набору инструкций, устанавливать начальные точки для дизассемблирования вручную, комментировать отдельные инструкции и сохранять результат дизассемблирования на диск, т.к. операция построения графа вызовов и разметки структур весьма затратна, ну а возиться с одним файлом можно днями. Но, как мы рассмотрели ранее, возможна ситуация, когда на диске в файле переход ведет на зашифрованный буфер, и дизассемблер в этом случае генерирует кашу из инструкций или останавливается. В этом случае, надо заполучить этот зашифрованный буфер прямо в runtime, когда он открыто лежит в памяти, а для этого требуется отладчик.

Основная задача отладчика — остановить программу в самом интересном месте. Для этого используется несколько способов. Можно открыть память процесса, и вместо одной из инструкций вписать int 3 — в этом случае процессор, выполняя эту инструкцию сгенерирует исключение, а отладчик обработает его, откроет свое окно, восстановит оригинальную инструкцию и покажет, что находится в этой области памяти. Можно включить в процессоре флаг трассировки, и тогда процессор будет генерировать это исключение на каждой инструкции. Наконец, у процессора есть отладочные регистры, можно поместиь в них некоторый адрес, и процессор, получив доступ к памяти по этому адресу, остановится. Так что, например, поставив breakpoint на доступ к адресу начала зашифрованного буфера мы остановимся первый раз, когда декриптор начнет расшифрование и прочитает первый байт буфера, а второй раз, когда передаст туда управление. В этот момент содержимое буфера можно записать на диск, натравить на него дизассемблер и узнать все его секреты. В продвинутых защитах вообще не существует такого момента времени, когда в памяти лежит полный рабочий код программы — части кода расшифровываются кусками по мере надобности. В этих случаях реверсеру приходится собирать dump по кускам.

Защита от исследования кода

Тема защиты исполняемого кода от исследования достойна десятка статей, поэтому в рамках рассматриваемого вопроса остановимся лишь на нескольких моментах. Статическая защита кода от исследования представляет собой различные методы запутывания исполняемого кода и шифрование буферов с важными участками кода с последующим расшифрованием в runtime. Запутывание кода можно реализовать при помощи специальных, обфусцирующих код компиляторов, а шифрование — при помощи рассматриваемых ниже полиморфных движков (к которым с точки зрения кода относятся и коммерческие защиты).

Динамическая защита подразумевает, что программа может в runtime определить отлаживают ли её и предпринять в связи с этим некоторые действия. Например, прочитав буфер с собственным кодом программа может сравнить его контрольную сумму с эталонной, и, если отладчик вставил в код int 3 (см.выше), понять что её отлаживают или каким-то другим способом модифицировали её код. Но самый, пожалуй, надежный и переносимый способ понять, что тебя отлаживают — это измерение времени исполнения характерных участков кода. Смысл простой: измеряется время (в секундах, попугаях или тактах процессора) между инструкциями в некотором буфере, и, если оно больше некоторого порогового значения — значит в середине программу останавливали. Защита, поняв, что ее отлаживают, может, к примеру, игнорировать ветви, внутри которых может остановиться реверсер и тупо не срабатывать, а вирус, удалить себя из системы. Для борьбы с такими ситуациями реверсеры работают в контролируемых средах, которые можно легко воспроизвести — например в виртуальных машинах, для которых можно воспроизвести все, вплоть до параметров BIOS. Поэтому, исследуя код вируса или защиты необходимо помнить о том, что программа вполне может обнаружить факт исследования и сделать что-нибудь нехорошее.

Полиморфные движки или «код мельчал, движок крепчал»

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

Принцип работы упаковщика довольно прост:

  1. берем буфер с исполняемым кодом (кодовую секцию, например);
  2. упаковываем её;
  3. берем позиционно независимый код распаковщика и дополняем его правильными адресами начала и конца буфера с запакованным кодом;
  4. добавляем в конец распаковщика переход на OEP (первую инструкцию распакованного кода);
  5. размещаем распаковщик и буфер со сжатым кодом в исполняемом файле (правим размеры секций и/или EP).


Получившийся файл по размеру получается намного меньше, чем оригинальный. После появления новых, крутейших винчестеров с объёмом 100Мб это стало не столь актуально, но, упаковка открыла вирмейкерам и разработчикам защит много новых возможностей:

  • размер вируса (несмотря на наш крутейший винчестер в 100Мб) все таки важен. Если payload-код жирный и многофункциональный, то весь вирус будет труднее запихать в файл, особенно если используется что-то хитрее, чем дописывание в конец файла новой секции. Использование упаковки позволит почти весь большой и сложный код вируса упаковать в буфер, который в разы меньше оригинального размера
  • буфер с упакованным кодом необязательно располагать в секции с флагом исполнения. Для продвинутых инфекторов это очень важный фактор, ведь основное тело вируса можно спокойно положить куда угодно. После распаковки распаковщик должен позаботиться, чтобы в области памяти, в которую был распакован код, было разрешено исполнение. Именно поэтому Windows API, работающие с атрибутами доступа к памяти (всякие VirtualProtect, VirtualProtectEx, VirtualOuery и VirtualQuervEx) неизменно привлекают внимание эвристиков
  • ну и на сладкое, самое важное — вместо упаковки или после неё буфер с кодом можно зашифровать, а ключ положить в распаковщик. Теперь это будет не распаковщик, а декриптор. При каждом новом инфицировании (или навешивании защиты на исполняемый файл) буфер с кодом можно зашифровать при помощи нового ключа, и тогда буфер с кодом будет иметь совершенно новое содержание (разумеется при использовании хороших алгоритмов шифрования).:w В дальнейшем я не буду писать «упакован», но предполагаю, что упаковка может быть включена в процесс шифрования.


Ну вот он, собственно, и есть — первый полиморфный движок. Распишем поподробней примерный алгоритм инфицирования:

  1. Генерируем новый ключ шифрования.
  2. Берем код декриптора (где и как — поговорим позже, в простейшем случае тупо достаем готовый код из нашего тела).
  3. Внедряем в него (в код декриптора) наш новый ключ шифрования.
  4. Внедряем в код вируса передачу управления из файла-жертвы и обратно (пока код еще не зашифрован).
  5. Зашифровываем новым ключом наш большой буфер с кодом.
  6. Бесхитростно укладываем зашифрованный буфер в файл-жертву (он существенно отличается от предыдущего, поэтому можно особо не прятаться).
  7. Добавляем переход на начало зашифрованного буфера в конец декриптора.
  8. Хитро (насколько это возможно) укладываем декриптор в файл-жертву.


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

Такое упрощение задачи послужило причиной появления более продвинутых полиморфных движков, которые при заражении изменяют только код декриптора — ведь разобраться с небольшим куском кода гораздо проще, чем со всем payload-кодом. Радостные вирмейкеры и разработчики защит потирают руки и изучают способы спрятать маленький декриптор похитрее, а аверы и крэкеры чинят дизассемблеры, у которых после попыток дизассемблировать рандомные строки байт, на которые в коде присутствует JMP, едет крыша.

Эволюция вирусных движков

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

NOP зоны или «авось пронесёт»

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

addr1:  nop

               nop

               ;...                           еще очень много NOP-ов

               nop

 

addr2: jmp    addr3;          shellcode

               pop esi;                       shellcode

               xor edx,edx            shellcode

               ;...


Теперь можно сделать переход «куда-то туда», в NOP-зону. Если известно только приблизительное расположение в памяти, этот прием позволяет успешно выполнить shellcode.

Так же беcхитростно можно поступить и с декриптором, просто при инфицировании помещаем его в разные места длинной NOP-строки. А кое-где (там, где это не разломает переходы) можно напихать этих NOP-ов прямо в код. В этом случае все будет корректно работать, но смещения характерной сигнатуры всегда будут разные. Разумеется смещения для инструкций переходов придется пересчитывать.
Слишком халявное решение не сильно напрягло авера, который просто добавил в базу признак «пропусти все NOP-ы при подсчете сигнатуры», но этот маленький шаг весьма примечателен тем, что впервые детектор начал рассматривать инструкции, а не байты. Но об этом позже.

Пермутация или «сложи как нибудь»

Размышляя, как бы дискредитировать сравнение по сигнатуре, не разломав код декриптора, вирмейкер приходит к идее пермутации. Пермутация — это перестановка блоков кода в каждом новом поколении. Код состоит из некоторого количества блоков, эти блоки переставляются местами в каждом новом поколении вируса, и связываются JMP-ами. Как всегда, на бумаге всё просто, а проблемы начинаются в реализации. Внутри блоков есть условные и безусловные переходы и вызовы функций, поэтому такие, логические блоки должны оставаться целыми. При этом, чем толще блоки, тем меньше вариативность получившегося декриптора, а чем меньше размер блока, тем больше приходится добавлять переходов, раздувая код декриптора, и тем сложнее соблюсти целостность. Для выравнивания блоков по длине можно, например, использовать NOP-зоны.

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

 

[block 1]

[block 2]

[block 3]

[...]

[block N]

[jmp block 1]

[block 2]
[jmp block 3]

[block 1]
[jmp block2]

[block 3]
[jmp block 4]

[...]

[block 4]
[jmp block 5]

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

Теперь в антивирусной базе лежит следующее указание: начиная с точки входа шагай по инструкциям, совершая переходы соответственно встреченным JMP-ам, и, пройдя N инструкций, сравни сигнатуру. Если сигнатура находится в десятом блоке, придется пройти до десятого перехода, если внутри возможны условные переходы (JZ), то их условно можно считать двумя переходами — на следующую инструкцию и на адрес перехода, и, соответственно, разветвлять проход по инструкциям. Разумеется, никто не отменял и детектирование попроще, например если блоки у вируса фиксированной длины L и их N штук, можно просто провести N сравнений по сигнатуре по смещениям [0, (1 * L), (2 * L), ..., ((N-1) * L)].

Оценим трудоёмкость процесса поиска с использованием дизассемблера. Дизассемблер минимально должен обеспечивать определение длины инструкции и преобразование VA (Vitual Address) to RVA (Relative Virtual Address) (адрес, указанный в JMP в смещение в файле). Определение длины инструкции — это в принципе достаточно быстрый алгоритм (обращение к элементу массива и вычисление следующего шага на основе флагов, записанных в соотв. элементе массива), а преобразование адреса это пара элементарных операций сложения адресов, на основе информации о том, какой секции принадлежит адрес. Плюс немного ума для определения дешевых трюков для замены банального JMP next_block_address, таких, например, как:

        XOR eax,eax;

        JZ next_block_address;

 

        ; или

        PUSH next_block_address;

        RET;

 

        ; или

        MOV eax, next_block_address;

        CALL eax;


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

Как это водится, если что-то, что включили, а оно тормозит, надо либо оптимизировать это, либо постараться не включать это без необходимости. Первый способ, увы, не катит — в простом дизассемблере много не наоптимизируешь, поэтому авер переходит к любимому месту всех антивирусов — эвристическому анализатору.

Эвристический анализатор или «вскрытие покажет»

В первой статье мы уже коснулись эвристического анализа — действительно, существуют признаки, которые с разной степенью достоверности могут говорить, что в файл был инжектирован код. И тогда, авер действительно выделил некоторые из них, которые были подозрительными, но никак не тянули на право заявлять о 100% факте зараженности файла. Тогда он их просто закомментировал, т.к. потратил на них немало времени и удалять их совсем было жаль. Теперь на их основе можно принять решение — запускать ли более тяжелый, использующий дизассемблирование, анализ файла, или нет.

Есть и еще одна проблема — т.к. эвристик реагирует на всё подозрительное, коммерческие защиты вызывают у него неподдельный интерес, поэтому аверу пришлось завести в базе сигнатур еще пару сотен «белых» под популярные навесные защиты — их трогать нельзя. Именно благодаря им мы все таки можем нормально запускать различные коммерческие софтины. А при написании собственного софта, использующего методы работы с исполняемым кодом, неплохо бы перед релизом прогнать все файлы своей программы на всех популярных антивирусах где нибудь на virustotal. За непопулярные можно сильно не волноваться, эвристический анализатор трудно утащить так же просто, как базы сигнатур и вряд ли анализатор малопопулярного антивируса будет так же крут, как то, который разрабатывался долгие годы.
Стоит, конечно упомянуть и о попытках вирмейкера замаскировать свой вирус под популярную защиту. Для этого, нужна собственно сигнатура, и он начинает разбирать антивирусную базу, чтобы понять, куда бы положить нужные байты, чтобы антивирус принял его вирус за защиту. Да и вообще, изготавливая следующую версию вируса, неплохо бы ознакомиться с кодом, который детектирует текущую. Так что антивирусные базы тоже являются объектами реверс-инжиниринга, а код детектора также подвергается анализу со стороны вирмейкеров.
Но вернёмся к нашему эвристическому анализатору, приведём несколько эвристических признаков:

  • Точка входа в секции открытой для записи(rwx). Открытая для записи, исполняемая секция, в которую сразу передается управление, с большой вероятностью свидетельствует о наличии самомодифицирующегося кода, такие секции используются в подавляющем большинстве случаев вирусами и программными защитами.
  • Инструкция перехода в точке входа. Особого смысла в размещении инструкции перехода в точке входа нет и такой признак указывает на наличие самомодифицирующегося кода в файле.
  • Точка входа во второй половине секции. Вирусы, использующие расширение секции, в большинстве случаев располагаются в конце секции. Это нетипично для нормальных файлов, поэтому такая ситуация является подозрительной.
  • Поломки в заголовке. Некоторые модификации заголовка после инфицирования оставляют файл работоспособным, но сам заголовок при этом содержит ошибки, которые линкер бы не допустил. Это тоже подозрительно.
  • Нестандартный формат некоторых служебных секций. В исполняемых файлах есть служебные секции, такие как, например, .ctors, .dtors, .fini и т.п. Особенности этих секций могут использоваться вирусами для заражения файла. Нарушение формата такой секции также является подозрительным.
  • … и еще сотня таких признаков


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

Когда эвристические признаки говорят, что «файл 100% заражен», но тяжелый анализ ничего не нашел, антивирус пишет, что файл заражен вирусом с названием типа: «Generic Win32.Virus», или по-нашенски «Какой-то Win32 Вирус». Такие сообщения часто можно встретить на всяких кейгенах, лоадерах и т.п. В прошлой статье я уже говорил, что именно по этой причине в инструкциях по установке пиратского софта пишут «перед установкой отключите антивирус». Также я еще раз хочу обратить внимание на один из важнейших информационных активов антивирусных компаний — коллекцию исполняемых файлов достаточного объёма, чтобы на ней можно было бы тестировать анализатор, не боясь выпустить в мир версию, которая будет кидаться на легитимные файлы, которые туда обязательно добавляются. Обиженные кейгены и лоадеры наверняка возмущаются, что их туда не добавляют оперативно, но кто ж их, вирусню, слушает…

Итак, поработав над эвристиком авер приходит к следующему общему алгоритму детектирования:

  1. Проверить файл обычным сигнатурным поиском.
  2. Если успешно — считать файл заражённым.
  3. Если найдена «белая» защита — выйти молча.
  4. Проверить файл эвристическим анализатором.
  5. Если не найдено ни одного признака — выйти.
  6. Если найдены признаки достаточного веса, запустить анализ, использующий дизассемблирование.


При этом, если эвристические признаки достаточно серьёзны, чтобы говорить о заражении, считать файл зараженным вне зависимости от того, нашел анализатор что-либо, или нет.

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

Категория: Вирусы, банеры | Добавил: masterov (13.09.2016) E W
Просмотров: 334 | Теги: тело вируса, классификации, вирус, ложный вирус | Рейтинг: 0.0/0
Всего комментариев: 0
Добавлять комментарии могут только зарегистрированные пользователи.
[ Регистрация | Вход ]