You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
209 lines
8.9 KiB
209 lines
8.9 KiB
ТЕХНИЧЕСКОЕ ЗАДАНИЕ
|
|
АВТОМАТИЧЕСКИЙ ПОИСК АНТИВИРУСНЫХ ДЕТЕКТОВ В ИСХОДНОМ КОДЕ
|
|
|
|
|
|
ЦЕЛЬ
|
|
|
|
Уменьшить время чистки от антивирусных детектов путем автоматизации процесса.
|
|
|
|
ИДЕЯ
|
|
|
|
Обычный алгоритм чистки следующий:
|
|
Этап 1
|
|
1 берем проект, который нужно почистить
|
|
2 комментируем вообще все функции и глобальные переменные
|
|
3 делаем сборку в боевом профиле
|
|
4 получившийся бинарник заливаем на dyncheck и проверяем
|
|
5 если число детектов меньше заданного порога, гото этап 2, иначе
|
|
6 раскомментируем одну функцию (согласно графу зависимостей)
|
|
7 гото 3
|
|
|
|
Этап 2
|
|
для каждой найденной функции с детектами, отсекаем #ifdef'ом части функции по тому же принципу,
|
|
до тех пор пока не дойдем до одной строчки либо блока кода.
|
|
|
|
Есть оптимизация на шаге 6 - можно раскомментировать сразу несколько функций, оптимистично полагая что детект не здесь)
|
|
|
|
Если запилить программу, которая умеет разобрать исходники, построить граф зависимостей функций, и вставлять #ifdef FUNCTION1_NEVER .. #endif
|
|
в теле этих функций, то процесс можно автоматизировать.
|
|
|
|
РЕАЛИЗАЦИЯ
|
|
|
|
Программа должна быть оформлена как консольная утилита и написана на C++.
|
|
По возможности обеспечить кросс-платформенность.
|
|
Интерфейс пользователя - ключи командной строки (getopt) и вывод на stdout/stderr.
|
|
|
|
Нужно реализовать описанный выше алгоритм со следующими граничными условиями:
|
|
* поддержка проектов Visual Studio начиная с 2010, включает в себя:
|
|
- задание профиля сборки (Release/x64)
|
|
- запуск компиляции на каждой итерации и поиск собранного файла там, где сказано в файле проекта
|
|
* точка расширения на функции антивирусной проверки (используемой на шаге 5)
|
|
- принцип плагина - должна быть функция bool avcheck(const char* path), которую легко заменить для разных инструментов проверки -
|
|
как для локальных антивирусов, так и для интеграции с онлайн-сервисами
|
|
* анализ кода должен исключать заведомо сложные случаи, такие как
|
|
- template<>
|
|
- рекурсию в библиотечные исходники, включая CRT/STL/WinAPI
|
|
- все что усложняет реализацию, должно быть оговорено и упрощено.
|
|
Проще привести код к удобному для анализа виду, чем усложнять анализатор.
|
|
* объяснение на stdout что происходит:
|
|
Этап 1
|
|
итерация 1, закомментировано 1801 функция, число детектов 0
|
|
итерация 2, закомментировано 900 функция, число детектов 18
|
|
..
|
|
итерация 100, закомментировано 50 функций, число детектов 0
|
|
|
|
Этап 2
|
|
Функция foo(), убраны строки 100..200, число детектов 0
|
|
Функция foo(), убраны строки 190..200, число детектов 0
|
|
Функция foo(), убраны строки 195..200, число детектов 18
|
|
|
|
Детекты найдены в функциях:
|
|
foo(): 195..200
|
|
bar(): 400..402
|
|
dumb(): 151..152
|
|
|
|
Можно переделать готовые подходящие анализаторы кода - сейчас много статических анализаторов с готовым модулем синтаксического разбора.
|
|
|
|
|
|
РЕАЛИЗАЦИЯ, ВАРИАНТ №2, УПРОЩЕННЫЙ
|
|
|
|
Делаем то же самое без разбора исходного кода, путем анализа карты функций компоновщика (параметр /MAP компоновщика):
|
|
- заказываем у компоновщика карту бинарника ключом /map
|
|
- парсим выходную карту, находим границы функций
|
|
- зануляем функции ПРЯМО В БИНАРНИКЕ
|
|
Так можно избежать парсинга исходников на этапе 1 (на этапе 2 к сожалению не получится)
|
|
Но и реализация хотя бы в объеме этапа 1 очень сильно облегчила бы жизнь.
|
|
|
|
|
|
Т.к. в карте появляется слишком много левых символов, которые вовсе не требуют анализа (функции из CRT, всякая служебная мелочь),
|
|
то нужны дополнительные инструменты в интерфейсе программы:
|
|
- маски для исключения символов (черный список)
|
|
- маски списка проверки объектных файлов (.obj) (белый список)
|
|
- маски списка проверки символов
|
|
Также мелкие символы можно отсечь по размеру (см.ниже алгоритм)
|
|
|
|
Есть похожая реализация
|
|
https://github.com/vxlabinfo/SignFinder
|
|
основана на статьях
|
|
https://vxlab.info/%d1%87%d0%b8%d1%81%d1%82%d0%ba%d0%b0-pe32-%d1%87%d0%b0%d1%81%d1%82%d1%8c-1/
|
|
https://vxlab.info/%d1%87%d0%b8%d1%81%d1%82%d0%ba%d0%b0-pe32-%d1%87%d0%b0%d1%81%d1%82%d1%8c-2/
|
|
сайт уже протух, но остались копии, например здесь
|
|
https://ru-sfera.org/threads/chistka-ot-signaturnogo-detekta-antivirusov.2870/
|
|
|
|
Оттуда можно взять эвристики проверок отдельных секций, заголовков и импорта.
|
|
|
|
|
|
АЛГОРИТМ ПРОВЕРКИ
|
|
|
|
На входе алгоритма - нераскрашенный список символов (функций и глобальных данных).
|
|
На выходе алгоритма - раскрашенный список символов, так что каждому символу присвоен цвет - белый или черный.
|
|
Цель алгоритма - раскрасить все функции за минимальное число шагов.
|
|
|
|
Алгоритм:
|
|
1. Первый проход по списку: помечаем как "белые" все символы по списку исключения/не содержащиеся в списках проверки
|
|
2. Сортируем список по занимаемому в памяти размеру символа
|
|
3. Символы с размером ниже некоторого порога (настройка или эвристически определяемого значение) сразу можно раскрасить "белым"
|
|
|
|
На этом шаге следует занулить все нераскрашенные символы и сделать АВ-проверку.
|
|
Если проверка даст детект, выводим предупреждение что в бинарном файле есть детекты на самой первой итерации и завершаем работу.
|
|
Иначе, разнуляем все нераскрашенные символы.
|
|
|
|
Далее в алгоритме необходимо помнить состояние:
|
|
- список текущих проверяемых символов ("текущий список")
|
|
- список раскрашенных символов.
|
|
До конца работы алгоритма:
|
|
- Белые символы должны быть разнулены
|
|
- Черные символы должны быть занулены
|
|
|
|
4. Делаем отбор в текущий список: половина (50%) нераскрашенных символов файла
|
|
5. Разнуляем не раскрашенные символы текущего списка
|
|
6. АВ проверка - вызываем функцию проверки av_check()
|
|
7. Детект есть?
|
|
- нет: пометили разнуленную часть текущего списка как "белый", продолжаем выполнение (гото 8)
|
|
- да:
|
|
в разнуленной части 1 символ?
|
|
- да: пометили как черный, занулили до конца проверки, гото 6
|
|
- нет: занулили половину (50%) нераскрашенной части текущего списка, гото 6
|
|
8. Если остались нераскрашенные символы в текущем списке, гото 5
|
|
9. Если остались нераскрашенные символы в файле, гото 4
|
|
|
|
На этот алгоритм можно написать unit-тест, заставив av_check() выдавать детекты только на конкретный список функций.
|
|
|
|
|
|
USAGE
|
|
|
|
-i <input exe file> проверяемый файл. Аргумент обязательный.
|
|
-m <input map file> карта компоновщика .map. Аргумент обязательный.
|
|
-d <workdir> рабочий каталог, куда складываем промежуточные файлы. По умолчанию текущий.
|
|
-s <section> список тестируемых секций (.text, .data ...). Можно указать -s несколько раз, например -s .text -t .data.
|
|
По умолчанию все секции.
|
|
-z <Minimum size threshold> исключить из проверки символы размером меньше чем указанный; размер в байтах. По умолчанию 0 (нет порога).
|
|
-a defender|dyncheck проверка на указанном антивирусе. Умолчания нет, аргумент обязательный.
|
|
-f <functionmask> проверять только символы с именем, удовлетворяющим маске. Можно указать -f несколько раз, например -f symb1* -f symb2*
|
|
-M <modulename> проверять только символы из указанных модулей. Можно указать -f несколько раз, например -m module1* -m module2*
|
|
|
|
Аргументы -s, -z, -f, -M комбинируются по логическому И (пересечение множеств), т.е. уменьшают диапазон проверки.
|
|
|
|
|
|
ИНТЕГРАЦИЯ С АВ-ДВИЖКАМИ
|
|
|
|
На первом этапе обязательны интеграции с Windows Defender (Windows 10) и dyncheck.com через API.
|
|
Далее код на Powershell
|
|
|
|
* Объект Defender
|
|
$Defender = @{
|
|
#MALWAREPROTECTION_*
|
|
SCAN_STARTED = 1000
|
|
SCAN_COMPLETED = 1001
|
|
MALWARE_DETECTED = 1006
|
|
BEHAVIOR_DETECTED = 1015
|
|
STATE_MALWARE_DETECTED = 1116
|
|
STATE_MALWARE_ACTION_TAKEN = 1117
|
|
StartTime = $null
|
|
IsRunning = $false
|
|
ScanProc = $null
|
|
ScanId = $null
|
|
LastScanId = $null
|
|
}
|
|
|
|
* Запуск Windows Defender
|
|
$Defender.ScanProc = Start-Process `
|
|
-FilePath "$($env:programfiles)\Windows Defender\mpcmdrun.exe" `
|
|
-ArgumentList '-Scan', '-ScanType 3', "-File $f" `
|
|
-PassThru -NoNewWindow #-Wait
|
|
$Defender.StartTime = (Get-Date).AddSeconds(-5)
|
|
$Defender.IsRunning = $true
|
|
* Получение идентификатора проверки, для последующего чтения журнала:
|
|
$ScanStarted = Get-WinEvent -LogName "Microsoft-Windows-Windows Defender/Operational" |
|
|
Where-Object {
|
|
$_.TimeCreated -ge $Defender.StartTime -and
|
|
$_.Id -eq $Defender.SCAN_STARTED
|
|
}
|
|
if ($ScanStarted)
|
|
{
|
|
$Defender.ScanId = $ScanStarted.Properties[$ScanId].Value
|
|
$Defender.LastScanId = $Defender.ScanId
|
|
}
|
|
* Проверка завершения сканирования:
|
|
$ScanCompleted = Get-WinEvent -LogName "Microsoft-Windows-Windows Defender/Operational" |
|
|
Where-Object {
|
|
$_.TimeCreated -ge $Defender.StartTime -and
|
|
$_.Id -eq $Defender.SCAN_COMPLETED -and
|
|
$_.Properties[$ScanId].Value -eq $Defender.ScanId
|
|
}
|
|
* Наличие детекта в образце:
|
|
$MalwareDetected = Get-WinEvent -LogName "Microsoft-Windows-Windows Defender/Operational" |
|
|
Where-Object {
|
|
$_.TimeCreated -ge $Defender.StartTime -and
|
|
$_.Id -in `
|
|
$Defender.MALWARE_DETECTED, `
|
|
$Defender.BEHAVIOR_DETECTED, `
|
|
$Defender.STATE_MALWARE_DETECTED `
|
|
|
|
На втором этапе, нужна интеграция с:
|
|
- Eset NOD32
|
|
- Kaspersky
|
|
- Norton Antivirus
|
|
|
|
Третий этап:
|
|
- Avast
|