Eric Christopher | e6866b5 | 2018-04-03 07:01:33 +0000 | [diff] [blame] | 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 | |
Serge Guelton | 60ccceb | 2019-01-03 14:11:33 +0000 | [diff] [blame] | 13 | from __future__ import print_function |
| 14 | |
Eric Christopher | e6866b5 | 2018-04-03 07:01:33 +0000 | [diff] [blame] | 15 | import os |
| 16 | import sys |
| 17 | import re |
| 18 | import subprocess |
| 19 | import optparse |
| 20 | |
| 21 | # Look for indirect calls/jmps in a binary. re: (call|jmp).*\* |
| 22 | def look_for_indirect(file): |
| 23 | args = ['llvm-objdump'] |
| 24 | args.extend(["-d"]) |
| 25 | args.extend([file]) |
| 26 | |
| 27 | p = subprocess.Popen(args=args, stdin=None, stderr=subprocess.PIPE, stdout=subprocess.PIPE) |
| 28 | (stdout,stderr) = p.communicate() |
| 29 | |
| 30 | function = "" |
| 31 | for line in stdout.splitlines(): |
| 32 | if line.startswith(' ') == False: |
| 33 | function = line |
| 34 | result = re.search('(call|jmp).*\*', line) |
| 35 | if result != None: |
| 36 | # TODO: Perhaps use cxxfilt to demangle functions? |
Serge Guelton | 60ccceb | 2019-01-03 14:11:33 +0000 | [diff] [blame] | 37 | print(function) |
| 38 | print(line) |
Eric Christopher | e6866b5 | 2018-04-03 07:01:33 +0000 | [diff] [blame] | 39 | return |
| 40 | |
Eric Christopher | e6866b5 | 2018-04-03 07:01:33 +0000 | [diff] [blame] | 41 | def main(args): |
| 42 | # No options currently other than the binary. |
| 43 | parser = optparse.OptionParser("%prog [options] <binary>") |
| 44 | (opts, args) = parser.parse_args(args) |
| 45 | if len(args) != 2: |
| 46 | parser.error("invalid number of arguments: %s" % len(args)) |
| 47 | look_for_indirect(args[1]) |
| 48 | |
| 49 | if __name__ == '__main__': |
| 50 | main(sys.argv) |