zbyte_polyfile
(fork from zbyte_polyfile: https://github.com/trailofbits/polyfile)
A utility to identify and map the semantic and syntactic structure of files,
including polyglots, chimeras, and schizophrenic files. It has a pure-Python implementation of libmagic and can act as a drop-in replacement for the file command. However, unlike file, PolyFile can recursively identify embedded files, like binwalk.
PolyFile can be used in conjunction with its sister tool PolyTracker for Automated Lexical Annotation and Navigation of Parsers, a backronym devised solely for the purpose of collectively referring to the tools as The ALAN Parsers Project.
Quickstart
You can install the latest stable version of PolyFile from PyPI:
pip3 install zbyte_polyfile
To install PolyFile from source, in the same directory as this README, run:
pip3 install .
Important: Before installing from source, make sure Java is installed. Java is used to run the Kaitai Struct compiler, which compiles the file format definitions.
This will automatically install the polyfile and polymerge executables in your path.
Usage
Running polyfile on a file with no arguments will mimic the behavior of file --keep-going:
$ polyfile png-polyglot.png
PNG image data, 256 x 144, 8-bit/color RGB, non-interlaced
Brainfu** Program
Malformed PDF
PDF document, version 1.3, 1 pages
ZIP end of central directory record Java JAR archive
To generate an interactive hex viewer for the file, use the --html option:
$ polyfile --html output.html png-polyglot.png
Found a file of type application/pdf at byte offset 0
Found a file of type application/x-brainfuck at byte offset 0
Found a file of type image/png at byte offset 0
Found a file of type application/zip at byte offset 0
Found a file of type application/java-archive at byte offset 0
Saved HTML output to output.html
Run polyfile --help for full usage instructions.
Interactive Debugger
PolyFile has an interactive debugger both for its file matching and parsing. It can be used to debug a libmagic pattern
definition, determine why a specific file fails to be classified as the expected MIME type, or step through a parser.
You can run PolyFile with the debugger enabled using the -db option.
File Support
PolyFile has a cleanroom, pure Python implementation of the libmagic file classifier, and supports all 263 MIME types that it can identify.
It currently has support for parsing and semantically mapping the following formats:
- PDF, using an instrumented version of Didier Stevens' public domain, permissive, forensic parser
- ZIP, including recursive identification of all ZIP contents
- JPEG/JFIF, using its Kaitai Struct grammar
- iNES
- Any other format specified in a KSY grammar
For an example that exercises all of these file formats, run:
curl -v --silent https://www.sultanik.com/files/ESultanikResume.pdf | polyfile --html ESultanikResume.html -
Prior to PolyFile version 0.3.0, it used the TrID database for file identification rather than the libmagic file definitions. This proved to be very slow (since TrID has many duplicate entries) and prone to false positives (since TrID's file definitions are much simpler than libmagic's). The original TrID matching code is still shipped with PolyFile and can be invoked programmatically, but it is not used by default.
Output Format
PolyFile has several options for outputting its results, specified by its --format option. For computer-readable output, PolyFile has an extension of the SBuD JSON format described in the documentation. Prior to version 0.5.0 this was the default output format of PolyFile. However, now the default output format is to mimic the behavior of the file command. To maintain the original behavior, use the --format sbud option.
libmagic Implementation
PolyFile has a cleanroom implementation of libmagic (used in the file command).
It can be invoked programmatically by running:
from zbyte_polyfile.magic import MagicMatcher
with open("file_to_test", "rb") as f:
# the default instance automatically loads all file definitions
for match in MagicMatcher.DEFAULT_INSTANCE.match(f.read()):
for mimetype in match.mimetypes:
print(f"Matched MIME: {mimetype}")
print(f"Match string: {match!s}")
To load a specific or custom file definition:
list_of_paths_to_definitions = ["def1", "def2"]
matcher = MagicMatcher.parse(*list_of_paths_to_definitions)
with open("file_to_test", "rb") as f:
for match in matcher.match(f.read()):
...
Extending PolyFile
Instructions on extending PolyFile to support more file formats with new matchers and parsers is described [in the documentation](in the documentation).
License and Acknowledgements
This research was developed by Trail of Bits with funding from the Defense Advanced Research Projects Agency (DARPA) under the SafeDocs program as a subcontractor to Galois. It is licensed under the Apache 2.0 license. © 2019, Trail of Bits.
Metadata
Release files for zbyte-polyfile 20250310.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| zbyte_polyfile-20250310.0-py3-none-any.whl | Python 3 | none | any | Details for zbyte_polyfile-20250310.0-py3-none-any.whl |
Release files / zbyte_polyfile-20250310.0-py3-none-any.whl
| Download URL | zbyte_polyfile-20250310.0-py3-none-any.whl |
|---|---|
| Size | 1.7 MB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
19b876ade899c4b34fb1130755bae58103edce178422acf0934e041fa57e9303
|
|
BLAKE2b-256 checksum How to use checksums |
66c6f112865b602733a2db0126bb1292a5b8a14184f6a28fb42ac6f48566bda9
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.1.0 CPython/3.11.10
|
Security for zbyte-polyfile 20250310.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.