Сканирование бинарных файлов на сигнатуры вирусов

Я пытаюсь сканировать сигнатуру вируса в двоичном файле (без использования strstr()) и распечатываю, найдена сигнатура или нет. Но код не работает. Я читаю файлы вне функции.

К сожалению, код не работает, даже когда я пытаюсь просканировать саму сигнатуру вируса.

int searchForSignature(FILE* file_to_search, FILE* virus) {
    int v_size = 0;
    int f_size = 0;


    fseek(virus, 0L, SEEK_END);
    v_size = ftell(virus);
    fseek(virus, 0, SEEK_SET);
    fseek(file_to_search, 0L, SEEK_END);
    f_size = ftell(file_to_search);
    fseek(file_to_search, 0, SEEK_SET);

    printf("VIRUS SIZE: %d FILE SIZE: %d\n", v_size, f_size);

    if (v_size > f_size)
    {
        printf("VIRUS NOT FOUND\n");
        return 1;
    }

    int counter = 0;  char ch = ' '; char ch2 = ' ';
    while ((ch = (char)fgetc(file_to_search)) != EOF)
    {
        printf("%d\n", counter);
        if (counter == v_size)
        {
            printf("VIRUS FOUND\n");
            return 0;
        }
        else
        {
            ch2 = (char)fgetc(virus);
            if (ch == ch2)
            {
                counter++;
            }
            else
            {
                counter = 0;
            }
        }
    }

    printf("VIRUS NOT FOUND\n");
    return 1;
}

как я читаю файлы вне функции:

FILE* virus_file = NULL;
virus_file = fopen("example file path", "rb");
if (virus_file == NULL)
{
    printf("Error opening file");
    return 1;
}

FILE* file_to_scan = NULL;
file_to_scan = fopen("example file path 2", "rb");
if (file_to_scan == NULL)
{
    printf("Error opening file");
    return 1;
}

Можете ли вы уточнить, что «не работает» в этом коде?

Scott Hunter 13.05.2022 16:50

А как насчет минимальный воспроизводимый пример?

John Bollinger 13.05.2022 16:51

Отвечает ли это на ваш вопрос? fgetc не идентифицирует EOF

wovano 13.05.2022 16:52

<O/T> никогда не используйте строковые функции (например, strstr) при работе с двоичными данными. Строковые функции останавливаются, когда видят 0. В двоичных данных 0 абсолютно допустим. Я не смотрел внимательно на ваш код, но если вы ищете точную последовательность байтов, вам, вероятно, понадобится memcmp

yano 13.05.2022 16:57

Но почему нет memmem?

Joshua 13.05.2022 18:16

Обратите внимание, что fgetc возвращает int, потому что EOF равно -1. Когда вы приводите результат к char, байт данных законный 0xFF будет имитировать [ранний] EOF. Удалите приведение (char) и используйте int ch; Приведение возвращаемого значения fgetc к char фактически заставляет код запускать помедленнее на некоторых/большинстве процессоров.

Craig Estey 13.05.2022 18:44
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
6
59
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

По крайней мере эти проблемы

Успех слишком поздно

counter == v_size может быть правдой сразу после counter++;. В файле может не быть другого символа для следующего цикла if (counter == v_size). Вместо этого проверьте counter == v_size сразу после увеличения.

Без сброса

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

Рассмотреть возможность:

search file: "aaac"
virus:       "aac"

Поиск файл поиска завершается ошибкой на "aa(a)..." (3-й "a"), но должен быть возобновлен на "a(a)" (2-й "a").

Вирусный файл должен rewind() при неудачном совпадении. Я рекомендую читать всю сигнатуру вируса в выделенную память (например: unsigned char *virus = malloc(v_size); вместо повторного чтения из файла.

Потеря информации

int fgetc() возвращает 257 различных значений: 0-255 и EOF. Сохранение этого результата в char приводит к потере информации. Используйте int ch = fgetc(...), int ch2 = fgetc(...).

Это может объяснить, что «код OP не работает, даже когда я пытаюсь сканировать саму сигнатуру вируса». так как один из байтов вируса ошибочно соответствует EOF при преобразовании в char.

Приведения не нужны, чтобы решить эту проблему.

Неправильная длина типа

ftell(virus) возвращает long. Сохранение результата в int может привести к потере информации. Также в коде отсутствуют проверки ошибок.

Ненужный код

if (v_size > f_size) блок не нужен.


Альтернатива

// Pseudo code
Read virus into an allocated buffer.
Read a chunk of test file into a test buffer at least 2x virus size.
Walk test buffer (1 char at a time) trying `memcmp()`. 
  Stop if match found,
  until remaining test buffer not full enough for a possible match.
Move remaining test buffer to start and re-fill as able.
If not able to re-fill at all, we are done - no match.

Это O (размер_теста * размер_вируса). Более сложная «прогулка» — это O(test_size + virus_size).

Я считаю, что v_size > f_size предназначен для ярлыка - если вирус больше, чем файл, файл не может его содержать. Это может быть не обязательно, но позволяет избежать сравнения байтов, когда это может привести только к сбою.

Dave Meehan 13.05.2022 18:25

@Dave Meehan, согласен с тем, почему OP сделал это, но это остается бесполезным. Это стоит fseek(file_to_search, 0L, SEEK_END);, что может быть довольно дорого.

chux - Reinstate Monica 13.05.2022 18:29

Другие вопросы по теме