Closed ayrtonm closed 2 years ago
A more practical approach suggested by @thedataking is to use binary ninja to detect indirect branches. This should probably be done from the translate block callback like in option 2, but using binja instead of pattern matching the insn bytes. Detecting indirect branches ahead-of-time would be lower overhead, but it would rely on binja's code discovery capabilities which might miss cases on x86-64 (though it'd probably be ok on arm). Doing this just-in-time would also be simpler to implement since the interaction with binja would be minimal.
To implement this we'd pass the output of qemu_plugin_insn_data
to binja. Also we can use binja directly from C++ like in this example.
Another idea suggested by @travitch is to make an interface for using different backends to check if a given instruction is an indirect branch or not. This might look like this
bool is_indirect_branch(uint8_t *insn_data)
bool init_backend(char *arch_name)
where init_backend
returns a boolean indicating if the architecture is supported. Binja is probably the way to go for now, but it'd be good to avoid integrating too tightly with binja and stick to this simple interface.
It'd be nice to have this tool find indirect callsites automatically instead of passing in a list of callsites. The two options are
objdump
would require cross-compiling binutils for the target arch which isn't as user-friendly. I'd also need to expand the arm regex since it's missing some indirect jumps (e.g. ldr pc, Rn)Fixing this issue also means we don't have to pass in the binary name twice as explained here so the plugin would only require one arg for the output file.