Как читать файлы .evtx без машины с Windows

Журналы событий путешествуют: с изъятого ноутбука, из образа диска, экспортированные клиентом, чей сервер уже пересобран. Прибывает файл .evtx, а инструмент, который его открывает, — Просмотр событий — существует только в Windows и формирует половину того, что вы видите, из DLL на машине, записавшей журнал. Это руководство рассказывает, что файл .evtx содержит на самом деле, как провести его первичную сортировку где угодно с помощью локального в браузере просмотрщика EVTX, и о четырёх идентификаторах событий, которые отвечают на большинство первых вопросов.

Журнал никогда не находится на той машине, за которой вы сидите

Схема всегда одна и та же. Что-то произошло — подозрение на компрометацию, шквал блокировок, служба, умершая в 03:00, — и улика — это журнал событий Windows, который кто-то экспортировал, снял образ или скопировал с машины, которую вы не можете загрузить, в которую не можете войти или которую вам не разрешено трогать. Ваша собственная машина — это Mac, рабочая станция с Linux или заблокированный корпоративный ноутбук без виртуальной машины с Windows на горизонте. Просмотр событий на помощь не придёт.

Хорошая новость в том, что файл .evtx — это документированный, самодостаточный бинарный формат. Всё, что Просмотр событий показывает вам о записи, — за одним важным исключением, разобранным ниже, — находится внутри файла, и надлежащий парсер может прочитать его где угодно. Просмотрщик EVTX на этом сайте запускает такой парсер (крейт evtx на Rust, скомпилированный в WebAssembly) в вашей вкладке браузера, потому что журналы событий называют пользователей, машины и IP-адреса и их не следует загружать на случайный сайт-конвертер в той же мере, в какой не следует загружать захват пакетов. Дальше — рабочий метод, а не инструкция к инструменту: на что смотреть, в каком порядке, и что поля вам расскажут, а что — нет.

Что на самом деле находится внутри файла .evtx

Файл .evtx — это заголовок в 4096 байт, за которым следует последовательность блоков по 64 KB. Каждый блок содержит серию записей событий, а каждая запись хранится как бинарный XML (BinXML): блок System, который заполняет операционная система, плюс собственная полезная нагрузка поставщика в виде EventData или UserData. Откройте одну запись — и вы найдёте поля, а не прозу: EventID 4625, метку времени, канал и именованные значения вроде IpAddress, TargetUserName и LogonType. Эти поля и есть улика. Они же — всё, что парсер на чужой машине может вам честно дать.

Вот это исключение, и оно определяет всё остальное в этом руководстве: предложение, которое показывает Просмотр событий, — «Учётной записи не удалось войти в систему» — в файле отсутствует. Windows формирует его в момент просмотра из DLL сообщений, которые принадлежат каждому поставщику и живут на машине, записавшей журнал. Именно поэтому значения данных иногда выглядят как %%14592: это ссылки в таблицу сообщений, которой файл с собой не несёт. Просмотрщик на другой машине может показать вам каждое поле, которое событие записало, и его необработанный XML ровно в том виде, в каком он хранится, — но инструмент, который преподносит отполированный текст сообщения для чужого файла .evtx, реконструирует его из собственных копий DLL или угадывает. Сначала поля, в последнюю очередь проза — таков честный порядок.

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

Начните с блока System

Блок System каждой записи несёт один и тот же каркас: Provider (какой компонент её записал), EventID (что произошло, в нумерации этого поставщика), Level (от 1 — Критический — до 5 — Подробный, с 0 для событий без уровня), Channel (Security, System, Application и сотни операционных журналов под Microsoft-Windows-*), Computer, метку времени в UTC и EventRecordID. Первичная сортировка начинается с раскладывания всего журнала по этому каркасу: сколько записей, за какой временной диапазон, из каких каналов, с преобладанием каких идентификаторов событий. Журнал «Безопасность», на 80 % состоящий из одного идентификатора события, обычно рассказывает историю об одной вещи — о межсетевом экране, принимающем решения, о службе, аутентифицирующейся в цикле, — и сводка расскажет вам об этом до того, как вы прочитаете хоть одну запись.

Ссылайтесь на EventRecordID из блока System, когда упоминаете запись. Файлы, которые были вырезаны, отобраны или переэкспортированы, могут иметь заголовки записей, перенумерованные инструментом, который их произвёл, в то время как блок System сохраняет идентификатор, который машина присвоила изначально, — разница между «записью 7 из этого отрывка» и «EventRecordID 319457858 в исходном журнале» становится важной в тот момент, когда кто-то попытается воспроизвести ваш вывод. Метки времени заслуживают той же аккуратности: внутри файла они всегда в UTC. Просмотр событий преобразует их в местное время той машины, которая открывает журнал, и именно поэтому два снимка экрана одной записи могут расходиться на часы. Выберите UTC для отчёта и скажите об этом.

Четыре идентификатора событий, которые окупают себя

1102 — журнал аудита был очищен. Журнал «Безопасность» записывает собственное стирание как первое событие в новом журнале. Его поля называют пользователя, который его очистил. При инциденте событие 1102 — одновременно улика и граница: всё, что было до него в этом журнале, из имеющегося у вас файла исчезло, а сама очистка — факт, достойный строки в отчёте. Если самая ранняя запись журнала — это 1102 с меткой времени внутри вашего окна интереса, скажите об этом до того, как кто-то построит теорию на отсутствии более ранних событий.

4624 и 4625 — входы в систему, успешные и неудачные. Это рабочие лошадки расследований по учётным записям. Поля, которые имеют значение, — это TargetUserName, IpAddress и прежде всего LogonType: 3 — сетевой вход, 10 — удалённый рабочий стол, 2 — интерактивный вход с консоли, 7 — разблокировка. Схема перебора паролей читается как шквал событий 4625 против одной учётной записи с одного адреса, за которым следует — момент, который имеет значение, — событие 4624. Одно событие 4625 — это опечатка; сигналом является форма последовательности, и именно поэтому вы фильтруете и считаете, а не прокручиваете.

4688 — был создан процесс. Когда политика аудита это записывает, каждое событие 4688 называет новый процесс (NewProcessName), учётную запись, которая его запустила, и часто родительский процесс — сырьё для вопроса «что работало на этой машине и когда». Две оговорки сохраняют вашу честность: событие 4688 существует только если на исходной машине был включён «Аудит создания процессов» (его отсутствие ничего не доказывает о том, что работало), а захват командной строки — это ещё и отдельная настройка. Относитесь к богатому следу 4688 как к подарку, а не как к положенной норме.

Эти четыре — стартовый набор, а не учебный план: родственное событие специального входа 4672 для 4624, вход с явными учётными данными 4648 и установка службы 7045 в журнале «Система» — обычные следующие остановки. Но замечательная доля вопросов первого дня — был ли журнал стёрт, кто вошёл, откуда и что они запустили — отвечает одними лишь событиями 1102, 4624, 4625 и 4688.

Чего поля рассказать не могут

Дисциплина в отношении отсутствия — это большая часть работы с журналами. Файл не может показать вам события, которые исходная машина никогда не записывала: политика аудита решает, что существует, а машина с настройками по умолчанию протоколирует куда меньше, чем надеется следователь. Он не может показать вам текст сообщения, как разобрано выше, — ссылка %% — это указатель на строку на машине, которой у вас нет. Он не может сам по себе доказать ни вмешательство, ни его отсутствие: разрывы в идентификаторах записей появляются и в честных вырезанных файлах, и в очищенных, и именно поэтому опираться следует на явную запись 1102, а не на разрыв.

И журнал — это один свидетель. Метки времени берутся с часов исходной машины, которые могли идти неверно; учётные записи фигурируют под именами, которые машина знала; IP сетевого входа — это адрес, который машина видела, включая NAT и VPN. Поля — это ровно то, что машина записала, — не меньше, и дисциплина состоит в том, чтобы помнить: не больше.

Пятиминутная процедура первичной сортировки

Первая минута: откройте файл в просмотрщике EVTX и прочитайте сводку до любой записи — общее количество, временной диапазон, каналы и главные идентификаторы событий. Отметьте все блоки, которые просмотрщик сообщает как нечитаемые, с их смещениями; эта оговорка принадлежит вашим заметкам с самого начала, а не сноске в конце.

Вторая минута: проверьте событие 1102. Если журнал был очищен, весь ваш подход меняется, а время очистки и учётная запись — ваши первые твёрдые факты. Третья минута: отфильтруйте 4625 и посмотрите на форму — количество по учётным записям, по адресам источников. Шквал, за которым следует 4624 для той же учётной записи с того же адреса, — это и есть вывод; отметьте точные метки времени. Четвёртая минута: зафиксировав подозрительное окно, отфильтруйте 4688 (и 4624 с типом 10, если под вопросом удалённый доступ) внутри этого окна и перечислите, что работало и кто входил. Пятая минута: экспортируйте отфильтрованные записи как JSON или CSV и напишите абзац, пока цифры перед вами, — идентификаторы записей, время в UTC, учётную запись, адреса. Экспорт — ваш рабочий документ; абзац, с оговоркой о нечитаемых блоках и пределе текста сообщений, — результат.

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

Часто задаваемые вопросы

Я экспортировал журнал из Просмотра событий как CSV или XML. Могу ли я прочитать это вместо него?

Эти экспорты — другая, меньшая вещь. Экспорт в CSV уплощает каждое событие до столбцов, которые Просмотр событий случайно показал, и выбрасывает большую часть структурированных EventData — полей, с которыми первичная сортировка на самом деле работает. Если у вас ещё есть доступ к источнику, переэкспортируйте командой «Сохранить все события как…» и выберите .evtx; если всё, что у вас есть, — это CSV, электронная таблица расскажет вам о нём больше, чем любой инструмент для .evtx, потому что в структурированном смысле это больше не журнал событий.

Почему метки времени здесь отличаются от снимка экрана, сделанного в Просмотре событий?

Потому что Просмотр событий преобразует. Метки времени внутри файла .evtx хранятся в UTC; Просмотр событий показывает их в местном времени машины, открывающей журнал. Одна и та же запись может честно выглядеть отстоящей на часы в двух инструментах. Просмотрщик на этом сайте остаётся в UTC и помечает столбец соответствующим образом, и рабочее правило для отчётов то же: указывайте UTC, называйте пояс и никогда не смешивайте оба в одной хронологии.

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

Одни разрывы этого не доказывают. Записи пропадают по будничным причинам — блоки, повреждённые на умирающем диске, файл, вырезанный из незанятого пространства, экспорт, выбравший подмножество, — а вырезанные файлы могут даже иметь перенумерованные заголовки, в то время как блоки System сохраняют исходные идентификаторы. Намеренная очистка оставляет собственную запись: событие 1102, записанное как первая запись нового журнала «Безопасность» и называющее учётную запись, которая его очистила. Ищите его, прежде чем делать выводы из отсутствия.