Any firmware download in → one canonical raw firmware .bin + a JSON label out.
fwext takes a vendor firmware download — an installer .exe, a self-extracting
flasher, an archive (zip/7z/rar/cab/gzip/bz2), a PE with the image in a resource or
overlay, or a plain raw image — and produces exactly one flashable raw firmware
image plus a JSON sidecar describing it. Extraction is signature-based (no
hardcoded offsets), deterministic (same input → same output), and 100%
offline (no network, no running the vendor tool).
It was originally built to recover optical-drive (CD/DVD/BD) firmware at scale, but the pipeline is generic and vendor-agnostic.
brew install MattJackson/tap/fwextUpgrades come through Homebrew: brew upgrade fwext.
Grab a build for your platform from the latest release, or use these stable "always the newest" URLs:
| Platform | Download |
|---|---|
| Linux x86_64 (static musl) | fwext-x86_64-unknown-linux-musl.tar.gz |
| macOS Apple Silicon | fwext-aarch64-apple-darwin.tar.gz |
| macOS Intel | fwext-x86_64-apple-darwin.tar.gz |
| Windows x86_64 | fwext-x86_64-pc-windows-msvc.zip |
Each archive ships with a matching .sha256. Verify before use, e.g.:
shasum -a 256 -c fwext-x86_64-unknown-linux-musl.tar.gz.sha256cargo install --git https://github.com/MattJackson/firmware-extractor --tag v0.1.0fwext <input> # writes <stem>.fw.bin + <stem>.fw.json next to cwd
fwext <input> -o OUTDIR # write outputs to OUTDIR
fwext <input> --print # print the JSON label only (no files written)Exit code 0 when a firmware image was produced, 2 when none could be carved
(the JSON still explains why).
For each input fwext runs an identify → dispatch → carve pipeline:
- identify the container/format by magic bytes.
- decode in-memory containers (zip, word-swapped zip, gzip, bz2) and shell out
to
7z/unar/innoextract/upx/binwalkfor archives and self-extractors (each optional — a missing tool is skipped). - unpack vendor runtime packers offline (e.g. the MediaTek "XFlash"
af7df9fdaPLib-variant SFX, PEBundle wrappers). - carve the firmware image by family signature (8051 reset/vector tables, vendor boot headers, distribution headers, INQUIRY banners) with size/entropy validation.
- label it: sha256, size, detected chipset/part, boot banner, entropy-based
payload form, and a self-signoff
confidence.
confident— a real firmware image (chipset/banner/vendor magic, or a plausible plaintext/code image): this is the bin.confident-encrypted— a valid final image that is encrypted at rest (opaque, but it is the firmware).unconfirmed— a blob was extracted but still looks like a wrapper/container; likely not the final bin.none— no firmware bytes could be produced (thestatussays why).
cargo build --release # -> target/release/fwext
cargo test # unit tests (no external corpus needed)Minimum supported Rust: 1.86.
Optional external tools that widen coverage when present on PATH: 7z, unar,
innoextract, upx, binwalk.
Issues and pull requests are welcome. Please read CONTRIBUTING.md
and our Code of Conduct first. CI runs cargo fmt --check,
cargo clippy -D warnings, and the test suite on every push and pull request, plus
macOS/Windows compile checks for changes headed to main.
Found a vulnerability? Please follow the process in SECURITY.md rather than opening a public issue.
See CHANGELOG.md. This project follows Semantic Versioning and Keep a Changelog.
Licensed under the MIT License © Matthew Jackson.