Last active
April 15, 2021 07:36
-
-
Save obfusk/c70a6f6816ba475f161caf82002c33d5 to your computer and use it in GitHub Desktop.
find/strip UTC timestamps from ZIP files' CD extra fields
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/python3 | |
| # encoding: utf-8 | |
| import struct | |
| import sys | |
| import zipfile | |
| def _has_timestamp(info): | |
| xtr = info.extra | |
| while len(xtr) >= 4: | |
| hdr_id, size = struct.unpack("<HH", xtr[:4]) | |
| if size > len(xtr) - 4: | |
| break | |
| if hdr_id == 0x5455: | |
| return True | |
| xtr = xtr[size + 4:] | |
| return False | |
| if __name__ == "__main__": | |
| with zipfile.ZipFile(sys.argv[1], "r") as zf: | |
| for info in zf.infolist(): | |
| if _has_timestamp(info): | |
| print(info.filename) | |
| # vim: set tw=80 sw=4 sts=4 et fdm=marker : |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/python3 | |
| # encoding: utf-8 | |
| import os | |
| import struct | |
| import sys | |
| import zipfile | |
| from collections import namedtuple | |
| ZipData = namedtuple("ZipData", ("cd_offset", "eocd_offset", "cd_and_eocd")) | |
| class ZipError(Exception): | |
| pass | |
| def copy_apk(input_apk, output_apk): | |
| with zipfile.ZipFile(input_apk, "r") as zf: | |
| infos = zf.infolist() | |
| zdata = zip_data(input_apk) | |
| with open(input_apk, "rb") as fhi, open(output_apk, "w+b") as fho: | |
| _copy_bytes(fhi, fho, zdata.cd_offset) | |
| for info in infos: | |
| hdr = fhi.read(46) | |
| if hdr[:4] != b"\x50\x4b\x01\x02": | |
| raise ZipError("Expected central directory file header signature") | |
| n, m, k = struct.unpack("<HHH", hdr[28:34]) | |
| hdr += fhi.read(n + m + k) | |
| xtr = _remove_timestamps(info) | |
| m_b = int.to_bytes(len(xtr), 2, "little") | |
| hdr = hdr[:30] + m_b + hdr[32:46 + n] + xtr + hdr[46 + n + m:] | |
| fho.write(hdr) | |
| eocd_offset = fho.tell() | |
| fho.write(zdata.cd_and_eocd[zdata.eocd_offset - zdata.cd_offset:]) | |
| fho.seek(eocd_offset + 8) | |
| fho.write(struct.pack("<HHLL", len(infos), len(infos), | |
| eocd_offset - zdata.cd_offset, zdata.cd_offset)) | |
| def _remove_timestamps(info): | |
| old_xtr = info.extra | |
| new_xtr = b"" | |
| while len(old_xtr) >= 4: | |
| hdr_id, size = struct.unpack("<HH", old_xtr[:4]) | |
| if size > len(old_xtr) - 4: | |
| break | |
| if hdr_id != 0x5455: | |
| new_xtr += old_xtr[:size + 4] | |
| old_xtr = old_xtr[size + 4:] | |
| return new_xtr + old_xtr | |
| def _copy_bytes(fhi, fho, size, blocksize=4096): | |
| while size > 0: | |
| data = fhi.read(min(size, blocksize)) | |
| if not data: | |
| break | |
| size -= len(data) | |
| fho.write(data) | |
| if size != 0: | |
| raise ZipError("Unexpected EOF") | |
| def zip_data(apkfile, count=1024): | |
| with open(apkfile, "rb") as fh: | |
| fh.seek(-count, os.SEEK_END) | |
| data = fh.read() | |
| pos = data.rfind(b"\x50\x4b\x05\x06") | |
| if pos == -1: | |
| raise ZipError("Expected end of central directory record (EOCD)") | |
| fh.seek(pos - len(data), os.SEEK_CUR) | |
| eocd_offset = fh.tell() | |
| fh.seek(16, os.SEEK_CUR) | |
| cd_offset = int.from_bytes(fh.read(4), "little") | |
| fh.seek(cd_offset) | |
| cd_and_eocd = fh.read() | |
| return ZipData(cd_offset, eocd_offset, cd_and_eocd) | |
| if __name__ == "__main__": | |
| copy_apk(sys.argv[1], sys.argv[2]) | |
| # vim: set tw=80 sw=4 sts=4 et fdm=marker : |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment