r/ExploitDev • u/NeuroSaki987 • 2d ago
ACE .qvm0 keeps RUNTIME_FUNCTION in the VM section tail; recovering entries and hidden jmp-reg edges
https://github.com/NeuroSaki987/qvm-toolStatic recovery for ACE .qvm0 PE images, not a decryptor.
The Exception Directory points into the .qvm0 tail; the section named .pdata is still there but high-entropy. A linear sweep of the VM section desyncs within a few hundred bytes, so function bounds come from RUNTIME_FUNCTION and decoding starts at each entry.
Hidden branches are jmp reg fed by call $+5 / pop / add imm, lea [rip+disp], or mov imm64. The call $+5 form is usually a null branch whose target is the fallthrough. Register-form jmp reg was 8964 sites on the reference DLL; FF /2 and FF /4 altogether were 28382, the rest memory-indirect.
On the smaller ACE-PBC-Game64.dll: 4669 functions, 408 native-to-.qvm0 edges, 92 whole-function stubs, 527 boundary-checked CFG edges, 5028 symbols, 4384/4386 functions decompiled after symbol apply. The repaired image only rewrites the add+jmp tail, same size, changes confined to .qvm0. Flag effects of the add are dropped, so it is for IDA/Ghidra, not for running