#!/usr/bin/env python3
"""revive + title-lifecycle trace from a fresh spawn."""
import json, sys, time, subprocess, frida
ADB = "/opt/android-sdk/platform-tools/adb"
C = json.load(open("/root/ants/combo2.json"))
A, TL = C["fixes"], C["trace"]

JS = r"""
var A = %s, TL = %s;
function ins(){
  var m=Process.findModuleByName("libil2cpp.so"); if(!m) return false;
  var b=m.base;
  var e=m.findExportByName?m.findExportByName("il2cpp_string_new"):Module.getGlobalExportByName("il2cpp_string_new");
  var strnew=new NativeFunction(e,'pointer',['pointer']);
  // fixes
  Interceptor.attach(b.add(A["get_sessionId"]),{onLeave:function(rv){var em=true;try{if(!rv.isNull())em=(rv.add(8).readS32()<=0);}catch(e){} if(em)rv.replace(strnew(Memory.allocUtf8String("revived-session-0001")));}});
  ["get_TermsAccepted","get_FacebookTermsAccepted"].forEach(function(k){if(A[k])Interceptor.attach(b.add(A[k]),{onLeave:function(rv){rv.replace(ptr(1));}});});
  if(A["Check25RoundsPlayed"])Interceptor.replace(b.add(A["Check25RoundsPlayed"]),new NativeCallback(function(s){},'void',['pointer']));
  // trace
  for(var n in TL){(function(n,r){try{
      if(n=="BOOT.MoveNext"){
        var lastpc=-99;
        Interceptor.attach(b.add(r),{onEnter:function(a){this.s=a[0];},onLeave:function(rv){try{var pc=this.s.add(0x3c).readS32();if(pc!=lastpc){lastpc=pc;send({ev:"BOOT pc="+pc});}}catch(e){}}});
      } else if(n=="Director.OnEvent"){
        Interceptor.attach(b.add(r),{onEnter:function(a){send({ev:"OnEvent "+a[1].toInt32()});}});
      } else {
        Interceptor.attach(b.add(r),{onEnter:function(){send({ev:n});}});
      }
    }catch(e){send({ev:"ERR "+n});}})(n,TL[n]);}
  send({ev:"__hooks_ready"});
  return true;
}
if(!ins()){var iv=setInterval(function(){if(ins())clearInterval(iv);},150);}
""" % (json.dumps(A), json.dumps(TL))

dev = frida.get_device_manager().add_remote_device("127.0.0.1:27042")
subprocess.run([ADB,"shell","am","force-stop","se.foglo.svt"])
subprocess.run([ADB,"shell","monkey","-p","se.foglo.svt","-c","android.intent.category.LAUNCHER","1"],stdout=subprocess.DEVNULL,stderr=subprocess.DEVNULL)
pid=None
for _ in range(80):
    out=subprocess.run([ADB,"shell","pidof","se.foglo.svt"],capture_output=True,text=True).stdout.strip()
    if out: pid=int(out.split()[0]); break
    time.sleep(0.25)
print("pid",pid,flush=True)
s=dev.attach(pid); sc=s.create_script(JS); t0=time.time()
def om(m,d):
    if m["type"]=="send": print("[%6.2fs] %s"%(time.time()-t0,m["payload"]["ev"]),flush=True)
    else: print("ERR",m,flush=True)
sc.on("message",om); sc.load()
time.sleep(int(sys.argv[1]) if len(sys.argv)>1 else 90)
