# Роль обратной разработки в понимании артефактов: когда документация — враг, а декомпилятор — друг Максим Суханов · CICADA8 MOSCOW FORENSICS DAY ’25 · День 2 — пятница, 12 сентября 2025: день информационной безопасности · По программе 13:45–14:15 · В записи 06:35:14–06:58:14 Расшифровка выступления · https://2025.moscow-forensics-day.workers.dev/transcript/15-sukhanov Саммари: https://2025.moscow-forensics-day.workers.dev/summary/15-sukhanov · Слайды: https://2025.moscow-forensics-day.workers.dev/slides/14-suhanov-obratnaya-razrabotka · Смотреть с 06:35:14: https://youtu.be/4V7Wez3L_58?t=23714 --- ## Подводка ведущего Не всегда можно понять в целом, кто тебе друг, а кто тебе враг. Причем друзья, как и враги, они бывают довольно неожиданными. Другом нашего следующего спикера стал декомпилятор, а врагом — документация. Как все это работает, расскажет нам Максим Суханов. Давайте поддержим его аплодисментами. *[аплодисменты]* Максим, вот тебе микрофон. Кликер что-то у нас немножко лагает, сейчас я проверю. Все, держи, пожалуйста, начинай. ## Доклад и вопросы Всем привет. Меня попросили как-то взбодрить аудиторию, поэтому пообещаю, что в течение доклада я ни разу не произнесу слово «бизнес». При ответе на вопрос я могу его произнести. Вот так я постараюсь сделать как-то менее душным доклад. Тема доклада, ну, вам известно, немножко о себе написано на слайде, то есть я занимаюсь реагированием на инциденты кибербезопасности, их расследованием, пишу различный софт для реагирования на инциденты и криминалистики, парсер NTFS, реестр, ну и так далее. Проблема. Проблема выражается в том, как может человек, судебный эксперт, такой идеальный пример, обосновать какую-то интерпретацию каких-то артефактов, следов или, еще хуже, аномалий. То есть есть что-то, что человек наблюдает, глядя на компьютерную информацию, и как ему объяснить, что там произошло. Есть в принципе два подхода, то есть мы видим какую-то временную метку, а что это за временная метка, мы ссылаемся на статью, книгу, документацию или иные чужие результаты, то есть мы говорим, что мы интерпретируем вот эти байты таким образом, почему мы это делаем, потому что вот есть другие результаты, то есть чей-то чужой опыт. Также мы можем сделать какой-то экспертный эксперимент и получить вот этот опыт самостоятельно. То есть интерпретацию какой-то временной метки можно найти самостоятельно. Я подчеркнул слово «документацию», потому что здесь в дальнейшем конкретно рассмотрим именно пример с документацией. Есть в нашей сфере ряд чатов в Telegram, где люди общаются, и где-то год назад была дискуссия по теме этого выступления моего. И был такой небольшой вывод, который я еще сократил, что если судебный эксперт скажет, что я доверяю документации, то в принципе можно как-то считать такой подход вполне справедливым в какой-то ситуации. Посмотрим, почему это проблема, а не решение. Вендоры, то есть производители программного обеспечения, то есть та же самая корпорация Microsoft, могут обманывать людей. Обманывать, естественно, в кавычках. Это не обман, который делается из злого умысла, а неправда, которая сообщается по каким-то иным причинам. Если мы откроем сайт Microsoft, документацию, посмотрим, как они описывают атрибут $STANDARD_INFORMATION в NTFS, то мы увидим, что там нет такого понятия, как временные метки. То есть мы видим объявление соответствующей структуры на языке C, мы видим текстовое описание и видим, что те места, которые используются под хранение временных меток, зарезервированы. Соответственно, вывод: если мы слепо доверяем документации, что временных меток в атрибуте $STANDARD_INFORMATION нет. Естественно, это такой экстремальный пример. То есть мы пытаемся опровергнуть первоначальный тезис, сведя его в абсурд, но в абсурд реальный. То есть тут понятно, что так быть не может. Также мы можем обратиться к аналогичной документации, к атрибуту $FILE_NAME и увидеть, что там кроме имени файла, длины имени файла и флагов ничего нет, никаких временных меток. Еще есть поле, которое ссылается на родительскую директорию у файловой записи. Опять же, это все не соответствует действительности. Это все обман. Но обман в кавычках, потому что у него есть так называемая уважительная причина. Вендор защищает служебные структуры от кривых ручек так называемых. То есть он сознательно скрывает часть внутренностей, внутренностей, которые есть в его операционной системе, чтобы туда не лезли те, кому не надо туда лезть. То есть программисту Васе Пупкину туда лезть не надо, пусть он черпает информацию из других источников. И в связи с этим, и судя по всему, только с этим, документация вымарывается, поэтому ненужные поля помечаются как зарезервированные. Это вот экстремальный пример, вот это вот, так сказать, наибольший абсурд, который можно было встретить. И аналогичного я привести, к сожалению, не могу. То есть это вот максимальный градус вот такого вот несоответствия действительности. Также вендор, который распространяет какой-то софт, может забыть, что его код уже давно поменялся и делает все не так. А документация в связи с этой забывчивостью не обновлялась. Вот уже, так сказать, наболевший пример. Вот есть теневые копии. Шифровальщики, когда шифруют какие-то данные, они обычно перед этим удаляют все теневые копии. Но в некоторых случаях, например, если шифрование инициировано по сети, через шары, теневые копии не удаляются. И они могут уцелеть. Если мы взглянем в такую теневую копию, то мы увидим, что во многих случаях, начиная с Windows 8, мы там вместо пользовательских документов, каких-то файлов с историей браузера и тому подобного, мы видим какую-то кашу из нулевых байтов. И этот эффект наблюдается довольно-таки часто. То есть люди, которые занимаются расследованием атак шифровальщика, они знают, что такое встречается. Если обратиться к документации, к сервису теневого копирования, то увидим, что такого происходить не должно. То есть теневые копии захватывают все занятое пространство файловой системы и исключить что-то пользовательское оттуда можно, но только через задание специального значения в реестре. А по умолчанию все должно туда включаться. Вот слева показан пример в hex-редакторе. Из текущего состояния файловой системы некий фрагмент истории браузера, Chrome, и снизу этот же файл, извлеченный из теневой копии. Сверху данные есть, то есть в текущем состоянии файловой системы данные есть, а из теневой копии данных нет. То есть все пространство забито нулевыми байтами. И ответ на эту загадку простой. Начиная с Windows 8, пользовательские файлы исключаются из теневой копии. Тут звездочка в конце. Поскольку теневое копирование происходит блоками с гранулярностью 16 килобайт, те самые, которые на 1024, а размер кластера по умолчанию 4 килобайта, то такие вот заходы на пользовательские файлы все-таки могут быть, поэтому часть пользовательских данных в теневых копиях все равно будет обнаружена. Это поведение никак не задокументировано и что самое, так сказать, прекрасное, компания Microsoft отвечала как минимум двум клиентам с объяснением этого поведения. То есть они говорили, что в одном случае у вас данные, которые пошифровал шифровальщик, нельзя восстановить, потому что пользовательские файлы не включаются в теневые копии. Спасибо, до свидания. Эти ответы были найдены в интернете уже в режиме, когда понятно, что было искать. То есть есть ключевое слово, оно называется scoped, scoped shadow copy, если полностью. То есть можно найти упоминание того, как кто-то сослался на ответ вендора в какой-то статье. Вот. И вот это поведение, оно совершенно, так сказать, внезапное для тех, кто пострадал. То есть, с одной стороны, теневые копии есть, согласно документации, там пользовательские файлы должны быть, то есть всякие Excel-документы и тому подобное, а в реальности, скорее всего, большая часть там не будет, если речь идет про Windows 8 и выше. Как это происходит? Сначала создается полная теневая копия, но поскольку копирование происходит в режиме copy-on-write, то есть реально данные не копируются в виде какой-то резервной копии, которая представляет собой теневую, до их изменения, то есть копирование происходит по мере изменения данных, то эта теневая копия не сразу содержит все то, что потом будет показано пользователю. И сразу после этого процесс srtasks.exe запускает весьма сложную процедуру, которая проходит по всему файлу MFT, ищет файловые записи, реконструирует их пути и по расширениям, ну и не только, исключает эти файлы в битмапе того, что подлежит копированию по мере изменения. То есть теневая копия при изменении пользовательских файлов не будет содержать старую версию измененных данных. И это касается только пользовательских файлов, системные файлы, всякие экзешники, дллки. Они будут скопированы и попадут в теневую копию именно в старом состоянии, как и требуется. Делается это для того, чтобы сократить размер теневых копий, поскольку сейчас теневые копии – это больше инструмент восстановления работоспособности, исправности операционной системы, чем инструмент резервного копирования. На серверных версиях Windows все не так, и там все работает как надо. То есть уменьшение, так сказать, скоупа копируемых данных в теневую копию, оно там не происходит, и вместо этого все как надо, все как Windows 7. Также бывает такая ситуация, что вендор документирует не ту реализацию файловой системы, которая у него есть. Если вернуться в 90-е, ну и в начало 2000-х, мы вспомним, что помимо Windows NT была еще ветка 95, 98 и Millennium. Эти ветки операционных систем — это разные семейства, это разный код. То есть люди, разработчики там разные, код разный, и какое-то пересечение не охватывает драйверы файловых систем. И именно тогда была разработана спецификация файловой системы FAT от Microsoft, которая теперь используется для форматирования файловых систем EFI System Partition. И эта спецификация, к сожалению, базируется именно на том коде, который был в Windows 95. Вот как ни странно. То есть этой спецификации драйвер FAT в Windows NT, Windows 10, 11, Windows XP, он не следует. И это порождает различные такие ситуации, когда разработчики сторонних драйверов файловой системы FAT, например, в Linux, они внезапно понимают, что те требования, которые, как сегодня говорят, обязательные требования, хотя требования вроде всегда обязательные, когда вот такие требования с самим вендором не соблюдаются, и в частности требуется в связи с этим модифицировать логику, например, проверки файловой системы на ошибки, чтобы не задетектировать ошибку там, где она по спецификации как будто есть, но на самом деле ошибки нет, если верить коду. Но это уже так немножечко душно. Другой кейс – это уже обман, который возник в связи с изменением заголовочных файлов втихую. То есть это обман на низком уровне. Это Prefetch. Вот скажите мне, кто знает, что хранится в файлах с именем такого формата? То есть OP, дефис, имя процесса, дефис что-то там, дефис еще что-то,.pf. Prefetch-файл, который в директории Prefetch находится. Ну, многие, наверное, не знают, потому что не часто с таким сталкиваешься, особенно не часто, когда там есть какие-то действительно значимые данные. Я попытался со всего интернета, в том числе из англоязычного сегмента, собрать гипотезы того, что может храниться в этом файле. Ну, их принципиально четыре. Самое, так сказать, будоражащее – это третья, потому что она происходит из обмана, так сказать, вот этого несознательного, из-за устаревания данных в заголовочных файлах, а все остальные – это уже, так сказать, отсебятина, это уже именно гипотезы, которые, так сказать, набрасываются. А третий — это, можно сказать, уже не просто гипотеза, а это уже и версия. Проблема в том, что всегда, уже очень давно, правильный ответ есть в блоге Microsoft про ASP.NET, но там этот артефакт упоминается вскользь, и такое упоминание в блоге навевает такую мысль, а не ошибка ли это, то есть упоминание вскользь, насколько оно релевантно, или может быть там все правильно, или нет. Потому что люди, которые пишут такие статьи, они могут все-таки ошибаться. Из блога ответ вот этот правильный выглядит так. То есть есть некие вызовы функции API Windows OperationStart, OperationEnd, в результате которых генерируется вот такой вот файл, который выделен желтым. Это так называемый Operation Based Prefetching. Из этого не следует, ну если как бы читать, тут не сделан акцент на то, что именно файл вот с таким форматом имени должен создаваться. То есть это проходит по тексту в виде такого смысла, но здесь на это внимание не акцентируется, что это именно так и это железобетонно. Но давайте попытаемся пойти самым сложным путем именно из кода. Если посмотреть, с чего вообще в таких случаях начинают. У нас есть шаблон имени файла, есть расширение, есть префикс, можно его поискать в исполняемых файлах внутри C:\Windows\System32. Просто эти строчки. Затем отсеять все лишнее. Поскольку с Windows поставляются отладочные символы, то мы будем знать, в каких функциях используются строки, которые мы найдем. И единственное вхождение, которое, так сказать, после отсеивания всего ненужного, это в ядре, файле ntoskrnl.exe. Ну и в других файлах, в зависимости от того, как скомпилировано это ядро, но в общем это там. Так, что-то все без моего участия. В общем, мы находим там шаблон такого имени, и это имя без расширения, с которым что-то делается. И вызов функции PfSnBeginScenario и за пределами этой ветки кода PfSnEndProcessTrace. Что это такое? Откуда вызывается вот эта функция, код которой приведен в декомпиляторе? Он вызывается из функции PfSnSetPrefetcherInformation, если в качестве аргумента передается некий параметр, значение которого равно 5. И эта функция называется, которая показана на предыдущем слайде, PfSnOperationProcess. То есть у нас есть некий prefetcher, он имеет некоторую функцию. Если мы в вызов этой функции передадим аргумент, который равен 5, этот аргумент называется, его поле называется PrefetcherInformationClass, то у нас происходит создание вот такого файла, и в него что-то записывается. Вопрос. Что значит вот эта пятерка? Вот это какая-то константа, смысл которой непонятен. И если это все гуглить, на GitHub есть проект Process Hacker. Туда вливают заголовочные файлы из SDK Windows. То есть все, что опубликовано на сайте Microsoft для разработчиков, туда вливается вместе с какими-то результатами обратной разработки со стороны сообщества. Вот конкретно эти константы, скорее всего, были взяты из старых заголовочных файлов Microsoft, на это указывает ряд признаков, в том числе характер, так сказать, именования, но этот SDK, скорее всего, уже больше недоступен, то есть эти сведения были получены из какой-то такой вот давнишней версии SDK, комплекта заголовочных файлов для разработчика, которые сейчас не опубликованы. И проблема в том, что константа, которая равна 5, называется PrefetcherBootControl. Именно отсюда, кто-то посмотрел, где вызывается функция, которая создает файл с именем такого формата, посмотрел, что значит константа равная 5, увидел, что она называется PrefetcherBootControl. И в связи с этим в ряде документаций в интернете, не от Microsoft, есть такое упоминание, что файлы Prefetch, OP, дефис, что-то там,.pf, они создаются во время загрузки. Это какой-то загрузочный Prefetch, который загружает какие-то страницы до того, как они будут прочитаны. Но проблема в том, что это не актуальное название, то есть в данном случае заголовочный файл не соответствует коду. То есть вот эта полудокументация, полу что-то другое, оно не актуально. Оно было когда-то актуально, но сейчас все переделали. Это я назад переключился. Если перейти уже к методу тестирования черным ящиком, то есть мы знаем, какие функции отвечают за создание этих файлов, OperationStart, OperationEnd. Если мы на питоне набросаем обертку для всего этого, то увидим, что никакого отношения к загрузке, к процессу загрузки операционной системы здесь нет. То есть эти файлы Prefetch, которые создаются, они создаются при вызове просто нужных функций, и процесс загрузки вообще никаким боком здесь не стоит рядом. Можно некоторые закономерности выбрать, вытащить из результатов тестирования черным ящиком путем просмотра кода в декомпиляторе, что, во-первых, эта трасса создается при вызове этой функции, завершается при вызове OperationEnd функции, при этом в рамках одного процесса может в один момент времени создаваться только одна трасса, и если там не менее 32 запросов ввода-вывода, то результаты не сохраняются, считается, что тут нечего префетчить. Но если напоминать, как работает Prefetch, он смотрит, к каким файлам обращается программа при запуске или после вызова функции OperationStart и предварительно загружает эти файлы в память, чтобы эти данные уже находились в оперативной памяти, когда потребуется их прочитать, чтобы не было лага из-за того, что у нас программа читает очень медленно файлы, а нам данные нужны гораздо быстрее. Поэтому Windows со стороны ядра эти данные подгружает заранее. То есть 32 запроса, page fault так называемый, если они происходят, то трасса сохраняется, и при следующем вызове функции OperationStart эти данные будут подгружены в память ядром. Вот прямо из этих файлов. По тексту доклада был ряд ссылок обозначен. Вот я честно на все ссылаюсь, то есть вот здесь вот под номером 4 это статья, которую удалось найти про то, почему в теневых копиях нет пользовательских файлов, и там есть ссылка на ответ со стороны Microsoft. То есть люди озадачились по результатам расследования инцидента с шифровальщиком вопросом вот этим, почему нет пользовательских данных, когда теневые копии остались. И они это все опубликовали, но в интернете это найти сложно. То есть надо знать, что искать. Надо знать, что процесс называется scoped, scoping. Вот. Различные… Ну, вот так вот. В общем, надеюсь, хоть что-то было понятно. Спасибо за внимание. Готов ответить на вопросы. *[аплодисменты]* — Зато было по-честному. Ни разу не сказал слово «бизнес». Итак, коллеги, ваши вопросы. Мне кажется, ты опять сломал мне аудиторию. Если вопросов нет, Максим, большое спасибо. Это было круто. Максим остается еще здесь. В целом можно будет у него что-то спросить.