import arm119 as M, struct, zipfile, capstone, bisect
S=M.S;TYPES=M.TYPES;METHODS=M.METHODS
b=zipfile.ZipFile('/root/ants/SvT-Playable-Beta.apk').read('lib/x86/libil2cpp.so')
e_shoff,=struct.unpack_from('<I',b,0x20); esz,en,estr=struct.unpack_from('<HHH',b,0x2e)
secs=[struct.unpack_from('<IIIIIIIIII',b,e_shoff+i*esz) for i in range(en)]
shstr=secs[estr][4]
def sn(n):e=b.index(b'\0',shstr+n);return b[shstr+n:e].decode()
Sx={sn(s[0]):s for s in secs}
def va2off(v):
    for nm,s in Sx.items():
        a,sz,of=s[3],s[5],s[4]
        if s[1]!=8 and a<=v<a+sz: return of+(v-a)
    return None
dro=Sx['.data.rel.ro']; mp_off=dro[4]+(0x1da1458-dro[3]); mp=struct.unpack_from('<44170I',b,mp_off)
ent=[]; addr={}
for t in TYPES:
    ns,nm=S(t[1]),S(t[0]); cls=(ns+'.' if ns else '')+nm
    for k in range(t[20]):
        m=METHODS[t[13]+k]; a=mp[m[6]]; full=cls+"::"+S(m[0])
        if a: ent.append((a,full)); 
        if a and full not in addr: addr[full]=a
ent.sort(); adrs=[e[0] for e in ent]
def rez(v):
    i=bisect.bisect_right(adrs,v)-1
    return "%s+0x%x"%(ent[i][1],v-ent[i][0]) if i>=0 else "?"
md=capstone.Cs(capstone.CS_ARCH_X86,capstone.CS_MODE_32); md.detail=True
def il2str(va):
    o=va2off(va)
    if o is None: return None
    try:
        l=struct.unpack_from('<i',b,o+8)[0]
        if l<0 or l>300: return None
        return b[o+0xc:o+0xc+l*2].decode('utf-16-le','replace')
    except: return None
def u32(va):
    o=va2off(va); return struct.unpack_from('<I',b,o)[0] if o is not None else None
def dis(va,end=None,nins=None,onlybranch=False):
    if end is None: 
        i=bisect.bisect_right(adrs,va); end=adrs[i] if i<len(adrs) else va+0x800
    off=va2off(va); cnt=0
    # compute ebx base for string resolution: find pop ebx / add ebx,imm
    ebx=None
    for ins in md.disasm(b[off:off+(end-va)+16],va):
        if ins.mnemonic=="pop" and ins.op_str=="ebx": popaddr=ins.address
        if ins.mnemonic=="add" and ins.op_str.startswith("ebx,"):
            try: ebx=popaddr+int(ins.op_str.split(",")[1].strip(),16)
            except: pass
            break
    for ins in md.disasm(b[off:off+(end-va)+16],va):
        ann=""
        if ins.mnemonic=="call":
            try:
                r=rez(int(ins.op_str,16))
                if not r.startswith("UnityEngine") and "WritableAttribute" not in r and "Tilemap" not in r: ann="  ; "+r
            except: pass
        # string literal resolve: lea reg,[ebx+disp]
        if ebx is not None and ins.mnemonic=="lea" and "ebx +" in ins.op_str:
            import re
            m2=re.search(r'\[ebx \+ (0x[0-9a-f]+)\]',ins.op_str)
            if m2:
                slot=ebx+int(m2.group(1),16); p=u32(slot); st=il2str(p) if p else None
                if st is not None: ann+="   ; STR=%r"%st
        if onlybranch and not (ins.mnemonic=="call" or ins.mnemonic[0]=='j' or ins.mnemonic in("cmp","test","mov","lea")):
            pass
        print("  0x%x: %-9s %s%s"%(ins.address,ins.mnemonic,ins.op_str,ann))
        cnt+=1
        if nins and cnt>=nins: break
        if ins.address>=end: break
