VirusTotal своими руками: Создаем публичный сервис для проверки файла несколькими антивирусамиНедавно я прочитал статью Криса Касперски, посвященную VirusTotal'у, и всерьез загорелся идеей созданием такого сервиса. Почему бы и нет? Проблема малвари сейчас стоит довольно остро, а необходимость проверки одного, но весьма подозрительного файла появляется у пользователей с завидным постоянством. Материалы и методыИтак, что же нам нужно? Рассмотрим по пунктам.
Перейдем к практикеНабросаем небольшой план. Что должна делать наша софтина? Она запускает консольный сканер антивируса, читает и парсит его stdout. Чтобы понять стиль поведения антивируса, запустим его с параметром --help, внимательно вкурим в результат, а затем скормим ему здоровый и зараженный (поочередно, естественно) файлы и сравним вывод антивируса. Как это будет реализовано в софте? Как тебе уже известно (если ты читал мою статью в майском ][ ), в Qt есть очень полезный класс QProcess, который служит для запуска внешних программ. Он умеет запускать программу, получать ее вывод и сообщать нам о завершении программы. Но нам этого недостаточно, поэтому мы немного допишем класс. Что будет в новом классе? Он должен собирать выведенный в консоль текст по мере его поступления и генерировать сигнал с этим самым выводом и именем процесса при его завершении. Сказано — сделано:
Как видишь, класс наследуется от QProcess. Рассмотрим методы и слоты этого класса:
Как нетрудно догадаться, этот метод служит для запуска программы и сохранения имени процесса перед запуском. Код, заключенный в слот onReadyRead, просто аппендит прочитанный вывод к уже имеющемуся, а слот onFinished() генерирует сигнал emit onAvFinished(this, avName, avBuffer, exitCode). Все тривиально, поэтому я предлагаю двигаться дальше, к главному классу:
Разберем код по порядку. За запуск антивирусов у нас отвечает функция startCheck():
В параметр fName, как нетрудно догадаться, передается имя файла, который мы будем проверять. В данной статье я буду показывать взаимодействие только с одним антивирусом — дальше ты сможешь продолжить сам. Кстати говоря, знаешь, почему параметр передается в таком странном виде (const QString &fName)? Дело в том, что при передаче параметра по значению (то есть, например, просто QString fName) в стек переменная будет копироваться целиком, и это совсем не гуд, а при передаче по указателю (QString fName) в стек будет копироваться только адрес переменной. Минус в том, что мы будем вынуждены работать с ней как с указателем. Ну а передача по константной ссылке — const QString &fName — это комбинация двух предыдущих методов. В итоге в стек копируется только указатель на переменную (то есть sizeof(void*)), и работаем мы с ней, как с обычной переменной. Не обошлось, конечно же, и без ложки дегтя — мы не можем изменять переменную в нашей функции. А оно нам надо? В данном случае — нет, ну а если понадобится, то можно завести переменную в самой функции и скопировать ее туда. «Некрасиво», — скажешь ты. Может быть, зато очень эффективно — функция будет вызываться намного быстрее, если все переменные влезут в регистры (при условии юзанья фастколла). Ладно, лирику в сторону, поехали дальше.
Наверное, ты обратил внимание на qDebug(). Что это? Это поток для вывода отладочной информации в Qt (очень удобная вещь, между прочим).
Как только процесс завершается, начинает свою работу слот onAvFinished().
И снова введу тебя в курс дела: avs — это QMap из typedef QPair<QString, QString > QResultPair; Одна из важнейших функций в нашей софтине — parseOutput(). Как видно из названия, она парсит вывод антивируса при его завершении и выдает результат сканирования. Выглядит она так:
Тут происходит самый обыкновенный разбор строки. Если мы не находим какого-то ключевого слова — значит, ошибка. Если находим слово, соответствующее отрицательному результату (то есть, файл не заражен) — возвращаем ОК. Иначе — копируем вывод антивируса и возвращаем его. Вернемся к слоту onAvFinished(). После парсинга вывода мы пишем результат в файл в виде HTML-таблицы для удобного вывода в браузер. Все! Костяк сервиса создан. Встает вопрос: «А как на этом можно заработать»? На мой взгляд, есть два варианта:
ЗаключениеКак показала практика, самый напряжный момент в разработке — создание сайта. Ненавижу PHP! После понятного и логичного C++ разработка на PHP + Ajax подобна пытке, но в итоге использование в качестве Ajax-библиотеки Sajax, а SQL-базы SQLite решило все мои проблемы. На этом позволь свернуть мое краткое повествование и пожелать тебе удачной разработки. А будут вопросы — пиши. Мыла не указываю, поскольку настоящий хакер всегда и так сможет меня найти :).. «Слот» onAvFinished()
|