pdf-parser помогает разобрать PDF на отдельные объекты, словари, ссылки и потоки, найти JavaScript, автоматические действия, вложения и подозрительные ключи, распаковать поддерживаемые фильтры, извлечь выбранное содержимое и подготовить структурированные результаты для дальнейшего анализа.
Работа строится вокруг одного входного файла и набора параметров: сначала команда выводит общую статистику, затем пользователь сужает разбор по типу объекта, номеру, ключу словаря, ссылке или содержимому потока. Такой подход позволяет не открывать подозрительный документ в просмотрщике и постепенно переходить от безопасной инвентаризации к извлечению конкретных данных.
Практический порядок обычно выглядит так: проверить структуру параметром -a, повторить подсчёт с раскрытием объектных потоков через -O, найти опасные конструкции поиском, исследовать связанные объекты, применить фильтры только к нужным потокам и сохранить результат в отдельный файл. Команды хорошо соединяются с хешированием, YARA-правилами и обработкой JSON, поэтому ручной разбор легко превращается в воспроизводимый сценарий.
Скачать pdf-parser
- Редактирование PDF
- Русский интерфейс
- Просто новичкам
- Только командная строка
- Не отображает страницы
- Не все фильтры PDF
Как устроена работа с pdf-parser
Программа читает синтаксис PDF последовательно и показывает фундаментальные элементы документа: комментарии, косвенные объекты, таблицы перекрёстных ссылок, словари, маркеры начала и окончания потоков, трейлер и указатель startxref. На экране не появляется макет страницы, шрифты не превращаются в визуальный текст, а изображения не собираются в готовую композицию. Вместо этого пользователь видит то, из чего документ построен: номера объектов, поколения, пары ключей и значений, ссылки вида 12 0 R, длины потоков, фильтры и хеши.
Базовая команда состоит из имени интерпретатора, файла pdf-parser.py, параметров и анализируемого документа. На системах, где команда Python называется python3, удобно сразу использовать её во всех примерах. Имя исследуемого файла лучше заключать в кавычки, если в пути есть пробелы. Вывод можно читать в терминале, перенаправлять в текстовый файл либо отправлять следующей утилите через конвейер.
python3 pdf-parser.py -a "образец.pdf"
python3 pdf-parser.py -O -a "образец.pdf" > "статистика.txt"
python3 pdf-parser.py -o 12 "образец.pdf"
У каждой операции есть чёткая область действия. Параметр статистики охватывает весь документ, выбор объекта ограничивает вывод конкретным номером, поиск по ключу или строке отбирает совпадения, а декодирование фильтров меняет представление только потоковых данных. Если объединить слишком много параметров без понимания приоритетов, можно получить пустой вывод или исследовать не ту часть файла. Поэтому полезно сохранять команды в журнале и переходить от широкого запроса к узкому.
Подготовка к первому запуску
Для запуска требуется доступный интерпретатор Python и сам файл сценария. После распаковки архив удобно поместить в отдельную рабочую папку вместе с копиями исследуемых документов. Оригиналы лучше хранить только для чтения, а результаты извлечения направлять в подкаталог с понятным именем. Такой порядок защищает исходный образец от случайной перезаписи и позволяет позже повторить каждое действие.
Проверка запуска выполняется вызовом справки. Параметр -h показывает краткий перечень ключей, а -m печатает расширенное руководство. Если оболочка сообщает, что Python не найден, следует проверить имя команды и путь к интерпретатору. Если не найден pdf-parser.py, нужно перейти в каталог со сценарием либо указать полный путь. Ошибка доступа к PDF обычно означает неверное имя, недостаточные права или блокировку файла другим процессом.
python3 pdf-parser.py -h
python3 pdf-parser.py -m
В повседневной работе полезно заранее создать короткий командный файл или функцию оболочки, которая подставляет полный путь к сценарию. При этом исследуемый документ всё равно передаётся явно, чтобы случайно не обработать другой файл. Для повторяемых параметров предусмотрена переменная окружения PDFPARSER_OPTIONS, однако добавлять туда следует только нейтральные настройки вывода. Параметры извлечения, декодирования или выбора объекта безопаснее оставлять в самой команде: так журнал анализа сохраняет точное действие.
Дополнительные возможности подключаются только при необходимости. Для правил YARA нужен соответствующий модуль Python. Для AES-зашифрованных ZIP-контейнеров используется модуль pyzipper. Отсутствие этих компонентов не мешает обычному разбору PDF, но команда с зависимой функцией завершится сообщением об ошибке. Устанавливать расширения стоит в отдельное виртуальное окружение, чтобы не менять системный Python и можно было зафиксировать набор зависимостей.
Быстрая инвентаризация документа
Первый содержательный шаг — статистика -a. Она подсчитывает комментарии, элементы перекрёстных ссылок, трейлеры, маркеры startxref, косвенные объекты и объекты с потоками. Отдельно группируются значения ключа /Type, перечисляются типичные подозрительные ключи и отмечаются объекты, на которые никто не ссылается. Это не вердикт о безопасности, а карта, по которой выбираются следующие команды.
Нормальный документ может содержать JavaScript для форм, URI для обычных гиперссылок, встроенный файл как легитимное вложение или несколько трейлеров после последовательных сохранений. Значение имеет сочетание признаков. Например, /OpenAction рядом с /JavaScript указывает на действие при открытии, а /Launch требует проверки команды и целевого объекта. Большое число неиспользуемых объектов может быть следствием редактирования, но также служит местом для скрытых данных.

Статистика полезна и для сравнения двух образцов. Если документы визуально похожи, но один содержит дополнительные объектные потоки, действия или вложения, различие быстро проявится в счётчиках. Для автоматизированной сортировки вывод можно сохранить и извлечь нужные строки средствами оболочки. Однако числовой порог сам по себе ненадёжен: компактный вредоносный PDF может состоять из нескольких объектов, а сложная интерактивная форма — из тысяч.
Параметр -H добавляет хеши потоков. По умолчанию используется MD5, а переменная DSS_DEFAULT_HASH_ALGORITHMS позволяет выбрать другой алгоритм, например SHA-256. Хеш помогает заметить одинаковый полезный груз в документах с разной оболочкой, но его следует вычислять после одинаковой стадии обработки. Хеш сырого потока и хеш распакованного содержимого закономерно различаются.
Почему статистику стоит повторять с параметром -O
Современный PDF может хранить несколько косвенных объектов внутри специального потока /ObjStm. Без раскрытия такого контейнера внешний разбор видит сам поток, но не обязательно показывает каждый упакованный объект как отдельную сущность. Параметр -O извлекает внутренние записи и включает их в поиск, статистику и выбор по номеру. Для анализа подозрительного файла это принципиально: действие, URI или JavaScript могут находиться именно внутри объектного потока.

Полезно сохранить два отчёта: обычный и с -O. Разница в количестве объектов и ключевых слов показывает, что именно скрывала упаковка. Если после включения параметра появляется /URI, /JavaScript или другой интересующий ключ, дальнейший анализ ведётся уже по найденным номерам. В выводе также указывается контейнер, из которого извлечён объект, что помогает связать внутреннюю запись с физическим расположением данных.

Само наличие /ObjStm не является признаком атаки: объектные потоки применяются для уменьшения размера файла. Риск возникает, когда аналитик ограничивается поверхностным поиском и принимает отсутствие совпадений за отсутствие содержимого. Поэтому для неизвестного документа разумно считать разбор с -O обязательной второй проверкой, а не редкой дополнительной операцией.
python3 pdf-parser.py -a "образец.pdf"
python3 pdf-parser.py -O -a "образец.pdf"
python3 pdf-parser.py -O -s /JavaScript "образец.pdf"
Выбор конкретного объекта
Параметр -o выводит указанный косвенный объект. Номер берётся из статистики, результатов поиска или ссылки в другом словаре. Можно передать несколько номеров через запятую, чтобы получить связанные элементы одним вызовом. Вывод содержит заголовок объекта, словарь, сведения о потоке, фильтрах и ссылках. Это основной способ перейти от общего признака к фактическому содержимому.

При чтении словаря важно различать прямые значения и ссылки. Запись /Length 148 задаёт число непосредственно, а /Length 21 0 R отправляет к другому объекту, где находится фактическая длина. Аналогично действие может ссылаться на JavaScript, вложение — на файловую спецификацию, а файловая спецификация — на поток с данными. Один подозрительный ключ часто приводит к цепочке из трёх или четырёх объектов.
python3 pdf-parser.py -o 12 "образец.pdf"
python3 pdf-parser.py -o 12,18,21 "образец.pdf"
python3 pdf-parser.py -O -o 7 "образец.pdf"
Если номер существует только внутри /ObjStm, выбор без -O может ничего не показать. В таком случае следует повторить команду с раскрытием контейнеров. Если объект повреждён, полезен параметр -x, допускающий извлечение при нетипичном оформлении. Полученный результат всё равно нужно проверять вручную: восстановление границ по эвристике может захватить лишние байты или пропустить часть потока.
Поиск по содержимому объектов
Параметр -s ищет строку в косвенных объектах, не включая потоковые данные. По умолчанию поиск нечувствителен к регистру и допускает частичное совпадение. Это удобно для ключей словаря: запрос /JavaScript находит объекты, где ключ записан явно или после каноникализации имени. Для точного регистра добавляется --casesensitive, а регулярное выражение включается через --regex.
Поиск по ключу лучше начинать с начального слеша, чтобы уменьшить случайные совпадения в строках. Помимо /JavaScript и /JS, часто проверяют /OpenAction, /AA, /Launch, /EmbeddedFile, /RichMedia, /XFA и /URI. Каждый результат следует раскрыть параметром -o и пройти по ссылкам. Ключ говорит о механизме, но не показывает намерение и не заменяет чтение значения.
python3 pdf-parser.py -s /OpenAction "образец.pdf"
python3 pdf-parser.py -O -s /EmbeddedFile "образец.pdf"
python3 pdf-parser.py --regex -s "/J(S|avaScript)" "образец.pdf"
Параметр -r решает обратную задачу: показывает объекты, которые ссылаются на выбранный номер. Он полезен, когда найден интересный поток, но неизвестно, как документ его использует. Если на объект с JavaScript ссылается действие открытия, связь становится очевидной. Если объект не имеет входящих ссылок, он может быть остатком предыдущего сохранения, скрытым грузом или просто неиспользуемой записью; контекст определяют по содержимому и соседним структурам.
Для поиска по ключу словаря предназначен -k. В отличие от общей строки, этот режим ориентируется на структуру словаря и помогает извлекать значения определённого имени. Он удобен при массовой обработке, когда нужны, например, все значения /URI или сведения о фильтрах. Результаты всё равно требуют нормализации: значение может быть строкой, именем, массивом либо ссылкой на отдельный объект.
Каноникализация имён и обфускация через #xx
В PDF имя может содержать шестнадцатеричное экранирование: последовательность #xx представляет один байт. Поэтому опасный ключ иногда записывается как /J#61vaScript или разбивается аналогичным способом. pdf-parser по умолчанию приводит такие имена к каноническому виду, и обычный поиск находит их без ручного перечисления всех вариантов. Это снижает риск пропустить простую обфускацию.
Параметр -n отключает каноникализацию вывода. Он нужен, когда важно увидеть исходное написание и доказать, что автор документа намеренно маскировал ключ. Практический приём — сначала искать в нормализованном представлении, затем повторить вывод найденного объекта с -n и сохранить оба результата. Первый удобен для классификации, второй — для технической фиксации исходных байтов.
python3 pdf-parser.py -s /JavaScript "образец.pdf"
python3 pdf-parser.py -n -o 24 "образец.pdf"
Каноникализация относится к именам PDF, а не к произвольным строкам внутри потока. Если JavaScript дополнительно закодирован, сжат или собран из фрагментов, одного поиска по ключу недостаточно. Сначала нужно найти объект действия, затем перейти к потоку или строке сценария, применить фильтры и только после этого анализировать код.
Исследование JavaScript и автоматических действий
JavaScript в PDF может обслуживать расчёты формы, проверять ввод, менять интерфейс документа или выполнять действия при открытии и закрытии. Анализ начинается не с попытки запустить код, а с построения цепочки ссылок. Сначала ищутся /OpenAction, /AA, /JavaScript и /JS, затем выводятся найденные объекты и объекты, на которые они ссылаются. Цель — определить три вещи: когда код вызывается, где хранится и какие данные получает.

Короткий сценарий может находиться прямо в строке после /JS. Длинный код обычно вынесен в поток. В первом случае важны экранирование скобок, обратные слеши и шестнадцатеричные строки; во втором — цепочка фильтров. После декодирования результат следует сохранять в отдельный текстовый файл и анализировать как данные, не открывая в среде, где сценарий может автоматически выполниться.
python3 pdf-parser.py -O -s /OpenAction "образец.pdf"
python3 pdf-parser.py -O -s /JavaScript "образец.pdf"
python3 pdf-parser.py -O -o 7 -f -d "javascript.txt" "образец.pdf"
Признаки вредоносного поведения ищутся уже в содержимом: длинные строки с процентным кодированием, большие массивы, сборка имён функций, обращения к объектам приложения, подготовка данных для уязвимости, запуск вложения или переход на внешний ресурс. Наличие обфускации увеличивает подозрение, но не доказывает атаку. Формы крупных организаций также могут содержать сложный код, поэтому вывод связывают с событием запуска, происхождением файла и другими объектами.
Параметр --searchstream помогает найти строку непосредственно в потоках. Его полезно сочетать с -f, если искомый текст становится видимым только после распаковки. Для регулярных выражений добавляется --regex. При массовой проверке следует ограничивать шаблон достаточно специфичными признаками: общий поиск слова eval или последовательности http создаёт много шумных совпадений.
Потоки и параметр -f
Поток PDF — последовательность байтов между маркерами stream и endstream, описанная словарём. В нём могут находиться команды рисования страницы, изображения, шрифты, JavaScript, вложения, цветовые профили или объектные потоки. Ключ /Filter сообщает, как данные преобразованы. Параметр -f применяет поддерживаемые фильтры и показывает декодированное содержимое.
Распознаются FlateDecode, ASCIIHexDecode, ASCII85Decode, LZWDecode и RunLengthDecode. Фильтры могут образовывать цепочку, и тогда преобразования выполняются в указанном порядке. Если словарь содержит сокращённые имена или массив фильтров, программа учитывает структуру записи. Для потока изображения с DCTDecode или CCITTFaxDecode универсального текстового декодирования не будет; такой объект лучше сохранить и передать специализированному инструменту.
python3 pdf-parser.py -o 30 -f "образец.pdf"
python3 pdf-parser.py -o 30 -f -d "поток.bin" "образец.pdf"
python3 pdf-parser.py -o 30 -d "сырой-поток.bin" "образец.pdf"
Сравнение сырого и декодированного потока помогает понять, на каком уровне возникла ошибка. Если без -f данные извлекаются, а с фильтрами команда завершается ошибкой, причина обычно в неподдерживаемом фильтре, неверном параметре декодирования или повреждении данных. Если не извлекается даже сырой поток, нужно проверить границы, значение /Length и возможность использовать -x.
Параметр --unfiltered отбирает потоки без фильтров. Он полезен при поиске данных, которые автор оставил в открытом виде, и при быстрой инвентаризации простых документов. Напротив, --overridingfilters позволяет задать собственную цепочку декодирования вместо словаря. Значение raw заставляет обращаться с данными как с необработанными. Такой режим применяют осторожно: он сознательно игнорирует описание объекта и нужен главным образом для повреждённых или намеренно вводящих в заблуждение файлов.
Сохранение потока и сырой вывод
Параметр -d записывает поток выбранного объекта в файл. Если вместо имени указать дефис, байты отправляются в стандартный вывод, что позволяет построить конвейер. Для бинарных данных безопаснее использовать файл: терминал может исказить управляющие символы, а оболочка — применить преобразование кодировки. При извлечении нескольких объектов нужно давать каждому уникальное имя или запускать команду отдельно, иначе результаты будут перезаписаны.
Параметр -w переключает вывод на сырой режим. Он особенно важен для двоичных потоков и точной фиксации байтов, когда обычное представление добавляет служебное оформление. Сырые данные удобно хешировать, сравнивать побайтово и передавать другим анализаторам. При перенаправлении в файл следует убедиться, что в стандартный поток не попадают диагностические сообщения; их при необходимости направляют отдельно средствами оболочки.
python3 pdf-parser.py -o 45 -f -w -d - "образец.pdf" > "объект-45.bin"
python3 pdf-parser.py -o 45 -H "образец.pdf"
Имя расширения выбирается после определения содержимого, а не по типу объекта. Поток /EmbeddedFile может быть исполняемым файлом, архивом, изображением или документом. Сначала проверяют сигнатуру, затем назначают подходящее расширение и открывают только безопасным инструментом. Если первые байты не соответствуют ожидаемому типу, возможны дополнительное кодирование, контейнер или маскировка.
Объектные потоки /ObjStm на практике
Объектный поток содержит заголовочную таблицу пар номер — смещение и последовательность тел объектов. Словарь задаёт число записей и позицию, где начинается содержимое. При -O pdf-parser разбирает эту внутреннюю структуру и показывает упакованные объекты так, словно они доступны отдельно. В выводе отмечается номер контейнера, что позволяет проверить исходный поток и восстановить контекст.

Если поиск находит подозрительный объект внутри контейнера, полезно исследовать и сам /ObjStm. Сначала выводится внутренний объект, затем контейнер без фильтров и после декодирования. Это показывает, правильно ли интерпретирована таблица смещений и нет ли дополнительных байтов, которые не вошли в выделенные записи. Намеренно повреждённые документы иногда используют несогласованность между объявленным количеством объектов и фактическим содержимым.
python3 pdf-parser.py -O -o 7 "образец.pdf"
python3 pdf-parser.py -o 1 -f -d "objstm-1.bin" "образец.pdf"
Различие между видимым номером внутреннего объекта и номером контейнера важно при составлении отчёта. Запись объект 7 содержит JavaScript неполна, если физически он находится в потоке объекта 1. Правильная фиксация облегчает повторный анализ другим специалистом и объясняет, почему поверхностный инструмент не нашёл тот же ключ.
Вложения и файловые спецификации
Встроенный файл обычно представлен цепочкой из словаря имён или аннотации, файловой спецификации и потока типа /EmbeddedFile. Поиск ключа находит поток либо объект, который на него ссылается. Затем параметр -r помогает подняться по цепочке и определить отображаемое имя, отношение к странице и способ запуска. Извлекать только первый найденный поток недостаточно: документ может содержать несколько вложений, эскизы или дублирующие представления.
python3 pdf-parser.py -O -s /EmbeddedFile "образец.pdf"
python3 pdf-parser.py -r 52 "образец.pdf"
python3 pdf-parser.py -o 52 -f -d "вложение.bin" "образец.pdf"
Словарь файловой спецификации может хранить имя в ключах /F и /UF, а дополнительные параметры — размер, контрольную сумму и даты. Эти значения полезны для проверки, но доверять им нельзя: автор файла может указать любое имя и размер. Истинный тип определяется по извлечённым байтам, а размер сверяется с фактическим файлом.
Особое внимание уделяется сочетанию /EmbeddedFile с /Launch, действием открытия или JavaScript. В этом случае вложение может быть предназначено не для ручного просмотра, а для автоматического запуска или социальной инженерии. Безопасный рабочий процесс исключает двойной щелчок по извлечённому файлу; сначала вычисляется хеш, проверяется сигнатура и выполняется статический анализ.
Если поток вложения использует неподдерживаемый фильтр, pdf-parser всё равно может сохранить сырые байты. Дальнейшее декодирование выполняется специализированным инструментом с явным указанием алгоритма. В отчёте нужно различать извлечён поток и восстановлен исходный файл: это не всегда одно и то же.
URI, переходы и действия запуска
Ключ /URI встречается в аннотациях ссылок и действиях. Сам по себе он обычен, но адрес может вести на загрузку, фишинговую страницу или командный ресурс. pdf-parser показывает строку URI и окружающий словарь, поэтому можно установить, к какой аннотации или области страницы относится действие. При наличии объектного потока поиск обязательно повторяется с -O.


Параметр /Launch описывает запуск приложения или файла. Нужно исследовать не только значение рядом с ключом, но и платформенные словари, файловую спецификацию и параметры. Некоторые поля могут содержаться в отдельных объектах. Команда -r показывает, что ссылается на действие, а выбор объектов по номерам раскрывает всю цепочку.
Действия перехода /GoTo, /GoToR и /GoToE используются для навигации внутри документа, к внешнему PDF или к цели во вложении. В легитимных руководствах они нормальны. Опасность определяется целью, автоматическим событием и соседними механизмами. Аналитик должен отделять техническую возможность от фактического поведения и не считать каждую внешнюю ссылку вредоносной.
Строки адресов иногда записываются в шестнадцатеричном виде, разбиваются на части или находятся внутри сценария. Поиск /URI тогда находит механизм, но не обязательно конечное значение. Требуется раскрыть ссылочный объект, декодировать строки и при необходимости исследовать JavaScript. В публичном отчёте адрес лучше обезвредить, чтобы он не стал случайно кликабельным.
Поиск непосредственно в потоках
Обычный -s не сканирует содержимое потоков. Для этого предназначен --searchstream. В сочетании с -f он ищет уже после применения поддерживаемых фильтров. Такой режим подходит для JavaScript, команд содержимого страницы, фрагментов XML, имён файлов и текстовых индикаторов. Если декодирование невозможно, поиск по сырому потоку всё ещё может обнаружить сигнатуру или незашифрованный маркер.
python3 pdf-parser.py --searchstream "eval" -f "образец.pdf"
python3 pdf-parser.py --searchstream "[A-Za-z0-9+/]{120,}={0,2}" --regex -f "образец.pdf"
Регулярные выражения следует подбирать с учётом объёма. Шаблон длинной Base64-подобной строки находит потенциально закодированные блоки, но также совпадает с легитимными ресурсами. Более точный запрос объединяет структуру и индикатор: сначала отбираются потоки определённого типа, затем исследуется их содержимое. Для больших документов лучше сохранить список номеров и обрабатывать каждый объект отдельно, чтобы вывод оставался читаемым.
Параметр --casesensitive полезен для языков и идентификаторов, где регистр значим. Для PDF-ключей он обычно не нужен, поскольку имена чувствительны к регистру, но подозрительная строка может быть специально изменена. При расследовании рекомендуется зафиксировать и нечувствительный, и точный поиск, если различие имеет значение для вывода.
Нулевой результат не доказывает отсутствия индикатора. Данные могут быть зашифрованы, преобразованы неподдерживаемым фильтром, собраны программно или храниться в объекте, который парсер не смог выделить из повреждённой структуры. В таком случае переходят к сырому извлечению, проверке словаря, параметру -x и альтернативным анализаторам.
YARA-правила и декодеры
Параметр -y применяет YARA-правила к потокам. Правило можно передать файлом, каталогом или встроенным выражением в поддерживаемом формате. Сочетание с -f позволяет проверять декодированное содержимое, что особенно полезно для сжатого JavaScript или вложений. Параметр --yarastrings добавляет сведения о совпавших строках, чтобы результат можно было проверить вручную.
YARA должна использоваться как фильтр, а не как окончательное решение. Совпадение по общей строке может быть ложным, а отсутствие совпадения — следствием другого кодирования. Хорошее правило привязано к нескольким независимым признакам, учитывает границы и не полагается на один короткий литерал. В отчёте указывают имя правила, объект, стадию декодирования и совпавшие фрагменты.
python3 pdf-parser.py -O -f -y "правила.yar" --yarastrings "образец.pdf"
python3 pdf-parser.py -O -f --decoders "decoder_xor1.py" -y "правила.yar" "образец.pdf"
Декодеры подключаются параметром --decoders. Они перебирают дополнительные преобразования потока перед проверкой YARA. Параметр --decoderoptions передаёт конкретному декодеру настройки. Такой механизм полезен для однобайтового XOR, сдвигов и других простых схем, встречающихся в вредоносных документах. Подключать следует только проверенный код: декодер выполняется интерпретатором и получает данные анализируемого файла.
При большом числе потоков и декодеров объём работы быстро растёт. Сначала статистика и поиск должны сократить набор объектов, затем YARA применяется к выбранным кандидатам. Это уменьшает время, шум и риск исчерпания памяти на специально подготовленном документе. Для массовой проверки устанавливают ограничения времени и размера на уровне оболочки или среды исполнения.
JSON для автоматизированной обработки
Параметр -j формирует структурированный вывод всех потоковых объектов. Содержимое кодируется Base64, поэтому бинарные данные остаются корректными внутри JSON. Если добавить -f, в структуру попадают потоки после применения поддерживаемых фильтров. Такой результат удобно читать скриптом, загружать в систему анализа или сравнивать между образцами без разбора терминального оформления.
python3 pdf-parser.py -j "образец.pdf" > "потоки.json"
python3 pdf-parser.py -f -j "образец.pdf" > "потоки-декодированные.json"
Перед автоматической обработкой нужно проверить, что стандартный вывод содержит только JSON. Диагностические сообщения и ошибки следует направлять отдельно. Программа-получатель должна ограничивать размер Base64-полей и корректно обрабатывать отсутствие декодированного содержимого. Недоверенный PDF может объявлять огромные размеры или содержать поток, который сильно увеличивается после распаковки.
JSON не заменяет структурный отчёт. Он хорошо переносит номера, данные и метаданные потоков, но связь между объектами всё равно приходится строить по ссылкам и словарям. Практический конвейер сначала отбирает подозрительные номера по статистике и ключам, затем извлекает соответствующие записи из JSON и сохраняет артефакты с однозначными именами.
При сравнении результатов важно использовать одинаковый режим. Поток до и после -f — разные представления, а включение -O меняет набор видимых объектов. В журнале обработки следует фиксировать все параметры, хеш исходного PDF и хеш созданного JSON. Тогда отчёт можно воспроизвести и проверить независимо.
Хеширование потоков и поиск повторов
Параметр -H вычисляет хеш потоковых данных и показывает его рядом с объектом. Это помогает находить повторяющийся JavaScript, одинаковые вложения или шаблонные компоненты в разных PDF. Для надёжной идентификации предпочтителен SHA-256, задаваемый переменной DSS_DEFAULT_HASH_ALGORITHMS. При необходимости можно выбрать несколько алгоритмов, если синтаксис окружения и рабочий процесс это предусматривают.
DSS_DEFAULT_HASH_ALGORITHMS=sha256 python3 pdf-parser.py -H "образец.pdf"
На Windows переменная задаётся синтаксисом соответствующей оболочки; смысл остаётся тем же. Команду лучше сохранить вместе с отчётом, потому что один и тот же объект даст разные хеши в сыром и декодированном представлении. Для поиска повторов сначала выбирают единую стадию: например, все потоки после FlateDecode. Затем сравнивают хеши только между сопоставимыми данными.
Совпадающий хеш доказывает идентичность байтов, но не равен идентичности документа. Один и тот же поток может быть подключён к разным событиям или вообще не использоваться. Поэтому после совпадения проверяют входящие ссылки и словари действий. Обратная ситуация тоже возможна: функционально одинаковый сценарий с изменёнными пробелами или именами переменных даст другой хеш.
При расследовании полезно создать таблицу хеш — объект — контейнер — тип — ссылки. Она показывает повторное использование и отделяет общий ресурс от полезной нагрузки. pdf-parser предоставляет необходимые номера и хеши, а объединение выполняется небольшим скриптом или таблицей анализа.
Неиспользуемые объекты и следы последовательных сохранений
Статистика отмечает объекты, на которые нет ссылок из других разобранных объектов. Такие записи появляются после редактирования, удаления страниц и инкрементальных сохранений, когда старые данные остаются в файле. Они также могут хранить скрытый текст, предыдущую форму, удалённое вложение или преднамеренно спрятанный поток. Список служит очередью для проверки, а не автоматическим признаком вредоносности.

Каждый неиспользуемый объект выводят по номеру, определяют тип и проверяют наличие потока. Если это старый каталог или дерево страниц, по ссылкам можно восстановить предыдущую структуру документа. Если это поток с исполняемой сигнатурой или сценарием, данные извлекают и хешируют. Объекты нулевой длины, служебные записи и устаревшие таблицы обычно менее интересны, но окончательное решение зависит от задачи.
Несколько трейлеров и цепочка /Prev указывают на последовательные обновления. Анализ должен учитывать, какая таблица ссылок активна и какие объекты заменены более поздними поколениями. Простое перечисление всех записей может смешать текущие и устаревшие состояния. Для спорных случаев полезно дополнить pdf-parser инструментом, который умеет материализовать отдельные ревизии PDF.
Отсутствие входящих ссылок может быть следствием повреждения или особенностей разбора. Перед выводом о скрытом объекте нужно проверить, не находится ли ссылка внутри нераскрытого /ObjStm, закодированного потока или нестандартного элемента. Повтор статистики с -O и поиск номера через -r уменьшают риск ошибки.
Повреждённые и намеренно искажённые PDF
Некоторые документы нарушают спецификацию случайно, другие делают это намеренно, рассчитывая на различия между просмотрщиками и анализаторами. Типичные проблемы — неверная длина потока, лишние байты до endstream, отсутствующая таблица ссылок, повторяющиеся номера объектов, несогласованные поколения и обрезанный конец файла. pdf-parser старается читать фундаментальные элементы без полноценного рендеринга, но не может однозначно восстановить каждый случай.
Параметр -x включает извлечение при повреждённом оформлении и помогает получить содержимое, которое обычный режим отвергает. Результат следует помечать как эвристический. После сохранения проверяют начало и конец, сигнатуру, заявленный размер и наличие посторонних байтов. Если извлечённый поток является архивом, его тестируют без распаковки; если изображением — проверяют декодером, не запускающим сценарии.
python3 pdf-parser.py -x -o 31 -d "объект-31.bin" "повреждённый.pdf"
python3 pdf-parser.py -D -a "повреждённый.pdf" > "debug.log"
Параметр отладки -D записывает техническую информацию, полезную при сбое парсера. В журнале могут находиться пути и данные образца, поэтому его хранят вместе с материалами расследования. Сообщение об ошибке нужно сопоставлять с позицией в файле и ближайшими маркерами. Простая правка исходного PDF недопустима: все эксперименты выполняют на копии, а хеш оригинала остаётся неизменным.
Когда два анализатора дают разные результаты, это не обязательно ошибка одного из них. Просмотрщик может восстанавливать таблицу ссылок, выбирать последнее определение объекта или игнорировать мусор иначе. В отчёте следует описать конкретное расхождение: какой объект видит каждый инструмент, какое значение считает активным и как это влияет на поведение документа.
Выбор элементов через -e
Параметр -e ограничивает вывод категориями фундаментальных элементов. Буква c выбирает комментарии, x — таблицы перекрёстных ссылок, t — трейлеры, s — маркеры startxref, i — косвенные объекты. Несколько букв комбинируются. Такой фильтр полезен, когда полный разбор слишком велик или нужно исследовать только структуру обновлений.
python3 pdf-parser.py -e xts "образец.pdf"
python3 pdf-parser.py -e i "образец.pdf"
Вывод таблиц и трейлеров помогает проверить цепочку /Prev, размер пространства объектов и положение корневого каталога. Комментарии могут содержать нестандартные маркеры, данные до заголовка PDF или служебные заметки генератора. Косвенные объекты составляют основную массу документа, поэтому режим i разумно сочетать с поиском или выбором номера.
Фильтрация элементов не декодирует потоки и не определяет безопасность. Она лишь уменьшает область вывода. Если задача — найти вложение или сценарий, эффективнее использовать ключевой поиск и статистику. Режим -e особенно ценен при изучении синтаксических аномалий и ручном сопоставлении смещений.
Типы объектов и параметр -t
Параметр -t отбирает объекты по значению ключа /Type. Он помогает быстро сосредоточиться на страницах, каталогах, объектных потоках, файловых спецификациях и других структурных категориях. Значение указывается в том виде, в каком оно встречается в PDF, обычно с начальным слешем. Не каждый объект имеет /Type, поэтому нулевой результат не означает отсутствия нужной функции.
python3 pdf-parser.py -t /ObjStm "образец.pdf"
python3 pdf-parser.py -t /EmbeddedFile "образец.pdf"
python3 pdf-parser.py -t /Page "образец.pdf"
Для вложений тип часто находится непосредственно в потоке, а имя и действие — в связанных объектах. Для JavaScript значение /Type может отсутствовать, поэтому лучше искать ключи /JS и /JavaScript. Типовой фильтр удобен как часть стратегии, но не заменяет поиск по словарям и ссылкам.
Если документ использует объектные потоки, добавляется -O. Иначе некоторые типизированные объекты останутся внутри контейнера. При сравнении количества объектов по типам важно фиксировать режим раскрытия, поскольку цифры без него и с ним относятся к разным представлениям структуры.
Генерация сценария для воспроизведения структуры
Параметр -g создаёт Python-код, способный сформировать разобранный PDF. Этот режим используют для учебного исследования, минимизации образца и воспроизведения отдельных конструкций. Сгенерированный код следует считать недоверенным артефактом: перед запуском его читают, выполняют в изолированной среде и направляют результат в новый файл.
Сгенерированный сценарий удобен, когда нужно передать коллеге воспроизводимый пример или последовательно удалить несущественные объекты. Однако автоматически созданный образец может не сохранить нестандартные повреждения, исходные смещения и конкурирующие определения, от которых зависело поведение оригинала.
python3 pdf-parser.py -g "образец.pdf" > "воссоздать.py"
Перед распространением сгенерированного сценария удаляют конфиденциальные строки и проверяют, не содержит ли он полезную нагрузку. В отчёте указывают, что это реконструкция, а не побайтовая копия. Хеш созданного PDF закономерно отличается, даже если логическая структура близка.
Анализ PDF внутри ZIP
В качестве входа можно передать ZIP-контейнер. Для распространённых исследовательских архивов поддерживается пароль infected. Это позволяет разбирать образец, не извлекая его вручную в рабочую папку. Если архив зашифрован AES, требуется модуль pyzipper. Обычный ZIP обрабатывается стандартными средствами Python.
python3 pdf-parser.py -a "образец.zip"
python3 pdf-parser.py -O -s /JavaScript "образец.zip"
Архив должен содержать однозначно выбираемый PDF. Если внутри несколько файлов, вложенные каталоги или необычные имена, поведение необходимо проверить на тестовой копии. Для доказательного анализа лучше отдельно записать хеш ZIP и хеш PDF после контролируемого извлечения, чтобы было понятно, к какому уровню относится каждый результат.
Ошибка пароля, неподдерживаемое шифрование или повреждённая центральная директория не связаны с синтаксисом PDF. Сначала проверяют сам архив специализированной командой без распаковки, затем наличие pyzipper и правильность пароля. Не следует менять расширение ZIP на PDF: это скрывает контейнер и усложняет воспроизводимость.
Обработка файла по сетевому адресу
Программа умеет принимать адрес PDF как вход. Это удобно для лабораторной автоматизации, но требует особой осторожности: загрузка создаёт сетевой запрос, раскрывает адрес исследовательской системы и может получить изменившийся файл. Для серьёзного расследования предпочтительнее сначала скачать образец контролируемым средством, зафиксировать время, заголовки, размер и хеш, а затем анализировать локальную копию.
Если прямой вход всё же используется, адрес передают как единственный аргумент файла. Нельзя вставлять в команду секреты, токены или адреса из непроверенного отчёта без экранирования. Перенаправления, сертификаты, прокси и ограничения сети могут изменить результат. Ошибка загрузки не говорит ничего о валидности PDF и должна рассматриваться отдельно от ошибок парсинга.
Сетевой сервер способен отдавать разные данные по времени, региону и заголовку клиента. Поэтому вывод pdf-parser обязательно связывают с хешем фактически полученных байтов. Если важен повторный анализ, копию сохраняют в хранилище образцов с контролем доступа. В публичных материалах опасный адрес обезвреживают и не делают кликабельным.
Практический сценарий: подозрительное письмо с PDF
Полученный из письма документ сначала копируют в изолированную папку и вычисляют хеш всего файла. Затем запускают статистику без раскрытия объектных потоков и с -O. Сравнивают число объектов, потоки и ключи /OpenAction, /AA, /JavaScript, /Launch, /EmbeddedFile и /URI. Уже на этом этапе можно определить приоритет дальнейших действий.
Если найдено автоматическое действие, его объект выводят и проходят по каждой ссылке. Сценарий или вложение сохраняют отдельно, вычисляют хеш и определяют тип по сигнатуре. Поток декодируют только поддерживаемыми фильтрами; при ошибке сохраняют сырые байты. Все команды и номера объектов записывают, чтобы другой аналитик мог повторить путь.
Если опасные ключи не найдены, проверяют потоки поиском по строкам, неиспользуемые объекты и различия после -O. Отсутствие очевидного JavaScript не исключает фишинг: обычная ссылка или визуально поддельная форма может быть достаточной. pdf-parser отвечает за структуру, а визуальную часть при необходимости получают безопасным рендерером в песочнице.
Итоговый вывод формулируют конкретно: какие механизмы присутствуют, какое событие их вызывает, где находятся данные и удалось ли их декодировать. Формулировка PDF вредоносный без объекта, действия и артефакта хуже проверяется и не помогает защите.
Практический сценарий: поиск встроенного файла
Начальная команда ищет /EmbeddedFile с раскрытием объектных потоков. Для каждого совпадения выводится словарь и фиксируется номер. Затем -r показывает файловую спецификацию или дерево имён, которые ссылаются на поток. Из этих объектов извлекаются имя, описание и дополнительные параметры. Только после построения цепочки поток сохраняется на диск.
Если указан фильтр, сначала создают декодированную копию, затем при необходимости сырую. Обе получают разные имена и хеши. Сигнатура определяет реальный формат; заявленное имя используется только как подсказка. Если файл начинается с сигнатуры исполняемого формата, его не запускают и не передают обычному просмотрщику.
Далее проверяется, связан ли объект с /Launch, JavaScript или аннотацией. Вложение, доступное только через панель вложений, имеет иной риск, чем автоматически запускаемый объект. Отчёт должен отражать способ активации. Если ссылок нет, объект рассматривается как неиспользуемый артефакт, но его содержимое всё равно может быть значимым.
Практический сценарий: сравнение двух похожих PDF
Для двух документов выполняют одинаковый набор команд: статистика с -O, хеши потоков, перечень типов и ключевой поиск. Результаты сохраняют в отдельные файлы с одинаковой схемой имён. Сначала сравнивают количество объектов и ключевых конструкций, затем сопоставляют хеши потоков. Совпавшие хеши позволяют исключить общие ресурсы и сосредоточиться на различиях.
Если номера объектов не совпадают, сопоставление по номеру ненадёжно. Лучше использовать тип, размер, хеш и входящие ссылки. Один и тот же сценарий может находиться под другим номером, а перестроенный PDF — полностью перенумеровать ресурсы. Для текстовых потоков дополнительно применяют нормализацию пробелов только в отдельной копии, не заменяя ею исходный хеш.
Различие в одном URI, действии или вложении может быть существеннее сотен изменений в шрифтах. Поэтому сравнение строится по семантическому приоритету: автоматические события, исполняемые данные, внешние переходы, формы, затем ресурсы отображения. pdf-parser предоставляет низкоуровневые факты, а приоритет задаёт аналитик.
Практический сценарий: массовая первичная сортировка
Для каталога документов можно запускать статистику в цикле и сохранять отдельный отчёт на каждый файл. Имена отчётов должны строиться безопасно, без выполнения фрагментов исходного имени. Перед обработкой проверяют расширение и сигнатуру, устанавливают лимит времени и не разрешают записи за пределы рабочей папки. Ошибка одного образца не должна останавливать весь пакет.
На первом проходе извлекают счётчики ключей и число потоков. На втором обрабатывают только документы с интересующими признаками, включая -O, поиск и YARA. Такой двухступенчатый процесс быстрее полного декодирования каждого потока. При этом выбор порогов фиксируют и периодически пересматривают на доброкачественной выборке, чтобы оценить ложные срабатывания.
JSON-режим упрощает передачу потоков в собственный анализатор, но Base64 увеличивает объём. Для очень больших документов лучше извлекать только выбранные объекты. Хеш исходного файла, команда, код завершения и размер отчёта должны храниться в журнале. Это позволяет отличить чистый результат от сбоя или тайм-аута.
Автоматическая сортировка не заменяет ручной анализ редких конструкций. Документы без типовых ключей могут использовать формы, подписи, повреждение или социальную инженерию. Очередь должна включать случайную проверку чистых файлов и механизм повторной обработки после обновления правил.
Ошибки при декодировании потоков
Сообщение об ошибке после -f чаще всего связано с неподдерживаемым фильтром, неверными параметрами, повреждёнными байтами или неправильной границей потока. Сначала выводят словарь без декодирования и записывают значение /Filter и /DecodeParms. Затем сохраняют сырой поток. Если его размер отличается от ожидаемого, проверяют /Length и связанные объекты.
Для цепочки фильтров важно соблюдать порядок. Попытка вручную применить только последний этап к исходным данным даст ошибку. Если pdf-parser поддерживает не всю цепочку, можно сохранить результат после доступного этапа только с явным переопределением и затем продолжить специализированным инструментом. В отчёте обязательно указывают, какие преобразования действительно выполнены.
Потоки изображений часто используют DCTDecode или JPXDecode. Их не нужно превращать в текст. Сырые данные могут уже быть корректным JPEG или JPEG 2000, который проверяется безопасным декодером. CCITTFaxDecode требует параметров ширины, высоты и режима, поэтому один поток без словаря недостаточен для восстановления изображения.
При подозрении на zip bomb или чрезмерное расширение устанавливают предел памяти и размера результата. Даже корректный Flate-поток может распаковаться в гигабайты. pdf-parser не должен запускаться с неограниченными ресурсами на недоверенной коллекции.
Ошибки выбора и пустой вывод
Пустой результат -o обычно означает неверный номер, отсутствие объекта в активной структуре или необходимость -O. Сначала повторяют статистику, затем ищут номер через -r и проверяют, не является ли он внутренним объектом контейнера. Номер поколения тоже важен при повторных определениях, хотя большинство команд ориентируется на представление, которое удалось разобрать.
Пустой поиск -s может быть следствием обфускации, другого регистра, хранения в потоке или шифрования. Последовательно проверяют каноникализацию, --casesensitive, --searchstream, -f и -O. Одновременное включение всех параметров затрудняет диагностику; лучше менять по одному и сохранять результат.
Если команда выводит слишком много объектов, запрос нужно сузить. Используются тип, номер, ключ или регулярное выражение. Перенаправление огромного бинарного потока в терминал ухудшает читаемость и может повредить сеанс; для него применяют -d и файл. Для текстового отчёта предпочтительна кодировка UTF-8 и просмотрщик, который не исполняет управляющие последовательности.
Систематизация результатов анализа
Удобная структура рабочей папки содержит неизменяемый оригинал, текстовые отчёты, извлечённые объекты, правила и журнал команд. Имя каждого артефакта включает номер объекта и стадию: raw, filtered, decoded или reconstructed. Это предотвращает путаницу между исходными и преобразованными данными.
Для каждого результата записывают SHA-256, размер, команду создания и связь с объектом PDF. Если поток находился в /ObjStm, добавляют номер контейнера. Если применялся декодер или YARA, фиксируют его имя и параметры. Такой минимум позволяет подтвердить происхождение файла без доверия к памяти аналитика.
Снимки терминала полезны для иллюстрации, но не заменяют машиночитаемый журнал. Текстовый вывод можно искать, сравнивать и повторно обрабатывать. Скриншот сохраняют только для контекста или отчёта, а исходный вывод оставляют рядом. Конфиденциальные пути и имена при публикации удаляют из копии, не меняя оригинальный материал расследования.
Разбор содержимого страницы без рендеринга
Поток содержимого страницы хранит графические операторы: выбор шрифта, вывод строк, построение контуров, преобразование координат, размещение изображений и переключение графического состояния. pdf-parser может найти объект страницы, пройти к ключу /Contents, вывести связанные потоки и распаковать их параметром -f. Результат показывает команды, но не собирает их в изображение, поэтому координаты, ресурсы и матрицы приходится интерпретировать отдельно.
Для поиска нужной страницы сначала отбирают объекты типа /Page, затем изучают словарь ресурсов и /Contents. Значение может быть одной ссылкой или массивом ссылок, если содержимое разделено на несколько потоков. Каждый поток сохраняют отдельно и отмечают порядок в массиве. Перестановка частей меняет результат отображения, поэтому объединять их без фиксации порядка нельзя.
python3 pdf-parser.py -t /Page "образец.pdf"
python3 pdf-parser.py -o 14 "образец.pdf"
python3 pdf-parser.py -o 19 -f -d "page-1-content.txt" "образец.pdf"
Текст в потоке не всегда читается как обычная строка. Он может использовать шестнадцатеричные коды, составные шрифты и таблицы /ToUnicode. pdf-parser показывает байты и ссылки на ресурсы, но полноценное извлечение текста требует интерпретации кодировки шрифта. Если задача состоит в поиске визуальной надписи, структурный разбор дополняют специализированным экстрактором текста или безопасным рендерером.
Скрытые элементы ищут по сочетанию операторов и графического состояния. Нулевой размер, цвет фона, маска, обрезка или размещение за пределами страницы могут сделать объект невидимым. Сам поток даёт материал для проверки, но вывод о видимости требует расчёта матриц и границ. Поэтому полезно сохранять номер страницы, поток, используемые ресурсы и соответствующий визуальный кадр из отдельной среды.
Формы AcroForm и XFA
Ключ /AcroForm в каталоге ведёт к структуре интерактивной формы. Поля могут содержать значения, действия, сценарии проверки, форматирования и вычисления. Поиск начинается с /AcroForm, затем раскрываются массив /Fields, дочерние элементы /Kids и дополнительные действия /AA. Один логический элемент формы нередко распределён между несколькими объектами.
Значения полей могут находиться в /V, варианты выбора — в /Opt, а внешний вид — в потоках /AP. Несовпадение значения и внешнего вида важно: просмотрщик может показать старую картинку поля, хотя структурное значение уже изменено. pdf-parser позволяет сравнить ссылки и содержимое, но визуальное подтверждение выполняется рендерером.
Ключ /XFA указывает на XML Forms Architecture. Данные могут быть массивом имён и потоков либо одним большим потоком. После выбора объекта и применения -f часто получается XML, который сохраняют как текст и проверяют отдельным безопасным анализатором. Внутри могут находиться сценарии, адреса отправки, шаблоны и данные пользователя.
python3 pdf-parser.py -O -s /AcroForm "образец.pdf"
python3 pdf-parser.py -O -s /XFA "образец.pdf"
python3 pdf-parser.py -o 64 -f -d "xfa.xml" "образец.pdf"
Форма не является вредоносной только из-за наличия JavaScript или XFA. Проверяется событие, которое вызывает код, операции с данными и внешние действия. Особого внимания требуют отправка формы, скрытые поля, действия при фокусе и автоматическое выполнение при открытии. Итоговый отчёт должен разделять обычную логику проверки ввода и поведение, выходящее за пределы документа.
Шифрование и ограничения доступа
Зашифрованный PDF содержит словарь /Encrypt, идентификаторы документа и параметры алгоритма. Даже если просмотр разрешён без запроса пароля, строки и потоки могут храниться в зашифрованном виде. pdf-parser показывает доступные структурные элементы, но чтение содержимого зависит от схемы и ключей. Нечитаемый поток нельзя автоматически считать обфускацией: сначала проверяют наличие шифрования.
Поиск /Encrypt и вывод трейлера показывают ссылку на словарь. В нём анализируют /Filter, /V, /R, длину ключа и криптографические фильтры. Эти значения нужны для совместимости с инструментом расшифрования. Не следует публиковать пароли или ключевой материал в командной строке общего журнала, где они могут сохраниться в истории оболочки.
После контролируемой расшифровки создаётся новый файл, а оригинал остаётся неизменным. Для обоих вычисляют хеши и отмечают применённую операцию. Статистику и поиск выполняют повторно по расшифрованной копии, потому что ранее скрытые строки и потоки становятся доступными. Сравнение отчётов показывает, какие ограничения были связаны именно с криптографией.
Разрешения на печать, копирование и изменение — часть словаря безопасности, но они не являются технической гарантией отсутствия доступа. Для анализа важнее фактическая возможность получить содержимое законным и разрешённым способом. pdf-parser не следует использовать для обхода защиты; работа ведётся с документами, на исследование которых у пользователя есть полномочия.
Перекрёстные ссылки, трейлер и startxref
Таблица перекрёстных ссылок связывает номер объекта с его положением в файле. Трейлер указывает корневой каталог, размер пространства объектов, словарь шифрования, идентификаторы и предыдущую таблицу. Маркер startxref сообщает смещение активной структуры. Параметр -e xts выделяет эти элементы и позволяет изучить их без вывода всех объектов.
В классическом PDF xref представлен текстовой таблицей, а в более компактном варианте — потоком типа /XRef. Объект может быть свободным, находиться по прямому смещению или внутри /ObjStm. Несогласованность между таблицей и фактическими маркерами иногда возникает после повреждения, а иногда используется для обхода анализаторов. Просмотрщики способны восстанавливать структуру по-разному.
Цепочка /Prev ведёт к предыдущим сохранениям. Если документ менялся инкрементально, последующий объект с тем же номером заменяет раннее состояние. Для анализа важно понимать, какое определение активно и какие данные остались только в старой ревизии. pdf-parser показывает элементы, но реконструкцию каждой ревизии удобнее подтверждать qpdf или другим инструментом, предназначенным для структурных преобразований.
python3 pdf-parser.py -e xts "образец.pdf"
python3 pdf-parser.py -s /XRef "образец.pdf"
python3 pdf-parser.py -s /Prev "образец.pdf"
Ошибочное значение startxref не всегда мешает просмотрщику открыть файл, потому что тот может просканировать маркеры объектов. Для доказательного отчёта фиксируют заявленное смещение, фактическое положение и поведение нескольких инструментов. Формулировка должна описывать расхождение, а не только сообщение об ошибке.
Цифровые подписи и инкрементальные изменения
Подпись PDF обычно связана со словарём поля, ключом /V, объектом сигнатуры и диапазоном /ByteRange. Значение /Contents содержит криптографический контейнер. pdf-parser помогает найти эти объекты, проверить ссылки и увидеть диапазоны байтов, но не выполняет полноценную криптографическую проверку доверия. Для неё требуется средство, которое проверяет сертификат, цепочку и метку времени.
/ByteRange перечисляет части файла, покрытые подписью, оставляя промежуток для самого контейнера. Сумма диапазонов должна соответствовать ожидаемой структуре. Данные, добавленные после подписанного диапазона, могут быть допустимым последующим обновлением или нежелательным изменением. Аналитик сопоставляет границы с xref, трейлерами и объектами поздней ревизии.
Поиск полей подписи выполняют по /Sig, /ByteRange и /Contents. Большой шестнадцатеричный блок не следует печатать полностью в терминал; лучше сохранить выбранный объект в отчёт и при необходимости извлечь контейнер отдельным скриптом. Хеш всего PDF не заменяет проверку подписи, потому что любое разрешённое инкрементальное изменение меняет хеш файла.
Практический вывод формулируют аккуратно: структура подписи найдена, диапазоны определены, поздние объекты перечислены, а криптографический статус проверен или не проверен отдельным валидатором. pdf-parser предоставляет факты о размещении данных и помогает обнаружить неожиданный хвост после подписанной области.
Проверка собственных команд на тестовом PDF
Перед анализом неизвестного образца полезно создать маленький тестовый PDF с известной структурой: одной страницей, URI, простым потоком и вложением. На нём проверяют синтаксис команд, пути вывода и работу дополнительных модулей. Тестовый файл не должен содержать активную полезную нагрузку; его задача — показать ожидаемые номера, фильтры и результаты поиска.
Сначала сохраняют эталонную статистику, затем запускают те же команды в рабочей среде. Если вывод отличается, проверяют Python, переменные окружения и набор декодеров. Такой контроль особенно полезен после обновления среды или переноса сценария на другой компьютер. Он отделяет проблему конфигурации от особенностей подозрительного документа.
Для YARA создают правило, совпадающее с уникальной безопасной строкой в тестовом потоке. Проверяют режим без -f, после фильтра и с --yarastrings. Для JSON убеждаются, что результат разбирается стандартным парсером и Base64 декодируется в ожидаемые байты. Для -d сверяют хеш извлечённого файла с заранее рассчитанным значением.
Эталонные команды становятся частью рабочей инструкции. Они позволяют быстро диагностировать пустой вывод, ошибку зависимости или неверное перенаправление. После успешного теста применяют тот же шаблон к образцу, меняя только имя файла и номера объектов, полученные из его статистики.
Сравнение pdf-parser с аналогами
Инструменты низкоуровневой работы с PDF пересекаются по отдельным функциям, но решают разные задачи. pdf-parser ориентирован на пообъектный разбор, подозрительные ключи, потоки, YARA и воспроизводимые команды. При выборе важно понять, требуется ли интерактивная исследовательская оболочка, восстановление структуры, преобразование файла, быстрый сканер признаков или визуальное редактирование.
| Программа | Лучше подходит для | Главное ограничение |
|---|---|---|
| pdf-parser | Пообъектного анализа, декодирования потоков, YARA и извлечения артефактов | Нет визуального представления страниц |
| peepdf | Интерактивного исследования подозрительных PDF, ревизий и зашифрованных объектов | Более сложная среда и набор зависимостей |
| qpdf | Проверки синтаксиса, нормализации, отключения объектных потоков и структурных преобразований | Не ориентирован на индикаторы вредоносных действий и YARA |
| MuPDF mutool | Быстрого просмотра трейлера, xref, объектов, JavaScript и извлечения ресурсов | Меньше специализированной логики для первичной сортировки угроз |
| PDFiD | Очень быстрого подсчёта подозрительных ключей без глубокого разбора | Не раскрывает полное содержимое объектов и потоков |
| PDF Commander | Редактирования страниц, текста, изображений и обычных пользовательских задач | Не предназначен для низкоуровневой криминалистики объектов |
Для первичного статического расследования и извлечения конкретного объекта рационален pdf-parser. peepdf удобнее, когда нужна интерактивная сессия и просмотр нескольких состояний документа. qpdf выбирают для проверки и нормализации структуры, а mutool — для широкого набора операций вокруг формата и ресурсов. PDFiD подходит как быстрый предфильтр. PDF Commander нужен пользователю, который редактирует содержимое и страницы, а не исследует внутренний синтаксис.
Практические ограничения pdf-parser
Программа не рендерит страницу, поэтому не показывает поддельную кнопку, невидимый слой, перекрывающую аннотацию или визуальное расхождение между объектами. Для таких задач нужен безопасный рендерер, запускаемый отдельно. Сопоставление структуры и изображения особенно важно при фишинге, где PDF может не содержать кода, но убедительно имитировать форму входа.
Поддерживается не каждый потоковый фильтр. Это заметно на изображениях, факсимильных данных и некоторых сложных цепочках. Неподдерживаемый поток всё равно можно сохранить сырым, но восстановление требует другого декодера и параметров из словаря. Ошибочно считать файл пустым только потому, что -f не дал читаемого текста.
Командный вывод требует понимания синтаксиса PDF. Номера объектов, ссылки и словари не объясняют сами себя, а одинаковый ключ может быть легитимным или опасным в зависимости от контекста. Новичку полезно начинать с небольших доброкачественных документов, сравнивать их структуру и только затем переходить к подозрительным образцам.
Шифрованный документ может ограничить доступ к содержимому. Некоторые инструменты лучше справляются с паролями, криптографией и восстановлением. pdf-parser полезен для видимой структуры и отдельных случаев, но не заменяет полный набор средств анализа PDF. Результаты следует проверять вторым инструментом, если от вывода зависит решение о безопасности.
Запуск Python-кода, декодеров и YARA-модулей создаёт собственную поверхность риска. Сценарий и расширения должны поступать по проверенному каналу, а работа с недоверенными файлами — выполняться в ограниченной среде. Статический анализ безопаснее открытия документа, но не абсолютно безопасен при неограниченных ресурсах и сторонних модулях.
Рабочая памятка
Начинайте с хеша исходного PDF и статистики -a. Сразу повторяйте статистику с -O и сравнивайте результаты. Затем ищите автоматические действия, JavaScript, вложения, URI и запуск файлов. Каждый найденный объект раскрывайте по номеру, проходите по ссылкам в обе стороны и фиксируйте контейнер /ObjStm, если он используется.
Потоки сначала сохраняйте сырыми, затем применяйте -f и вычисляйте отдельные хеши. Неподдерживаемый фильтр не является тупиком: словарь и сырые байты передаются подходящему декодеру. Для большого числа объектов используйте поиск в потоках, YARA и JSON, но ограничивайте ресурсы и сохраняйте точную команду.
Не делайте вывод по одному ключу или счётчику. Связывайте механизм с событием, объектом данных и входящими ссылками. Проверяйте неиспользуемые объекты и последовательные обновления, особенно если видимое содержимое не объясняет размер файла. Для визуальных признаков применяйте отдельный безопасный рендерер.
Анализ считается завершённым, когда другой специалист может повторить команды, получить те же номера и хеши, увидеть путь от триггера к содержимому и понять ограничения декодирования. Такой отчёт полезнее общей оценки: он показывает, что именно делает документ, где это хранится и какие артефакты извлечены без запуска активного содержимого.