Пример построения простого antimalware сканера с собственными базами

Пример построения простого antimalware сканера с собственными базами

Previous pageReturn to chapter overview

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

Рассмотрим типовой пример:

 

var

SignDB     : TStrings; // Сигнатурная база

MalwareCnt : integer; // Счетчик найденных зловредов

DelMalwareCnt : integer; // Счетчик удаленных зловредов

DeleteMalware : boolean; // Признак того, что делать с найденными Malware

 

// Обработка найденного файла

Procedure ScanFile(AFileName : string);

var

FMD5 : string;

begin

SetStatusBarText(AFileName);

// Вычисление MD5 суммы                                                        

FMD5 := CalkFileMD5(AFileName);

// Поиск MD5 в базе                                                        

if (FMD5 <> '') and (SignDB.IndexOf(FMD5) >= 0) then begin

AddToLog('Найден malware, файл = '+AFileName);

 inc(MalwareCnt);

if DeleteMalware then begin

  DeleteFile(AFileName);

  inc(DelMalwareCnt);

end;

end;

end;

 

// Сканирование каталога

Procedure ScanDir(ADirName : string; AScanSubDir : boolean);

var

FS : TFileSearch;

begin

ADirName := NormalDir(ADirName);

FS := TFileSearch.Create(nil);

FS.FindFirst(ADirName + '*.*');

while FS.Found do begin

// В зависимости от типа - или сканируем подкаталог, или изучаем файл

if (FS.FileName <> '.')   and (FS.FileName <> '..') then

  if FS.IsDir and AScanSubDir then

   ScanDir(ADirName + FS.FileName, AScanSubDir)

  else

   ScanFile(ADirName + FS.FileName);

 FS.FindNext;

end;

FS.Free;

end;

 

begin

// Режим сканирования

DeleteMalware := false;

// Обнуляем счетчик зловредов

MalwareCnt := 0; DelMalwareCnt := 0;

// Загружаем сигнатурную базу

SignDB := TStringList.Create;

SignDB.LoadFromFile('my_sign_db.txt');

AddToLog('Баз загружена, количество сигнатур = '+inttostr(SignDB.Count));

// Задействуем антируткит

SearchRootkit(true, true);

// Проверка дисков и (или) папок

ScanDir('c:\', true);

ScanDir('d:\MyFolder\', false);

// Зачистка следов зловредов, если таковые были найдены

if DelMalwareCnt > 0 then begin

SaveLog('scan_result.txt');

// Включение AVZGuard - он помешает зловредам восстановиться

SetAVZGuardStatus(true);

// Активация BootCleaner

BC_ImportALL;

BC_Activate;

// Эвристическая чистка

ExecuteSysClean;

// Перезагрузка

RebootWindows(true);

end;

end.

 

для работы данного примера необходима сигнатурная база. В нашем случае роли сигнатуры выступает MD5 сумма файла - ее крайне неудобно применять в реальных ситуациях (так как изменение хотя-бы одного байта в файле приведет к изменению его MD5), однако для простейшего сканера такой подход удобен, так как рассчитать MD5 любого файла очень просто, например в AVZ меню "Сервис/Вычислить MD5 сумму файла". Записи базы просты - по одной MD5 сумме в каждой строке, без пробелов до или после суммы
Для примера можем создать базу my_sign_db.txt, состоящую из единственной записи:

 

44D88612FEA8A8F36DE82E1278ABB02F

 

Это MD5 сумма файла EICAR - тестового "вируса", который можно взять где угодно, например вот тут: http://support.kaspersky.ru/downloads/eicar/eicar.zip (только нужно не забыть распаковать его - так как наш пример архивы не проверяет).
 
Работа данного примера достаточно просто, разберем ее шаг за шагом:
1. В скрипте декларируется класс SignDB для работы с массивами строк типа TStringList.
2. Производится загрузка базы. Обработку ошибок в скрипте мы не производим, поэтому в случае ошибки AVZ прервет работу скрипта и выведет сообщение об ошибке
3. С помощью SearchRootkit нейтрализуем перехваты. Это необязательный шаг, однако перехватчик может маскировать или блокировать доступ к файлам зловреда, что затруднит его поиск
4. Производим поиск с помощью созданной нами функции ScanDir. У нее два параметра - стартовый каталог и режим сканирования подкаталогов. Если второй параметр TRUE, то сканируется указанный каталог и все его подкаталоги. Если FALSE, то подкаталоги не сканируются - это в частности удобно для поиска файлов в корне диска. Вызовов ScanDir может быть несколько.
5. Проверяем показания нашего счетчика DelMalwareCnt - если он больше нуля, то в ходе работы были удалены описанной базой программы. В этом случае производится сохранение протокола работы, активация AVZGuard при помощи SetAVZGuardStatus, настройка BootCleaner, после чего выполняется эвриcтическая чистка системы и перезагрузка при помощи RebootWindows. Конкретный набор операций определяется конкретной задачей, в минимуме можно оставить:

 
if DelMalwareCnt > 0 then begin

// Эвристическая чистка

ExecuteSysClean;

end;

 
Процедура ScanDir в данном скрипте отвечает за рекурсивный обход каталогов на диске и поиск файлов, ничего примечательного в ее работе нет, используется описанный в справке AVZ класс TFileSearch

 

Процедура ScanFile выполняет самое интересное - изучение файла. Она выполняет следующие операции:

1. Выводит в строке статуса имя сканируемого файла через SetStatusBarText. Это чисто "косметическая" операция, которая замедляет работу скрипта, зато можно наблюдать за тем, как идет сканирование. Из реального скрипта ее можно исключить

2. При помощи CalkFileMD5 вычисляется MD5 сумма файла

3. Если MD5 вычислен успешно (в этом случае CalkFileMD5 возвращает строку с MD5 суммой) и такая MD5 сумма найдена в базе, то выполняются действия над найденным файлом - делается отметка в протоколе, а файл удаляется при условии, что DeleteMalware = true. В данном случае если DeleteMalware = true, то получаем "режим лечилки", если False - то "режим сканера" (данный параметр задается в начале скрипта).

 

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

 

var

SignDB     : TStrings; // Сигнатурная база

 

// Обработка найденного файла

Procedure ScanFile(AFileName : string);

var

FMD5 : string;

begin

SetStatusBarText(AFileName);

// Вычисление MD5 суммы

FMD5 := CalkFileMD5(AFileName);

// Добавление в базу без повторов                            

if (FMD5 <> '') and (SignDB.IndexOf(FMD5) < 0) then

 SignDB.Add(Trim(FMD5));

end;

 

// Сканирование каталога

Procedure ScanDir(ADirName : string; AScanSubDir : boolean);

var

FS : TFileSearch;

begin

ADirName := NormalDir(ADirName);

FS := TFileSearch.Create(nil);

FS.FindFirst(ADirName + '*.*');

while FS.Found do begin

// В зависимости от типа - или сканируем подкаталог, или изучаем файл

if (FS.FileName <> '.')   and (FS.FileName <> '..') then

  if FS.IsDir and AScanSubDir and then

   ScanDir(ADirName + FS.FileName, AScanSubDir)

  else

   ScanFile(ADirName + FS.FileName);

 FS.FindNext;

end;

FS.Free;

end;

 

begin

// Инициализируем сигнатурную базу

SignDB := TStringList.Create;

SignDB.LoadFromFile('my_sign_db.txt');

AddToLog('Баз загружена, количество сигнатур = '+inttostr(SignDB.Count));

// Сканирование папки с образцами Malware

ScanDir('c:\MalwareSamplesDir\', true);

// Сохранение базы

AddToLog('Баз пополнена, количество сигнатур = '+inttostr(SignDB.Count));

SignDB.SaveToFile('my_sign_db.txt');

SignDB.Free;

end.

 

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