copy/extract/patch android apk signatures & compare apks
Project description
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 requiresapksigner
.
Debian/Ubuntu
$ apt install python3-click
$ apt install apksigner # only needed for the compare command
License
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
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
Algorithm | Hash digest | |
---|---|---|
SHA256 | a93891ad5b2d34e50b9c0a28ca9661e0dc3cb54a44b9b78287b14fbf8d5ca029 |
|
MD5 | 81016fc9113af566d69f604dc359aad3 |
|
BLAKE2b-256 | 35b526a2a3ef1b86bcf0b7d68215f68c49ae9a777eb0944566d162c952826fa5 |
File details
Details for the file apksigcopier-1.1.0-py3-none-any.whl
.
File metadata
- Download URL: apksigcopier-1.1.0-py3-none-any.whl
- Upload date:
- Size: 26.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/4.0.1 CPython/3.10.8
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 111879c201e436456e7f1255c0fbb8d8a3689d9a8402f4cdcafbf770ab66b376 |
|
MD5 | 96bacee07035e02152ecee6166915866 |
|
BLAKE2b-256 | 1f107a06193fc8300a7327c87d3577742baca918c1e9768c472234e1ee057ecd |