import sys, re, json, struct
from pathlib import Path
sys.path.insert(0, str(Path(__file__).parents[2] / 'dev/tools/enshrouded'))
from discovery.pe import PE
from capstone import Cs, CS_ARCH_X86, CS_MODE_64
from capstone.x86_const import X86_OP_MEM, X86_REG_RIP, X86_OP_IMM

BASE = Path(r'A:\17 Cloud\OneDrive\Downloads\Creative Mode 146 1.2 2026-10-13T10-28Z U89dZfAAM')
OUT = Path(__file__).parent
def cstr(pe, rva):
    pos = pe.raw(rva)
    end = pe.data.find(b'\0', pos)
    return pe.data[pos:end].decode('ascii', 'replace')

def inspect(path):
    p = PE(path)
    nt = p.unpack('<I', 0x3c)[0]
    opt = nt+24
    imports = []
    rva, size = p.unpack('<II', opt+112+8)
    if rva:
        for j in range(4096):
            oft,stamp,fc,name,ft=p.u('<IIIII',rva+20*j)
            if not any((oft,stamp,fc,name,ft)): break
            funcs=[]
            for k in range(16384):
                q=p.u('<Q',(oft or ft)+k*8)[0]
                if not q: break
                funcs.append(dict(name=f'ordinal:{q&65535}' if q>>63 else cstr(p,q+2),iatRva=ft+8*k))
            imports.append(dict(module=cstr(p,name),functions=funcs))
    exports=[]
    erva,esize=p.unpack('<II',opt+112)
    if erva:
        a=p.u('<IIHHIIIIIII',erva)
        base,nfunc,nnames,functions,names,ordinals=a[5:]
        for j in range(nnames):
            ordinal=p.u('<H',ordinals+2*j)[0]
            addr=p.u('<I',functions+4*ordinal)[0]
            exports.append(dict(name=cstr(p,p.u('<I',names+4*j)[0]),ordinal=base+ordinal,rva=addr,forwarder=cstr(p,addr) if erva<=addr<erva+esize else None))
    strings=[]
    for s in p.sections:
        for m in re.finditer(rb'[\x20-\x7e]{5,}',p.data[s['raw']:s['raw']+s['rawSize']]):
            strings.append(dict(rva=s['rva']+m.start(),text=m.group().decode('ascii')))
        for m in re.finditer(rb'(?:[\x20-\x7e]\x00){5,}',p.data[s['raw']:s['raw']+s['rawSize']]):
            strings.append(dict(rva=s['rva']+m.start(),text=m.group().decode('utf-16le'),encoding='utf16'))
    md=Cs(CS_ARCH_X86,CS_MODE_64);md.detail=True
    refs={}
    for f in p.functions:
        for ins in md.disasm(p.read(f['beginRva'],f['endRva']-f['beginRva']),f['beginRva']):
            for op in ins.operands:
                t=None
                if op.type==X86_OP_MEM and op.mem.base==X86_REG_RIP:t=ins.address+ins.size+op.mem.disp
                if t is not None:refs.setdefault(t,[]).append(dict(rva=ins.address,functionRva=f.get('primaryBeginRva'),asm=ins.mnemonic+' '+ins.op_str))
    interesting=re.compile(r'imgui|dxgi|direct|render|swapchain|wndproc|windowproc|ui::|keen::ui|screen|widget|panel|menu|creative|dinput|hook|\.dll|build.?mode|inventory|teleport|fly|cursor|input|stylesheet|font|button|slider',re.I)
    relevant=[]
    for st in strings:
        if interesting.search(st['text']):relevant.append(dict(st,refs=refs.get(st['rva'],[])))
    result=dict(identity=p.identity(),base=p.base,entryRva=p.unpack('<I',opt+16)[0],sections=p.sections,functionCount=len(p.functions),imports=imports,exports=exports,strings=strings,relevantStrings=relevant)
    dest=OUT/(path.stem+'-ui-static.json')
    dest.write_text(json.dumps(result,indent=2),encoding='utf-8')
    print(path.name, len(p.data),'functions',len(p.functions),'strings',len(strings),'relevant',len(relevant))
    print('Imports', [(i['module'],len(i['functions'])) for i in imports])
    print('Exports',exports[:30])
    for st in relevant:
        if len(st['text'])<250 and st['refs']:print(hex(st['rva']),repr(st['text']),st['refs'][:5])

for path in [BASE/'dinput8.dll',BASE/'creative/creative.dll']:inspect(path)
