Доверяй, но проверяй: детальный анализ отчёта VirusTotal на примере Lagoscope

Прокомментировать Просмотры: 4

Привет, SE7EN!

В последнее время я работаю над пет-проектом Lagoscope — приложением, которое помогает обнаруживать лаги в играх и разбираться в их причинах. Задумка проста: с минимальной нагрузкой на компьютер собрать телеметрию игровой сессии, найти проблемные эпизоды и сопоставить их с состоянием системы в тот же момент. Для этого проект разделён на две части:

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

  2. Сервер — работает на удалённой машине и берёт на себя ресурсоёмкую часть: принимает сырые данные, анализирует их, обнаруживает проблемные эпизоды, сопоставляет их с возможными причинами и готовит подробный отчёт.

Небольшое пояснение, которое поможет понять некоторые решения. Клиент распространяется через интернет и не подписан сертификатом издателя: подпись стоит денег, а проект, возможно, кроме меня никому не пригодится. При этом мне не хотелось с каждым обновлением заново нарабатывать репутацию в Windows SmartScreen. Без подписи она, по сути, привязана к хешу исполняемого файла. Поэтому я выбрал распространённую схему, которую используют, например, Chrome и Steam: пользователь скачивает с сайта загрузчик, хеш которого мы стараемся не менять, а тот загружает и устанавливает свежую версию клиента.

Я понимал, что пользователь не обязан на слово доверять случайному .exe из интернета без подписи и репутации. Поэтому с самого начала включил в процесс сборки автоматическую проверку на VirusTotal: каждая версия собиралась, упаковывалась в установщик через Inno Setup и отправлялась в VT. Программа запрашивает права администратора, работает в фоне и передаёт данные в интернет, поэтому без срабатываний обойтись было сложно. Я установил порог в пять детектов примерно из 70 доступных проверок: если он не превышен, новая версия публикуется для скачивания, существующие клиенты получают её через автообновление, а на сайте появляется ссылка на отчёт.

В итоге я собрал проект, опубликовал его и рассказал о нём на DTF — ресурсе, который показался мне наиболее подходящим по тематике. Ожидаемо в комментариях появились вопросы о безопасности клиента, и я написал вторую статью. В ней я вкратце изложил сказанное выше, описал устройство клиента и пообещал подробно разобрать отчёт VirusTotal, чтобы по возможности развеять сомнения.

Ещё немного об устройстве клиента. О загрузчике я уже рассказал: он получает установщик последней версии, а тот распаковывает четыре необходимых компонента:

  • Сам клиент, на который приходится основная работа.

  • PresentMon — утилита Intel, доступная на GitHub. Она предоставляет данные о кадрах, из которых рассчитываются frame time и FPS, а затем выявляются лаги. Версия утилиты зафиксирована, её хеш можно проверить.

  • Два вспомогательных компонента — DPC sidecar и ADLX helper — используются для работы с драйверами и задержками.

Подробности есть в оригинальной статье «Поговорим о безопасности Lagoscope».

Что пошло не так

Когда я взялся за обещанный разбор отчёта, обнаружились две неприятные детали:

  1. Пользователь скачивает с сайта загрузчик, а на проверку отправляется установщик. Это разные приложения с разными хешами. В результате для загрузчика отчёта нет, а хеш установщика пользователь не может проверить заранее.

  2. Установщик собирался в Inno Setup с включённым сжатием. Получалось, что проверке фактически доступен стандартный стартовый модуль Inno Setup: десять из одиннадцати секций совпадают с официальным SetupLdr.e32. Остальные 74,2% файла занимает оверлей с полезной нагрузкой клиента, но он сжат, его энтропия составляет 7,99992, и внутри теоретически может оказаться что угодно.

Посмотрев на результат, я решил изменить процесс выпуска. Теперь в VT отдельно отправляются:

  • Загрузчик — файл, который пользователь получает с сайта и хеш которого может самостоятельно сверить.

  • Установщик, скачиваемый загрузчиком. Он доступен и по прямой ссылке, например lagoscope.app/releases/0.0.12/Lagoscope-Setup-0.0.12.exe, поэтому его можно получить без загрузчика и до запуска сравнить хеш с отчётом. Кроме того, установщик теперь собирается без сжатия: размер вырос, зато его содержимое стало доступнее для проверки.

  • Сам клиент Lagoscope — приложение, которое запускает пользователь.

  • Два вспомогательных компонента, которые входят в комплект и при необходимости запускаются в фоне.

PresentMon я отдельно сканировать не стал: это сторонняя утилита известной компании, доступная из открытого источника.

Компоненты Lagoscope
Компоненты Lagoscope

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

Отчет VirusTotal по каждому компоненту на сайте
Отчёты VirusTotal по отдельным компонентам на сайте

На этом предыстория заканчивается, и можно перейти к главному: подробно изучить один из отчётов VT и разобраться, какие сведения он даёт и на что стоит обращать внимание. В качестве образца я выбрал исполняемый файл клиента Lagoscope. Именно он выполняет основную работу, обращается к сети и собирает метрики, но, в отличие от установщика с Inno Setup, не содержит сторонних программ. Впрочем, описанный подход применим к любому отчёту. Разбор получился длинным и технически подробным, поэтому я принёс его на SE7EN, а не на DTF. Посмотрим, что содержится в отчёте.

Что мы проверяем?

Хедер отчета VirusTotal
Шапка отчёта VirusTotal

Прежде всего нужно убедиться, что отчёт относится именно к нужному файлу. Допустим, клиент уже скачан и установлен, а в папке программы лежит lagoscope-client.exe версии 0.0.12. Выполним команду:

> Get-FileHash lagoscope-client.exe

Она покажет SHA-256 хеш файла. Его нужно сравнить со значением в отчёте. Для этой версии оно равно 662c4135c48df8440b1e4ed9227330f06e366825299fa5ea723698b68179392d. Совпадение подтверждает, что отчёт относится к проверяемому файлу, хотя само по себе не доказывает его безопасность.

В шапке также есть поле Last Analysis Date — дата последней проверки. VirusTotal может периодически проверять файлы повторно, поэтому результаты со временем меняются. В статье приведены данные, актуальные на момент её написания.

Detection — результаты антивирусов

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

  • Gridinsoft (GridinSoft LLC) — украинская компания из Киева, разработчик Gridinsoft Anti-Malware. Участвует в VirusTotal с октября 2020 года.

  • Trapmine — эстонская компания из Таллина. Её продукт защищает рабочие станции (EDR/EPP) и, согласно описанию, использует машинное обучение.

Крупные и широко известные поставщики в списке не сочли файл опасным; сработали продукты двух небольших компаний. Это не повод игнорировать их выводы, но основание рассмотреть результаты критически.

Теперь посмотрим на сами названия обнаруженных угроз:

  • Trojan.Heur!.02016023

  • Malicious.moderate.ml.score

Обе метки обобщённые и не указывают на конкретный известный вирус. Первая содержит Heur, что указывает на эвристическое обнаружение, и номер, вероятно обозначающий правило срабатывания. Во второй есть ml.score: по всей видимости, модель машинного обучения присвоила файлу достаточно высокий показатель подозрительности.

Мы знаем, что программа собирает сведения о компьютере в фоне и отправляет их в интернет. Такое поведение действительно может напоминать действия трояна. Поэтому сами срабатывания объяснимы, хотя в данном случае я считаю их ложными.

Details — устройство файла

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

Basic properties

Здесь собраны свойства, хеши и другие сведения об exe-файле. В частности:

TrID: Rust Windows 64bit Executable (97%) Win64 Executable (generic) (1%) Win16 NE executable (generic) …

DetectItEasy: PE64 Compiler: Rust (x86_64-pc-windows-msvc) Compiler: Microsoft Visual C/C++ (19.36.36260) [C] Linker: Microsoft Linker (14.36.36260)…

В основном это Rust, дополненный инструментами Microsoft. Всё соответствует ожиданиям.

History

Здесь внимание привлекает неожиданная дата создания файла — далеко в будущем.

Creation Time 2102-08-07 19:41:41 UTC

На самом деле ничего необычного в этом нет. Если при компиляции записывать реальное время создания, хеш будет меняться при каждой пересборке. Чтобы этого избежать, используется флаг линкера /Brepro: вместо времени в соответствующее поле помещается стабильное значение, зависящее от содержимого файла.

Sections

Exe-файл состоит из секций с разным содержимым: в .text находится код, в .rdata и .data — данные, в .rsrc — значки и другие ресурсы. Windows работает с ними по-разному: например, код можно выполнять, а данные — читать или изменять.

Секции внутри exe клиента
Секции исполняемого файла клиента

Обратим внимание на столбец Entropy. Энтропия измеряет «случайность» байтов по шкале от 0 до 8: чем значение ближе к верхней границе, тем больше данные напоминают сжатые или зашифрованные. Для обычного исполняемого кода характерно значение около 6. Вспомним число 7,99992 из начала статьи: данные выглядели почти случайными, что заслуживало внимания.

Здесь значения в основном не превышают 6,44 и выглядят естественно. Исключение — секция .rsrc с энтропией 7,4. Но в ней находятся ресурсы, включая PNG-иконки, а этот формат использует сжатие, так что значение объяснимо.

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

Imports

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

OpenProcess, CreateToolhelp32Snapshot, GetProcessTimes, GetProcessIoCounters

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

EnumWindows, GetWindowTextW

Получение списка окон для ручного выбора игры. Читаются только владелец окна и его заголовок

CryptProtectData

Шифрование токена устройства

winhttp, secur32, Cert*

Сетевое взаимодействие и TLS для передачи данных

Icmp*, wlanapi, CM_Register_Notification, pdh

Пинг, Wi-Fi, USB и системные счётчики

Стоит отметить и отсутствующие импорты: WriteProcessMemory, ReadProcessMemory, CreateRemoteThread, VirtualAllocEx, SetWindowsHookEx, GetAsyncKeyState. Это согласуется с тем, что клиент не вмешивается в чужие процессы и не отслеживает нажатия клавиш, хотя один только список импортов не даёт полной гарантии.

Contained Resources by Type

В ресурсах перечислены десять иконок, две группы и манифест.

Relations

Здесь показаны связи клиента Lagoscope с другими объектами в базе VirusTotal: адреса, домены и IP, к которым он обращался в песочнице, его составные части и созданные файлы.

Contacted URLs, Contacted Domains, Contacted IP addresses

Все три адреса, к которым обращался клиент, принадлежат домену lagoscope.app. Через них приложение получает текущую конфигурацию сервера — сведения об обновлениях, актуальной версии и доступных возможностях, — регистрирует устройство по токену и передаёт данные. У каждого адреса ноль срабатываний из 93 проверок: в сомнительной активности они замечены не были. Коды ответа 401 и 404 могут насторожить, но объясняются тем, что клиент использует веб-сокеты, а сканер отправлял обычные HTTPS-запросы. Для /ingest к тому же требуется токен, поэтому возвращается 401.

В разделе Domains указаны lagoscope.app и atm.teams.mira.tm.svc.cloud.microsoft. Второй адрес не связан с клиентом и, скорее всего, относится к фоновой активности песочницы.

Ниже перечислены IP-адреса. Один принадлежит серверу Lagoscope, остальные относятся к подсети Microsoft.

Bundled Files, PE Resource Children

Здесь, по сути, представлены те же части exe-файла, которые мы видели в разделе Sections: код, данные и манифест. Любопытная деталь: секцию .fptable VirusTotal распознал как ISO-образ, хотя она занимает 512 байт и полностью состоит из нулей.

Behavior

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

В нашем случае программу запускали в четырёх песочницах. В категориях Detections, IDS Rules (правила сетевого трафика) и Sigma rules (правила системных событий) указаны нулевые значения. Зато есть Mitre Signatures. MITRE — американская некоммерческая организация, которая поддерживает известные базы в области кибербезопасности. Здесь речь идёт о MITRE ATT&CK — открытом каталоге приёмов злоумышленников. Список оказался довольно длинным. Я собирался разобрать только сигнатуры уровня Medium, но столкнулся с вопросами, на которые не нашёл ответа.

Сводка по запуску в песочницах
Сводные результаты запуска в песочницах

В сводке указаны четыре сигнатуры Medium, однако в подробной таблице с соответствующим фильтром видны только две техники, причём одна входит в состав другой. Речь идёт о Timestomp (Indicator Removal) — подмене дат создания или изменения файла. Злоумышленники используют её, чтобы замаскировать свои файлы среди системных и затруднить их обнаружение по дате. Но в коде клиента нет мест, где изменяются даты файлов. При этом импорт SetFileTime присутствует: он пришёл из стандартной библиотеки Rust.

Скрытый текст

В Rust 1.99 функция открытия файла File::open после CreateFileW вызывает SetFileTime, но только если при открытии задан флаг, запрещающий обновлять дату последнего доступа или записи. Эти флаги экспериментальные, а клиент собирается стабильной версией Rust 1.99 и не может их включить. В коде клиента они тоже не используются. Однако параметры открытия хранятся в обычных полях структуры, поэтому компилятор не может доказать, что флаги всегда отключены. В результате ветка с SetFileTime остаётся в исполняемом файле, а функция — в списке импортов.

В сетевом блоке новой информации нет: всё это мы уже видели. Зато в разделе Memory Pattern Domains есть несколько интересных записей. Здесь перечислены домены, найденные сканером в памяти процесса, а не обязательно адреса, к которым программа обращалась. Помимо знакомого lagoscope.app, видим:

  • *.lencr.org — служебные адреса из сертификата Let’s Encrypt. Они оказываются в памяти клиента при установке TLS-соединения.

  • basement.studio — сначала этот адрес меня удивил, но объяснение нашлось. В клиенте используется шрифт Geist, а в его лицензии есть строка «Vercel, in collaboration with basement.studio». Иными словами, это метаданные шрифта.

  • http://127.0.0.1 — в клиент встроен небольшой сервер для работы с GSI: с его помощью игра сама сообщает о происходящем внутри неё. Такая возможность есть, например, в Dota 2 и включается флагом -gamestateintegration. Lagoscope может использовать эти сведения, чтобы сопоставлять падения FPS с игровыми событиями — скажем, напряжёнными сражениями с множеством эффектов, стадией матча и точным временем. Мне кажется, это перспективная возможность, поэтому я планирую развивать её и расширять список поддерживаемых игр.

Раздел файловых операций показывает, что клиент читал и куда записывал данные. Чтение ограничилось файлами из собственной папки приложения и файлами библиотек, запись — папкой приложения. На диск сохранялись токен устройства, конфигурация сервера и буферы перед отправкой данных. Среди удалённых файлов встречаются .tmp: это следствие обычной схемы записи, когда данные сначала помещаются во временный файл, а затем он переименовывается. Интересен и раздел Files Dropped — файлы, оставленные программой в системе. Он помогает заметить, например, загрузчики вредоносного ПО, которые скачивают и сохраняют исполняемые файлы. В нашем случае там находятся только данные приложения.

В реестре было открыто 204 ключа, но ни в один из них запись не выполнялась. Согласно коду, сам клиент читает только HKCU\Software\Valve\Steam, чтобы найти игру в библиотеке Steam. Остальные обращения выполняет Windows при запуске приложения: они связаны с кодеками изображений, сетью, отрисовкой, проверками совместимости и другими системными задачами.

Дочерних процессов клиент не создавал. Впрочем, в обычных условиях он запустил бы PresentMon для подсчёта кадров. В песочнице утилиты рядом не оказалось, поэтому запускать было нечего. Также видны связанные процессы wmiprvse.exe и wmiadap.exe — компоненты Windows Management Instrumentation, через которую клиент получает значительную часть сведений о состоянии системы. Есть и %TEMP%\ACQ65R5UXFHBE896.exe: точно сказать, что это, я не могу. Предположительно, одна из песочниц присвоила самому клиенту временное имя.

Остались детали вроде мьютекса Local\Lagoscope-client, который не позволяет запустить второй экземпляр приложения, и записей Highlighted actions: RtlWow64GetCurrentMachine и RtlWow64IsWowGuestMachineSupported. Они относятся к проверке архитектуры процессора. В импортах клиента этих функций нет — при запуске их вызывает сама Windows.

Выводы

Мы полностью прошли отчёт по клиенту Lagoscope: явных опасных признаков в нём не обнаружилось, а необычным деталям нашлись объяснения. Но важнее другое: теперь у вас есть краткий план чтения отчётов VirusTotal. В шапке стоит сверить хеш и дату проверки, в Detection — изучить не только количество срабатываний, но и их источники и названия, в Details — проверить энтропию и импорты, в Relations — сетевые связи, а в Behavior — действия программы в песочнице.

Как читать отчет VirusTotal
Как разбирать отчёт VirusTotal

И напоследок: ни один отчёт не гарантирует безопасность программы. Он лишь помогает узнать о ней больше, не запуская её на своём компьютере. Решение остаётся за вами, но принимать его можно уже не вслепую.


Спасибо, что дочитали этот лонгрид. Если появились вопросы, задавайте их в комментариях — постараюсь ответить каждому. А если хотите помочь с тестированием Lagoscope или предложить идеи для развития проекта, тоже пишите либо присоединяйтесь к обсуждению в телеграм-канале. Там я планирую делиться новостями разработки и собирать обратную связь.

 

Источник

Похожие статьи

Поиск по играм, новостям и статьям…

Введите не менее двух символов

Введите не менее двух символов