PDF Stream Dumper помогает разобрать подозрительный PDF по объектам, декодировать сжатые потоки, найти JavaScript, вложения и действия запуска, а затем проверить извлечённый код средствами деобфускации, шестнадцатеричного просмотра и анализа shellcode.
Работа начинается с загрузки копии исследуемого документа в поле PDF Path или перетаскивания файла в окно. Слева появляется перечень обнаруженных объектов и потоков, справа открываются представления Text, HexDump и Stream Details, а нижние вкладки Errors, Search и Debug показывают ошибки разбора, результаты поиска и диагностические сообщения.
Практический порядок таков: сначала оценить цветовые метки и счётчики подозрительных сущностей, затем отфильтровать JavaScript, действия, шрифты или внедрённые данные, сохранить нужные потоки отдельно и только после этого переходить к запуску декодеров либо эмуляторов. Такой маршрут уменьшает число ручных операций и помогает не смешивать содержимое разных объектов.
Скачать PDF Stream Dumper
- Редактирование PDF
- Русский интерфейс
- Просто новичкам
- Только Windows
- .NET нужен для фильтров
- Неполный разбор PDF
Как устроено главное окно
Основное окно разделено на три рабочие зоны. Слева располагается список объектов PDF: каждая строка соответствует найденному заголовку объекта или потоку, а выделение строки немедленно обновляет содержимое правой части. Верхняя правая область предназначена для просмотра выбранного элемента, нижняя — для служебных сообщений и поиска. Поэтому переход между объектами не требует открывать отдельные окна или каждый раз сохранять данные во внешний файл.
Поле PDF Path принимает путь к документу. Рядом находятся кнопки Load и Abort: первая запускает разбор, вторая останавливает длительную обработку. Остановка полезна для повреждённых файлов, документов с большим числом вложенных потоков и образцов, в которых намеренно указаны некорректные длины. После прерывания следует закрыть файл, сделать новую копию и повторить загрузку с отключёнными декомпрессорами, если зависание возникло именно на распаковке.
Вкладка Text показывает текстовое представление заголовка или распакованного потока. HexDump выводит байты шестнадцатеричными значениями вместе с печатной областью, что удобно для поиска сигнатур исполняемого кода и проверки реального начала файла. Stream Details собирает сведения о фильтрах, длине и состоянии декодирования. Переключение между этими вкладками помогает отделить структуру объекта от его полезной нагрузки.
Нижняя вкладка Errors содержит сообщения о нераспознанных фильтрах, ошибках декомпрессии и проблемах с зашифрованными объектами. Search хранит результаты поисковых команд, а Debug показывает технический ход обработки. При разборе сложного образца полезно сначала сохранить содержимое Errors, потому что оно объясняет, почему отдельный поток отображается в сыром виде или не попал в результаты поиска.
Загрузка подозрительного документа без лишнего риска
Исследуемый PDF следует копировать в отдельный каталог, где нет рабочих документов и учётных данных. Программа извлекает и, по команде пользователя, может передавать содержимое внешним компонентам, поэтому безопасная схема предполагает изолированную виртуальную машину, отключённые общие папки и отдельный снимок состояния. Простого открытия файла в анализаторе обычно недостаточно для выполнения встроенного сценария, однако дальнейшие действия с JavaScript и shellcode уже могут создавать риск.
Перетаскивание файла в поле пути экономит время, но перед этим нужно убедиться, что системный проводник не формирует миниатюру через уязвимый обработчик. В лаборатории лучше использовать каталог с отключённой областью предварительного просмотра. После загрузки не открывайте образец в обычной программе чтения PDF, пока не изучены действия /OpenAction, /AA, /Launch и внедрённые файлы.
Если документ получен из почты или сжатого пакета, сохраните исходное имя и контрольную сумму отдельно. PDF Stream Dumper позволяет изменять и заменять потоки, поэтому все эксперименты следует выполнять только с копией. Команды Wipe Object, Replace Stream и Update Current Stream полезны для нейтрализации и повторного тестирования, но после их применения полученный файл уже не является исходным доказательством.
Первый проход рекомендуется выполнять без ручного запуска JavaScript и без живого исполнения shellcode. Цель этого этапа — составить карту объектов, определить типы данных и выгрузить подозрительные элементы. Только после статического анализа стоит решать, нужен ли эмулятор, отладчик или просмотр поведения в отдельной песочнице.
Что означают цвета объектов и счётчики
Цветовая разметка списка ускоряет первичную сортировку. Красным отмечаются заголовки, в которых обнаружены признаки JavaScript. Синий используется для объектных потоков, где несколько объектов упакованы в один контейнер. Зелёный выделяет действия /Launch, /Action, /OpenAction и /AA. Фиолетовый указывает на /EmbeddedFiles, оранжевый — на неподдерживаемый фильтр или ошибку декомпрессии, жёлтый — на шрифты TrueType, розовый — на XML.
Цвет не заменяет чтение заголовка. Например, зелёная строка сообщает о наличии действия, но не доказывает вредоносность: допустимый документ может использовать переход к странице или печать. Важны значения ключей, цепочка ссылок между объектами и содержимое связанного потока. Поэтому после выбора цветной строки нужно открыть Text, найти номер связанного объекта и проверить его отдельно.
Строка состояния выводит суммарные показатели: число потоков, JavaScript-объектов, вложений, страниц, шрифтов TTF, объектов U3D, Flash, неизвестных фильтров, действий и PRC. Эти значения полезны для сравнения нескольких вариантов одного образца. Если после декодирования или удаления дубликатов число потоков меняется, а счётчики JavaScript и действий остаются прежними, можно сосредоточиться на конкретных связанных объектах.
Нулевой счётчик не гарантирует отсутствия соответствующего содержимого. Имена ключей могут быть записаны с шестнадцатеричными заменами, сценарий может собираться из строк или находиться внутри потока с неподдерживаемым фильтром. Для проверки таких случаев служат Obfuscated Headers, поиск строк, просмотр сырого заголовка и ручная обработка фильтра.
Заголовок объекта, сырой поток и декодированный поток
PDF-объект обычно состоит из словаря между маркерами << и >>, а при наличии данных — из участка между stream и endstream. В заголовке находятся тип, длина, фильтры и ссылки на другие объекты. Поток содержит код, изображение, шрифт, XML, Flash или иной двоичный блок. Программа показывает эти части отдельно, что позволяет проверять заявленные параметры и фактические байты.
Команда Show Raw Header/Object нужна, когда визуальное форматирование скрывает необычную запись. Вредоносный документ может разделять имя пробелами, использовать комментарии, шестнадцатеричные подстановки в именах или указывать неверную длину. Сырой просмотр сохраняет исходное написание и помогает понять, почему автоматический поиск не заметил ключ.
Декодированный поток — результат применения фильтров в порядке, заданном словарём. Если указан массив фильтров, нельзя ограничиваться последним элементом: сначала данные проходят первый декодер, затем второй и так далее. Результат каждого шага стоит проверять по сигнатуре. Текст JavaScript должен становиться читаемым кодом, SWF начинается характерной сигнатурой, PE-файл — буквами MZ, а изображение имеет собственный заголовок.
Сохранение сырого и распакованного вариантов одновременно облегчает повторную проверку. Сырой файл нужен для воспроизводимости и анализа упаковки, распакованный — для антивирусного сканирования, поиска строк и открытия профильным инструментом. Имена экспортируемых файлов лучше дополнять номером объекта и типом представления, например obj_27_raw.bin и obj_27_decoded.js.
Поиск JavaScript, действий и внедрённых данных
Меню Search For содержит отдельные команды для JavaScript, Flash, U3D, шрифтов TTF, тегов действий, обфусцированных заголовков, PRC, XML, цепочек фильтров и извлечения URL. Команда не просто печатает совпадения: она выделяет связанные объекты в списке, после чего к ним можно применить массовое сохранение или скрыть остальные строки.
Поиск JavaScript следует запускать дважды: сначала по структуре, затем обычным поиском строк. Структурный вариант находит ключи /JS и /JavaScript, а строковый помогает обнаружить фрагменты, собранные внутри потока или записанные без типичного словаря. Для каждого совпадения проверяйте объект действия, объект сценария и объект, который инициирует действие. Эта цепочка объясняет, запускается ли код при открытии документа, переходе на страницу или другом событии.
Команда поиска Action Tags охватывает /Launch, /Action, /OpenAction и /AA. После её выполнения не ограничивайтесь зелёными строками. Словарь действия может ссылаться на другой объект, где находится имя файла, команда, URI или JavaScript. Переход по номеру через Goto Object быстрее ручной прокрутки большого списка.
Поиск Embedded Files и XML помогает найти контейнеры, которые не видны на страницах. Вложение может быть обычным документом, сжатым пакетом либо исполняемым файлом. XML иногда содержит формы XFA, конфигурацию или фрагменты сценария. Сохраняйте такие потоки с нейтральным расширением .bin, а тип определяйте по сигнатуре, чтобы система случайно не запустила файл по ассоциации.
Фильтры PDF и цепочки декомпрессии
PDF Stream Dumper умеет обрабатывать распространённые фильтры FlateDecode, RunLengthDecode, ASCIIHexDecode, ASCII85Decode, LZWDecode, факсовое кодирование и JBIG2Decode. Для некоторых вариантов используются внешние библиотеки и компоненты .NET. Если требуемый декодер недоступен, объект получает оранжевую метку, а подробность появляется во вкладке Errors.
FlateDecode встречается чаще всего и основан на zlib/DEFLATE. После распаковки может открыться текст, изображение или ещё один закодированный слой. ASCIIHexDecode превращает пары шестнадцатеричных символов в байты, а ASCII85Decode уплотняет двоичные данные в печатный диапазон. RunLengthDecode использует серии повторов, LZWDecode — словарное сжатие. Название фильтра определяет только преобразование, но не тип итогового содержимого.
В цепочке фильтров порядок принципиален. Например, поток может сначала быть переведён в ASCII85, а затем сжат Flate. При чтении словаря программа применяет операции в заданной последовательности декодирования. Если автоматическая цепочка даёт ошибку, откройте Manual Filters, загрузите сырой поток и повторяйте этапы по одному, сохраняя промежуточный результат.
Параметр Predictor после Flate или LZW меняет интерпретацию распакованных байтов, особенно у изображений. Ошибка предиктора может дать поток правильной длины, но с визуально бессмысленным содержимым. Сверяйте Columns, Colors и BitsPerComponent со словарём изображения. Если автоматический результат выглядит повреждённым, отключите общий декомпрессор и обработайте объект вручную.
Ручная обработка потоков
Окно Manual Filters принимает текущий активный поток, данные из буфера обмена или файл. Это позволяет использовать его как отдельный конвейер: загрузить исходные байты, применить один декодер, посмотреть шестнадцатеричный результат и сохранить буфер для следующего этапа. Команда показа оригинала возвращает к исходным данным без повторного открытия PDF.
Для факсового декодирования доступны параметры Columns, Rows, K, EndOfLine, EncodedByteAlign, EndOfBlock и BlackIs1. Их нельзя выбирать наугад: значения нужно брать из DecodeParms анализируемого объекта. Неверное число столбцов сдвигает строки, неправильный K меняет режим Group 3/Group 4, а инверсия BlackIs1 даёт негатив.
Для факсовых данных предусмотрены разные реализации декодера. Если один вариант завершается ошибкой, второй может корректнее обработать нестандартный поток. Различие результатов нужно фиксировать: сохраните оба изображения и сравните размеры, видимые артефакты и количество необработанных байтов. Это особенно важно, когда данные намеренно искажены для обхода защитных средств.
Ручное окно полезно и для проверки гипотезы о неверном словаре. Если поток успешно распаковывается фильтром, который не указан в объекте, это может означать повреждение файла, попытку маскировки или ошибку извлечения. Такой результат не следует автоматически считать корректным; сопоставьте его с соседними объектами, ссылками и ожидаемым типом ресурса.
Сканирование известных эксплойтов
Команда Exploits Scan проверяет выделенные или найденные данные по строковым признакам и сигнатурам. Результат показывает название правила, связанный объект и совпавший фрагмент. Такой поиск помогает быстро обратить внимание на вызовы функций и шаблоны, связанные с известными уязвимостями, но не выполняет полноценную эмуляцию PDF-просмотрщика.
Совпадение является поводом для дальнейшей проверки, а не доказательством эксплуатации. Обычный документ может содержать имя функции в учебном тексте, комментарии или неисполняемом вложении. С другой стороны, обфускация, динамическое построение строк и нестандартный фильтр могут скрыть опасный вызов от простого сканера. Поэтому вывод нужно подтверждать связями объектов, декодированным JavaScript и поведением в эмуляторе.
Практический маршрут после совпадения: перейти к указанному объекту, открыть сырой заголовок, сохранить декодированный поток, найти вызывающую функцию и определить событие запуска. Затем выполнить форматирование сценария, раскрыть escape-последовательности и проверить буферы, которые могут содержать shellcode. Если сигнатура относится к функции вроде util.printf или collectEmailInfo, важны аргументы и способ их формирования.
Отсутствие результатов тоже нужно интерпретировать осторожно. Проверьте, нет ли оранжевых объектов с ошибкой фильтра, не скрыты ли дубликаты и не отключены ли декомпрессоры. Запустите поиск JavaScript и Action Tags отдельно, затем сохраните все подозрительные потоки для проверки другими средствами. Сканер лучше использовать как ускоритель сортировки, а не как единственный детектор.
Работа с JavaScript UI
Окно JavaScript UI предназначено для разбора сценариев, извлечённых из PDF. В нём есть области кода и результата, кнопка Run, поле pageNum, значение app.viewerVersion, меню форматирования и инструменты анализа shellcode. В верхней части явно указано, что сценарии выполняются без песочницы; это предупреждение нужно воспринимать буквально.
Безопаснее начинать с форматирования, поиска строк и ручного раскрытия простых выражений. Нажатие Run допускается только в одноразовой виртуальной машине без сети и общих ресурсов. Даже если сценарий рассчитан на API PDF-просмотрщика, он может использовать доступные функции среды, создавать файлы или передавать байты в нативный компонент анализа.
Сценарий можно загрузить из текущего объекта, отдельного JavaScript-файла или буфера. Перед загрузкой полезно сохранить исходную кодировку и проверить нулевые байты. Если текст отображается с разрывами, откройте поток в HexDump и определите, не используется ли UTF-16, шестнадцатеричная строка PDF или дополнительный слой escape-кодирования.
Поле pageNum помогает воспроизвести сценарии, поведение которых зависит от номера страницы. Значение app.viewerVersion можно менять для ветвлений по версии просмотрщика. Эти параметры не эмулируют весь документ, но позволяют пройти конкретные условия в коде и увидеть, какой буфер формируется в выбранной ветке.
Форматирование и поэтапная деобфускация JavaScript
Команда Format Javascript расставляет отступы и переносы, делая функции и условия заметнее. Её следует применять к копии текста: вредоносный код иногда зависит от необычного размещения комментариев или от строк, которые визуально похожи на код. После форматирования сравните количество строковых литералов и скобок с исходником.
Unescape Selection раскрывает выделенные escape-последовательности. Эта операция удобна для строк вида %uXXXX и процентовых кодов, но результат зависит от порядка байтов. После преобразования откройте HexDump и проверьте, не получилась ли последовательность инструкций x86, заголовок PE или ещё один текстовый слой. Непечатные байты не означают ошибку: они могут быть shellcode.
Manual Escapes позволяет выбирать преобразование вручную, когда автоматическое раскрытие смешивает строки разных типов. Работайте небольшими выделениями: отдельно декодируйте имя функции, отдельно большой буфер, отдельно URL. Такой подход сохраняет контекст и упрощает поиск места, где к данным добавляется ключ XOR или смещение.
Инструменты Basic Refactor и Strip Inline Decoder Calls упрощают часто встречающиеся конструкции. После каждого шага нужно сохранять промежуточный текст, потому что агрессивное преобразование может изменить выражение, которое зависит от побочного эффекта. Надёжный журнал включает исходный поток, отформатированную копию, результат каждого декодера и итоговый буфер.
Режим No Reset сохраняет переменные между запусками. Он удобен, если декодер выполняется в несколько стадий: первый фрагмент создаёт массив, второй заполняет его, третий выводит строку. Одновременно этот режим повышает риск неверной интерпретации, потому что остаточные значения влияют на новый сценарий. Перед анализом другого объекта снимите флажок или перезапустите окно.
Встроенная модель API и её ограничения
Среда предоставляет часть объектов и методов, характерных для JavaScript в PDF: значения doc.numPages, app.viewerVersion, pageNum, отдельные функции документа, уведомления и таймеры. Этого достаточно для многих декодеров, которые проверяют версию, число страниц или читают слова со страницы, но недостаточно для точного воспроизведения всего поведения Adobe Reader.
Некоторые методы реализованы частично. Например, получение аннотаций может возвращать только отдельные свойства, а сложные формы, мультимедиа и редкие плагины не моделируются. Если сценарий падает на неизвестном методе, не удаляйте вызов сразу. Сначала определите, используется ли возвращаемое значение для дешифрования или только для проверки среды.
Есть синтаксические ограничения встроенного движка. Конструкция доступа к массиву через квадратные скобки может обрабатываться иначе, чем ожидает код; в проблемном месте помогает замена на charAt или явный вызов свойства. Такие изменения следует отмечать в рабочей копии и не переносить в исходный образец.
Таймеры setInterval и вычисления через eval требуют особой осторожности. Сценарий может намеренно разбивать декодирование на задержанные этапы или генерировать код во время исполнения. Для статического разбора лучше извлечь строку, передаваемую в eval, и анализировать её отдельно, не запуская весь исходный сценарий.
Полезные функции JavaScript Toolbox
Набор вспомогательных функций сокращает ручные операции. GetClipboard и сохранение в буфер помогают переносить небольшие результаты, Hexdump показывает байты, WriteFile и ReadFile работают с файлами, HexString2Bytes превращает шестнадцатеричную строку в массив, а Disasm отправляет буфер на дизассемблирование.
Функция unescape рассчитана на работу с Unicode-последовательностями, встречающимися в shellcode. После её вызова важно проверить порядок байтов: строка %u9090 в памяти может дать байты 90 90, тогда как буквальное чтение символов вводит в заблуждение. Для больших буферов лучше сразу сохранить байты в файл и вычислить контрольную сумму.
GetStream позволяет обратиться к данным объекта из сценария. Это удобно, когда один JavaScript собирает полезную нагрузку из нескольких PDF-потоков. Запишите номера всех обращаемых объектов и выгрузите их отдельно через главное окно; так можно воспроизвести сборку внешним скриптом без запуска исходного кода.
Функции чтения слов со страницы помогают анализировать код, который использует видимый текст как ключ. Значения GetPageNumWords и GetPageNthWord зависят от результатов извлечения текста, поэтому при сложной разметке могут отличаться от конкретного просмотрщика. Если ключ не сходится, сравните порядок слов с другим PDF-парсером.
CRC32 полезен для сравнения промежуточных буферов и обнаружения повторов, но не является криптографическим хешем. Для фиксации доказательств дополнительно используйте SHA-256 внешним инструментом. Внутренний CRC удобен именно для быстрой группировки одинаковых потоков и проверки, изменился ли буфер после очередного шага.
Выделение и подготовка shellcode
Shellcode часто появляется после раскрытия длинных %u-строк, сложения фрагментов или XOR-декодирования. Прежде чем передавать буфер анализатору, найдите точную границу: исключите кавычки, операторы JavaScript и завершающий нулевой символ, если он не входит в полезную нагрузку. Ошибка на один байт сдвигает инструкции и делает дизассемблирование бессмысленным.
Команда сохранения байтов создаёт отдельный файл. Дайте ему нейтральное расширение и храните в каталоге без автоматического запуска. Сразу вычислите размер и хеш, затем откройте в HexDump. Повторяющиеся 90, короткий декодирующий цикл, таблица разрешения API и строки библиотек помогают подтвердить, что это код, а не сжатые данные.
Встроенные варианты анализа включают scDbg, scSigs, XOR BruteForcer, создание исполняемой оболочки и передачу в IDA. Выбор зависит от задачи. Сначала применяйте сигнатурный поиск и эмуляцию, затем ручное дизассемблирование. Живое исполнение должно оставаться последним вариантом и проводиться только в одноразовой лаборатории.
Если shellcode содержит самораспаковку, первый проход эмулятора может показать только цикл преобразования. Сохраните дамп после выхода из цикла и проанализируйте уже распакованный буфер. Наличие сетевых строк или имени файла в исходном фрагменте не гарантирует, что они используются: проверьте перекрёстные ссылки и вызовы API.
Эмуляция shellcode через scDbg
scDbg использует эмуляцию на базе libemu и обычно безопаснее живого исполнения. В диалоге можно выбрать режим отчёта, сканирование таблицы API, неограниченное число шагов, поиск подходящей точки старта, создание дампа и интерактивные перехваты. Эти параметры помогают работать с кодом, который начинается не с первого байта или содержит длинный декодер.
Опция поиска shellcode полезна, если выделение включает префикс или мусор. Однако найденное смещение нужно проверить вручную: эвристика может принять данные за допустимые инструкции. Запустите эмуляцию с несколькими близкими смещениями и сравните, появляется ли устойчивый поток вызовов API.
Ограничение числа шагов защищает от бесконечного цикла. Снимать его стоит только после понимания причины остановки. Вредоносный код может ждать события, проверять окружение или намеренно тратить время. Сначала увеличьте лимит постепенно, включите журнал чтения и записи памяти и найдите участок, где состояние перестаёт меняться.
Интерактивные hooks позволяют подставлять ответы системных функций. Это полезно для кода, который запрашивает путь временного каталога, открывает файл или проверяет сеть. Все подстановки фиксируйте, потому что другой ответ может привести к иной ветке. Не используйте реальные рабочие пути и сетевые адреса.
Дамп после эмуляции следует считать новым артефактом. Проверьте его сигнатуру, строки, энтропию и хеш. Если появился PE-файл, не запускайте его; передайте в статический анализатор. Если результат остаётся без заголовка, найдите область, куда код записывал данные, и сохраните именно этот диапазон.
Сигнатурная проверка scSigs и поиск XOR
scSigs сочетает проверку известных байтовых признаков с возможностью распаковки через libemu. Оно быстро показывает вызовы, строки и шаблоны, которые помогают определить назначение буфера. Результат нужно сопоставлять с размером и смещениями, потому что короткая сигнатура может случайно встретиться в данных.
XOR BruteForcer нужен для однобайтового или простого повторяющегося XOR. Успешный ключ обычно приводит к заметным структурам: MZ, HTTP-подобным строкам, именам DLL или читаемому сценарию. Оценка только по доле печатных символов ненадёжна, особенно для машинного кода. Проверяйте сигнатуры и дизассемблирование.
Если декодер использует изменяющийся ключ, сложение или вращение, перебор XOR не даст результата. В этом случае найдите цикл в JavaScript либо shellcode и перепишите его в отдельный безопасный скрипт. Входные байты, начальный ключ и число итераций должны точно соответствовать исходному коду.
Сигнатурная проверка особенно полезна перед эмуляцией: она помогает определить предполагаемую архитектуру и наличие известных загрузчиков. Однако окончательный вывод делается по потоку управления и вызовам API. Отчёт scSigs следует хранить рядом с исходным буфером, чтобы смещения можно было воспроизвести.
Почему sclog требует максимальной изоляции
sclog запускает shellcode вживую и перехватывает часть действий. В его окне доступны журнал выделения памяти, адреса, шестнадцатеричные дампы, разрешение загрузки DLL, пошаговые API-вызовы, сохранение дампа, сетевое перенаправление и точки останова. Наличие журналирования не превращает запуск в безопасную эмуляцию.
Флажок, снимающий защитные ограничения, нельзя включать в обычной системе. Даже с перенаправлением сети код может изменить файлы, внедриться в процесс или использовать неподдержанный системный вызов. Перед запуском необходима виртуальная машина без доступа к локальной сети, без буфера обмена и общих папок, с заранее подготовленным снимком состояния.
Разрешение загрузки DLL увеличивает реалистичность, но открывает дополнительные пути выполнения. Если код требует библиотеку, сначала выясните её имя статически и подготовьте чистую копию в лаборатории. Не разрешайте поиск DLL по каталогам рабочей системы. Журналируйте каждый загруженный модуль и его хеш.
Сетевое перенаправление должно вести на контролируемый эмулятор сервисов, а не в интернет. Даже DNS-запрос может раскрыть факт исследования или активировать внешнюю инфраструктуру. Если задача решается scDbg, ручным дизассемблированием или песочницей с лучшей изоляцией, sclog использовать не следует.
После живого запуска виртуальную машину лучше откатить, а не продолжать работу в том же состоянии. Выгрузите только заранее определённые журналы и дампы через безопасный канал. Любой созданный процесс, файл или ключ реестра рассматривайте как потенциально вредоносный.
Сохранение потоков и массовое извлечение
Контекстное меню списка содержит команды Save Raw Stream, Save Decompressed Stream и варианты сохранения всех выбранных объектов. Сырой поток сохраняется в том виде, в каком он находится в PDF; декомпрессированный — после применения поддерживаемых фильтров. Для расследования нужны оба варианта.
Перед массовым сохранением используйте поиск и скрытие строк. Например, найдите шрифты TTF, скройте невыделенные объекты и сохраните все декодированные потоки. Аналогично можно выгрузить Flash, XML или действия. Этот порядок снижает риск перепутать расширения и упрощает последующую проверку.
Команда Hide Duplicate Streams использует контрольные значения для удаления повторов из текущего представления. Она не изменяет исходный PDF, а лишь сокращает список. Перед её включением запишите общее число потоков: одинаковое содержимое в разных объектах иногда имеет разный контекст, поэтому номер каждого дубликата может быть важен.
Hide Header Only Objects убирает объекты без потоковой части. Это удобно при массовом извлечении, но опасно для анализа действий и ссылок: многие критичные словари не содержат stream. После выгрузки данных верните полный список и проверьте заголовочные объекты отдельно.
Имена файлов при экспорте должны отражать объект и состояние: obj_15_raw, obj_15_flate, obj_15_unescaped. Не назначайте расширение .exe только по предположению. Сначала проверьте магические байты, затем копируйте артефакт в каталог статического анализа.
Пакетный режим /extract
Для автоматизированного извлечения предусмотрен параметр /extract. Команда принимает путь к PDF и каталог назначения, например pdfstreamdumper "C:\Samplesile.pdf" /extract "C:\Outputile". Интерфейс при этом остаётся видимым, а программа создаёт файлы потоков, которые смогла обработать.
Пакетный режим удобен для первичного сбора, но не заменяет просмотр ошибок. После завершения проверьте вкладку Errors или журнал, чтобы узнать, какие объекты не распаковались. Имена вида stream_x.ext нужно сопоставить с номерами объектов; сохраните рядом таблицу соответствия, если дальнейший анализ проводится другим человеком.
Каталог назначения должен быть пустым и находиться внутри лаборатории. Не запускайте пакетное извлечение прямо в папку синхронизации или общий ресурс: среди результатов может оказаться исполняемый файл, документ с активным содержимым или большой объём данных. Ограничьте права каталога и отключите автоматическую индексацию.
При серии образцов создавайте отдельный каталог для каждого SHA-256. Это предотвращает перезапись одинаково названных потоков и позволяет сравнивать наборы. После извлечения сформируйте список размеров и хешей, затем сгруппируйте совпадающие артефакты.
Извлечение шрифтов, Flash и 3D-объектов
Поиск TTF Fonts выделяет потоки, связанные со шрифтами TrueType. Вредоносный шрифт может использовать уязвимость рендерера, а обычный — лишь обеспечивать внешний вид документа. Сохраните декодированный поток и проверьте таблицы шрифта специализированным валидатором; простое наличие TTF не является признаком атаки.
Для уменьшения повторов можно включить скрытие дубликатов, выполнить поиск TTF, скрыть невыделенные строки и сохранить все декодированные потоки. Затем верните полный список и изучите словари FontDescriptor, потому что они связывают поток с конкретным ресурсом страницы.
Flash Objects находят SWF, встроенные в PDF. Команды декомпрессии и декомпиляции помогают получить содержимое, но результат следует открывать только статическим декомпилятором. Проверьте сигнатуру FWS, CWS или ZWS, заявленную длину и наличие ActionScript. Несовпадение длины может означать повреждение либо дополнительную упаковку.
U3D и PRC относятся к трёхмерным данным. Они могут быть крупными и сложными для парсинга, поэтому автоматический просмотр ограничен. Сохраните поток, проверьте заголовок и используйте отдельный анализатор формата. Не открывайте объект в обычном PDF-просмотрщике ради проверки: именно обработчик 3D может быть целью эксплойта.
Розовые XML-потоки часто связаны с формами или метаданными. Ищите внутри сценарии, ссылки, имена событий и закодированные блоки. Если XML содержит Base64, используйте встроенный декодер и сохраняйте результат как отдельный артефакт, не подменяя исходный поток.
Base64, zlib и другие вспомогательные инструменты
В меню Tools есть операции Base64 для буфера обмена и файлов. Они удобны при разборе XML, JavaScript и конфигураций, где полезная нагрузка записана печатной строкой. Перед декодированием удаляйте только явно допустимые пробелы и переносы; посторонний символ может быть частью другой схемы обфускации.
Команды zlib compress/decompress работают с отдельными файлами, а Zlib Brute Forcer ищет смещение, с которого начинается корректный поток. Это помогает, когда перед сжатыми данными добавлен заголовок, мусор или части другого формата. Найденное смещение необходимо записать и проверить по исходному объекту.
Успешная распаковка zlib не доказывает, что весь результат корректен. Проверьте, закончился ли поток без остатка, совпадает ли ожидаемая длина и есть ли разумная сигнатура. Вредоносный образец может содержать несколько zlib-потоков или специально подобранный префикс.
Операция скачивания URL присутствует среди инструментов, но при анализе вредоносного документа её лучше не использовать с реальным адресом из образца. Сначала извлеките строку, нормализуйте её вручную и проверьте через изолированную инфраструктуру. Прямое обращение из лаборатории может раскрыть адрес или получить активную нагрузку.
Просмотр байтов и определение формата
Встроенный HexDump показывает смещение, шестнадцатеричные байты и печатные символы. Он нужен для проверки сигнатур, границ и нулевых байтов. При выборе большого потока включите автоматическое переключение на двоичную вкладку, чтобы текстовый контрол не пытался интерпретировать бинарные данные.
Команда открытия в отдельном hex-редакторе удобна для сравнения двух потоков и поиска структуры. Если используется внешняя программа, настройте её только на чтение и передавайте копию. Внутренний и внешний просмотр могут по-разному отображать кодировки, поэтому важные смещения следует считать по байтам.
Тип файла определяйте по нескольким признакам: магическим байтам, внутренним полям длины, структуре и содержимому. Например, MZ в начале предполагает PE, но нужно найти PE-заголовок и корректные секции. Для PNG должны присутствовать сигнатура и чанки, для ZIP — центральный каталог, для SWF — согласованная длина.
Если поток начинается не с сигнатуры, выполните поиск внутри. Встраиваемый файл может иметь префикс, оболочку или несколько частей. Сохраните смещение найденного заголовка и извлеките диапазон в отдельный файл, не изменяя исходный артефакт.
Изменение, замена и нейтрализация объектов
Update Current Stream записывает отредактированное содержимое обратно в выбранный поток, Replace Stream подставляет данные из файла, а Wipe Object очищает объект. Эти команды полезны для контролируемого эксперимента: удалить JavaScript, заменить вложение пустым блоком или проверить, исчезает ли срабатывание после нейтрализации конкретного элемента.
Изменение потока может потребовать пересчёта длины и повторного сжатия. После сохранения откройте полученный PDF заново в анализаторе и сравните список объектов, ошибки и счётчики. Если документ перестал разбираться, проверьте /Length, фильтры и границы stream/endstream.
Команда Mark Stream помогает отметить объект в длинном списке перед серией операций. Используйте метки для исходного сценария, промежуточного буфера и связанного действия. Так меньше риск изменить соседний объект с похожим содержимым.
Нейтрализованный документ нельзя считать безопасным только потому, что он открывается без заметного поведения. В нём могут остаться альтернативные действия, вложения или повреждённые структуры. После каждой модификации повторите поиски JavaScript, Action Tags, Embedded Files и Obfuscated Headers, а затем проверьте файл независимым парсером.
Поиск строк и замена значений
Обычный поиск работает по заголовкам и декодированному содержимому. Ищите имена API, домены без схемы, расширения файлов, команды оболочки и характерные фрагменты JavaScript. Для кодированных данных полезны короткие устойчивые части, потому что полная строка может собираться динамически.
Find/Replace следует применять только к копии и после фиксации исходного совпадения. Замена одинаковой длины облегчает сохранение структуры, но не гарантирует корректность, если поток сжат. Для декодированного текста сначала измените данные, затем используйте предусмотренную команду обновления, чтобы программа корректно обработала поток.
Поиск по всем объектам может давать множество совпадений в шрифтах или изображениях. Ограничьте представление найденной категорией, скройте невыбранное и повторите поиск. Если строка обнаружена в сыром потоке, а после декомпрессии исчезает, проверьте, не является ли совпадение случайным.
При поиске URL учитывайте конкатенацию, escape-коды и замену символов. Извлечённый адрес не нужно открывать напрямую. Сначала восстановите его в текстовом файле, укажите объект и смещение, затем передайте на отдельную проверку.
Клавиатурные команды и управление выбором
Ctrl+A выделяет все строки, Ctrl+N снимает выделение, Ctrl+I инвертирует его. Эти сочетания ускоряют массовое сохранение и скрытие. Перед применением команды ко всем объектам проверьте строку состояния и первый с последним выделенный элемент, чтобы не выгрузить лишнее.
Ctrl+D удаляет выбранные строки из текущего списка, но не изменяет сам PDF. Это способ очистить представление, а не средство нейтрализации. Для возврата удалённых строк проще перезагрузить документ. Не путайте это действие с Wipe Object, которое действительно меняет содержимое рабочей копии.
Контекстные команды применяются ко всем выбранным строкам, поэтому множественный выбор требует внимания. Перед сохранением декомпрессированных потоков убедитесь, что у всех объектов совместимый статус декодирования. Оранжевые строки лучше обработать отдельно, иначе в одном каталоге окажутся сырые и распакованные данные с похожими именами.
Goto Object переходит к номеру объекта и удобен при чтении ссылок вида 27 0 R. Если номер отсутствует в списке, возможны повреждение, объектный поток, инкрементальное обновление или особенность упрощённого разбора. В таком случае найдите номер в сыром файле через hex-редактор.
Настройки декомпрессоров и отображения
Опция Always use Zlib for FlateDecode заставляет применять zlib к Flate-потокам. Она помогает обходить различия между реализациями, но может скрыть проблему в параметрах предиктора. Если результат сомнителен, сравните его с альтернативным декомпрессором и ручным режимом.
Disable iText Decompressors отключает декодеры библиотеки iTextSharp, а Disable All Decompressors оставляет потоки сырыми. Второй режим нужен, когда документ зависает или вызывает исключение при автоматической распаковке. После успешной загрузки подозрительные объекты можно обрабатывать по одному.
Disable Decryption Support исключает попытки расшифровки. Это полезно для диагностики, если зашифрованный файл вызывает ошибку на старте. При включённой поддержке сравнивайте расшифрованный поток с заголовком шифрования и не предполагайте, что отсутствие запроса пароля означает полное раскрытие всех объектов.
Enable JBIG2 Decoding Support активирует обработку JBIG2. Такой декодер нужен для некоторых сканированных документов, но сложные или вредоносные потоки лучше сначала сохранить в сыром виде. Если при включении появляются сбои, отключите поддержку и используйте специализированный изолированный декодер.
Опции визуального форматирования заголовков и автоматического раскрытия escape-последовательностей делают чтение быстрее, но для доказательного анализа всегда доступен сырой вид. Сравнение двух представлений помогает обнаружить, какие символы были нормализованы.
Скрытие объектов и автоматическое переключение вкладок
Hide Duplicate Streams сокращает повторяющиеся потоки, Hide Header Only Objects оставляет только объекты с данными, а команды Hide Selected и Hide Unselected формируют рабочую выборку. Эти фильтры не меняют файл, но меняют контекст списка, поэтому перед важным переходом запишите активный режим.
Для сценария поиска полезна схема: найти категорию, скрыть невыбранное, обработать результаты, затем перезагрузить документ. Простое обратное скрытие может быть сложнее, если последовательно применено несколько фильтров. Перезагрузка гарантирует исходный порядок строк.
AutoSwitch Tabs for Binary Data автоматически открывает HexDump для двоичного потока. Функция снижает вероятность, что текстовое поле будет медленно обрабатывать мегабайты бинарных данных. Если она ошибочно считает текст двоичным из-за нулевых байтов UTF-16, переключитесь на Text вручную и проверьте кодировку.
Open Last PDF on Startup лучше отключить в лаборатории. Автоматическое повторное открытие вредоносного образца затрудняет контроль состояния и может снова запустить тяжёлую декомпрессию. Начинать сеанс безопаснее с пустого окна и явно выбранной копии.
Разбор обфусцированных заголовков
Имена PDF допускают шестнадцатеричные подстановки вида #XX. Поэтому /JavaScript можно записать так, что простой строковый поиск не увидит слово целиком. Команда Obfuscated Headers ищет подобные конструкции, а опция автоматического раскрытия показывает нормализованное имя.
После обнаружения обфускации обязательно откройте сырой заголовок. Нужно зафиксировать исходные байты и понять, применяется ли маскировка только к одному ключу или ко всей цепочке. Массовое использование подстановок может быть признаком попытки обхода сигнатур, но встречается и в корректно сгенерированных файлах.
Обфускация может сочетаться с комментариями и нестандартными пробелами. Упрощённый парсер извлекает объекты и заголовки, но не гарантирует полное соответствие всем особенностям спецификации. Если ссылка или ключ выглядят пропущенными, откройте весь PDF в hex-редакторе и сравните с независимым парсером.
Не заменяйте обфусцированное имя прямо в исходном образце до завершения анализа. Нормализация меняет байты и может повлиять на сигнатуры, смещения и инкрементальные обновления. Для эксперимента создайте отдельную копию.
Понимание ограниченного парсера
Основной механизм ориентирован на извлечение объектов, потоков и заголовков, а не на полное построение модели PDF. Он удобен для быстрой криминалистической сортировки, но может не восстановить каждую таблицу перекрёстных ссылок, инкрементальную редакцию или редкую конструкцию так же, как полнофункциональный движок просмотра.
Если объект отсутствует, это не означает, что его нет в файле. Проверьте объектные потоки, xref-потоки, повреждённые маркеры и более ранние инкрементальные секции. Сравнение с pdf-parser.py или peepdf помогает найти расхождение и определить, связано ли оно с нестандартной структурой.
Рендеринг страниц не является основной задачей программы. Видимое содержимое следует проверять отдельным безопасным рендерером, а здесь сосредоточиться на структуре, потоках и активных элементах. Несовпадение между визуальным изображением и объектами само по себе может быть важным признаком.
Программа также не заменяет антивирус, песочницу и ручный реверс. Она связывает этапы: показывает объект, декодирует поток, помогает раскрыть JavaScript и передать shellcode анализатору. Итоговая оценка требует корреляции всех результатов.
Ошибки декомпрессии и оранжевые объекты
Оранжевая строка указывает на неподдерживаемый фильтр или ошибку декомпрессии. Сначала откройте Stream Details и Errors, затем сохраните сырой поток. Не пытайтесь многократно нажимать сохранение декодированного варианта: одинаковая ошибка не добавит информации и может замедлить сеанс.
Проверьте написание фильтра, наличие массива и параметры DecodeParms. Имя может быть сокращено по допустимым правилам PDF или обфусцировано. Если автоматическая цепочка неверно определена, загрузите поток в Manual Filters и применяйте операции по одной.
Несовпадение /Length часто мешает извлечению. Сравните заявленную длину с фактическим расстоянием до endstream, учитывая перевод строки после stream. Для повреждённого файла сохраните оба возможных диапазона и проверьте, какой корректно декодируется.
Если ошибка появляется только при включённом iText-декодере, отключите его и попробуйте zlib или ручной вариант. Если наоборот не работает встроенный путь, верните iText. Разные реализации по-разному относятся к обрезанным данным и ошибочным контрольным суммам.
Проблемы с .NET и компонентами интерфейса
Часть декодеров и вспомогательных функций требует компонентов .NET поколения 2.0/3.x. На новых системах соответствующая возможность Windows может быть отключена. Признаки проблемы — ошибка загрузки сборки, недоступный фильтр или сбой при открытии окна, использующего iTextSharp. Устанавливать случайные DLL из каталогов программ не следует; активируйте системный компонент через доверенный системный канал.
Интерфейс использует классические OCX-компоненты. Если появляется сообщение о незарегистрированном элементе управления, запустите штатный установщик с административными правами в изолированной машине. Ручная регистрация файла допустима только после проверки, что он входит в официальный пакет и находится в правильном системном каталоге.
На 64-разрядной Windows программа и её компоненты работают как 32-разрядные. Поэтому пути регистрации и системные каталоги могут отличаться от ожидаемых. Не заменяйте 32-разрядную OCX случайной 64-разрядной версией: интерфейс либо не загрузится, либо будет работать нестабильно.
Если окно запускается, но отдельная вкладка остаётся пустой, проверьте права на временный каталог и путь установки. Некоторые вспомогательные инструменты создают временные файлы рядом с программой. Каталог только для чтения или защита от записи может блокировать операцию без понятного сообщения.
Если PDF не загружается или список пуст
Пустой список после загрузки может означать, что файл не является PDF, сильно повреждён, использует необычную структуру или был выбран не тот путь. Откройте первые байты в HexDump внешнего редактора и найдите сигнатуру %PDF-. Она может находиться не в нулевом смещении, если перед документом добавлен префикс.
Проверьте размер файла и доступ на чтение. Нулевой или частично скопированный образец часто выглядит как проблема парсера. Если файл находится на сетевом ресурсе, скопируйте его в локальный лабораторный каталог и повторите попытку.
Отключите все декомпрессоры и загрузите документ снова. Если список появился, проблема связана с конкретным потоком. Включайте декодеры по очереди или обрабатывайте оранжевые объекты вручную. Если список всё ещё пуст, сравните файл независимым инструментом и найдите границы объектов в сыром виде.
Повреждённая таблица xref не всегда мешает извлечению по маркерам, но нестандартные объектные потоки могут быть пропущены. В таком случае используйте второй парсер для восстановления номеров, а PDF Stream Dumper — для анализа уже найденных потоков и JavaScript.
Если JavaScript не выполняется или даёт другой результат
Ошибка неизвестного метода обычно означает, что встроенная модель API не поддерживает функцию просмотрщика. Найдите место вызова и определите, нужно ли реальное возвращаемое значение. Для проверки ветки можно заменить только этот вызов контролируемой константой в рабочей копии сценария, записав изменение.
Если результат зависит от массива и появляется синтаксическая ошибка, перепишите доступ через charAt или явные методы. Это обход ограничения движка, а не исправление исходного кода. Сохраните исходный и адаптированный варианты рядом.
При поэтапном декодировании проверьте флажок No Reset. Если он снят, переменные между запусками исчезают; если установлен, старые значения могут загрязнить новый тест. Для воспроизводимости начинайте с чистого состояния и выполняйте шаги в фиксированном порядке.
Различие с поведением реального просмотрщика может быть связано с номером страницы, значением версии, порядком слов на странице или объектом app.doc. Настройте доступные параметры, но не пытайтесь имитировать неизвестную часть догадками. Для точной динамики используйте отдельную песочницу с нужным просмотрщиком.
Если сканер не находит очевидный код
Сначала убедитесь, что поток декодирован. Сигнатуры не сработают по данным, скрытым Flate, ASCII85 или XOR. Оранжевые объекты, неизвестные фильтры и длинные строки высокой энтропии требуют ручной обработки.
Проверьте обфусцированные заголовки и альтернативные события. Сценарий может быть связан не с /OpenAction, а с /AA страницы, поля формы или аннотации. Перейдите по ссылкам между объектами и ищите /S /JavaScript в сыром заголовке.
Код может собираться из нескольких коротких строк или извлекаться из видимого текста. Используйте поиск имён функций, eval, unescape, fromCharCode и циклов декодирования. Сохраните все части и восстановите порядок конкатенации.
Если автоматический поиск остаётся пустым, выгрузите потоки и примените независимые правила YARA или строковый анализ. Отрицательный результат одного средства не должен закрывать исследование документа с подозрительной структурой.
Работа с зашифрованными документами
Зашифрованный PDF может содержать открытый словарь /Encrypt и недоступные потоки. Поддержка расшифровки помогает в части случаев, но зависит от алгоритма, параметров и наличия пароля. Сообщение об успешной загрузке не гарантирует, что каждый объект расшифрован.
Команда принудительной расшифровки используется на копии. После неё повторно откройте файл и сравните число объектов, ошибки и содержимое потоков. Если текст по-прежнему выглядит случайным, проверьте, не применён ли дополнительный фильтр после шифрования.
Не подбирайте пароль внутри рабочей среды с доступом к секретным данным. Для легитимного документа запросите пароль у владельца. В расследовании используйте отдельный инструмент и фиксируйте правовое основание доступа.
При отключении поддержки шифрования можно изучить открытые заголовки и структуру, не вызывая проблемный декодер. Это помогает определить тип защиты и собрать данные для следующего этапа.
Практический сценарий анализа подозрительного вложения
Создайте каталог по SHA-256 образца и поместите туда неизменяемую копию. Загрузите рабочую копию, сохраните снимок счётчиков и список ошибок. Затем выполните поиски JavaScript, Action Tags, Embedded Files, Obfuscated Headers и Filter Chains. Для каждой категории запишите номера объектов.
Перейдите к объекту действия и проследите ссылки до сценария. Сохраните сырой и декодированный поток. Откройте JavaScript UI, но сначала используйте только форматирование, unescape и поиск функций. Отделите большие строки, предполагаемые буферы и адреса.
Если найден shellcode, сохраните его байты и проверьте scSigs. Затем запустите scDbg с ограниченным числом шагов и журналом API. Сравните обнаруженные строки, пути и сетевые адреса с теми, что были в JavaScript. Несовпадение может означать второй слой распаковки.
Вложенные файлы выгрузите отдельно и определите тип по сигнатуре. Не открывайте их обычным приложением. Для каждого артефакта вычислите хеш и запишите исходный объект. В конце сформируйте карту: событие запуска → JavaScript → декодер → shellcode → созданный или загружаемый файл.
Только после статического и эмулируемого этапов решайте, нужна ли динамика. Если нужна, используйте новую виртуальную машину и заранее подготовленное наблюдение за процессами, файлами, реестром и сетью. Результаты сопоставьте с объектами, найденными в PDF Stream Dumper.
Проверка ложных срабатываний
Документ с JavaScript не обязательно вредоносен: сценарии используются в формах, расчётах и навигации. Отличайте функцию от контекста. Автоматическое действие при открытии, обфускация, heap spray, длинные escape-строки и загрузка внешнего файла повышают риск, но каждый признак нужно подтвердить.
Встроенный шрифт или 3D-объект также не является доказательством атаки. Проверьте валидность формата, связь с страницей и необычные размеры. Уязвимый тип содержимого становится существенным, когда структура повреждена, данные специально сформированы или документ нацелен на конкретный обработчик.
Совпадение сигнатуры эксплойта может находиться в тексте статьи или вложенном отчёте. Определите, исполняется ли содержащий её объект. Если он не связан с действием и не обрабатывается активным компонентом, риск ниже, но артефакт всё равно следует описать.
Отчёт должен разделять наблюдение и вывод: в объекте 12 обнаружена строка отличается от код вызывает функцию. Такая точность позволяет другому аналитику воспроизвести решение и исправить ошибочную интерпретацию.
Совместимость и организация лаборатории
Интерфейс и вспомогательные модули рассчитаны на Windows. На современных выпусках системы могут потребоваться включение совместимости для классических компонентов, установка функции .NET 2.0/3.x и запуск установщика с правами администратора. Сам анализ лучше проводить в отдельной 32-разрядно совместимой виртуальной машине, где все зависимости проверены заранее.
Перед началом создайте эталонный снимок виртуальной машины, отключите сеть либо подключите её к контролируемому сегменту, запретите общий буфер обмена и перетаскивание файлов. Для передачи результатов используйте защищённый пакет с паролем и отдельный шлюз проверки. Эти меры особенно важны при работе с Run в JavaScript UI и sclog.
Антивирус в лаборатории может удалять извлечённые буферы и искажать результаты. Не отключайте защиту на рабочей системе. В изолированной машине настройте контролируемое исключение только для каталога образца, сохраняя журналы срабатываний и не подключая этот каталог к сети организации.
Размещайте приложение, временные файлы и результаты на диске с достаточным свободным местом. Маленький PDF может распаковываться в большой поток, а массовое извлечение создаёт десятки файлов. Ограничение диска помогает предотвратить переполнение, но его значение должно учитывать ожидаемый размер декодированных данных.
Разбор действий /Launch, /OpenAction и /AA
Объект /OpenAction определяет действие, выполняемое при открытии документа. Его значение может быть непосредственным словарём или ссылкой на другой объект. Сначала выпишите номер ссылки, затем перейдите через Goto Object и проверьте ключ /S, который задаёт тип действия. Для JavaScript ожидается /S /JavaScript, для запуска файла — /S /Launch, для перехода по адресу — другой соответствующий тип.
/AA обозначает дополнительные действия и может находиться не только в каталоге документа. Проверяйте страницы, аннотации, поля формы и другие словари. Событие способно срабатывать при входе на страницу, уходе с неё, наведении, нажатии или изменении значения. Поэтому отсутствие опасного /OpenAction не исключает автоматического запуска позже.
Для /Launch изучите все платформенные ветки словаря, имя файла, параметры и рабочий каталог. Строка может быть разбита на несколько объектов или записана в шестнадцатеричном виде. Не копируйте команду в системный терминал. Восстановите её в обычном текстовом файле и отдельно отметьте, какие части поступают из документа, а какие добавляются просмотрщиком.
Если действие ссылается на внедрённый файл, проследите цепочку до Filespec и EmbeddedFile. Сохраните вложенный поток в сыром и декодированном виде, проверьте магические байты и вычислите хеш. Имя в Filespec не всегда соответствует реальному типу: расширение может быть безобидным, тогда как содержимое начинается с MZ или ZIP.
Действия перехода по URI тоже требуют анализа. Адрес может быть собран JavaScript, содержать escape-последовательности или вести на нестандартную схему. В отчёте фиксируйте строку без открытия. Для проверки домена и загрузки используйте отдельную сетевую лабораторию, а не команду Download URL в той же машине, где разбирается образец.
При нейтрализации действия безопаснее сначала заменить ссылку в рабочей копии, а не удалять случайный поток. Затем повторно загрузите PDF и убедитесь, что структура остаётся читаемой, а остальные действия не появились в результате инкрементального обновления. Проверка независимым парсером обязательна, потому что старое действие может сохраняться в предыдущей секции файла.
Объектные потоки, поколения и инкрементальные изменения
Синие строки соответствуют объектным потокам, где несколько небольших объектов объединены и сжаты. Внутренний объект может содержать словарь действия или ссылку, хотя отдельного обычного блока obj/endobj в файле не видно. При расхождении результатов с другим парсером проверьте, раскрыт ли соответствующий /ObjStm.
Номер объекта используется вместе с поколением. Большинство файлов содержит поколение 0, но полная ссылка включает оба значения. Не объединяйте объекты только по первому числу, если документ имеет обновления. В отчёте пишите полную форму, например 27 0 R.
Инкрементальное сохранение добавляет новую секцию в конец PDF, не удаляя старые байты. Безопасная новая редакция может перекрывать прежний вредоносный объект, либо наоборот — позднее обновление добавляет действие. Упрощённый список нужно сопоставлять с сырой последовательностью секций и цепочкой /Prev.
Если после удаления JavaScript сканер всё ещё находит строку в файле, она может оставаться в старой редакции. Это важно для криминалистики и для реального обезвреживания. Простая замена активной ссылки предотвращает выполнение в корректном просмотрщике, но не удаляет исторические данные; для публикации очищенного документа требуется полная пересборка доверенным средством.
Повреждённые xref-таблицы и xref-потоки могут направлять просмотрщик к другим смещениям, чем ожидает поиск по маркерам. Сравните фактическую позицию объекта, запись xref и результат второго парсера. Различие иногда объясняет, почему один просмотрщик запускает действие, а другой его игнорирует.
Проверка результатов на нескольких инструментах
После извлечения ключевых объектов повторите их поиск другим парсером. Совпадение номеров, фильтров и размеров повышает доверие к результату. Расхождение не следует автоматически считать ошибкой PDF Stream Dumper: разные программы по-разному восстанавливают повреждённые документы, обрабатывают лишние пробелы и выбирают активную инкрементальную редакцию.
PDFiD удобно использовать до и после разбора для сравнения количества ключей /JS, /JavaScript, /AA, /OpenAction, /Launch и /EmbeddedFile. Если счётчики расходятся, откройте обфусцированные заголовки и объектные потоки. Быстрый сканер может считать текстовые совпадения, тогда как список PDF Stream Dumper ориентируется на извлечённые объекты.
pdf-parser.py полезен для выборки конкретного номера и декомпрессии потока из командной строки. Сравните SHA-256 полученных байтов. Разный хеш при одинаковом сыром потоке указывает на различие декодеров, предикторов или границ извлечения. Сохраняйте оба результата, пока не установлена причина.
peepdf помогает посмотреть версии документа и связи в интерактивной консоли. Его вывод особенно полезен для инкрементальных обновлений и объектов, которые не отображаются ожидаемым образом. The Pdfalyzer дополняет картину деревом и YARA-проверкой потоков. Ни один из этих результатов не нужно переносить в PDF Stream Dumper через буфер без фиксации происхождения данных и номера объекта.
Взаимная проверка заканчивается не тогда, когда инструменты показывают одинаковое слово, а когда совпадает цепочка данных: объект действия, ссылка на сценарий, декодированный буфер, смещение shellcode и наблюдаемые вызовы API. Такой уровень совпадения позволяет отделить реальную функциональность образца от случайной сигнатуры.
Сравнение PDF Stream Dumper с аналогами
| Программа | Лучше подходит для | Главное ограничение |
|---|---|---|
| PDF Stream Dumper | Графического разбора объектов, JavaScript и shellcode в одном рабочем процессе | Основной парсер не строит полную модель PDF |
| peepdf | Интерактивного анализа структуры, версий документа и подозрительных элементов через консоль | Требует уверенной работы с командами и Python-средой |
| pdf-parser.py | Точного выборочного извлечения объектов и потоков в автоматизированных сценариях | Нет объединённого графического анализа JavaScript и shellcode |
| PDFiD | Очень быстрой первичной оценки ключевых слов и активных конструкций | Не декодирует и не исследует содержимое как полноценный парсер |
| The Pdfalyzer | Визуализации дерева PDF и проверки потоков правилами YARA | Для глубокой ручной деобфускации нужны дополнительные средства |
Для ручного исследования одного подозрительного файла с переходом от объекта к JavaScript и затем к shellcode удобнее PDF Stream Dumper. Для пакетных скриптов и воспроизводимого извлечения отдельных объектов практичнее pdf-parser.py, для интерактивной консольной проверки сложной структуры — peepdf, а PDFiD подходит как быстрый предварительный фильтр. The Pdfalyzer полезен, когда важны дерево связей и YARA-проверка потоков; итоговый выбор можно сочетать, используя разные инструменты для взаимной проверки.
Как фиксировать результаты исследования
Для каждого значимого объекта запишите номер, поколение, тип, ключевые поля заголовка, фильтры, размер сырого и декодированного потока, SHA-256 экспортированных файлов и действие, которое на него ссылается. Одного снимка экрана недостаточно: он не сохраняет все байты и может скрыть часть строки.
Сохраняйте журнал преобразований JavaScript. Каждая стадия должна иметь отдельный файл: исходный код, форматированный вариант, результат unescape, текст после рефакторинга и извлечённый буфер. В имени указывайте номер объекта и последовательность шага.
Для scDbg и scSigs храните параметры запуска и полный вывод. Смещение старта, лимит шагов и выбранные hooks влияют на результат. Для sclog дополнительно фиксируйте состояние виртуальной машины, сетевую схему и все разрешённые действия.
Финальное заключение должно связывать факты, а не перечислять срабатывания. Укажите, какое событие инициирует код, как он декодирует полезную нагрузку, какие API вызывает и какой объект создаёт или загружает. Отдельно перечислите ограничения анализа: неподдержанный фильтр, неэмулированный метод или недоступный пароль.
Контрольный порядок перед завершением
- Верните полный список объектов и повторите поиски JavaScript, действий, вложений и обфусцированных заголовков.
- Проверьте вкладку Errors и убедитесь, что каждый оранжевый поток сохранён в сыром виде.
- Сопоставьте номера объектов с экспортированными файлами и вычисленными хешами.
- Сохраните исходный и декодированный JavaScript, не оставляя результат только в окне.
- Зафиксируйте параметры эмуляции shellcode и отделите её от живого исполнения.
- Откатите лабораторную машину после опасных запусков и проверьте экспортируемые отчёты.
Завершённый анализ должен позволять другому специалисту повторить путь от строки в списке объектов до конечного артефакта. Если вывод зависит от неподтверждённой догадки, вернитесь к сырому заголовку, фильтрам и связям объектов. Сильная сторона PDF Stream Dumper проявляется именно в последовательном переходе между этими уровнями: структура, декодированный поток, сценарий и машинный код.
При корректной организации процесса программа помогает быстро локализовать активное содержимое, раскрыть распространённые схемы упаковки и подготовить артефакты для внешних анализаторов. Ограниченный парсер, неполная модель JavaScript API и опасность живого выполнения не мешают работе, если каждый автоматический результат проверяется по исходным байтам, а потенциально исполняемые данные остаются внутри изолированной лаборатории.