QEMU - Playable-Quotes/QuoteKit GitHub Wiki
Launch the emulator
$ qemu-system-i386 -m 64M -hda software.qcow2 -monitor stdio #where software.qcow2 is a qcow2 file of the software
Attach Frida to the emulator
$ frida -l script.js qemu-system-i386
Hook the main loop
let main_loop_addr = DebugSymbol.fromName("main_loop_wait").address;
Interceptor.attach(main_loop_addr, () => {
...
}
})
Compute call rates
let count = 0
let start = null;
let main_loop_addr = DebugSymbol.fromName("main_loop_wait").address;
Interceptor.attach(main_loop_addr, () => {
if (start === null) {
start = Date.now()
}
const now = Date.now()
let avg = (now - start) / count++;
if (count % 100 == 1) {
console.log('avg: ' + avg + 'ms')
console.log('fps: ' + 1/avg * 1000)
}
})
Get the main memory range
let mainMemoryRange = mainModule.base; // Get the base address of the main module
let mainMemorySize = mainModule.size; // Get the size of the main module
console.log(`Main module base address: ${mainMemoryRange}`);
console.log(`Main module size: ${mainMemorySize}`);
Get a save state
let main_loop_wait = DebugSymbol.fromName("main_loop_wait").address;
let save_state = DebugSymbol.fromName("save_snapshot").address;
const save_state_native = new NativeFunction(save_state, "bool",
["pointer", "bool", "pointer", "bool", "pointer", "pointer"]);
let snapshot_count = 0;
Interceptor.attach(main_loop_wait, () => {
let res = save_state_native(Memory.allocUtf8String(`snapshot_${snapshot_count++}`), 1, NULL, 0, NULL, NULL);
console.log(`save_state: ${res}`);
});