import json,sys,time,frida,bisect,struct
# build addr->name for return-address symbolication
exec(open('/tmp/claude-0/-root-ants/f0a0d69c-fbe4-4887-8c0d-a5302a0da398/scratchpad/x86bridge.py').read().split("print('\\n--- registration")[0])
sm=open(SYM,'rb').read(); n,=struct.unpack_from('<I',sm,0)
starts=[]
for i in range(n):
    a,s=struct.unpack_from('<QI',sm,4+i*12); starts.append(a)
starts.sort()
CODEREG=0x1d3728c; mpCount=u32(CODEREG); mpPtr=u32(CODEREG+4)
MP=struct.unpack_from('<%dI'%mpCount,B,va2off(mpPtr))
A2N={}
for ti,t in enumerate(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]] if m[6]<mpCount else 0
        if a: A2N.setdefault(a,'%s::%s'%(cls,S(m[0])))
def owner(va):
    i=bisect.bisect_right(starts,va)-1; return starts[i] if i>=0 else 0
def name(va): return A2N.get(owner(va),'sub_%x'%va)

SUB=17728867  # Dataset::Subscribe -- recompute below
import json as J
addrs=J.load(open('/root/ants/x86addrs.json'))
SUB=addrs['Gu3.Dataset::Subscribe/1']
ADD=None
for k,v in addrs.items():
    if 'add_onSectionChange' in k: ADD=v
JS=r"""
var addrs=%s; var base=null;
function ins(){var m=Process.findModuleByName('libil2cpp.so'); if(m===null)return false; base=m.base;
  for(var nm in addrs){(function(nm,rva){Interceptor.attach(base.add(rva),{onEnter:function(a){
    var ret=this.returnAddress.sub(base);
    send({t:'sub',n:nm,ret:ret.toInt32()});
  }});})(nm,addrs[nm]);}
  send({t:'info',m:'hooks '+Object.keys(addrs).length}); return true;}
if(!ins()){var iv=setInterval(function(){if(ins())clearInterval(iv);},100);}
""" % J.dumps({k:v for k,v in addrs.items() if 'Subscribe' in k or 'onSectionChange' in k})
dev=frida.get_device_manager().add_remote_device('127.0.0.1:27042')
pid=dev.spawn(['se.foglo.svt']); ses=dev.attach(pid); sc=ses.create_script(JS)
def om(m,d):
    if m['type']!='send': print('!!',m); return
    p=m['payload']
    if p['t']=='sub':
        rip = MP_base + p['ret'] if False else p['ret']
        print('%7.2fs  %s  <- caller %s (rva 0x%x)'%(time.time()-t0,p['n'],name(p['ret']),p['ret']))
    else: print('[info]',p['m'])
sc.on('message',om); sc.load(); t0=time.time(); dev.resume(pid)
time.sleep(int(sys.argv[1]) if len(sys.argv)>1 else 25)
