29 lines
1.2 KiB
Python
29 lines
1.2 KiB
Python
#!/usr/bin/env python3
|
|
"""Minimal zipalign: uncompressed entries start on 4-byte boundaries (like the SDK's
|
|
`zipalign 4`). Safe after v1 (JAR) signing, which covers entry contents, not zip layout.
|
|
usage: zipalign.py in.apk out.apk"""
|
|
import struct
|
|
import sys
|
|
import zipfile
|
|
|
|
src, dst = sys.argv[1], sys.argv[2]
|
|
with zipfile.ZipFile(src) as zin, open(dst, "wb") as f:
|
|
with zipfile.ZipFile(f, "w") as zout:
|
|
for info in zin.infolist():
|
|
data = zin.read(info.filename)
|
|
out = zipfile.ZipInfo(info.filename, info.date_time)
|
|
out.compress_type = info.compress_type
|
|
out.external_attr = info.external_attr
|
|
if info.compress_type == zipfile.ZIP_STORED:
|
|
header_end = f.tell() + 30 + len(info.filename.encode("utf-8"))
|
|
out.extra = b"\0" * ((4 - header_end % 4) % 4)
|
|
zout.writestr(out, data)
|
|
|
|
with open(dst, "rb") as raw, zipfile.ZipFile(dst) as z:
|
|
for info in z.infolist():
|
|
if info.compress_type == zipfile.ZIP_STORED:
|
|
raw.seek(info.header_offset + 26)
|
|
n, m = struct.unpack("<HH", raw.read(4))
|
|
assert (info.header_offset + 30 + n + m) % 4 == 0, info.filename
|
|
print("aligned", dst)
|