Skip to content

Instantly share code, notes, and snippets.

@obfusk
Last active April 15, 2021 07:36
Show Gist options
  • Select an option

  • Save obfusk/c70a6f6816ba475f161caf82002c33d5 to your computer and use it in GitHub Desktop.

Select an option

Save obfusk/c70a6f6816ba475f161caf82002c33d5 to your computer and use it in GitHub Desktop.
find/strip UTC timestamps from ZIP files' CD extra fields
#!/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 :
#!/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