1 #!/usr/bin/env python 2 3 """A tool for looking for indirect jumps and calls in x86 binaries. 4 5 Helpful to verify whether or not retpoline mitigations are catching 6 all of the indirect branches in a binary and telling you which 7 functions the remaining ones are in (assembly, etc). 8 9 Depends on llvm-objdump being in your path and is tied to the 10 dump format. 11 """ 12 13 import os 14 import sys 15 import re 16 import subprocess 17 import optparse 18 19 # Look for indirect calls/jmps in a binary. re: (call|jmp).*\* 20 def look_for_indirect(file): 21 args = ['llvm-objdump'] 22 args.extend(["-d"]) 23 args.extend([file]) 24 25 p = subprocess.Popen(args=args, stdin=None, stderr=subprocess.PIPE, stdout=subprocess.PIPE) 26 (stdout,stderr) = p.communicate() 27 28 function = "" 29 for line in stdout.splitlines(): 30 if line.startswith(' ') == False: 31 function = line 32 result = re.search('(call|jmp).*\*', line) 33 if result != None: 34 # TODO: Perhaps use cxxfilt to demangle functions? 35 print function 36 print line 37 return 38 39 def main(args): 40 # No options currently other than the binary. 41 parser = optparse.OptionParser("%prog [options] <binary>") 42 (opts, args) = parser.parse_args(args) 43 if len(args) != 2: 44 parser.error("invalid number of arguments: %s" % len(args)) 45 look_for_indirect(args[1]) 46 47 if __name__ == '__main__': 48 main(sys.argv) 49