Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@barrebas
Created September 13, 2014 06:41
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save barrebas/4fc86eaf0e9b124813a3 to your computer and use it in GitHub Desktop.
Save barrebas/4fc86eaf0e9b124813a3 to your computer and use it in GitHub Desktop.
#!/usr/bin/python
import commands, sys, getopt
def generate_hexdump(infile):
# objdump -d $binary -> disassemble...
# --insn-width=1 -> 1 byte per output line
# | egrep \' [0-9a-f]*:\' -> disregards anything that doesn't look like ' addr: opcode blah'
# | awk {\'print $1 $2\'} -> print addr & opcode
# |sort -r -> sort in reverse for easy processing, because we need to look *back* from each ret/jmp/call
commands.getstatusoutput("objdump -d "+infile+" --insn-width=1 | egrep \' [0-9a-f]*:\' | awk {\'print $1 $2\'} |sort -r > dump.txt")
f = open("dump.txt")
lines = f.readlines()
f.close()
return lines
#depth=10 # how far back should we search for rop gadgets?
def scanforgadgets(lines, depth):
# output for rasm2 to disassemble
output_string_ret=""
output_string_call_reg=""
output_string_jmp_reg=""
possible_call_reg=0
# set to depth, so we now how far to scan
output_ret=0
output_call_reg=0
output_jmp_reg=0
for line in lines:
addr = line.strip().split(":")[0] # address
opcode = line.strip().split(":")[1] # opcode
# if we've detected a ret, we should start checking for gadgets
if output_ret:
output_string_ret = opcode+output_string_ret # prepend the hex pair to the string that rasm2 will disassemble
(success, rop_gadgets) = commands.getstatusoutput("rasm2 -d "+output_string_ret+" |sed 's#$#; #' |tr -d '\\n'")
# did it find a valid rop gadget?
if not "invalid" in rop_gadgets:
if "ret" in rop_gadgets:
print "RET: 0x" + addr + ": " + rop_gadgets
output_ret = output_ret - 1
if output_call_reg:
output_string_call_reg = opcode+output_string_call_reg # prepend the hex pair to the string that rasm2 will disassemble
(success, rop_gadgets) = commands.getstatusoutput("rasm2 -d "+output_string_call_reg+" |sed 's#$#; #' |tr -d '\\n'")
# did it find a valid rop gadget?
if not "invalid" in rop_gadgets:
if "call e" in rop_gadgets:
print "CALL_REG: 0x" + addr + ": " + rop_gadgets
output_call_reg = output_call_reg-1
if output_jmp_reg:
output_string_jmp_reg = opcode+output_string_jmp_reg # prepend the hex pair to the string that rasm2 will disassemble
(success, rop_gadgets) = commands.getstatusoutput("rasm2 -d "+output_string_jmp_reg+" |sed 's#$#; #' |tr -d '\\n'")
# did it find a valid rop gadget?
if not "invalid" in rop_gadgets:
if "jmp e" in rop_gadgets:
print "JMP_REG: 0x" + addr + ": " + rop_gadgets
output_jmp_reg = output_jmp_reg-1
# is this a return opcode? if so, start building rop gadgets
if "c3" in opcode and output_ret==0:
output_ret = depth # how deep should we look
output_string_ret=opcode # start with 'c3' -> ret
if "ff" in opcode:
possible_call_reg=1
# CALL reg32
if possible_call_reg == 1 and list(opcode)[0] == "d":
output_call_reg = depth
output_string_call_reg="ff"+opcode
possible_call_reg=0
# JMP reg32
if possible_call_reg == 1 and list(opcode)[0] == "e":
output_jmp_reg = depth
output_string_jmp_reg="ff"+opcode
possible_call_reg=0
if __name__=="__main__":
#
print "[+] ropgadget search v0.03 by @barrebas"
print "[+] searches for ret, call_reg and jmp_reg gadgets"
infile = ""
depth = 10 # default depth
try:
opts, args = getopt.getopt(sys.argv[1:],"hi:d:",["infile=","depth="])
except getopt.GetoptError:
print '%s -i <inputfile> -d <depth>' % sys.argv[0]
sys.exit(2)
for opt, arg in opts:
if opt == '-h':
print '%s -i <inputfile> -d <depth>' % sys.argv[0]
sys.exit()
elif opt in ("-i", "--infile"):
infile = arg
elif opt in ("-d", "--depth"):
depth = arg
hexdump = generate_hexdump(infile)
scanforgadgets(hexdump, int(depth))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment