За 35 лет работы с программным обеспечением я наблюдал смену поколений антивирусов, эволюцию подходов к обнаружению угроз и бесконечный цикл гонки между авторами вредоносного ПО и разработчиками средств защиты. Однако сама суть проблемы осталась неизменной.
Появляется новый вредоносный файл. Его обнаруживают, анализируют, классифицируют, добавляют в базы или модели обнаружения. Затем появляется модификация, обходящая существующие правила, — и цикл повторяется.
Мне давно было интересно другое: что, если строить детект не вокруг вопроса «знаем ли мы этот файл?», а вокруг вопроса «насколько поведение и структура этого файла характерны для вредоносной программы?»
Так появился экспериментальный проект HAV — Heuristic AntiVirus. Это не коммерческий продукт и не попытка заменить существующие решения. Это исследовательский эксперимент, цель которого — проверить, насколько далеко можно продвинуться в обнаружении вредоносного ПО с помощью статического и динамического анализа, статистики и эвристических моделей. Репозиторий проекта опубликован в открытом доступе.
Классический сигнатурный подход эффективен против уже известных угроз: известен образец или семейство — можно описать его сигнатурой или правилом. Это быстро, надёжно и дёшево. Но у этого подхода есть фундаментальное ограничение: сначала должен появиться признак, который кто‑то успел описать. Для нового образца такой информации может не быть.
Современные антивирусные продукты, разумеется, не ограничиваются сигнатурами — они используют репутационные системы, песочницы, поведенческий анализ, машинное обучение и эмуляцию. Однако меня интересовал более узкий вопрос: какого качества можно добиться, если сделать основной акцент именно на анализе структуры и поведения, а сигнатурную часть оставить вспомогательной? Это вполне проверяемая инженерная гипотеза.
Цели и требования к сканеру
На начальном этапе я сформулировал несколько ключевых требований к экспериментальному сканеру.
Сканер должен минимально зависеть от постоянно обновляемых сигнатур, работать локально без облачной инфраструктуры, иметь компактную базу и низкое потребление ресурсов. Ключевые задачи — анализ неизвестных образцов, минимизация ложных срабатываний и простая архитектура.
Последний пункт для меня особенно важен.
Средство защиты не должно мешать пользователю работать. Если антивирус блокирует легитимные файлы, потребляет значительную часть ресурсов или постоянно требует внимания — пользователь рано или поздно начнёт искать способ отключить защиту. А это сводит на нет весь смысл её существования.
Как устроен HAV
Статический анализ
Файл рассматривается как структурированный объект, а не просто последовательность байтов.
В зависимости от формата анализируются структура исполняемого файла, его секции, размеры и распределение данных, импортируемые и экспортируемые функции, строки, особенности размещения кода и данных, признаки упаковки и обфускации, энтропия, распределение байтов, вотермарки, манифесты, тагганты, формы, ресурсы, GUIDs, сертификаты и статистические характеристики.
Набор признаков варьируется в зависимости от типа файла. Само по себе наличие одного подозрительного признака ещё ничего не означает.
Например, высокая энтропия может быть совершенно нормальной для сжатых данных. Энтропия сама по себе не является детектором вредоносного ПО. Однако участки с высокой энтропией могут указывать на сжатие, шифрование или упаковку — методы, которые вредоносные программы часто используют для сокрытия содержимого. Поэтому энтропийные метрики используются в HAV не как самостоятельный детектор, а как корректирующий коэффициент для других слоёв анализа, усиливающий или ослабляющий их вес в зависимости от контекста.
Необычная структура может встречаться и в легитимном программном обеспечении. Наличие определённого API само по себе не делает программу вредоносной.
Поэтому HAV не использует принцип «признак найден → файл вредоносный». Вместо этого применяется совокупная оценка. В среднем в решении участвует около трёх признаков. Многолетний опыт позволил выделить наиболее характерные из них — настолько, что в ряде случаев даже совокупная оценка оказывается избыточной.
Статистический анализ
Для анализа байтовых последовательностей применяются распределения, N‑граммы, частотные и другие статистические характеристики.
Идея достаточно проста. Если рассматривать большие коллекции файлов, у различных классов программ обнаруживаются статистические закономерности. Задача модели — не найти конкретную последовательность, соответствующую конкретному вирусу, а определить, насколько исследуемый объект похож на известные классы вредоносного ПО. Главное — выделить опорные признаки.
В результате формируется своего рода «статистический отпечаток» файла.
Лингвистический анализ
Отдельное направление — анализ строк и текстовых последовательностей.
В фокусе внимания — API‑вызовы, командные строки, имена файлов, URL, параметры запуска, характерные последовательности, признаки обфускации и распределение символов.
При этом интерес представляет не только конкретная строка, но и её контекст. В дальнейшем акцент на лингвистическом анализе будет усилен — потенциал этого направления значителен.
Почему используется весовая модель
Одна из самых распространённых проблем эвристического обнаружения — чрезмерная агрессивность. Можно легко сделать антивирус, который обнаруживает почти всё подозрительное. Но вместе с вредоносными программами он начнёт блокировать и огромное количество легитимного ПО.
Поэтому HAV использует систему весов. Условно: A → +2, B → +5, C → +1, D → –3.
При этом признаки не рассматриваются изолированно. Некоторые комбинации существенно повышают вероятность вредоносности, тогда как наличие других характеристик, наоборот, её снижает.
Именно совокупность признаков формирует итоговый вердикт. Это позволяет отказаться от логики «если есть X — удаляем» в пользу подхода «насколько совокупность наблюдаемых характеристик соответствует вредоносному поведению?».
Сканер построен как многослойная эвристическая модель. Каждый слой анализирует файл с определённой точки зрения.
Важно: точное количество слоёв и их коэффициенты являются ноу‑хау и не раскрываются. Это позволяет сохранить уникальность подхода и не давать злоумышленникам готовых ориентиров для адаптации.
Динамический анализ
Статический анализ имеет очевидное ограничение: код может быть намеренно скрыт. Упаковка, обфускация, динамическое получение адресов функций и другие техники существенно усложняют анализ.
Поэтому в HAV используется также динамический анализ. Код исполняется в контролируемой среде с помощью эмуляции (для исполняемых файлов) и интерпретации (для скриптов). Это позволяет наблюдать не только то, что содержится в файле, но и то, что он пытается делать. Особый интерес представляют программы, которые выглядят относительно безобидно при статическом анализе.
Аномалии системных вызовов и цепочек событий
Вместо поиска сигнатур я анализирую поведение файла в момент выполнения — прежде всего на уровне системных вызовов и их последовательностей. Многие наблюдаемые действия получают статус именованных событий и учитываются в цепочках.
Почему это работает:
Системные вызовы — это язык, на котором программа общается с ОС. Их нельзя имитировать или скрыть, не нарушив логику работы.
Даже если файл упакован ENIGMA, THEMIDA или VMProtect, паттерн вызовов остаётся стабильным.
Чистое ПО демонстрирует иные паттерны вызовов, чем вредоносное. HAV научился их различать.
Поддерживаемые форматы
Эмулятор работает не только с исполняемыми файлами Windows:
Формат | Метод | Особенность |
PE 32/64-bit | Эмуляция системных вызовов | 64-битный код эмулируется в 32-битной среде через адаптеры вызовов |
ELF (Linux) | Статический анализ («скелет признаков») | Отдельный конфиг |
VB | Эмуляция native‑кода | Отдельный конфиг |
DOTNET | Эмуляция IL‑кода | Отдельный конфиг |
Такой подход позволяет охватить все актуальные платформы, используя единую логику принятия решений и общую базу реализаций API. ARM и Android остались за рамками проекта — ограничение по времени и ресурсам.
Особенности эмуляции: совместимость и сложные протекторы
Из‑за большого количества версий Windows и критических изменений, влияющих на совместимость ПО, при эмуляции я вынужден поддерживать некую усреднённую Windows. Такой подход обеспечивает максимальную воспроизводимость результата, хотя и несколько снижает результативность.
Сложные протекторы: THEMIDA, MoleBox и другие
На файлах, упакованных THEMIDA, эмулятору приходится воспроизводить многозадачность внутри виртуальной машины протектора — и всё это в одном потоке. Время обработки таких образцов — 3–5 минут, что приемлемо, учитывая сложность защиты.
Файлы, упакованные MoleBox, требуют обработки гигантского числа системных вызовов (до 40 млн). Эмулятор справляется с этим за минуты, возвращая полностью распакованный файл для дальнейшего анализа.
Большинство коммерческих решений на таких образцах либо зависают, либо дают ложное срабатывание.
Сигнатуры‑ловушки: для 20% сложных случаев
Эвристика и эмуляция покрывают 70–80% всех случаев. Для оставшихся 20%, которые не поддаются этим методам, используется точечный механизм: генерируется универсальная сигнатура. Такие сигнатуры не устаревают в ближайшее тысячелетие — их невозможно обойти, не сломав функциональность файла.
Их на порядки меньше, чем в классических AV, поэтому база остаётся компактной (60 МБ) и требует гораздо более редких обновлений (поддерживается 1–2 аналитиками).
Ограничения
Динамический анализ не следует считать универсальным решением, поскольку любая эмуляция имеет ограничения. Вредоносное ПО может определять среду исполнения, изменять поведение при обнаружении эмуляции, использовать временные задержки, проверять наличие неучтённых компонентов или выполнять вредоносную часть только при выполнении конкретных условий.
Сканер не обещает «100% защиты» — это был бы маркетинг. Я честно говорю, что некоторые типы файлов могут требовать доработки модели, экспериментальный статус означает, что проект продолжает развиваться, а HAV готов к тестированию на реальных данных и ждёт обратной связи.
Почему я не хочу делать ставку на огромную базу
Большая база сигнатур — вполне рабочий инструмент. Но у неё есть цена. Её необходимо: создавать; проверять; обновлять; распространять; хранить; тестировать на конфликты; поддерживать в актуальном состоянии.
HAV смещает центр тяжести с базы известных образцов на модели и статистические признаки. Это позволяет сохранять компактность и независимость от постоянного обновления, не жертвуя качеством обнаружения.
В текущей экспериментальной версии база занимает порядка десятков мегабайт, и все решения принимаются локально.
Это не означает, что сигнатуры больше не нужны. Они остаются полезным дополнением там, где точное знание образца позволяет принять однозначное решение.
Но насколько маленькой может быть эта часть системы? Многократные еженедельные проверки на весьма представительной выборке вирусных файлов пока не требовали значительного роста числа записей. Во внутренние тесты включены практически все коллекционные файлы из MalwareBazaar, VirusShare и VirusSign. Более того: с совершенствованием эвристики многие записи в текущей базе становятся избыточными. При необходимости база может быть уменьшена до 40–50 МБ.
HAV может работать с произвольным количеством файлов баз — порядок их загрузки и последовательность записей внутри не имеют значения.
Важно: в HAV есть ноу‑хау, которые могут стать предметом промышленного шпионажа, а их понимание может облегчить жизнь злоумышленникам. В частности, это защита от ARC‑бомб, уверенный детект упакованных файлов с привязкой к классификации без их распаковки, и другие. Поэтому часть технологий остаётся за ширмой.
Ложные срабатывания
На текущий момент результаты обнадёживают. HAV постоянно проверяется на крупной подборке чистого ПО — в общей сложности 15 ТБ. В неё входят сотни тысяч контейнеров и десятки миллионов файлов: практически все версии Windows и программ Microsoft, около 30 популярных сборок Linux, практически полное содержимое софтверных сайтов SourceForge, APKPure, SoftPortal, ComSS, репозиториев Nuget и NPM (из последнего — только JS‑скрипты, около 12 млн). Появление новых версий популярного ПО по возможности отслеживается.
На всей этой массе файлов ложные срабатывания были — это естественная зависимость: чем выше детект, тем больше фолсов. Однако в процентном отношении они составляют 0.01–0.1% (около 3000–4000 случаев), на скриптах — 0.001–0.01%. Все эти случаи известны, персонально разобраны и заблокированы индивидуальными записями. Это количество качественно ниже среднего по индустрии.
Диагностический потенциал
Поскольку HAV отслеживает аномалии на уровне системных вызовов, его можно рассматривать и как диагностическое средство. Даже ложное срабатывание — это сигнал: программа, вероятно, содержит ошибку в коде. Ошибку, которую не замечают компиляторы, не находят статические анализаторы вроде PVS Studio или Clang Static Analyzer, и уж тем более не замечает «облачный ИИ».
Эмулятор HAV видит, как код ведёт себя в динамике. Он фиксирует аномалии, которые не прослеживаются в исходном тексте. Он обнаруживает участки, которые «пахнут» подозрительно. В современном ПО — особенно в огромных ООП‑программах с многотысячными иерархиями наследования, абстракциями и зависимостями — такие аномалии встречаются гораздо чаще, чем можно предположить: мной зафиксировано около 100 случаев очевидно некорректного кода.
Больших надежд на этот побочный эффект я не возлагаю, но если заострить на нём внимание...
Классификация: known и risky
В HAV два основных вердикта: known и risky. Они отражают разные уровни уверенности и разные подходы к анализу.
known — это подтверждённая аномалия. Срабатывание происходит по точному структурному паттерну, который уже был проверен на чистой коллекции и доказал свою эффективность. Если HAV говорит known, значит, файл либо точно вредоносный, либо содержит известную аномалию, которую система научилась распознавать. Это не сигнатура — это не MD5, не SHA, не имя файла. Это почерк, который остаётся стабильным, даже если зловред меняет обёртки.
risky — это взвешенное подозрение. Здесь нет точного паттерна, но совокупность признаков (энтропия, системные вызовы, структура, поведение) превышает порог. Файл не подходит ни под один known‑паттерн, но ведёт себя как минимум необычно. Это рискованная зона, где HAV не говорит «точно вредоносный», но говорит «с этим лучше разобраться».
Что получилось
На текущем этапе проект показывает обнадёживающие результаты на внутренних наборах данных. Уровень обнаружения составляет около 99,5% на указанных выше коллекциях, включая свежие файлы вплоть до сегодняшнего дня.
Однако здесь необходимо сделать оговорку. Эта цифра не является доказательством того, что HAV обнаруживает 99,5% всего существующего вредоносного ПО.
Результат может зависеть от состава тестового набора, распределения семейств, способа формирования выборки, временного разрыва между обучением и тестированием и множества других факторов. Например, на Malware Bazaar бывают дни, когда преобладают APK, дни скриптов, дни ELF и так далее.
К сожалению, у меня нет полноценного доступа к такой огромной коллекции образцов, как VirusTotal, что тоже влияет на объективность оценки.
Поэтому я считаю гораздо более интересным не сам процент, а возможность построить воспроизводимый независимый бенчмарк. Именно это направление сейчас представляет для проекта наибольший интерес.
Высокая чувствительность сама по себе не является достаточным критерием качества. Нужно одновременно смотреть как минимум на две величины: TPR (True Positive Rate) — долю обнаруженных вредоносных образцов; FPR (False Positive Rate) — долю ошибочно классифицированных чистых файлов.
Именно их баланс заслуживает внимания в первую очередь.
Матрица ошибок
Корректная оценка должна выглядеть примерно так:
Фактически Malware | Фактически Clean | |
HAV: Malware | TP (True Positive) | FP (False Positive) |
HAV: Clean | FN (False Negative) | TN (True Negative) |
Из этой матрицы можно получить detection rate, false positive rate, precision, recall, F1, ROC/PR‑кривые и результаты по отдельным семействам.
Именно такие измерения гораздо информативнее рекламной (хотя и подтверждённой на наших тестовых наборах) цифры «99,5%». В дальнейшем я хотел бы публиковать результаты именно в таком формате.
Можно ли вообще обойтись без постоянных обновлений?
Вот здесь самое интересное.
Теоретически хочется построить модель, которая будет хорошо работать без постоянной подпитки новыми сигнатурами. Практически это очень сложная задача.
Вредоносное ПО тоже эволюционирует. Если защитник научился обнаруживать определённый набор признаков, атакующий получает стимул изменить программу так, чтобы сохранить вредоносную функциональность, но изменить наблюдаемые признаки.
Поэтому утверждать, что антивирусу больше никогда не понадобятся обновления, было бы неправильно.
Цель эксперимента скромнее: проверить, насколько можно увеличить срок жизни модели между обновлениями, сохраняя приемлемые показатели обнаружения.
Если окажется, что обновлять её достаточно раз в месяц — это интересно. Если окажется, что требуется раз в неделю — тоже полезный результат. Если выяснится, что без постоянного обновления модель быстро деградирует — это тоже результат. Но я нацелен в конечном итоге на годовой срок — поскольку знаю что, знаю как. В дефиците только время.
Почему я вообще решил заниматься этим самостоятельно
Антивирус — очень сложная система. В промышленном продукте есть драйверы, сервисы, облачные компоненты, песочницы, базы, системы телеметрии, обновления и множество других подсистем. Для коммерческого продукта всё это приемлемо.
Но иногда полезно сделать шаг назад и спросить: а какая минимальная система вообще способна решить задачу? Не обязательно сразу строить промышленный комбайн. Можно начать с небольшой программы и проверить одну конкретную гипотезу.
Приглашение к сотрудничеству
Мне было бы интересно обсудить, может ли этот проект найти применение в ваших исследовательских целях или быть полезным как независимый инструмент.
Особенно интересны люди, которые захотят не просто написать «работает/не работает», а попытаться его сломать, опровергнуть мои доводы. Если вы занимаетесь malware research, reverse engineering, машинным обучением, анализом бинарных файлов или просто любите устраивать программам неприятные тесты — это именно тот случай, когда критика полезнее похвалы.
Интересны: независимое тестирование; новые наборы образцов; поиск false positive; поиск false negative; adversarial‑тестирование; сравнение с другими подходами; анализ алгоритмов; предложения по улучшению модели.
Заключение
Я не думаю, что сигнатурный подход умер. HAV тоже умеет работать с сигнатурами. Нет проблемы полностью автоматически, без участия человека, сгенерировать базу записей по имеющимся детектам — вопрос конфликтности давно снят. Но её размер составит 500 Мбайт. Хотя объём баз нисколько не влияет на скорость проверки, зачем тогда я всё это писал?
Я не думаю, что машинное обучение решит проблему вредоносного ПО. Не думаю, что один небольшой проект сможет заменить все системы, над которыми десятилетиями работали огромные команды.
Но я уверен в другом. Иногда полезно попробовать сделать всё максимально просто. Не строить ещё одну огромную инфраструктуру.
А задать более простой вопрос: что общего есть у вредоносных программ как у класса объектов? Если ответ на этот вопрос существует, можно ли его превратить в алгоритм?
HAV — одна из таких попыток. И я очень доволен её результатами. Но пока это эксперимент. И именно поэтому я делаю его публичным. Не чтобы объявить победу над антивирусной индустрией. А чтобы проверить, насколько далеко можно зайти, если начать с другой стороны.
35 лет спустя рукава — самое время наконец попробовать.
Остаются вопросы
Конечно, остаются нерешёнными и несогласованными множество этических аспектов и нюансов. В следующей версии они должны быть проработаны. Например: как лучше поступать с нерабочими программами, выполнение которых привязано к датам, имени файла, параметрам командной строки, версии или специфике ОС, времени триальной защиты; как быть с откровенно «битыми» файлами, которых в вирусных коллекциях изрядное количество; стоит ли принципиально различать adware и malware? (На мой взгляд, реклама — хуже вирусов.)
Статус проекта
Исходные материалы проекта опубликованы на GitHub. Проект распространяется бесплатно. В публичной версии отключено удаление вредоносных файлов (во избежание), оставлено только информирование.
https://github.com/evgenvasiliev62-code/hav
https://github.com/evgenvasiliev62-code/hav/releases/download/hav/hav01.zip

