Package: pdfalyzer
THE PDFALYZERA PDF analysis tool forvisualizingthe inner tree-like data structure[^1] of a PDF inspectacularly large and colorful diagramsas well as scanning the binary streams embedded in the PDF for hidden potentially malicious content. The Pdfalyzer makes heavy use of YARA (viaThe Yaralyzer) for matching/extracting byte patterns.PyPi Users:This document renders a lot betteron GitHub. Pictures, footnotes, etc.Quick Startpipxinstallpdfalyzer
pdfalyze"martin_heidegger-being_illmatic.pdf"What It DoGenerate in depth visualizations of PDF tree structures[^1]. Shows every property of every PDF object at a glance. See theExample Outputsection below for details.Scan for mad sus content with a bunch of PDF specificYARArules.Forcibly decode suspect bytes.The Yaralyzerdoes the heavy lifting.Display detailed information about embedded fonts.With character maps.Usable as a library for your own PDF related code.If you're looking for one of these things this may be the tool for you.What It Don't DoThis tool is mostly for examining/working with a PDF's data and logical structure. As such it doesn't have much to offer as far as extracting text, rendering[^3], writing, etc. etc.InstallationInstallation withpipx[^4] is preferred thoughpip3should also work.pipxinstallpdfalyzerSeePyPDF2 installation notesaboutPyCryptodomeif you plan topdfalyzeany files that use AES encryption.Troubleshooting The InstallationIf you usedpip3instead ofpipxand have an issue you should try to install withpipx.If you run into an issue about missing YARA try to installyara-python.If you encounter an error building the pythoncryptographypackage check yourpipversion (pip --version). If it's less than 22.0, upgradepipwithpip install --upgrade pip.On Linux if you encounter an error buildingwheelorcffiyou may need to install some packages:sudoapt-getinstallbuild-essentiallibssl-devlibffi-devrustcUsageRunpdfalyze --helpto see usage instructions. As of right now these are the options:Runtime OptionsIf you provide none of the flags in theANALYSIS SELECTIONsection of the--helpthen all of the analyses will be doneexceptthe--streams.  In other words, these two commands are equivalent:pdfalyzer lacan_buys_the_dip.pdfpdfalyzer lacan_buys_the_dip.pdf -d -t -r -f -y -cThe--streamsoutput is the one used to hunt for patterns in the embedded bytes and can beextremelyverbose depending on the--quote-charoptions chosen (or not chosen) and contents of the PDF.The Yaralyzer) handles this task; if you want to hunt for patterns in the bytes other than bytes surrounded by backticks/frontslashes/brackets/quotes/etc. you may want to use The Yaralyzer directly. As The Yaralyzer is a prequisite for The Pdfalyzer you may already have theyaralyzecommand installed and available.Setting Command Line Options Permanently With A.pdfalyzerFileWhen you runpdfalyzeon some PDF the tool will check for a file called.pdfalyzerfirst in the current directory and then in the home directory. If it finds a file in either such place it will load configuration options from it. Documentation on the options that can be configured with these files lives in.pdfalyzer.examplewhich doubles as an example file you can copy into place and edit to your needs. Handy if you find yourself typing the same command line options over and over again.Environment VariablesEven if don't configure your own.pdfalyzerfile you may still glean some insight from reading the descriptions of the various variables in.pdfalyzer.example; there's a little more exposition there than in the output ofpdfalyze -h.Colors And ThemesRunpdfalyzer_show_color_themeto see the color theme employed.GuaranteesWarnings will be printed if any PDF object ID between 1 and the/Sizereported by the PDF itself could not be successfully placed in the tree. If you do not get any warnings then all[^2] of the inner PDF objects should be seen in the output.TroubleshootingIf you can't get thepdfalyzecommand to work trypython -m pdfalyzer. It's an equivalent but more portable version of the same command that does not rely on your python script paths being set up in a sane way.While The Pdfalyzer has been tested on quite a few large and very complicated PDFs there are no doubt a bunch of edge cases that will trip up the code. If that does happen and you hit an error, please opena GitHub issuewith the compressed (.zip,.gz, whatever) PDF that is causing the problem attached (if possible) and I'll take a look when I can. I willnottake a look at any uncompressed PDFs due to the security risks so make sure you zip it before you ship it.Use As A Code LibraryFor info about setting up a dev environment seeContributingbelow.At its core The Pdfalyzer is taking PDF internal objects gathered byPyPDF2and wrapping them inAnyTree'sNodeMixinclass.  Given that things like searching the tree or accessing internal PDF properties will be done through those packages' code it may be helpful to review their documentation.As far as The Pdfalyzer's unique functionality goes,Pdfalyzeris the class at the heart of the operation. It holds the PDF's logical tree as well as a few other data structures. Chief among these are theFontInfoclass which pulls together various properties of a font strewn across 3 or 4 different PDF objects and theBinaryScannerclass which lets you dig through the embedded streams' bytes looking for suspicious patterns.Here's a short intro to how to access these objects:frompdfalyzer.pdfalyzerimportPdfalyzer# Load a PDF and parse its nodes into the tree.pdfalyzer=Pdfalyzer("/path/to/the/evil_or_non_evil.pdf")actual_pdf_tree:PdfTreeNode=pdfalyzer.pdf_tree# The PdfalyzerPresenter handles formatting/prettifying outputPdfalyzerPresenter(pdfalyzer).print_everything()# Iterate over all nodes in the PDF treefornodeinpdfalyzer.node_iterator():do_stuff(node)# Iterate over the fontsforfontinpdfalyzer.font_infos:do_stuff(font)# Iterate over all stream objects:fornodeinpdfalyzer.stream_nodes():do_stuff(node.stream_data)# Find an internal PDF object by its ID in the PDFnode=pdfalyzer.find_node_by_idnum(44)pdf_object:PdfObject=node.obj# Use anytree's findall_by_attr to find nodes with a given propertyfromanytree.searchimportfindall_by_attrpage_nodes=findall_by_attr(pdfalyzer.pdf_tree,name='type',value='/Page')# Iterate over backtick quoted strings from a font binary and process themfont_info:FontInfo=pdfalyzer.font_infos[0]forbacktick_quoted_stringinfont.binary_scanner.extract_backtick_quoted_bytes():do_stuff(backtick_quoted_string)Example OutputThe Pdfalyzer can export visualizations to HTML, ANSI colored text, and SVG images using the file export functionality that comes withRich. SVGs can be turned intopngformat images with a tool like Inkscape orcairosvg(Inkscape works a lot better in our experience). Seepdfalyze --helpfor the specifics.Basic Tree ViewAs you can see the suspicious/OpenActionrelationship is highlighted bright red, as would be a couple of other sus PDF instructions like/JavaScriptor/AcroFormif they exist in the PDF being pdfalyzed.The dimmer (as in "harder to see") nodes[^5] marked withNon Child Referencegive you a way to visualize the relationships between PDF objects that exist outside of the tree structure's parent/child relationships.That's a pretty basic document.Here's the basic tree for a more complicated PDF containing an NMAP cheat sheet.Rich Tree ViewThis image shows a more in-depth view of of the PDF tree for the same document shown above. This tree (AKA the "rich" tree) has almost everything. Shows all PDF object properties, all relationships between objects, and sizable previews of any binary data streams embedded or encrypted in the document. Note that in addition to/OpenAction, the Adobe Type1 font binary is also red (Google's project zero regards any Adobe Type1 font as "mad sus").And here's the rich tree for the same more complicated NMAP cheat sheet PDF linked instead of shown directly in the previous section.FontsExtract character mappings from ancient Adobe font formats:It's actuallyPyPDF2doing the lifting here but we're happy to take the credit.View the properties of the fonts in the PDF. Comes with a preview of the beginning and end of the font's raw binary data stream (if it's that kind of font).Binary Analysis (And Lots Of It)YARA Scan:Check PDF for malicious content.This repo containsall the PDF specific YARA rules I could dig upthat identify byte patterns indicating a PDF may have been modified for evil. While the real dangers exist in PDF modifications no one has seen yet (and thus we have no YARA rules for), there are still a bunch of 'sus' indicators (e.g. has a Type1 font, is incorrectly terminated, etc.) that will be tripped when you scan a PDF with The Pdfalyzer.Search Internal Binary Data for Sus Content No Malware Scanner Will Catch[^6]:Things like, say, a hidden binary/F(PDF instruction meaning "URL") followed by aJS(I'll let you guess what "JS" stands for) and then a binary»character (AKA "the character the PDF specification uses to close a section of the PDF's logical structure"). Put all that together and it says that you're looking at a secret JavaScript instruction embedded in the encrypted part of a font binary. A secret instruction that causes the PDF renderer to pop out of its frame prematurely as it renders the font.Extract And Decode Binary Patterns:Like, say, bytes between common regular expression markers that you might want to force a decode of in a lot of different encodings.See stats:When all is said and done you can see some stats that may help you figure out what the character encoding may or may not be for the bytes matched by those patterns:Fancy Table To Tell You What ThechardetLibrary Would Rank As The Most Likely Encoding For A Chunk Of Binary DataPDF Resources3rd Party PDF ToolsInstalling Didier Stevens's PDF Analysis ToolsStevens's tools provide comprehensive info about the contents of a PDF, are guaranteed not to trigger the rendering of any malicious content (especiallypdfid.py), and have been battle tested for well over a decade. It would probably be a good idea to analyze your PDF with his tools before you start working with this one.If you're lazy and don't want to retrieve his tools yourself there'sa simple bash scriptto download them from his github repo and place them in atools/subdirectory off the project root. Just run this:scripts/install_didier_stevens_pdf_tools.shIf there is a discrepancy between the output of betweeen his tools and this one you should assume his tool is correct and The Pdfalyzer is wrong until you conclusively prove otherwise.Installing Thet1utilsFont Suitet1utilsis a suite of old but battle tested apps for manipulating old Adobe font formats.  You don't need it unless you're dealing with an older Type 1 or Type 2 font binary but given that those have been very popular exploit vectors in the past few years it can be extremely helpful. One of the tools in the suite,t1disasm, is particularly useful because it decrypts and decompiles Adobe Type 1 font binaries into a more human readable string representation.There'sa scriptto help you install the suite if you need it:scripts/install_t1utils.shDocumentationOfficial Adobe DocumentationOfficial Adobe PDF 1.7 Specification- Indispensable map when navigating a PDF forest.Adobe Type 1 Font Format Specification- Official spec for Adobe's original font description language and file format. Useful if you have suspicions about malicious fonts. Type1 seems to be the attack vector of choice recently which isn't so surprising when you consider that it's a 30 year old technology and the code that renders these fonts probably hasn't been extensively tested in decades because almost no one uses them anymore outside of people who want to use them as attack vectors.Adobe CMap and CIDFont Files Specification- Official spec for the character mappings used by Type1 fonts / basically part of the overall Type1 font specification.Adobe Type 2 Charstring Format- Describes the newer Type 2 font operators which are also used in some multiple-master Type 1 fonts.Other StuffDidier Stevens's free book about malicious PDFs- The master of the malicious PDFs wrote a whole book about how to analyze them. It's an old book but the PDF spec was last changed in 2008 so it's still relevant.Analyzing Malicious PDFs Cheat Sheet- Like it says on the tin. If that link fails there's a copyhere in the repo.T1Utils Github Repo- Suite of tools for manipulating Type1 fonts.t1disasmManual- Probably the most useful part of the T1Utils suite because it can decompile encrypted ancient Adobe Type 1 fonts into something human readable.PDF Flaws 101from Black Hat 2020.A Curious Exploration of Malicious PDF Documentsby Julian Lindenhofer, Rene Offenthaler and Martin Pirker, 2020. Overview of all the possible execution paths that can lead to a PDF executing JavaScript, opening loca/remote files, or making web requests.Malicious PDF Generatoris a well maintained GitHub project that does what it says on the tin.PDF is Broken, and so is this fileis a 2021 report on what happens when you challenge cybersecurity teams to turn PDFs into weapons. (Among other things they managed to create a PDF that launches a webserver when you open it.)Did The World Really Need Another PDF Tool?This tool was built to fill a gap in the PDF assessment landscape followingmy own recent experience trying to find malicious content in a PDF file. Didier Stevens'spdfid.pyandpdf-parser.pyare still the best game in town when it comes to PDF analysis tools but they lack in the visualization department and also don't give you much to work with as far as giving you a data model you can write your own code around.Peepdfseemed promising but turned out to be in a buggy, out of date, and more or less unfixable state. And neither of them offered much in the way of tooling for embedded binary analysis.Thus I felt the world might be slightly improved if I strung together a couple of more stable/well known/actively maintained open source projects (AnyTree,PyPDF2,Rich, andYARAviaThe Yaralyzer) into this tool.ContributingOne easy way of contributing is to runthe script to test against all the PDFs in~/Documentsand reporting any issues.Beyond that seeCONTRIBUTING.md.Code GlossaryThese are the naming conventions at play in The Pdfalyzer code base:TermMeaningPDF ObjectInstance of aPyPDF2class that represents the information stored in the PDF binary between open and close guillemet quotes (« and »)reference_keyString found in a PDF object that names a property (e.g./BaseFontor/Subtype)referenceLinkfroma PDF objecttoanother node. Outward facing relationships, basically.addressreference_keyplus a hash key or numerical array index if that's how the reference works. e.g. if node A has a reference key/Resourcespointing to a dict{'/Font2': [IndirectObject(55), IndirectObject(2)]}the address ofIndirectObject(55)from node A would be/Resources[/Font2][0]tree_addressLike theaddressbut starting at the root of the tree. Describes the series of objects you would step through if you walked the tree from the root to this node.relationshipAny link between nodes created by addresses/reference keysnon_tree_relationshipany link between nodes that is not considered a parent/child tree relationshipindeterminate_nodeany node whose place in the tree cannot be decided until every node has been seenlink_nodenodes like/Destthat just contain a pointer to another nodeTODOHighlight decodes with a lot of Javascript keywordshttps://github.com/mandiant/flare-floss(https://github.com/mandiant/flare-floss/releases/download/v2.1.0/floss-v2.1.0-linux.zip)https://github.com/1Project/Scanr/blob/master/emulator/emulator.py[^1]: The official Adobe PDF specification calls this tree the PDF's "logical structure", which is a good example of nomenclature that does not help those who see it understand anything about what is being described. I can forgive them given that they named this thing back in the 80s, though it's a good example of why picking good names for things at the beginning is so important.[^2]: An exception will be raised if there's any issue placing a node while parsing or if there are any nodes not reachable from the root of the tree at the end of parsing. If there are no exceptions then all internal PDF objects are guaranteed to exist in the tree except in these situations when warnings will be printed:/ObjStm(object stream) is a collection of objects in a single stream that will be unrolled into its component objects./XRefCross-reference stream objects which hold the same references as the/Trailerare hacked in as symlinks of the/Trailer[^3]: Given the nature of the PDFs this tool is meant to be scan anything resembling "rendering" the document is pointedly NOT offered.[^4]:pipxis a tool that basically runspip installfor a python package but in such a way that the installed package's requirements are isolated from your system's python packages. If you don't feel like installingpipxthenpip installshould work fine as long as there are no conflicts between The Pdfalyzer's required packages and those on your system already. (If you aren't using other python based command line tools then your odds of a conflict are basically 0%.)[^5]: Technically they areSymlinkNodes, a really nice feature ofAnyTree.[^6]: At least they weren't catching it as of September 2022.