Skip to main content

copy/extract/patch android apk signatures & compare apks

Project description

GitHub Release PyPI Version Python Versions CI GPLv3+

Packaging status Packaging status

apksigcopier

copy/extract/patch android apk signatures & compare apks

apksigcopier is a tool for copying android APK signatures from a signed APK to an unsigned one (in order to verify reproducible builds). It can also be used to compare two APKs with different signatures. Its command-line tool offers four operations:

  • copy signatures directly from a signed to an unsigned APK
  • extract signatures from a signed APK to a directory
  • patch previously extracted signatures onto an unsigned APK
  • compare two APKs with different signatures

Extract

$ mkdir meta
$ apksigcopier extract signed.apk meta
$ ls -1 meta
8BEA2A77.RSA
8BEA2A77.SF
APKSigningBlock
APKSigningBlockOffset
MANIFEST.MF

Patch

$ apksigcopier patch meta unsigned.apk out.apk

Copy (Extract & Patch)

$ apksigcopier copy signed.apk unsigned.apk out.apk

Compare (Copy to temporary file & Verify)

This command requires apksigner.

$ apksigcopier compare foo-from-fdroid.apk foo-built-locally.apk
$ apksigcopier compare --unsigned foo.apk foo-unsigned.apk

Help

$ apksigcopier --help
$ apksigcopier copy --help      # extract --help, patch --help, etc.

$ man apksigcopier              # requires the man page to be installed

Environment Variables

The following environment variables can be set to 1, yes, or true to override the default behaviour:

  • set APKSIGCOPIER_EXCLUDE_ALL_META=1 to exclude all metadata files
  • set APKSIGCOPIER_COPY_EXTRA_BYTES=1 to copy extra bytes after data (e.g. a v2 sig)

Python API

>>> from apksigcopier import do_extract, do_patch, do_copy, do_compare
>>> do_extract(signed_apk, output_dir, v1_only=NO)
>>> do_patch(metadata_dir, unsigned_apk, output_apk, v1_only=NO)
>>> do_copy(signed_apk, unsigned_apk, output_apk, v1_only=NO)
>>> do_compare(first_apk, second_apk, unsigned=False)

You can use False, None, and True instead of NO, AUTO, and YES respectively.

The following global variables (which default to False), can be set to override the default behaviour:

  • set exclude_all_meta=True to exclude all metadata files
  • set copy_extra_bytes=True to copy extra bytes after data (e.g. a v2 sig)

FAQ

What kind of signatures does apksigcopier support?

It currently supports v1 + v2 + v3 (which is a variant of v2).

It should also support v4, since these are stored in a separate file (and require a complementary v2/v3 signature).

When using the extract command, the v2/v3 signature is saved as APKSigningBlock + APKSigningBlockOffset.

How does patching work?

First it copies the APK exactly like apksigner would when signing it, including re-aligning ZIP entries and skipping existing v1 signature files.

Then it adds the extracted v1 signature files (.SF, .RSA/.DSA/.EC, MANIFEST.MF) to the APK, using the correct ZIP metadata (either the same metadata as apksigner would, or from differences.json).

And lastly it inserts the extracted APK Signing Block at the correct offset (adding zero padding if needed) and updates the CD offset in the EOCD.

What about APKs signed by gradle/zipflinger/signflinger instead of apksigner?

Compared to APKs signed by apksigner, APKs signed with a v1 signature by zipflinger/signflinger (e.g. using gradle) have different ZIP metadata -- create_system, create_version, external_attr, extract_version, flag_bits -- and compresslevel for the v1 signature files (.SF, .RSA/.DSA/.EC, MANIFEST.MF); they also usually have a 132-byte virtual entry at the start as well.

Recent versions of apksigcopier will detect these ZIP metadata differences and the virtual entry (if any); extract will save them in a differences.json file (if they exist), which patch will read (if it exists); copy and compare simply pass the same information along internally.

What are these virtual entries?

A virtual entry is a ZIP entry with an empty filename, an extra field filled with zero bytes, and no corresponding central directory entry (so it should be effectively invisible to most ZIP tools).

When zipflinger deletes an entry it leaves a "hole" in the archive when there remain non-deleted entries after it. It later fills these "holes" with virtual entries.

There is usually a 132-byte virtual entry at the start of an APK signed with a v1 signature by signflinger/zipflinger; almost certainly this is a default manifest ZIP entry created at initialisation, deleted (from the central directory but not from the file) during v1 signing, and eventually replaced by a virtual entry.

Depending on what value of Created-By and Built-By were used for the default manifest, this virtual entry may be a different size; apksigcopier supports any size between 30 and 4096 bytes.

Tab Completion

NB: the syntax for the environment variable changed in click >= 8.0, use e.g. source_bash instead of bash_source for older versions.

For Bash, add this to ~/.bashrc:

eval "$(_APKSIGCOPIER_COMPLETE=bash_source apksigcopier)"

For Zsh, add this to ~/.zshrc:

eval "$(_APKSIGCOPIER_COMPLETE=zsh_source apksigcopier)"

For Fish, add this to ~/.config/fish/completions/apksigcopier.fish:

eval (env _APKSIGCOPIER_COMPLETE=fish_source apksigcopier)

Installing

Debian

Official packages are available in Debian and Ubuntu.

$ apt install apksigcopier

You can also manually build a Debian package using the debian/sid branch, or download a pre-built .deb via GitHub releases.

NixOS & Arch Linux

Official packages are also available in nixpkgs and Arch Linux (and derivatives).

Using pip

$ pip install apksigcopier

NB: depending on your system you may need to use e.g. pip3 --user instead of just pip.

From git

NB: this installs the latest development version, not the latest release.

$ git clone https://github.com/obfusk/apksigcopier.git
$ cd apksigcopier
$ pip install -e .

NB: you may need to add e.g. ~/.local/bin to your $PATH in order to run apksigcopier.

To update to the latest development version:

$ cd apksigcopier
$ git pull --rebase

Dependencies

  • Python >= 3.7 + click.
  • The compare command also requires apksigner.

Debian/Ubuntu

$ apt install python3-click
$ apt install apksigner         # only needed for the compare command

License

GPLv3+

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

apksigcopier-1.1.0.tar.gz (29.6 kB view details)

Uploaded Source

Built Distribution

apksigcopier-1.1.0-py3-none-any.whl (26.5 kB view details)

Uploaded Python 3

File details

Details for the file apksigcopier-1.1.0.tar.gz.

File metadata

  • Download URL: apksigcopier-1.1.0.tar.gz
  • Upload date:
  • Size: 29.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/4.0.1 CPython/3.10.8

File hashes

Hashes for apksigcopier-1.1.0.tar.gz
Algorithm Hash digest
SHA256 a93891ad5b2d34e50b9c0a28ca9661e0dc3cb54a44b9b78287b14fbf8d5ca029
MD5 81016fc9113af566d69f604dc359aad3
BLAKE2b-256 35b526a2a3ef1b86bcf0b7d68215f68c49ae9a777eb0944566d162c952826fa5

See more details on using hashes here.

File details

Details for the file apksigcopier-1.1.0-py3-none-any.whl.

File metadata

File hashes

Hashes for apksigcopier-1.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 111879c201e436456e7f1255c0fbb8d8a3689d9a8402f4cdcafbf770ab66b376
MD5 96bacee07035e02152ecee6166915866
BLAKE2b-256 1f107a06193fc8300a7327c87d3577742baca918c1e9768c472234e1ee057ecd

See more details on using hashes here.

Supported by

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