42 lines
2.3 KiB
JavaScript
42 lines
2.3 KiB
JavaScript
// Current .54 SHA 4aa08a0706f27d2cf9951b61920c179140ece9ea94f7e34422c18e46922939b6.
|
|
// Exact Row.FromBinary -> Add -> lazy GetAll chain in comic-*-current.asm.
|
|
// Only two flat config getters; no repository/scene/gameplay constructors.
|
|
const module = Process.getModuleByName('GameAssembly.dll');
|
|
const tables = [['cycle', 0x1eafb230], ['level', 0x1e2556c0]];
|
|
for (const [name,rva] of tables) {
|
|
if (module.base.add(rva).readU32()!==0x28ec8348) throw Error('Getter differs: '+name);
|
|
}
|
|
const serializer=module.base.add(0x1d46c040);
|
|
const serialize=new NativeFunction(serializer,'pointer',['pointer','pointer']);
|
|
const marker='GAC_COMIC_FLAT_TICK';
|
|
let table=0,index=0,count=0,entries=null,done=false,busy=false;
|
|
Interceptor.attach(serializer,{
|
|
onEnter(args){
|
|
this.trigger=false;if(done||busy)return;
|
|
try{this.trigger=args[0].add(0x10).readS32()===marker.length&&args[0].add(0x14).readUtf16String(marker.length)===marker;}catch(_){}
|
|
},
|
|
onLeave(){
|
|
if(!this.trigger||done||busy)return;busy=true;
|
|
try{
|
|
if(entries===null){
|
|
const get=new NativeFunction(module.base.add(tables[table][1]),'pointer',['pointer']);
|
|
const dict=get(ptr(0));if(dict.isNull())throw Error('Missing dictionary');
|
|
count=dict.add(0x20).readU32();entries=dict.add(0x18).readPointer();index=0;
|
|
if(count>256||count>0&&(entries.isNull()||entries.add(0x18).readU32()<count))throw Error('Dictionary bound');
|
|
send({kind:'BEGIN',table:tables[table][0],count});
|
|
}
|
|
const rows=[];
|
|
for(let n=0;n<4&&index<count;n++){
|
|
const entry=entries.add(0x20+24*index++);if(entry.readS32()<0)continue;
|
|
const row=entry.add(16).readPointer();if(row.isNull())continue;
|
|
const value=serialize(row,ptr(0));if(value.isNull())throw Error('Missing serialization');
|
|
const length=value.add(0x10).readS32();if(length<2||length>32768)throw Error('Row size bound');
|
|
rows.push(value.add(0x14).readUtf16String(length));
|
|
}
|
|
send({kind:'ROWS',table:tables[table][0],rows});
|
|
if(index>=count){send({kind:'TABLE_END',table:tables[table][0],count});table++;entries=null;if(table===tables.length){done=true;send({kind:'END'});}}
|
|
}catch(e){done=true;send({kind:'ERROR',error:String(e)});}finally{busy=false;}
|
|
}
|
|
});
|
|
send({kind:'ATTACHED',scope:'two exact lazy flat getters, four rows per marker heartbeat',module:module.path});
|