Skip to main content

Extract partition images from Android OTA payload.bin files

Project description

android-payload-dumper

A Python tool to extract partition images (.img) from Android OTA firmware payload.bin files.

Android OTA updates ship as a payload.bin file inside the firmware ZIP. This file contains compressed partition images (system, boot, vendor, etc.) packed in Google's Chrome OS update format (CrAU). This tool parses the payload, decompresses each partition in parallel, verifies integrity via SHA-256 hashes, and writes individual .img files that can be flashed or mounted.

Prerequisites

  • Python 3.8 or higher
  • One of: pipx, uv, or pip

Installation

As a global CLI (recommended)

pipx install android-payload-dumper

This puts payload-dumper on your PATH so you can run it from anywhere without activating a venv.

Install from this repo (for development)
git clone https://github.com/manojanasuri16/payload_dumper.git
cd payload_dumper
uv sync

Then run via uv run payload-dumper … (shown in examples below).

Pip alternative:

git clone https://github.com/manojanasuri16/payload_dumper.git
cd payload_dumper
pip install -e .
Install straight from GitHub with pipx
pipx install git+https://github.com/manojanasuri16/payload_dumper.git

Useful if you want the latest main without waiting for a PyPI release.

Getting payload.bin

  1. Download the full OTA firmware ZIP for your device (from the manufacturer's website, or sites like Full OTA Images for Pixel)
  2. Extract the ZIP — you'll find payload.bin inside
  3. Copy payload.bin into the payload_dumper directory (or provide the full path)

Usage

Examples below assume you installed with pipx and payload-dumper is on your PATH. If you're running from a clone, prefix every command with uv run (e.g. uv run payload-dumper payload.bin).

Extract all partitions

payload-dumper payload.bin

All .img files are saved to the output/ directory. Partitions are extracted in parallel (up to 8 workers by default), with a live progress bar per partition and an overall total.

Extract specific partitions only

payload-dumper payload.bin -p boot system vendor

Custom output directory

payload-dumper payload.bin -o extracted/

Control parallelism

payload-dumper payload.bin -j 4     # 4 workers
payload-dumper payload.bin -j 1     # serial extraction

List partitions without extracting

payload-dumper payload.bin -l

Example output:

payload  minor_version=0  block_size=4096  partitions=35

  35 partitions
  ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━┳━━━━━━━━━━━━━━━━━━━┓
  ┃ Partition                  ┃ Ops ┃ Types             ┃
  ┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━╇━━━━━━━━━━━━━━━━━━━┩
  │ boot                       │  85 │ REPLACE_XZ        │
  │ dtbo                       │  12 │ REPLACE_XZ        │
  │ modem                      │  86 │ REPLACE_XZ        │
  │ system                     │ 384 │ REPLACE_XZ, ZERO  │
  │ vendor                     │ 205 │ REPLACE_XZ        │
  │ …                          │   … │ …                 │
  └────────────────────────────┴─────┴───────────────────┘

Command Reference

payload-dumper [-h] [-o OUTPUT] [-p NAME ...] [-l] [-j WORKERS] [-V] payload
Option Description
payload Path to the payload.bin file (required)
-o, --output DIR Output directory for extracted images (default: output/)
-p, --partitions NAME [NAME ...] Extract only the listed partitions
-l, --list List all partitions in the payload and exit
-j, --workers N Parallel extraction workers (default: min(8, cpu_count))
-V, --version Print version and exit
-h, --help Show help message

Also runnable as a module: python -m payload_dumper payload.bin.

Supported Compression Formats

Operation Compression Description
REPLACE None Raw uncompressed data
REPLACE_BZ bzip2 Bzip2 compressed data
REPLACE_XZ XZ / LZMA XZ or raw LZMA compressed data (with automatic format detection)
ZERO None Zero-filled blocks
DISCARD None Discarded/trimmed blocks

How It Works

  1. Header parsing — Reads and validates the CrAU magic bytes, payload format version (v1/v2), manifest size, and metadata signature
  2. Manifest deserialization — Uses Protocol Buffers to decode the DeltaArchiveManifest, which describes all partitions, their operations, and hash info
  3. Operation validation — Checks that all operations are supported up-front (full OTA only — no delta/incremental ops like SOURCE_COPY or BSDIFF) so a failure doesn't leave half-written images on disk
  4. Parallel extraction — Each partition is handed to a worker thread that opens its own file handle, iterates the ops in order, decompresses and writes, and updates a shared Rich progress bar
  5. Integrity verification — Each operation's compressed bytes are verified against its SHA-256 hash, and the final partition image is verified against the expected partition hash

Payload Binary Format

+---------------------+
| Magic: "CrAU"       |  4 bytes
| Format Version      |  8 bytes (uint64, big-endian)
| Manifest Size       |  8 bytes (uint64, big-endian)
| Metadata Sig Size   |  4 bytes (uint32, big-endian, v2 only)
| Manifest (protobuf) |  <manifest_size> bytes
| Metadata Signature  |  <metadata_sig_size> bytes
| Data Blobs          |  Remaining bytes (compressed partition data)
+---------------------+

Limitations

  • Full OTA only — Incremental/delta OTA payloads (containing SOURCE_COPY, SOURCE_BSDIFF, PUFFDIFF, BROTLI_BSDIFF, etc.) are not supported. These require the previous version's partition images to apply diffs against.
  • No streaming — The entire payload file must be accessible on disk (no stdin/pipe support).

Troubleshooting

ModuleNotFoundError: No module named 'google' or 'rich'

Install (or reinstall) the package so its dependencies come with it:

pipx install android-payload-dumper   # or: pipx upgrade android-payload-dumper
uv sync                               # if working from a clone
pip install -e .                      # pip-from-clone alternative

_lzma.LZMAError: Input format not supported by decoder

This was a bug in older versions. The current version automatically tries multiple LZMA formats (XZ container, LZMA alone, raw LZMA2) as fallbacks. Make sure you're using the latest version.

unsupported op error

Your payload is an incremental (delta) OTA, not a full OTA. This tool only supports full OTA payloads. Download the full OTA image for your device instead.

Regenerating Protobuf Bindings

If you modify update_metadata.proto, regenerate the Python bindings into the package:

uv add --dev grpcio-tools
uv run python -m grpc_tools.protoc \
    --python_out=src/payload_dumper \
    --proto_path=. \
    update_metadata.proto

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

android_payload_dumper-2.1.0.tar.gz (40.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

android_payload_dumper-2.1.0-py3-none-any.whl (11.4 kB view details)

Uploaded Python 3

File details

Details for the file android_payload_dumper-2.1.0.tar.gz.

File metadata

  • Download URL: android_payload_dumper-2.1.0.tar.gz
  • Upload date:
  • Size: 40.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for android_payload_dumper-2.1.0.tar.gz
Algorithm Hash digest
SHA256 9ac2a8c41be834af6b1d2db1f40bfd4abe0195e06de4464b360285f91d28c72e
MD5 9eacd457b7005edbceb2525bc4180bd3
BLAKE2b-256 28cfc521204c70df80a9aef0e62a42769589ce5dea8d7b05a957997c9428003b

See more details on using hashes here.

Provenance

The following attestation bundles were made for android_payload_dumper-2.1.0.tar.gz:

Publisher: release.yml on manojanasuri16/payload_dumper

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file android_payload_dumper-2.1.0-py3-none-any.whl.

File metadata

File hashes

Hashes for android_payload_dumper-2.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 b1a88044777d28734a085c2d94ce577a8562c3662c94acaadd16c13a1a81d821
MD5 9940a101a39c58b9a179f7191b60c9d8
BLAKE2b-256 8a425a6f3d79315fe7d9bcb409f6fb6a90cb672c853633b98c845cdc24f1ce10

See more details on using hashes here.

Provenance

The following attestation bundles were made for android_payload_dumper-2.1.0-py3-none-any.whl:

Publisher: release.yml on manojanasuri16/payload_dumper

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page