import frida, time, subprocess, sys
sys.path.insert(0,"/root/ants"); import emu
JS=r"""
var domain_get,dga,asm_img,cfn,onew,oinit,gmn,rinv,cgt,tgo;
function setup(mod){
 function E(n){var p=mod.findExportByName?mod.findExportByName(n):null; if(!p&&Module.getGlobalExportByName)p=Module.getGlobalExportByName(n); if(!p)throw new Error("no export "+n); return p;}
 domain_get=new NativeFunction(E("il2cpp_domain_get"),'pointer',[]);
 dga=new NativeFunction(E("il2cpp_domain_get_assemblies"),'pointer',['pointer','pointer']);
 asm_img=new NativeFunction(E("il2cpp_assembly_get_image"),'pointer',['pointer']);
 cfn=new NativeFunction(E("il2cpp_class_from_name"),'pointer',['pointer','pointer','pointer']);
 onew=new NativeFunction(E("il2cpp_object_new"),'pointer',['pointer']);
 oinit=new NativeFunction(E("il2cpp_runtime_object_init"),'void',['pointer']);
 gmn=new NativeFunction(E("il2cpp_class_get_method_from_name"),'pointer',['pointer','pointer','int']);
 rinv=new NativeFunction(E("il2cpp_runtime_invoke"),'pointer',['pointer','pointer','pointer','pointer']);
 cgt=new NativeFunction(E("il2cpp_class_get_type"),'pointer',['pointer']);
 tgo=new NativeFunction(E("il2cpp_type_get_object"),'pointer',['pointer']);
}
function cstr(s){return Memory.allocUtf8String(s);}
function findClass(ns,nm){
 var dom=domain_get();var cnt=Memory.alloc(8);var arr=dga(dom,cnt);var n=cnt.readU32();
 var nsp=cstr(ns),nmp=cstr(nm);
 for(var i=0;i<n;i++){var asm=arr.add(i*Process.pointerSize).readPointer();if(asm.isNull())continue;var img=asm_img(asm);if(img.isNull())continue;
  var k=cfn(img,nsp,nmp); if(!k.isNull())return k;}
 return ptr(0);
}
var armed=false, done=false, B=null, frames=0;
function doWork(){
 try{
  var PIERole=findClass("","PIERole");
  var GO=findClass("UnityEngine","GameObject");
  var PN=findClass("","PhotonNetwork");
  send({g:"cls PIERole="+PIERole+" GO="+GO+" PN="+PN});
  if(PIERole.isNull()||GO.isNull()){send({g:"MISSING CLASS"});return;}
  var exc=Memory.alloc(Process.pointerSize);
  // set offlineMode = true
  if(!PN.isNull()){
    var setOff=gmn(PN,cstr("set_offlineMode"),1);
    if(!setOff.isNull()){var bval=Memory.alloc(1);bval.writeU8(1);var pp=Memory.alloc(Process.pointerSize);pp.writePointer(bval);exc.writePointer(ptr(0));rinv(setOff,ptr(0),pp,exc);send({g:"offlineMode=true set"});}
  }
  // create GameObject + AddComponent<PIERole>
  var go=onew(GO); oinit(go); send({g:"go="+go});
  var ptype=tgo(cgt(PIERole));
  var addM=gmn(GO,cstr("AddComponent"),1);
  if(addM.isNull())addM=gmn(GO,cstr("Internal_AddComponentWithType"),1);
  send({g:"addM="+addM});
  var params=Memory.alloc(Process.pointerSize); params.writePointer(ptype);
  exc.writePointer(ptr(0));
  var comp=rinv(addM,go,params,exc); send({g:"comp="+comp+" exc="+exc.readPointer()});
  if(comp.isNull())comp=go; // fallback
  // ensure GameObject active + component enabled for StartCoroutine
  var osM=gmn(PIERole,cstr("OnSelectSniper"),0);
  var mp = osM.isNull()?ptr(0):osM.readPointer();
  send({g:"OnSelectSniper MethodInfo="+osM+" methodPtr="+mp+" expected="+B.add(0xd860ba)});
  // DIRECT call at known VA, passing this + MethodInfo
  var fn=new NativeFunction(B.add(0xd860ba),'void',['pointer','pointer']);
  send({g:"direct-calling OnSelectSniper(comp)"});
  try{ fn(comp, osM); send({g:"direct OnSelectSniper returned"}); }catch(e){ send({g:"direct call threw "+e}); }
 }catch(e){send({g:"doWork err "+e});}
}
function main(){
 var m=Process.findModuleByName("libil2cpp.so");if(!m){setTimeout(main,150);return;}
 B=m.base;
 try{setup(m);}catch(e){send({g:"setup err "+e});return;}
 function H(a,nm){try{Interceptor.attach(B.add(a),{onEnter:function(){send({g:"HIT "+nm});}});}catch(e){}}
 H(0xd31e77,"GetLocalPersona");H(0x786fca,"StartCoroutine");
 H(0xd85fc5,"CreateMatch");H(0xd34da2,"CreateBotMatch");H(0x7947d4,"LoadSceneAsync");H(0xd86224,"coro.MoveNext");
 H(0xe47cab,"GC.Awake");H(0xe4bd6a,"SpawnPlayers");H(0xe5a928,"AssemblePlayerList");
 // trampoline on NetworkController::Update (main thread, every frame)
 try{Interceptor.attach(B.add(0x100382f),{onEnter:function(){ frames++; if(frames==300&&!done){done=true; send({g:"=== trampoline firing doWork (frame "+frames+") ==="}); doWork();}}});}catch(e){send({g:"tramp err "+e});}
 send({g:"__ready"});
}
main();
"""
emu.sh("shell","am","force-stop","se.foglo.svt"); time.sleep(1)
emu.sh("shell","input","keyevent","3"); time.sleep(1)
emu.sh("shell","monkey","-p","se.foglo.svt","-c","android.intent.category.LAUNCHER","1")
print("launched, waiting 30s for app",flush=True); time.sleep(30)
dev=frida.get_usb_device(timeout=10)
pid=int(subprocess.run([emu.ADB,"shell","pidof","se.foglo.svt"],capture_output=True,text=True).stdout.split()[0])
print("pid",pid,flush=True)
s=dev.attach(pid); sc=s.create_script(JS)
sc.on("message",lambda m,d: print(m.get("payload",{}).get("g",""),flush=True) if isinstance(m.get("payload"),dict) else print("MSG",m,flush=True))
sc.load(); time.sleep(30)
try: emu.screenshot(); import shutil; shutil.copy("/root/ants/_emu.png","/root/ants/pie2state.png"); print("shot saved",flush=True)
except Exception as e: print("shot err",e,flush=True)
print("done",flush=True)
