import zipfile, hashlib, base64, struct, re
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import padding
from cryptography import x509

APK='PE-0.2.0-compat.apk'; ORIG='/root/pe/PE-a0.2.0-1.apk'
ok=lambda c: "PASS" if c else "FAIL"
res=[]

z=zipfile.ZipFile(APK); zo=zipfile.ZipFile(ORIG)
res.append(("zip integrity", z.testzip() is None))

# payload identical to original?
names=[n for n in zo.namelist() if not n.startswith("META-INF/") and n!="AndroidManifest.xml"]
same=all(hashlib.sha256(zo.read(n)).digest()==hashlib.sha256(z.read(n)).digest() for n in names)
res.append((f"{len(names)} payload entries byte-identical to original", same))
res.append(("libminecraftpe.so untouched",
    hashlib.sha256(zo.read('lib/armeabi-v7a/libminecraftpe.so')).digest()==
    hashlib.sha256(z.read('lib/armeabi-v7a/libminecraftpe.so')).digest()))
res.append(("classes.dex untouched",
    hashlib.sha256(zo.read('classes.dex')).digest()==hashlib.sha256(z.read('classes.dex')).digest()))

# v1 verification
mf=z.read('META-INF/MANIFEST.MF'); sf=z.read('META-INF/CERT.SF')
secs=dict(re.findall(rb"Name: (.+?)\r\nSHA-256-Digest: (.+?)\r\n", mf))
bad=[n for n in z.namelist() if not n.startswith("META-INF/")
     and base64.b64encode(hashlib.sha256(z.read(n)).digest())!=secs.get(n.encode())]
res.append((f"v1 MANIFEST.MF digests ({len(secs)} entries)", not bad and len(secs)==len(z.namelist())-3))
m=re.search(rb"SHA-256-Digest-Manifest: (.+?)\r\n", sf)
res.append(("v1 CERT.SF manifest digest", base64.b64encode(hashlib.sha256(mf).digest())==m.group(1)))

# v2 verification
d=open(APK,'rb').read()
mag=d.rfind(b"APK Sig Block 42")
res.append(("v2 signing block magic present", mag>0))
size2=struct.unpack_from('<Q',d,mag-8)[0]
blk_start=mag+16-8-size2
size1=struct.unpack_from('<Q',d,blk_start)[0]
res.append(("v2 block size fields agree", size1==size2))
p=blk_start+8; v2val=None
while p < mag-8:
    ln=struct.unpack_from('<Q',d,p)[0]; pid=struct.unpack_from('<I',d,p+8)[0]
    if pid==0x7109871a: v2val=d[p+12:p+8+ln]
    p+=8+ln
res.append(("v2 block id 0x7109871a found", v2val is not None))

def rd(b,o):
    n=struct.unpack_from('<I',b,o)[0]; return b[o+4:o+4+n], o+4+n
signers,_=rd(v2val,0); signer,_=rd(signers,0)
signed_data,o=rd(signer,0); signatures,o=rd(signer,o); pub,_=rd(signer,o)
digests,q=rd(signed_data,0); certs,q=rd(signed_data,q)
dg,_=rd(digests,0); stored=dg[4:]; stored=stored[4:]
cert_der,_=rd(certs,0); cert=x509.load_der_x509_certificate(cert_der)
sg,_=rd(signatures,0); sigbytes=sg[4:]; sigbytes=sigbytes[4:]

# recompute the v2 digest
eocd_off=d.rfind(b"PK\x05\x06")
cd_off=struct.unpack_from('<I',d,eocd_off+16)[0]
before=d[:blk_start]; cd=d[cd_off:eocd_off]
eocd=bytearray(d[eocd_off:]); struct.pack_into('<I',eocd,16,blk_start)
CH=1048576; digs=[]
for b in (before,cd,bytes(eocd)):
    for o2 in range(0,len(b),CH):
        c=b[o2:o2+CH]
        digs.append(hashlib.sha256(b"\xa5"+struct.pack('<I',len(c))+c).digest())
top=hashlib.sha256(b"\x5a"+struct.pack('<I',len(digs))+b"".join(digs)).digest()
res.append(("v2 content digest recomputes", top==stored))
try:
    cert.public_key().verify(sigbytes, signed_data, padding.PKCS1v15(), hashes.SHA256())
    res.append(("v2 signature verifies against cert", True))
except Exception as e:
    res.append((f"v2 signature verifies ({e})", False))
res.append(("v2 central-dir offset consistent", cd_off==blk_start+size2+8))

for label,c in res: print(f"  [{ok(c)}] {label}")
print("\nALL PASS" if all(c for _,c in res) else "\nSOME CHECKS FAILED")
