55 lines · python
1#!/usr/bin/env python2 3"""A tool for looking for indirect jumps and calls in x86 binaries.4 5 Helpful to verify whether or not retpoline mitigations are catching6 all of the indirect branches in a binary and telling you which7 functions the remaining ones are in (assembly, etc).8 9 Depends on llvm-objdump being in your path and is tied to the10 dump format.11"""12 13from __future__ import print_function14 15import os16import sys17import re18import subprocess19import optparse20 21# Look for indirect calls/jmps in a binary. re: (call|jmp).*\*22def look_for_indirect(file):23 args = ["llvm-objdump"]24 args.extend(["-d"])25 args.extend([file])26 27 p = subprocess.Popen(28 args=args, stdin=None, stderr=subprocess.PIPE, stdout=subprocess.PIPE29 )30 (stdout, stderr) = p.communicate()31 32 function = ""33 for line in stdout.splitlines():34 if not line.startswith(" "):35 function = line36 result = re.search("(call|jmp).*\*", line)37 if result is not None:38 # TODO: Perhaps use cxxfilt to demangle functions?39 print(function)40 print(line)41 return42 43 44def main(args):45 # No options currently other than the binary.46 parser = optparse.OptionParser("%prog [options] <binary>")47 (opts, args) = parser.parse_args(args)48 if len(args) != 2:49 parser.error("invalid number of arguments: %s" % len(args))50 look_for_indirect(args[1])51 52 53if __name__ == "__main__":54 main(sys.argv)55