Ваш ключ: необходима авторизация | MyProxy - бесплатный обменник валидных прокси между пользователями форума.

Пишем свой антивирус на C++

Тема в разделе Мануалы, способы заработать, создана пользователем Golden K., 1 июн 2016.

Войдите для ответа
  1. Golden K. Заблокирован

    Golden K.
    Статус:
    Вне сети
    Сообщения:
    541
    Симпатии:
    140
    Регистрация:
    04.05.16
    В статье рассматривается процесс написания простого антивирусного сканера.

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

    Помимо самого сканера мы также напишем программку для создания базы сигнатур.

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

    Что такое сигнатура

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

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

    В нашем сканере в качестве дополнительного параметра мы будем использовать смещение последовательности в файле относительно начала.
    Данный метод довольно универсален в том плане, что подходит абсолютно для любых файлов независимо от типа.
    Однако у использования смещения есть один очень значимый минус: чтобы "обмануть" сканер, достаточно слегка "передвинуть" последовательность байт в файле, т.е. изменить смещение последовательности (например, перекомпилировав вирус или добавив символ в случае скрипт-вируса).

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

    Антивирусная база

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

    Алгоритм работы сканера

    Алгоритм работы сканера, использующего сигнатуры, можно свести к нескольким пунктам:
    1. Загрузка базы сигнатур
    2. Открытие проверяемого файла
    3. Поиск сигнатуры в открытом файле
    4. Если сигнатура найдена
    - принятие соответствующих мер
    5. Если ни одна сигнатура из базы не найдена
    - закрытие файла и переход к проверке следующего

    Как видите, общий принцип работы сканера весьма прост.

    Впрочем, достаточно теории. Переходим к практике.
    Все дополнительные моменты будут разобраны в процессе написания сканера.

    Подготовка к реализации

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

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

    Программа создания базы -> База -> Сканер

    Однако прежде чем создавать базу, необходимо определиться с её форматом, который в свою очередь зависит от хранимой информации.

    Информация сигнатуры

    Сигнатура будет состоять из:
    - Смещения последовательности в файле
    - Размера последовательности
    - Хэша последовательности

    Для хэширования будем использовать алгоритм MD5.
    Каждый MD5-хэш состоит из 16 байт, или 4 двойных слов.
    Для хранения смещения и размера последовательности отведём по 4 байта для каждого.
     
    1 июн 2016 #1
  2. Golden K. Заблокирован

    Golden K.
    Статус:
    Вне сети
    Сообщения:
    541
    Симпатии:
    140
    Регистрация:
    04.05.16
    Таким образом сигнатуру можно описать следующей структурой:

    [Offset * 4 ]
    [Lenght * 4 ]
    [Hash * 16 ]

    Запись антивирусной базы

    Запись будет содержать:
    - Сигнатуру
    - Размер имени файла
    - Имя файла

    Под размер имени файла выделим 1 байт. Этого больше чем достаточно, плюс экономия места =)
    Имя файла может быть произвольного размера до 255 символов включительно.

    Получается следующая структура:

    [Signature]
    [NameLen * 1 ]
    [Name ... ]

    После раскрытия структуры сигнатуры получается вот такая запись:

    [Offset * 4 ]
    [Lenght * 4 ]
    [Hash * 16]
    [NameLen * 1 ]
    [Name ... ]

    Именно в таком виде одна за другой в файле будут лежать записи для всех известных сканеру зловредах.

    Помимо самих записей в файле базы должен быть заголовок, в котором будет содержаться число записей в базе и сигнатура файла "AVB" (не антивирусная :) ). Назначение сигнатуры – удостоверится, что это именно файл базы.

    Таким образом файл базы будет иметь структуру вида:

    [Sign * 3 ]
    [RecordCount * 4 ]
    [Records]

    Переходим к написанию кода.

    Реализация

    Базовые структуры

    Структур не много, всего 2.
    Данные структуры будут использоваться как сканером, так и программой создания антивирусной базы.
    Во-первых, необходимо объявить все нужные нам структуры.

    Первой структурой будет структура сигнатуры SAVSignature.
    Следующей структурой будет структура записи SAVRecord, объединяющая сигнатуру с именем.
    Данная структура для удобства также содержит функцию выделения памяти под имя зловреда (allocName).

    Все структуры будут находиться в заголовочном файле avrecord.h

    Листинг : Базовые структуры
    ---------------------------------------------------------------------------------------------------------
    #ifndef _AVRECORD_H__INCLUDED_
    #define _AVRECORD_H__INCLUDED_
    #include

    //! Структура сигнатуры
    typedef struct SAVSignature{
    SAVSignature(){
    this->Offset = 0;
    this->Lenght = 0;
    memset(this->Hash, 0, sizeof(this->Hash));
    }
    DWORD Offset; // - Смещение файле
    DWORD Hash[4]; // - MD5 хэш
    DWORD Lenght; // - Размер данных
    } * PSAVSignature;

    //! Структура записи о зловреде
    typedef struct SAVRecord{
    SAVRecord(){
    this->Name = NULL;
    this->NameLen = 0;
    }
    ~SAVRecord(){
    if(this->Name != NULL) this->Name;
    }
    //! Выделение памяти под имя
    void allocName(BYTE NameLen){
    if(this->Name == NULL){
    this->NameLen = NameLen;
    this->Name = new CHAR[this->NameLen + 1];
    memset(this->Name, 0, this->NameLen + 1);
    }
    }
    PSTR Name; // - Имя
    BYTE NameLen; // - Размер имени
    SAVSignature Signature; // - Сигнатура

    } * PSAVRecord;

    #endif
    -------------------------------------------------------------------------------------------------------

    Класс работы с файлом базы


    Теперь необходимо написать класс для работы с файлом антивирусной базы.
    Если точнее, то классов будет несколько:
    - Базовый класс файла "CAVBFile"
    - Класс чтения файла "CAVBFileReader"
    - Класс добавления записи "CAVBFileWriter"

    Объявления всех этих классов находятся в файле CAVBFile.h
    Вот его содержимое:

    Листинг : Объявления классов работы с файлом базы
    --------------------------------------------------------------------------------------------------------

    #ifndef _AVBFILE_H__INCLUDED_
    #define _AVBFILE_H__INCLUDED_
    #include
    #include
    #include "avrecord.h"
    using namespace std;


    /* Формат файла антивирусной базы

    [AVB] // - Сигнатура
    [RecordCount * 4 ] // - Число записей
    [Records ... ]

    Record:
    [Offset * 4 ] // - Смещение
    [Lenght * 4 ] // - Размер
    [Hash * 16 ] // - Контрольная сумма
    [NameLen * 1 ] // - Размер имени
    [Name ... ] // - Имя зловреда

    */


    //! Класс Файла антивирусной базы
    typedef class CAVBFile{
    protected:
    fstream hFile; // - Объект потока файла
    DWORD RecordCount; // - Число записей
    public:
    CAVBFile();

    //! Закрытие файла
    virtual void close();
    //! Проверка состояния файла
    virtual bool is_open();
    //! Получение числа записей
    virtual DWORD getRecordCount();
    } * PCAVBFile;


    //! Класс для записи файла
    typedef class CAVBFileWriter : public CAVBFile{
    public:
    CAVBFileWriter() : CAVBFile(){
    }

    //! Открытие файла
    bool open(PCSTR FileName);
    //! Добавление записи в файл
    bool addRecord(PSAVRecord Record);

    } * PCAVBFileWriter;

    //! Класс для чтения файла
    typedef class CAVBFileReader : public CAVBFile{
    public:
    CAVBFileReader() : CAVBFile(){

    }
    //! Открытие файла
    bool open(PCSTR FileName);
    //! Чтение записи
    bool readNextRecord(PSAVRecord Record);

    } * PCAVBFileReader;


    #endif
    --------------------------------------------------------------------------------------------------------
    Теперь перейдем к реализации объявленных классов.
    Их реализация будет находиться в файле AVBFile.cpp
    Естественно, помним, что необходимо подключить заголовочный файл AVBFile.h

    В некоторых функциях нам понадобится проверка существования файла, поэтому сначала напишем именно её.

    Листинг : Функция проверки существования файла
    ---------------------------------------------------------------------------------------------------------
    //! Проверка существования файла
    bool isFileExist(PCSTR FileName){
    return GetFileAttributesA(FileName) != DWORD(-1);
    };
    ---------------------------------------------------------------------------------------------------------
    Данный способ проверки существования файла является самым быстрым и используется в большинстве примеров в MSDN, так что его можно считать стандартом для Windows.
    Функция GetFileAttributes возвращает атрибуты файла или 0xffffffff в случае, если файл не найден.

    Переходим к реализации функций базового класса.

    Листинг : Реализация CAVBFile
    ----------------------------------------------------------------------------------------------------------

    CAVBFile::CAVBFile(){
    this->RecordCount = 0;
    }
    //! Закрытие файла
    void CAVBFile::close(){
    if(hFile.is_open()) hFile.close();
    }
    //! Проверка состояния файла
    bool CAVBFile::is_open(){
    return hFile.is_open();
    }
    //! Получение числа файлов
    DWORD CAVBFile::getRecordCount(){
    return this->RecordCount;
    }
    ----------------------------------------------------------------------------------------------------------
    Здесь всё просто и в комментариях не нуждается.

    Теперь реализуем функции класса для записи файла

    Листинг : Реализация CAVBFileWriter
    ----------------------------------------------------------------------------------------------------------


    //
    // - CAVBFileWriter
    //

    //! Открытие файла
    bool CAVBFileWriter::open(PCSTR FileName){
    if(FileName == NULL) return false;
    // - Если файл не найден то создаем его прототип
    if(!isFileExist(FileName)){
    hFile.open(FileName, ios::out | ios::binary);
    if(!hFile.is_open()) return false;
    hFile.write("AVB", 3); // - Сигнатура файла
    hFile.write((PCSTR)&this->RecordCount, sizeof(DWORD)); // - Число записей
    // - Иначе открываем и проверяем валидность
    }else{
    hFile.open(FileName, ios::in | ios::out | ios::binary);
    if(!hFile.is_open()) return false;
    // - Проверка сигнатуры
    CHAR Sign[3];
    hFile.read((PSTR)Sign, 3);
    if(memcmp(Sign, "AVB", 3)){
    hFile.close(); // - Это чужой файл
    return false;
    }
    // - Читаем число записей
    hFile.read((PSTR)&this->RecordCount, sizeof(DWORD));
    }
    return true;
    }

    bool CAVBFileWriter::addRecord(PSAVRecord Record){
    if(Record == NULL || !hFile.is_open()) return false;
    // - Перемещаемся в конец файла
    hFile.seekp(0, ios::end);
    // - Добавляем запись
    hFile.write((PSTR)&Record->Signature.Offset, sizeof(DWORD)); // - Смещение сигнатуры
    hFile.write((PSTR)&Record->Signature.Lenght, sizeof(DWORD)); // - Размер сигнатуры
    hFile.write((PSTR)&Record->Signature.Hash, 4 * sizeof(DWORD)); // - Контрольная сумма
    hFile.write((PSTR)&Record->NameLen, sizeof(BYTE)); // - Размер имени
    hFile.write((PSTR)Record->Name, Record->NameLen); // - Имя
    // - Смещаемся к числу записей
    hFile.seekp(3, ios::beg);
    // - Увеличиваем счётчик записей
    this->RecordCount++;
    hFile.write((PSTR)&this->RecordCount, sizeof(DWORD));

    return true;
    }

    ----------------------------------------------------------------------------------------------------------
    При открытии файла, если файл не найден, создается новый файл и в него записывается заголовок файла (сигнатура и число записей).
    Если же файл существует, то происходит проверка сигнатуры файла и чтение числа записей.

    Функция addRecord в качестве параметра принимает ссылку на структуру добавляемой записи.
    Сначала происходит перемещение в конец файла (новый записи дописываются в конец файла).
    Затем происходит запись данных в файл согласно оговорённому выше формату.
    После записи происходит увеличение счётчика записей.


    Класс чтения записей немного проще.

    Листинг : Реализация CAVBFileReader
    ---------------------------------------------------------------------------------------------------------
    //
    // - CAVBFileReader
    //
    bool CAVBFileReader::open(PCSTR FileName){
    if(FileName == NULL) return false;
    // - Если файл не найден, то создаем его прототип
    if(isFileExist(FileName)){
    hFile.open(FileName, ios::in | ios::out | ios::binary);
    if(!hFile.is_open()) return false;
    // - Проверка сигнатуры
    CHAR Sign[3];
    hFile.read((PSTR)Sign, 3);
    if(memcmp(Sign, "AVB", 3)){
    hFile.close(); // - Это чужой файл
    return false;
    }
    // - Читаем число записей
    hFile.read((PSTR)&this->RecordCount, sizeof(DWORD));
    }else{ return false; }
    return true;
    }

    bool CAVBFileReader::readNextRecord(PSAVRecord Record){
    if(Record == NULL || !hFile.is_open()) return false;

    hFile.read((PSTR)&Record->Signature.Offset, sizeof(DWORD)); // - Смещение сигнатуры
    hFile.read((PSTR)&Record->Signature.Lenght, sizeof(DWORD)); // - Размер сигнатуры
    hFile.read((PSTR)&Record->Signature.Hash, 4 * sizeof(DWORD)); // - Контрольная сумма
    hFile.read((PSTR)&Record->NameLen, sizeof(BYTE)); // - Размер имени
    Record->allocName(Record->NameLen);
    hFile.read((PSTR)Record->Name, Record->NameLen); // - Имя
    return true;
    }
    ---------------------------------------------------------------------------------------------------------
    В данном случае если при попытке открытия файла выясняется, что файл не существует, функция вернет значение false, свидетельствующее об ошибке.
    Чтение записей происходит последовательно и обеспечивается функцией readNextRecord, которая в качестве параметра принимает ссылку на структуру записи, в которую будут прочитаны данные из файла.

    На этом написание общего кода закончено.
    Пора переходить к реализации программы создания записей и сканера.

    Реализация программы для создания базы

    Как было выяснено выше, сканнер без сигнатур не имеет смысла. Именно поэтому первым делом будет реализована программа для создания базы.

    В качестве параметров программа будет принимать путь до файла зловреда, путь до файла базы, смещение последовательности в файле зловреда, размер последовательности и, наконец, имя зловреда.
    Аргументы передаются формате -A[Value], где A – это соответствующий ключ, а Value – значение.
    Обозначим все аргументы:
    -s = Путь до файла зловреда
    -d = Путь до файла базы
    -o = Смещение последовательности
    -l = Размер последовательности
    -n = Имя файла

    Алгоритм работы программы следующий:
    1. Открыть файл зловреда
    2. Перейти по указанному смещению
    3. Расчитать MD5-хэш последовательности байт
    4. Добавить запись в базу
     
    1 июн 2016 #2
  3. Golden K. Заблокирован

    Golden K.
    Статус:
    Вне сети
    Сообщения:
    541
    Симпатии:
    140
    Регистрация:
    04.05.16
    Реализация алгоритма здесь приводится не будет, т.к. не относится к теме статьи, но её можно найти в файле md5hash.cpp
    Здесь же мы просто объявим соответствующую функцию getMD5, которая принимает указатель на данные, их размер и указатель на буфер из 16 байт, куда будет записан хэш.

    Код программы находится в файле avrec.cpp

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

    Листинг : Заголовок
    ----------------------------------------------------------------------------------------------------------
    // - Необходимые включения
    #include
    #include
    #include
    #include
    #include
    #include

    using namespace std;


    //! Копирование аргумента
    bool copyArg(PCSTR Arg, DWORD Offset, PSTR Buffer, DWORD Size){
    int ArgLen = strlen(Arg) - Offset;
    if(ArgLen > Size - 1 || ArgLen Can't open source file. Stop." << endl;
    return 0;
    }
    // - Чтение данных для расчёта контрольной суммы
    PBYTE Buffer = new BYTE[Record.Signature.Lenght];
    if(Buffer == NULL){
    cout << "> Can't alloc memory for sign data. Stop." << endl;
    hSrcFile.close();
    return 0;
    }
    hSrcFile.seekg(Record.Signature.Offset, ios::beg);
    hSrcFile.read((PSTR)Buffer, Record.Signature.Lenght);
    // - Закрытие исходного файла
    hSrcFile.close();
    // - Расчёт хэша сигнатуры
    getMD5(Buffer, Record.Signature.Lenght, Record.Signature.Hash);

    // - Очистка буффера
    Buffer;

    ---------------------------------------------------------------------------------------------------------
    Сначала открываем файл, затем переходим к указанному смещению и вычисляем хэш.
    Всё просто.

    И наконец, добавляем запись в файл базы, попутно выводя информацию в консоль.
    Для добавления используется класс CAVBFileWriter.
    Листинг : Добавление записи в базу
    ----------------------------------------------------------------------------------------------------------

    // -
    // - Добавление сигнатуры
    cout << "Record info:" << endl;
    printf( " Name: %sn", Record.Name);
    printf( " Offset: 0x%x (%d)n", Record.Signature.Offset, Record.Signature.Offset);
    printf( " Lenght: 0x%x (%d)n", Record.Signature.Lenght, Record.Signature.Lenght);
    printf( " CheckSumm: 0x%x%x%x%xn", Record.Signature.Hash[0], Record.Signature.Hash[1], Record.Signature.Hash[2], Record.Signature.Hash[3]);
    CAVBFileWriter hAVBFile;
    hAVBFile.open(DstFile);
    if(!hAVBFile.is_open()){
    cout << "> Can't open database file. Stop." << endl;
    return 0;
    }
    hAVBFile.addRecord(&Record);
    hAVBFile.close();

    cout << "Record added." << endl;

    return 0;
    ----------------------------------------------------------------------------------------------------------
    На этом всё, программа готова. Можно компилировать :)
    А пока она компилируется, переходим к написанию самого сканера!

    Реализация сканера

    Наконец-то добрались и до главной цели - сканера.
    Сканер пока будет просто проверять является ли файл вредоносным, или нет.
    Лечение, удаление, карантин оставим на потом.
    Файл с базой должен находиться в одной папке со сканером и называться avbase.avb
    Программа принимает один-единственный параметр - путь до папки, в которой необходимо провести проверку.
    Кода в сканере будет немного больше, но в целом всё так же просто.

    Алгоритм работы следующий:
    1. Загрузка файла базы
    2. Получение списка файлов в указанной папке
    3. Если это файл - проверяем. Если папка - рекурсивно переходим к пункту 2.

    Загрузка файла базы будет происходить в специальную структуру SAVRecordCollection, которую мы объявим, несмотря на то, что можно было использовать стандартный vector или другой контейнер.

    Проверка файла сводится к простому перебору всех сигнатур.
    Если сигнатура присутствует, то сообщаем, что файл злой, в противном случае сообщаем, что всё хорошо.

    А теперь ближе к коду :)

    Листинг : Заголовок
    ----------------------------------------------------------------------------------------------------------

    #include
    #include
    #include
    #include

    #include
    #include


    using namespace std;

    //! Коллекция записей
    typedef struct SAVRecordCollection{
    SAVRecordCollection(DWORD RecordCount){
    this->RecordCount = RecordCount;
    this->Record = new SAVRecord[this->RecordCount];
    }
    ~SAVRecordCollection(){
    [] this->Record;
    }
    DWORD RecordCount;
    PSAVRecord Record;
    } * PSAVRecordCollection;

    // - Коллекция записей
    PSAVRecordCollection AVRCollection = NULL;

    void processPath(PCSTR Path);
    void getMD5(const void* pData, size_t nDataSize, PDWORD RetHash); ---------------------------------------------------------------------------------------------------------
    функция processPath будет рассмотрена ниже.
    Итак, вначале стандартный разбор аргументов, а также получение пути для

    Листинг : Разбор аргументов
    ---------------------------------------------------------------------------------------------------------

    if(argc 0){
    // - Создание коллекции
    AVRCollection = new SAVRecordCollection(hAVBFile.getRecordCount());
    for(DWORD RecID = 0; RecID RecordCount; RecID++){
    if(!hAVBFile.readNextRecord(&AVRCollection->Record[RecID])){
    cout << "> Error loading record #" << RecID << endl;
    }
    }
    hAVBFile.close();
    }else{
    hAVBFile.close();
    cout << "> Empty AV Base. Stop." << endl;
    return 0;
    }
    cout << "t" << AVRCollection->RecordCount << " records loaded." << endl;

    //
    cout << endl;
    cout << "Starting scan for viruses" << endl;
    cout << endl;

    processPath(SrcPath);

    ----------------------------------------------------------------------------------------------------------
    Открываем файл, выделяем память под записи, после чего читаем в них информацию из файла.
    Если всё прошло хорошо, то будет вызвана функция processPath, которая выполняет рекурсивную проверку по указанному пути.

    Вот так выглядит эта функция:

    Листинг : Функция проверки папки
    ----------------------------------------------------------------------------------------------------------


    void processPath(PCSTR Path){
    string SrcPath = Path;
    string File;
    File = Path;
    File += "*.*";

    WIN32_FIND_DATAA FindData;
    HANDLE hFind = FindFirstFileA(File.c_str(), &FindData);

    do{
    // - Пропускаем папки . и ..
    if(!strcmp(FindData.cFileName, ".") || !strcmp(FindData.cFileName, "..")) continue;

    File = Path;
    File += "";
    File += FindData.cFileName;

    // - Если папка, то сканируем рекурсивно
    if((FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)){
    processPath(File.c_str());
    // - Иначе проверяем на вирусы
    }else{
    checkFile(File.c_str());
    }

    } while(FindNextFileA(hFind, &FindData));


    }
    ----------------------------------------------------------------------------------------------------------
    Получаем список файлов и папок (за исключением папок "." и ".."), при этом если нам попалась папка, то проводим рекурсивный просмотр, а если файл, проверяем его функцией checkFile.

    Ниже приведён листинг функции checkFile

    Листинг : Функция проверки файла
    ----------------------------------------------------------------------------------------------------------


    void checkFile(PCSTR FileName){
    cout << FileName << "t";
    // - Открываем файл
    HANDLE hFile = CreateFileA(FileName, FILE_READ_ACCESS, NULL, NULL, OPEN_EXISTING, NULL, NULL);
    if(hFile == INVALID_HANDLE_VALUE){
    cout << "Error" << endl;
    return;
    }
    // - Получаем размер файла
    DWORD FileSize = GetFileSize(hFile, NULL);

    // - Отображаем файл в память
    HANDLE hMap = CreateFileMappingA(hFile, NULL, PAGE_READONLY, NULL, FileSize, NULL);
    if(hFile == INVALID_HANDLE_VALUE){
    cout << "Error" << endl;
    CloseHandle(hFile);
    return;
    }
    LPVOID File = MapViewOfFile(hMap, FILE_MAP_READ, NULL, NULL, FileSize);
    if(File == NULL){
    cout << "Error" << endl;
    CloseHandle(hMap);
    CloseHandle(hFile);
    return;
    }

    // - Поиск по сигнатурам
    bool Detected = false;
    for(DWORD RecID = 0; RecID RecordCount; RecID++){
    PSAVRecord Record = &AVRCollection->Record[RecID];
    // - Если файл слишком маленький, то пропускам запись
    if(FileSize Signature.Offset + Record->Signature.Lenght)) continue;
    // - Переходим вычисляем контрольную сумму для сигнатуры
    DWORD Hash[4];
    getMD5((PBYTE)((DWORD)File + Record->Signature.Offset), Record->Signature.Lenght, Hash);

    // - Детектим
    if(!memcmp(Hash, Record->Signature.Hash, 4 * sizeof(DWORD))){
    cout << " DETECTEDt" << Record->Name << endl;
    Detected = true;
    break;
    }
    }

    UnmapViewOfFile(File);
    CloseHandle(hMap);
    CloseHandle(hFile);

    if(!Detected) cout << "OK" << endl;
    }
    ----------------------------------------------------------------------------------------------------------
    Рассмотрим её подробнее.
    Во-первых, в функции вместо чтения файла использовано отображение файла в память, при котором файл помещается в адресное пространство процесса, и для доступа к файлу не требует производить операции чтения или записи. Доступ осуществляется, как к обычному массиву.
    Данный подход выбран по той причине, что при проверке сигнатур требуется постоянно перемещаться по файлу согласно смещению сигнатуры.
    Перемещение по массиву намного быстрее перемещения по файлу. Также для расчёта хэша достаточно просто передать указатель на начало последовательности.
    При стандартном подходе потребовалось бы каждый раз считывать информацию из файла, что не только медленно, но и просто неудобно.

    Функция MapViewOfFile возвращает адрес, начиная с которого отображен файл.
    Этот адрес и является началом файла, или если представить файл как массив, то данный адрес будет началом массива.

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

    Осталось только скомпилировать и протестировать.

    Листинг : Добавление записи
    ----------------------------------------------------------------------------------------------------------
    avrec.exe -sVirus.vbs -davbase.avb -o253 -l280 -nVirus.VBS.Baby
    ----------------------------------------------------------------------------------------------------------

    Исходник: http://av-school.ru/up/article/file/cpp/avscan.rar
     
    1 июн 2016 #3
    Hrum нравится это.
  4. PeNNy Местный

    PeNNy
    Статус:
    Вне сети
    Сообщения:
    173
    Симпатии:
    26
    Регистрация:
    01.06.15
    Смысл этого гемора?В интернете же полно антивирусов.Если просто ради обучения программированию то годно.
     
    1 июн 2016 #4
  5. Golden K. Заблокирован

    Golden K.
    Статус:
    Вне сети
    Сообщения:
    541
    Симпатии:
    140
    Регистрация:
    04.05.16
    для обучения я и писал, а вдруг найдёться среди нас тот кто по данному способу запустит свой ахеренный антивирус? и будет срубать капусту покруче чем Valve ? об это я уверен ты не подумал! ведь это хак форум и сдесь полно программистов ! удачи начинаниях :D
     
    1 июн 2016 #5
    Hrum нравится это.
  6. Golden K. Заблокирован

    Golden K.
    Статус:
    Вне сети
    Сообщения:
    541
    Симпатии:
    140
    Регистрация:
    04.05.16
    Up
     
    28 авг 2016 #6
    Hrum нравится это.
Загрузка...
Top