СlamAv изнутри

Читать исходники больших проектов можно как хорошие книги, особенно если код написан со знанием дела. СlamAv это особый случай, куда приятнее дебажить исходники чем распакованный дамп закрытого av.

Собираем ClamWin

  • качаем исходники
  • качаем базы
  • открываем “\contrib\msvc\clamav.sln
  • выбираем Debug-сборку и пробуем собрать

При старте отладки, управление получит clamscan, можно задать параметры сканирования через командную строку в свойствах проекта.

Мне было интереснее найти найти точку входа в сканер и написать код для нативного запуска. Подсмотрев экспорт собранной библиотеки, видим интересное имя “CWScanFile_W”, сделаем врезку в DllMain проекта libclamav:

Кроме того, давайте включим отладочные сообщение в консоль:

Теперь мы можем поставить бряк на cli_scanpe и рассмотреть старый сканер:

clamav debug

Дебажим clamav

Очень длинная функция cli_scanpe, включает в себя скан хидеров и сигнатуры. Это явно пережиток старых версий. Обратите внимание: x64 не поддерживается, а входная структура имеет параметр time_limit! Описывать весь проект не хватит сил, так что ставьте бряк на интересных вам функциях, будь то FSG unpacker или PDF parser =)

Новый тип сигнатур

О старом формате сигнатур мы писали ранее, в современной версии появились байткод-сигнатуры! Многие антивирусы и раньше получали в обновлениях куски исполнимого кода. Однако у clamav все несколько иначе, он использует LLVM-байткод!

На сам байткод можно посмотреть распаковав "bytecode.cvd"

На сам байткод можно посмотреть распаковав “bytecode.cvd”

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

\examples\in\pdf.c

\examples\in\pdf.c

Насколько я понял, байткод можно исполнять как в режиме интерпретации виртуальной машиной, так и в JIT. Разрабы уверяют, что побег из под виртуальной машины невозможен, так как прямого доступа к памяти нет. Всё что доступно байткоду – это внушительный набор API, описанных в документации:

Функция write намекает на вероятность побега

Функция write намекает на вероятность побега

Байткод может иметь функцию logical_trigger, проверяющую нужно ли исполнять эту сигнатуру.

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

Сравните с AvHeur, который до сих пор не сменил формат базы и ключ шифрования:

avira

Длинный и плохо оптимизированный список эвристик

Продвинутый и универсальный обход

Физически невозможно прогнать тысячи созданных автоматикой сигнатур при проверке конкретного файла. Они разбиваются на группы с общими внешними признаками:

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

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