indirect_calls.py 1.4 KB

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