include ROPGadget

This commit is contained in:
Liam Dalgarno
2020-11-25 15:38:46 +00:00
parent 688bb5a1be
commit 5f8099dde0
48 changed files with 3325 additions and 0 deletions

View File

@ -0,0 +1,29 @@
## -*- coding: utf-8 -*-
##
## Jonathan Salwan - 2014-05-12 - ROPgadget tool
##
## http://twitter.com/JonathanSalwan
## http://shell-storm.org/project/ROPgadget/
##
import ropgadget.args
import ropgadget.binary
import ropgadget.core
import ropgadget.gadgets
import ropgadget.options
import ropgadget.rgutils
import ropgadget.updateAlert
import ropgadget.version
import ropgadget.loaders
import ropgadget.ropchain
def main():
import sys
from ropgadget.args import Args
from ropgadget.core import Core
try:
args = Args()
except ValueError as e:
print(e)
sys.exit(-1)
sys.exit(0 if Core(args.getArgs()).analyze() else 1)

138
ROPgadget/ropgadget/args.py Normal file
View File

@ -0,0 +1,138 @@
## -*- coding: utf-8 -*-
##
## Jonathan Salwan - 2014-05-12 - ROPgadget tool
##
## http://twitter.com/JonathanSalwan
## http://shell-storm.org/project/ROPgadget/
##
import argparse
import sys
from ropgadget.updateAlert import UpdateAlert
from ropgadget.version import *
class Args(object):
def __init__(self, arguments=None):
self.__args = None
custom_arguments_provided = True
# If no custom arguments are provided, use the program arguments
if not arguments:
arguments = sys.argv[1:]
custom_arguments_provided = False
self.__parse(arguments, custom_arguments_provided)
def __parse(self, arguments, custom_arguments_provided=False):
parser = argparse.ArgumentParser(formatter_class=argparse.RawDescriptionHelpFormatter,
description="""description:
ROPgadget lets you search your gadgets on a binary. It supports several
file formats and architectures and uses the Capstone disassembler for
the search engine.
formats supported:
- ELF
- PE
- Mach-O
- Raw
architectures supported:
- x86
- x86-64
- ARM
- ARM64
- MIPS
- PowerPC
- Sparc
""",
epilog="""examples:
ROPgadget.py --binary ./test-suite-binaries/elf-Linux-x86
ROPgadget.py --binary ./test-suite-binaries/elf-Linux-x86 --ropchain
ROPgadget.py --binary ./test-suite-binaries/elf-Linux-x86 --depth 3
ROPgadget.py --binary ./test-suite-binaries/elf-Linux-x86 --string "main"
ROPgadget.py --binary ./test-suite-binaries/elf-Linux-x86 --string "m..n"
ROPgadget.py --binary ./test-suite-binaries/elf-Linux-x86 --opcode c9c3
ROPgadget.py --binary ./test-suite-binaries/elf-Linux-x86 --only "mov|ret"
ROPgadget.py --binary ./test-suite-binaries/elf-Linux-x86 --only "mov|pop|xor|ret"
ROPgadget.py --binary ./test-suite-binaries/elf-Linux-x86 --filter "xchg|add|sub|cmov.*"
ROPgadget.py --binary ./test-suite-binaries/elf-Linux-x86 --norop --nosys
ROPgadget.py --binary ./test-suite-binaries/elf-Linux-x86 --range 0x08041000-0x08042000
ROPgadget.py --binary ./test-suite-binaries/elf-Linux-x86 --string main --range 0x080c9aaa-0x080c9aba
ROPgadget.py --binary ./test-suite-binaries/elf-Linux-x86 --memstr "/bin/sh"
ROPgadget.py --binary ./test-suite-binaries/elf-Linux-x86 --console
ROPgadget.py --binary ./test-suite-binaries/elf-Linux-x86 --badbytes "00|01-1f|7f|42"
ROPgadget.py --binary ./test-suite-binaries/Linux_lib64.so --offset 0xdeadbeef00000000
ROPgadget.py --binary ./test-suite-binaries/elf-ARMv7-ls --depth 5
ROPgadget.py --binary ./test-suite-binaries/elf-ARM64-bash --depth 5
ROPgadget.py --binary ./test-suite-binaries/raw-x86.raw --rawArch=x86 --rawMode=32""")
parser.add_argument("-v", "--version", action="store_true", help="Display the ROPgadget's version")
parser.add_argument("-c", "--checkUpdate", action="store_true", help="Checks if a new version is available")
parser.add_argument("--binary", type=str, metavar="<binary>", help="Specify a binary filename to analyze")
parser.add_argument("--opcode", type=str, metavar="<opcodes>", help="Search opcode in executable segment")
parser.add_argument("--string", type=str, metavar="<string>", help="Search string in readable segment")
parser.add_argument("--memstr", type=str, metavar="<string>", help="Search each byte in all readable segment")
parser.add_argument("--depth", type=int, metavar="<nbyte>", default=10, help="Depth for search engine (default 10)")
parser.add_argument("--only", type=str, metavar="<key>", help="Only show specific instructions")
parser.add_argument("--filter", type=str, metavar="<key>", help="Suppress specific mnemonics")
parser.add_argument("--range", type=str, metavar="<start-end>", default="0x0-0x0", help="Search between two addresses (0x...-0x...)")
parser.add_argument("--badbytes", type=str, metavar="<byte>", help="Rejects specific bytes in the gadget's address")
parser.add_argument("--rawArch", type=str, metavar="<arch>", help="Specify an arch for a raw file")
parser.add_argument("--rawMode", type=str, metavar="<mode>", help="Specify a mode for a raw file")
parser.add_argument("--rawEndian", type=str, metavar="<endian>", help="Specify an endianness for a raw file")
parser.add_argument("--re", type=str, metavar="<re>", help="Regular expression")
parser.add_argument("--offset", type=str, metavar="<hexaddr>", help="Specify an offset for gadget addresses")
parser.add_argument("--ropchain", action="store_true", help="Enable the ROP chain generation")
parser.add_argument("--thumb" , action="store_true", help="Use the thumb mode for the search engine (ARM only)")
parser.add_argument("--console", action="store_true", help="Use an interactive console for search engine")
parser.add_argument("--norop", action="store_true", help="Disable ROP search engine")
parser.add_argument("--nojop", action="store_true", help="Disable JOP search engine")
parser.add_argument("--callPreceded", action="store_true", help="Only show gadgets which are call-preceded")
parser.add_argument("--nosys", action="store_true", help="Disable SYS search engine")
parser.add_argument("--multibr", action="store_true", help="Enable multiple branch gadgets")
parser.add_argument("--all", action="store_true", help="Disables the removal of duplicate gadgets")
parser.add_argument("--noinstr", action="store_true", help="Disable the gadget instructions console printing")
parser.add_argument("--dump", action="store_true", help="Outputs the gadget bytes")
parser.add_argument("--silent", action="store_true", help="Disables printing of gadgets during analysis")
self.__args = parser.parse_args(arguments)
if self.__args.noinstr and self.__args.only:
raise ValueError("[Error] --noinstr and --only=<key> can't be used together")
if self.__args.noinstr and self.__args.re:
raise ValueError("[Error] --noinstr and --re=<re> can't be used together")
if self.__args.version:
self.__printVersion()
sys.exit(0)
elif self.__args.checkUpdate:
UpdateAlert().checkUpdate()
sys.exit(0)
elif self.__args.depth < 2:
raise ValueError("[Error] The depth must be >= 2")
elif not custom_arguments_provided and not self.__args.binary and not self.__args.console:
raise ValueError("[Error] Need a binary filename (--binary/--console or --help)")
elif self.__args.range:
try:
rangeS = int(self.__args.range.split('-')[0], 16)
rangeE = int(self.__args.range.split('-')[1], 16)
except:
raise ValueError("[Error] A range must be set in hexadecimal. Ex: 0x08041000-0x08042000")
if rangeS > rangeE:
raise ValueError("[Error] The start value must be greater than end value")
def __printVersion(self):
print("Version: %s" %(PYROPGADGET_VERSION))
print("Author: Jonathan Salwan" )
print("Author page: https://twitter.com/JonathanSalwan" )
print("Project page: http://shell-storm.org/project/ROPgadget/" )
def getArgs(self):
return self.__args

View File

@ -0,0 +1,72 @@
## -*- coding: utf-8 -*-
##
## Jonathan Salwan - 2014-05-12 - ROPgadget tool
##
## http://twitter.com/JonathanSalwan
## http://shell-storm.org/project/ROPgadget/
##
from ropgadget.loaders.elf import *
from ropgadget.loaders.pe import *
from ropgadget.loaders.raw import *
from ropgadget.loaders.macho import *
from ropgadget.loaders.universal import *
from binascii import unhexlify
class Binary(object):
def __init__(self, options):
self.__fileName = options.binary
self.__rawBinary = None
self.__binary = None
try:
fd = open(self.__fileName, "rb")
self.__rawBinary = fd.read()
fd.close()
except:
print("[Error] Can't open the binary or binary not found")
return None
if options.rawArch and options.rawMode:
self.__binary = Raw(self.__rawBinary, options.rawArch, options.rawMode, options.rawEndian)
elif self.__rawBinary[:4] == unhexlify(b"7f454c46"):
self.__binary = ELF(self.__rawBinary)
elif self.__rawBinary[:2] == unhexlify(b"4d5a"):
self.__binary = PE(self.__rawBinary)
elif self.__rawBinary[:4] == unhexlify(b"cafebabe"):
self.__binary = UNIVERSAL(self.__rawBinary)
elif self.__rawBinary[:4] == unhexlify(b"cefaedfe") or self.__rawBinary[:4] == unhexlify(b"cffaedfe"):
self.__binary = MACHO(self.__rawBinary)
else:
print("[Error] Binary format not supported")
return None
def getFileName(self):
return self.__fileName
def getRawBinary(self):
return self.__rawBinary
def getBinary(self):
return self.__binary
def getEntryPoint(self):
return self.__binary.getEntryPoint()
def getDataSections(self):
return self.__binary.getDataSections()
def getExecSections(self):
return self.__binary.getExecSections()
def getArch(self):
return self.__binary.getArch()
def getArchMode(self):
return self.__binary.getArchMode()
def getEndian(self):
return self.__binary.getEndian()
def getFormat(self):
return self.__binary.getFormat()

652
ROPgadget/ropgadget/core.py Normal file
View File

@ -0,0 +1,652 @@
## -*- coding: utf-8 -*-
##
## Jonathan Salwan - 2014-05-17 - ROPgadget tool
##
## http://twitter.com/JonathanSalwan
## http://shell-storm.org/project/ROPgadget/
##
import cmd
import os
import re
import codecs
import ropgadget.rgutils as rgutils
import binascii
from ropgadget.binary import Binary
from capstone import CS_MODE_32
from ropgadget.gadgets import Gadgets
from ropgadget.options import Options
from ropgadget.ropchain.ropmaker import ROPMaker
class Core(cmd.Cmd):
def __init__(self, options):
cmd.Cmd.__init__(self)
self.__options = options
self.__binary = None
self.__gadgets = []
self.__offset = 0
self.prompt = '(ROPgadget)> '
def __checksBeforeManipulations(self):
if self.__binary == None or self.__binary.getBinary() == None or self.__binary.getArch() == None or self.__binary.getArchMode() == None or self.__binary.getEndian() == None:
return False
return True
def _sectionInRange(self, section):
"""
given a section and a range, edit the section so that all opcodes are within the range
"""
if self.__options.range == "0x0-0x0":
return section
rangeStart, rangeEnd = map(lambda x:int(x, 16), self.__options.range.split('-'))
sectionStart = section['vaddr']
sectionEnd = sectionStart + section['size']
opcodes = section['opcodes']
if rangeEnd < sectionStart or rangeStart > sectionEnd:
return None
if rangeStart > sectionStart:
diff = rangeStart - sectionStart
opcodes = opcodes[diff:]
section['vaddr'] += diff
section['offset'] += diff
section['size'] -= diff
if rangeEnd < sectionEnd:
diff = sectionEnd - rangeEnd
opcodes = opcodes[:-diff]
section['size'] -= diff
if not section['size']:
return None
section['opcodes'] = opcodes
return section
def __getGadgets(self):
if self.__checksBeforeManipulations() == False:
return False
G = Gadgets(self.__binary, self.__options, self.__offset)
execSections = self.__binary.getExecSections()
# Find ROP/JOP/SYS gadgets
self.__gadgets = []
for section in execSections:
section = self._sectionInRange(section)
if not section: continue
if not self.__options.norop: self.__gadgets += G.addROPGadgets(section)
if not self.__options.nojop: self.__gadgets += G.addJOPGadgets(section)
if not self.__options.nosys: self.__gadgets += G.addSYSGadgets(section)
# Delete duplicate gadgets
if not self.__options.all and not self.__options.noinstr:
self.__gadgets = rgutils.deleteDuplicateGadgets(self.__gadgets)
# Applicate some Options
self.__gadgets = Options(self.__options, self.__binary, self.__gadgets).getGadgets()
# Sorted alphabetically
if not self.__options.noinstr:
self.__gadgets = rgutils.alphaSortgadgets(self.__gadgets)
return True
def __lookingForGadgets(self):
if self.__checksBeforeManipulations() == False:
return False
if self.__options.silent:
return True
arch = self.__binary.getArchMode()
print("Gadgets information\n============================================================")
for gadget in self.__gadgets:
vaddr = gadget["vaddr"]
insts = gadget.get("gadget", "")
bytesStr = " // " + binascii.hexlify(gadget["bytes"]).decode('utf8') if self.__options.dump else ""
print(("0x%08x" %(vaddr) if arch == CS_MODE_32 else "0x%016x" %(vaddr)) +
(" : %s" %(insts) if insts else "") + bytesStr)
print("\nUnique gadgets found: %d" %(len(self.__gadgets)))
return True
def __lookingForAString(self, string):
if self.__checksBeforeManipulations() == False:
return False
if self.__options.silent:
return True
dataSections = self.__binary.getDataSections()
arch = self.__binary.getArchMode()
print("Strings information\n============================================================")
for section in dataSections:
section = self._sectionInRange(section)
if not section: continue
allRef = [m.start() for m in re.finditer(string.encode(), section["opcodes"])]
for ref in allRef:
vaddr = self.__offset + section["vaddr"] + ref
match = section["opcodes"][ref:ref+len(string)]
print(("0x%08x" %(vaddr) if arch == CS_MODE_32 else "0x%016x" %(vaddr)) + " : %s" %(match.decode()))
return True
def __lookingForOpcodes(self, opcodes):
import binascii
if self.__checksBeforeManipulations() == False:
return False
if self.__options.silent:
return True
execSections = self.__binary.getExecSections()
arch = self.__binary.getArchMode()
print("Opcodes information\n============================================================")
for section in execSections:
section = self._sectionInRange(section)
if not section: continue
allRef = [m.start() for m in re.finditer(re.escape(binascii.unhexlify(opcodes)), section["opcodes"])]
for ref in allRef:
vaddr = self.__offset + section["vaddr"] + ref
print(("0x%08x" %(vaddr) if arch == CS_MODE_32 else "0x%016x" %(vaddr)) + " : %s" %(opcodes))
return True
def __lookingForMemStr(self, memstr):
if self.__checksBeforeManipulations() == False:
return False
if self.__options.silent:
return True
sections = self.__binary.getExecSections()
sections += self.__binary.getDataSections()
arch = self.__binary.getArchMode()
print("Memory bytes information\n=======================================================")
chars = list(memstr)
for char in chars:
try:
for section in sections:
section = self._sectionInRange(section)
if not section: continue
allRef = [m.start() for m in re.finditer(char.encode('utf-8'), section["opcodes"])]
for ref in allRef:
vaddr = self.__offset + section["vaddr"] + ref
print(("0x%08x" %(vaddr) if arch == CS_MODE_32 else "0x%016x" %(vaddr)) + " : '%c'" %(char))
raise
except:
pass
return True
def analyze(self):
try:
self.__offset = int(self.__options.offset, 16) if self.__options.offset else 0
except ValueError:
print("[Error] The offset must be in hexadecimal")
return False
if self.__options.console:
if self.__options.binary:
self.__binary = Binary(self.__options)
if self.__checksBeforeManipulations() == False:
return False
self.cmdloop()
return True
self.__binary = Binary(self.__options)
if self.__checksBeforeManipulations() == False:
return False
if self.__options.string: return self.__lookingForAString(self.__options.string)
elif self.__options.opcode: return self.__lookingForOpcodes(self.__options.opcode)
elif self.__options.memstr: return self.__lookingForMemStr(self.__options.memstr)
else:
self.__getGadgets()
self.__lookingForGadgets()
if self.__options.ropchain:
ROPMaker(self.__binary, self.__gadgets, self.__offset)
return True
def gadgets(self):
return self.__gadgets
# Console methods ============================================
def do_binary(self, s, silent=False):
# Do not split the filename with spaces since it might contain
# whitespaces
if len(s) == 0:
if not silent:
return self.help_binary()
return False
binary = s
self.__options.binary = binary
self.__binary = Binary(self.__options)
if self.__checksBeforeManipulations() == False:
return False
if not silent:
print("[+] Binary loaded")
def help_binary(self):
print("Syntax: binary <file> -- Load a binary")
return False
def do_EOF(self, s, silent=False):
return self.do_quit(s, silent)
def do_quit(self, s, silent=False):
return True
def help_quit(self):
print("Syntax: quit -- Terminates the application")
return False
def do_load(self, s, silent=False):
if self.__binary == None:
if not silent:
print("[-] No binary loaded.")
return False
if not silent:
print("[+] Loading gadgets, please wait...")
self.__getGadgets()
if not silent:
print("[+] Gadgets loaded !")
def help_load(self):
print("Syntax: load -- Load all gadgets")
return False
def do_display(self, s, silent=False):
self.__lookingForGadgets()
def help_display(self):
print("Syntax: display -- Display all gadgets loaded")
return False
def do_depth(self, s, silent=False):
try:
depth = int(s.split()[0])
except:
if not silent:
return self.help_depth()
return False
if depth <= 0:
if not silent:
print("[-] The depth value must be > 0")
return False
self.__options.depth = int(depth)
if not silent:
print("[+] Depth updated. You have to reload gadgets")
def help_depth(self):
print("Syntax: depth <value> -- Set the depth search engine")
return False
def do_badbytes(self, s, silent=False):
try:
bb = s.split()[0]
except:
if not silent:
return self.help_badbytes()
else:
return False
self.__options.badbytes = bb
if not silent:
print("[+] Bad bytes updated. You have to reload gadgets")
def help_badbytes(self):
print("Syntax: badbytes <badbyte1|badbyte2...> -- ")
return False
def __withK(self, listK, gadget):
if len(listK) == 0:
return True
for a in listK:
if a not in gadget:
return False
return True
def __withoutK(self, listK, gadget):
for a in listK:
if a in gadget:
return False
return True
def do_search(self, s, silent=False):
args = s.split()
if not len(args):
return self.help_search()
withK, withoutK = [], []
for a in args:
if a[0:1] == "!":
withoutK += [a[1:]]
else:
withK += [a]
if self.__checksBeforeManipulations() == False:
if not silent:
print("[-] You have to load a binary")
return False
arch = self.__binary.getArchMode()
for gadget in self.__gadgets:
vaddr = gadget["vaddr"]
insts = gadget["gadget"]
if self.__withK(withK, insts) and self.__withoutK(withoutK, insts):
# What to do if silent = True?
print(("0x%08x" %(vaddr) if arch == CS_MODE_32 else "0x%016x" %(vaddr)) + " : %s" %(insts))
def help_search(self):
print("Syntax: search <keyword1 keyword2 keyword3...> -- Filter with or without keywords")
print("keyword = with")
print("!keyword = without")
return False
def count(self):
return len(self.__gadgets)
def do_count(self, s, silent=False):
if not silent:
print("[+] %d loaded gadgets." % self.count())
def help_count(self):
print("Shows the number of loaded gadgets.")
return False
def do_filter(self, s, silent=False):
try:
self.__options.filter = s.split()[0]
except:
if not silent:
return self.help_filter()
return False
if not silent:
print("[+] Filter setted. You have to reload gadgets")
def help_filter(self):
print("Syntax: filter <filter1|filter2|...> - Suppress specific mnemonics")
return False
def do_only(self, s, silent=False):
try:
if s.lower() == "none":
self.__options.only = None
else:
self.__options.only = s.split()[0]
except:
if not silent:
return self.help_only()
return False
if not silent:
print("[+] Only setted. You have to reload gadgets")
def help_only(self):
print("Syntax: only <only1|only2|...> - Only show specific instructions")
return False
def do_range(self, s, silent=False):
try:
rangeS = int(s.split('-')[0], 16)
rangeE = int(s.split('-')[1], 16)
self.__options.range = s.split()[0]
except:
if not silent:
return self.help_range()
return False
if rangeS > rangeE:
if not silent:
print("[-] The start value must be greater than the end value")
return False
if not silent:
print("[+] Range setted. You have to reload gadgets")
def help_range(self):
print("Syntax: range <start-and> - Search between two addresses (0x...-0x...)")
return False
def do_settings(self, s, silent=False):
print("All: %s" %(self.__options.all))
print("Badbytes: %s" %(self.__options.badbytes))
print("Binary: %s" %(self.__options.binary))
print("Depth: %s" %(self.__options.depth))
print("Filter: %s" %(self.__options.filter))
print("Memstr: %s" %(self.__options.memstr))
print("MultiBr: %s" %(self.__options.multibr))
print("NoJOP: %s" %(self.__options.nojop))
print("NoROP: %s" %(self.__options.norop))
print("NoSYS: %s" %(self.__options.nosys))
print("Offset: %s" %(self.__options.offset))
print("Only: %s" %(self.__options.only))
print("Opcode: %s" %(self.__options.opcode))
print("ROPchain: %s" %(self.__options.ropchain))
print("Range: %s" %(self.__options.range))
print("RawArch: %s" %(self.__options.rawArch))
print("RawMode: %s" %(self.__options.rawMode))
print("RawEndian: %s" %(self.__options.rawEndian))
print("Re: %s" %(self.__options.re))
print("String: %s" %(self.__options.string))
print("Thumb: %s" %(self.__options.thumb))
def help_settings(self):
print("Display setting's environment")
return False
def do_nojop(self, s, silent=False):
try:
arg = s.split()[0]
except:
return self.help_nojop()
if arg == "enable":
self.__options.nojop = True
if not silent:
print("[+] NoJOP enable. You have to reload gadgets")
elif arg == "disable":
self.__options.nojop = False
if not silent:
print("[+] NoJOP disable. You have to reload gadgets")
else:
if not silent:
return self.help_nojop()
return False
def help_nojop(self):
print("Syntax: nojop <enable|disable> - Disable JOP search engin")
return False
def do_norop(self, s, silent=False):
try:
arg = s.split()[0]
except:
return self.help_norop()
if arg == "enable":
self.__options.norop = True
if not silent:
print("[+] NoROP enable. You have to reload gadgets")
elif arg == "disable":
self.__options.norop = False
if not silent:
print("[+] NoROP disable. You have to reload gadgets")
else:
if not silent:
return self.help_norop()
return False
def help_norop(self):
print("Syntax: norop <enable|disable> - Disable ROP search engin")
return False
def do_nosys(self, s, silent=False):
try:
arg = s.split()[0]
except:
return self.help_nosys()
if arg == "enable":
self.__options.nosys = True
if not silent:
print("[+] NoSYS enable. You have to reload gadgets")
elif arg == "disable":
self.__options.nosys = False
if not silent:
print("[+] NoSYS disable. You have to reload gadgets")
else:
if not silent:
return self.help_nosys()
return False
def help_nosys(self):
print("Syntax: nosys <enable|disable> - Disable SYS search engin")
return False
def do_thumb(self, s, silent=False):
try:
arg = s.split()[0]
except:
return self.help_thumb()
if arg == "enable":
self.__options.thumb = True
if not silent:
print("[+] Thumb enable. You have to reload gadgets")
elif arg == "disable":
self.__options.thumb = False
if not silent:
print("[+] Thumb disable. You have to reload gadgets")
else:
if not silent:
return self.help_thumb()
return False
def help_thumb(self):
print("Syntax: thumb <enable|disable> - Use the thumb mode for the search engine (ARM only)")
return False
def do_all(self, s, silent=False):
if s == "enable":
self.__options.all = True
if not silent:
print("[+] Showing all gadgets enabled. You have to reload gadgets")
elif s == "disable":
self.__options.all = False
if not silent:
print("[+] Showing all gadgets disabled. You have to reload gadgets")
else:
if not silent:
return self.help_all()
return False
def help_multibr(self):
print("Syntax: multibr <enable|disable> - Enable/Disable multiple branch gadgets")
return False
def do_multibr(self, s, silent=False):
if s == "enable":
self.__options.multibr = True
if not silent:
print("[+] Multiple branch gadgets enabled. You have to reload gadgets")
elif s == "disable":
self.__options.multibr = False
if not silent:
print("[+] Multiple branch gadgets disabled. You have to reload gadgets")
else:
if not silent:
return self.help_all()
return False
def help_all(self):
print("Syntax: all <enable|disable - Show all gadgets (disable removing duplicate gadgets)")
return False
def help_re(self):
print("Syntax: re <pattern1 | pattern2 |...> - Regular expression")
return False
def do_re(self, s, silent=False):
if s.lower() == 'none':
self.__options.re = None
elif s == "":
self.help_re()
silent = True
else:
self.__options.re = s
if not silent:
print("[+] Re setted. You have to reload gadgets")

View File

@ -0,0 +1,358 @@
## -*- coding: utf-8 -*-
##
## Jonathan Salwan - 2014-05-12 - ROPgadget tool
##
## http://twitter.com/JonathanSalwan
## http://shell-storm.org/project/ROPgadget/
##
import re
from capstone import *
class Gadgets(object):
def __init__(self, binary, options, offset):
self.__binary = binary
self.__options = options
self.__offset = offset
self.__arch = self.__binary.getArch()
re_str = ""
if self.__arch == CS_ARCH_X86:
re_str = "db|int3"
elif self.__arch == CS_ARCH_ARM64:
re_str = "brk|smc|hvc"
if self.__options.filter:
if re_str:
re_str += "|"
re_str += self.__options.filter
self.__filterRE = re.compile("({})$".format(re_str)) if re_str else None
def __passCleanX86(self, decodes):
br = ["ret", "retf", "int", "sysenter", "jmp", "call", "syscall"]
if decodes[-1][2] not in br:
return True
if not self.__options.multibr and any(mnemonic in br for _, _, mnemonic, _ in decodes[:-1]):
return True
if any("ret" in mnemonic for _, _, mnemonic, _ in decodes[:-1]):
return True
return False
def __gadgetsFinding(self, section, gadgets, arch, mode):
PREV_BYTES = 9 # Number of bytes prior to the gadget to store.
opcodes = section["opcodes"]
sec_vaddr = section["vaddr"]
ret = []
md = Cs(arch, mode)
for gad_op, gad_size, gad_align in gadgets:
allRefRet = [m.start() for m in re.finditer(gad_op, opcodes)]
for ref in allRefRet:
end = ref + gad_size
for i in range(self.__options.depth):
start = ref - (i * gad_align)
if (sec_vaddr+start) % gad_align == 0:
code = opcodes[start:end]
decodes = md.disasm_lite(code, sec_vaddr+ref)
decodes = list(decodes)
if sum(size for _, size, _, _ in decodes) != i*gad_align + gad_size:
# We've read less instructions than planned so something went wrong
continue
if self.passClean(decodes):
continue
off = self.__offset
vaddr = off+sec_vaddr+start
g = {"vaddr" : vaddr}
if not self.__options.noinstr:
g["gadget"] = " ; ".join("{}{}{}".format(mnemonic, " " if op_str else "", op_str)
for _, _, mnemonic, op_str in decodes).replace(" ", " ")
if self.__options.callPreceded:
prevBytesAddr = max(sec_vaddr, vaddr - PREV_BYTES)
g["prev"] = opcodes[prevBytesAddr-sec_vaddr:vaddr-sec_vaddr]
if self.__options.dump:
g["bytes"] = code
ret.append(g)
return ret
def addROPGadgets(self, section):
arch = self.__binary.getArch()
arch_mode = self.__binary.getArchMode()
arch_endian = self.__binary.getEndian()
if arch == CS_ARCH_X86:
gadgets = [
[b"\xc3", 1, 1], # ret
[b"\xc2[\x00-\xff]{2}", 3, 1], # ret <imm>
[b"\xcb", 1, 1], # retf
[b"\xca[\x00-\xff]{2}", 3, 1], # retf <imm>
# MPX
[b"\xf2\xc3", 2, 1], # ret
[b"\xf2\xc2[\x00-\xff]{2}", 4, 1], # ret <imm>
]
elif arch == CS_ARCH_MIPS: gadgets = [] # MIPS doesn't contains RET instruction set. Only JOP gadgets
elif arch == CS_ARCH_PPC:
if arch_endian == CS_MODE_BIG_ENDIAN:
gadgets = [
[b"\x4e\x80\x00\x20", 4, 4] # blr
]
else:
gadgets = [
[b"\x20\x00\x80\x4e", 4, 4] # blr
]
elif arch == CS_ARCH_SPARC:
if arch_endian == CS_MODE_BIG_ENDIAN:
gadgets = [
[b"\x81\xc3\xe0\x08", 4, 4], # retl
[b"\x81\xc7\xe0\x08", 4, 4], # ret
[b"\x81\xe8\x00\x00", 4, 4] # restore
]
else:
gadgets = [
[b"\x08\xe0\xc3\x81", 4, 4], # retl
[b"\x08\xe0\xc7\x81", 4, 4], # ret
[b"\x00\x00\xe8\x81", 4, 4] # restore
]
arch_mode = 0
elif arch == CS_ARCH_ARM: gadgets = [] # ARM doesn't contains RET instruction set. Only JOP gadgets
elif arch == CS_ARCH_ARM64:
if arch_endian == CS_MODE_BIG_ENDIAN:
gadgets = [
[b"\xd6\x5f\x03\xc0", 4, 4] # ret
]
else:
gadgets = [
[b"\xc0\x03\x5f\xd6", 4, 4] # ret
]
arch_mode = CS_MODE_ARM
else:
print("Gadgets().addROPGadgets() - Architecture not supported")
return None
if len(gadgets) > 0 :
return self.__gadgetsFinding(section, gadgets, arch, arch_mode + arch_endian)
return gadgets
def addJOPGadgets(self, section):
arch = self.__binary.getArch()
arch_mode = self.__binary.getArchMode()
arch_endian = self.__binary.getEndian()
if arch == CS_ARCH_X86:
# we start with x86 and x64 common sequences operating on registers
gadgets = [
# call/jmp reg
# d0-d7=call,e0-e7=jmp
# x86: 0=eax,1=ecx,2=edx,3=ebx,4=esp,5=ebp,6=esi,7=edi
# x64: 0=rax,1=rcx,2=rdx,3=rbx,4=rsp,5=rbp,6=rsi,7=rdi
[b"\xff[\xd0-\xd7\xe0-\xe7]", 2, 1],
# call/jmp [reg]
# 10-17=call,20-27=jmp
# x86: 0=eax,1=ecx,2=edx,3=ebx, 6=esi,7=edi
# x64: 0=rax,1=rcx,2=rdx,3=rbx, 6=rsi,7=rdi
[b"\xff[\x10-\x13\x16-\x17\x20-\x23\x26-\x27]", 2, 1],
# call/jmp [reg]
# 14=call,24=jmp
# x86: esp
# x64: rsp
[b"\xff[\x14\x24]\x24", 3, 1],
# call/jmp [reg + offset], -0x80 <= offset <= 0x7f
# 50-57=call,60-67=jmp
# x86: 0=eax,1=ecx,2=edx,3=ebx, 5=ebp,6=esi,7=edi
# x64: 0=rax,1=rcx,2=rdx,3=rbx, 5=rbp,6=rsi,7=rdi
[b"\xff[\x50-\x53\x55-\x57\x60-\x63\x65-\x67][\x00-\xff]", 3, 1],
# call/jmp [reg + offset], -0x80 <= offset <= 0x7f
# 54=call,64=jmp
# x86: esp
# x64: rsp
[b"\xff[\x54\x64]\x24[\x00-\xff]", 4, 1],
# call/jmp [reg + offset], -0x80000000 <= offset <= 0x7fffffff
# 90-97=call,a0-a7=jmp
# x86: 0=eax,1=ecx,2=edx,3=ebx, 5=ebp,6=esi,7=edi
# x64: 0=rax,1=rcx,2=rdx,3=rbx, 5=rbp,6=rsi,7=rdi
[b"\xff[\x90-\x93\x95-\x97\xa0-\xa3\xa5-\xa7][\x00-\xff]{4}", 6, 1],
# call/jmp [reg + offset], -0x80000000 <= offset <= 0x7fffffff
# 94=call,a4=jmp
# x86: esp
# x64: rsp
[b"\xff[\x94\xa4]\x24[\x00-\xff]{4}", 7, 1]
]
# in x64, by adding 41 before a sequence with
# 0=rax,1=rcx,2=rdx,3=rbx,4=rsp,5=rbp,6=rsi,7=rdi
# we convert it to the same sequence with
# 0= r8,1= r9,2=r10,3=r11,4=r12,5=r13,6=r14,7=r15
if arch_mode == CS_MODE_64:
gadgets += [(b"\x41" + op, size + 1, align) for (op, size, align) in gadgets]
# finally, add extra sequences common to x86 and x64
gadgets += [
[b"\xeb[\x00-\xff]", 2, 1], # jmp offset
[b"\xe9[\x00-\xff]{4}", 5, 1], # jmp offset
# MPX
[b"\xf2\xff[\x20\x21\x22\x23\x26\x27]{1}", 3, 1], # jmp [reg]
[b"\xf2\xff[\xe0\xe1\xe2\xe3\xe4\xe6\xe7]{1}", 3, 1], # jmp [reg]
[b"\xf2\xff[\x10\x11\x12\x13\x16\x17]{1}", 3, 1], # jmp [reg]
[b"\xf2\xff[\xd0\xd1\xd2\xd3\xd4\xd6\xd7]{1}", 3, 1] # call [reg]
]
elif arch == CS_ARCH_MIPS:
if arch_endian == CS_MODE_BIG_ENDIAN:
gadgets = [
[b"\x00[\x40\x60\x80\xa0\xc0\xe0]\xf8\x09[\x00-\xff]{4}", 8, 4], # jalr $v[0-1]|$a[0-3]
[b"[\x01\x02][\x00\x20\x40\x60\x80\xa0\xc0\xe0]\xf8\x09[\x00-\xff]{4}", 8, 4], # jalr $t[0-7]|$s[0-7]
[b"\x03[\x00\x20\xc0\xe0]\xf8\x09[\x00-\xff]{4}", 8, 4], # jalr $t[8-9]|$s8|$ra
[b"\x00[\x40\x60\x80\xa0\xc0\xe0]\x00\x08[\x00-\xff]{4}", 8, 4], # jr $v[0-1]|$a[0-3]
[b"[\x01\x02][\x00\x20\x40\x60\x80\xa0\xc0\xe0]\x00\x08[\x00-\xff]{4}", 8, 4], # jr $t[0-7]|$s[0-7]
[b"\x03[\x00\x20\xc0\xe0]\x00\x08[\x00-\xff]{4}", 8, 4], # jr $t[8-9]|$s8|$ra
[b"[\x0c-\x0f][\x00-\xff]{7}", 8, 4], # jal addr
[b"[\x08-\x0b][\x00-\xff]{7}", 8, 4] # j addr
]
else:
gadgets = [
[b"\x09\xf8[\x40\x60\x80\xa0\xc0\xe0]\x00[\x00-\xff]{4}", 8, 4], # jalr $v[0-1]|$a[0-3]
[b"\x09\xf8[\x00\x20\x40\x60\x80\xa0\xc0\xe0][\x01\x02][\x00-\xff]{4}", 8, 4], # jalr $t[0-7]|$s[0-7]
[b"\x09\xf8[\x00\x20\xc0\xe0]\x03[\x00-\xff]{4}", 8, 4], # jalr $t[8-9]|$s8|$ra
[b"\x08\x00[\x40\x60\x80\xa0\xc0\xe0]\x00[\x00-\xff]{4}", 8, 4], # jr $v[0-1]|$a[0-3]
[b"\x08\x00[\x00\x20\x40\x60\x80\xa0\xc0\xe0][\x01\x02][\x00-\xff]{4}", 8, 4], # jr $t[0-7]|$s[0-7]
[b"\x08\x00[\x00\x20\xc0\xe0]\x03[\x00-\xff]{4}", 8, 4], # jr $t[8-9]|$s8|$ra
[b"[\x00-\xff]{3}[\x0c-\x0f][\x00-\xff]{4}", 8, 4], # jal addr
[b"[\x00-\xff]{3}[\x08-\x0b][\x00-\xff]{4}", 8, 4] # j addr
]
elif arch == CS_ARCH_PPC: gadgets = [] # PPC architecture doesn't contains reg branch instruction
elif arch == CS_ARCH_SPARC:
if arch_endian == CS_MODE_BIG_ENDIAN:
gadgets = [
[b"\x81\xc0[\x00\x40\x80\xc0]{1}\x00", 4, 4] # jmp %g[0-3]
]
else:
gadgets = [
[b"\x00[\x00\x40\x80\xc0]{1}\xc0\x81", 4, 4] # jmp %g[0-3]
]
arch_mode = 0
elif arch == CS_ARCH_ARM64:
if arch_endian == CS_MODE_BIG_ENDIAN:
gadgets = [
[b"\xd6[\x1f\x5f]{1}[\x00-\x03]{1}[\x00\x20\x40\x60\x80\xa0\xc0\xe0]{1}", 4, 4], # br reg
[b"\xd6\?[\x00-\x03]{1}[\x00\x20\x40\x60\x80\xa0\xc0\xe0]{1}", 4, 4] # blr reg
]
else:
gadgets = [
[b"[\x00\x20\x40\x60\x80\xa0\xc0\xe0]{1}[\x00-\x03]{1}[\x1f\x5f]{1}\xd6", 4, 4], # br reg
[b"[\x00\x20\x40\x60\x80\xa0\xc0\xe0]{1}[\x00-\x03]{1}\?\xd6", 4, 4] # blr reg
]
arch_mode = CS_MODE_ARM
elif arch == CS_ARCH_ARM:
if self.__options.thumb or self.__options.rawMode == "thumb":
if arch_endian == CS_MODE_BIG_ENDIAN:
gadgets = [
[b"\x47[\x00\x08\x10\x18\x20\x28\x30\x38\x40\x48\x70]{1}", 2, 2], # bx reg
[b"\x47[\x80\x88\x90\x98\xa0\xa8\xb0\xb8\xc0\xc8\xf0]{1}", 2, 2], # blx reg
[b"\xbd[\x00-\xff]{1}", 2, 2] # pop {,pc}
]
else:
gadgets = [
[b"[\x00\x08\x10\x18\x20\x28\x30\x38\x40\x48\x70]{1}\x47", 2, 2], # bx reg
[b"[\x80\x88\x90\x98\xa0\xa8\xb0\xb8\xc0\xc8\xf0]{1}\x47", 2, 2], # blx reg
[b"[\x00-\xff]{1}\xbd", 2, 2] # pop {,pc}
]
arch_mode = CS_MODE_THUMB
else:
if arch_endian == CS_MODE_BIG_ENDIAN:
gadgets = [
[b"\xe1\x2f\xff[\x10-\x19\x1e]{1}", 4, 4], # bx reg
[b"\xe1\x2f\xff[\x30-\x39\x3e]{1}", 4, 4], # blx reg
[b"[\xe8\xe9][\x10-\x1e\x30-\x3e\x50-\x5e\x70-\x7e\x90-\x9e\xb0-\xbe\xd0-\xde\xf0-\xfe][\x80-\xff][\x00-\xff]", 4, 4] # ldm {,pc}
]
else:
gadgets = [
[b"[\x10-\x19\x1e]{1}\xff\x2f\xe1", 4, 4], # bx reg
[b"[\x30-\x39\x3e]{1}\xff\x2f\xe1", 4, 4], # blx reg
[b"[\x00-\xff][\x80-\xff][\x10-\x1e\x30-\x3e\x50-\x5e\x70-\x7e\x90-\x9e\xb0-\xbe\xd0-\xde\xf0-\xfe][\xe8\xe9]", 4, 4] # ldm {,pc}
]
arch_mode = CS_MODE_ARM
else:
print("Gadgets().addJOPGadgets() - Architecture not supported")
return None
if len(gadgets) > 0 :
return self.__gadgetsFinding(section, gadgets, arch, arch_mode + arch_endian)
return gadgets
def addSYSGadgets(self, section):
arch = self.__binary.getArch()
arch_mode = self.__binary.getArchMode()
arch_endian = self.__binary.getEndian()
if arch == CS_ARCH_X86:
gadgets = [
[b"\xcd\x80", 2, 1], # int 0x80
[b"\x0f\x34", 2, 1], # sysenter
[b"\x0f\x05", 2, 1], # syscall
[b"\x65\xff\x15\x10\x00\x00\x00", 7, 1], # call DWORD PTR gs:0x10
[b"\xcd\x80\xc3", 3, 1], # int 0x80 ; ret
[b"\x0f\x34\xc3", 3, 1], # sysenter ; ret
[b"\x0f\x05\xc3", 3, 1], # syscall ; ret
[b"\x65\xff\x15\x10\x00\x00\x00\xc3", 8, 1], # call DWORD PTR gs:0x10 ; ret
]
elif arch == CS_ARCH_MIPS:
if arch_endian == CS_MODE_BIG_ENDIAN:
gadgets = [
[b"\x00\x00\x00\x0c", 4, 4] # syscall
]
else:
gadgets = [
[b"\x0c\x00\x00\x00", 4, 4] # syscall
]
elif arch == CS_ARCH_PPC: gadgets = [] # TODO (sc inst)
elif arch == CS_ARCH_SPARC: gadgets = [] # TODO (ta inst)
elif arch == CS_ARCH_ARM64: gadgets = [] # TODO
elif arch == CS_ARCH_ARM:
if self.__options.thumb or self.__options.rawMode == "thumb":
gadgets = [
[b"\x00-\xff]{1}\xef", 2, 2] # FIXME: svc
]
arch_mode = CS_MODE_THUMB
else:
gadgets = [
[b"\x00-\xff]{3}\xef", 4, 4] # FIXME: svc
]
arch_mode = CS_MODE_ARM
else:
print("Gadgets().addSYSGadgets() - Architecture not supported")
return None
if len(gadgets) > 0 :
return self.__gadgetsFinding(section, gadgets, arch, arch_mode + arch_endian)
return []
def passClean(self, decodes):
if not decodes:
return True
if self.__arch == CS_ARCH_X86 and self.__passCleanX86(decodes):
return True
if self.__filterRE and any(self.__filterRE.match(mnemonic) for _, _, mnemonic, _ in decodes):
return True
return False

View File

@ -0,0 +1,12 @@
## -*- coding: utf-8 -*-
##
## Jonathan Salwan - 2014-05-12 - ROPgadget tool
##
## http://twitter.com/JonathanSalwan
## http://shell-storm.org/project/ROPgadget/
##
import ropgadget.loaders.elf
import ropgadget.loaders.macho
import ropgadget.loaders.pe
import ropgadget.loaders.raw

View File

@ -0,0 +1,350 @@
## -*- coding: utf-8 -*-
##
## Jonathan Salwan - 2014-05-12 - ROPgadget tool
##
## http://twitter.com/JonathanSalwan
## http://shell-storm.org/project/ROPgadget/
##
from capstone import *
from ctypes import *
from struct import unpack
class ELFFlags(object):
ELFCLASS32 = 0x01
ELFCLASS64 = 0x02
EI_CLASS = 0x04
EI_DATA = 0x05
ELFDATA2LSB = 0x01
ELFDATA2MSB = 0x02
EM_386 = 0x03
EM_X86_64 = 0x3e
EM_ARM = 0x28
EM_MIPS = 0x08
EM_SPARCv8p = 0x12
EM_PowerPC = 0x14
EM_ARM64 = 0xb7
class Elf32_Ehdr_LSB(LittleEndianStructure):
_fields_ = [
("e_ident", c_ubyte * 16),
("e_type", c_ushort),
("e_machine", c_ushort),
("e_version", c_uint),
("e_entry", c_uint),
("e_phoff", c_uint),
("e_shoff", c_uint),
("e_flags", c_uint),
("e_ehsize", c_ushort),
("e_phentsize", c_ushort),
("e_phnum", c_ushort),
("e_shentsize", c_ushort),
("e_shnum", c_ushort),
("e_shstrndx", c_ushort)
]
class Elf64_Ehdr_LSB(LittleEndianStructure):
_fields_ = [
("e_ident", c_ubyte * 16),
("e_type", c_ushort),
("e_machine", c_ushort),
("e_version", c_uint),
("e_entry", c_ulonglong),
("e_phoff", c_ulonglong),
("e_shoff", c_ulonglong),
("e_flags", c_uint),
("e_ehsize", c_ushort),
("e_phentsize", c_ushort),
("e_phnum", c_ushort),
("e_shentsize", c_ushort),
("e_shnum", c_ushort),
("e_shstrndx", c_ushort)
]
class Elf32_Phdr_LSB(LittleEndianStructure):
_fields_ = [
("p_type", c_uint),
("p_offset", c_uint),
("p_vaddr", c_uint),
("p_paddr", c_uint),
("p_filesz", c_uint),
("p_memsz", c_uint),
("p_flags", c_uint),
("p_align", c_uint)
]
class Elf64_Phdr_LSB(LittleEndianStructure):
_fields_ = [
("p_type", c_uint),
("p_flags", c_uint),
("p_offset", c_ulonglong),
("p_vaddr", c_ulonglong),
("p_paddr", c_ulonglong),
("p_filesz", c_ulonglong),
("p_memsz", c_ulonglong),
("p_align", c_ulonglong)
]
class Elf32_Shdr_LSB(LittleEndianStructure):
_fields_ = [
("sh_name", c_uint),
("sh_type", c_uint),
("sh_flags", c_uint),
("sh_addr", c_uint),
("sh_offset", c_uint),
("sh_size", c_uint),
("sh_link", c_uint),
("sh_info", c_uint),
("sh_addralign", c_uint),
("sh_entsize", c_uint)
]
class Elf64_Shdr_LSB(LittleEndianStructure):
_fields_ = [
("sh_name", c_uint),
("sh_type", c_uint),
("sh_flags", c_ulonglong),
("sh_addr", c_ulonglong),
("sh_offset", c_ulonglong),
("sh_size", c_ulonglong),
("sh_link", c_uint),
("sh_info", c_uint),
("sh_addralign", c_ulonglong),
("sh_entsize", c_ulonglong)
]
class Elf32_Ehdr_MSB(BigEndianStructure):
_fields_ = [
("e_ident", c_ubyte * 16),
("e_type", c_ushort),
("e_machine", c_ushort),
("e_version", c_uint),
("e_entry", c_uint),
("e_phoff", c_uint),
("e_shoff", c_uint),
("e_flags", c_uint),
("e_ehsize", c_ushort),
("e_phentsize", c_ushort),
("e_phnum", c_ushort),
("e_shentsize", c_ushort),
("e_shnum", c_ushort),
("e_shstrndx", c_ushort)
]
class Elf64_Ehdr_MSB(BigEndianStructure):
_fields_ = [
("e_ident", c_ubyte * 16),
("e_type", c_ushort),
("e_machine", c_ushort),
("e_version", c_uint),
("e_entry", c_ulonglong),
("e_phoff", c_ulonglong),
("e_shoff", c_ulonglong),
("e_flags", c_uint),
("e_ehsize", c_ushort),
("e_phentsize", c_ushort),
("e_phnum", c_ushort),
("e_shentsize", c_ushort),
("e_shnum", c_ushort),
("e_shstrndx", c_ushort)
]
class Elf32_Phdr_MSB(BigEndianStructure):
_fields_ = [
("p_type", c_uint),
("p_offset", c_uint),
("p_vaddr", c_uint),
("p_paddr", c_uint),
("p_filesz", c_uint),
("p_memsz", c_uint),
("p_flags", c_uint),
("p_align", c_uint)
]
class Elf64_Phdr_MSB(BigEndianStructure):
_fields_ = [
("p_type", c_uint),
("p_flags", c_uint),
("p_offset", c_ulonglong),
("p_vaddr", c_ulonglong),
("p_paddr", c_ulonglong),
("p_filesz", c_ulonglong),
("p_memsz", c_ulonglong),
("p_align", c_ulonglong)
]
class Elf32_Shdr_MSB(BigEndianStructure):
_fields_ = [
("sh_name", c_uint),
("sh_type", c_uint),
("sh_flags", c_uint),
("sh_addr", c_uint),
("sh_offset", c_uint),
("sh_size", c_uint),
("sh_link", c_uint),
("sh_info", c_uint),
("sh_addralign", c_uint),
("sh_entsize", c_uint)
]
class Elf64_Shdr_MSB(BigEndianStructure):
_fields_ = [
("sh_name", c_uint),
("sh_type", c_uint),
("sh_flags", c_ulonglong),
("sh_addr", c_ulonglong),
("sh_offset", c_ulonglong),
("sh_size", c_ulonglong),
("sh_link", c_uint),
("sh_info", c_uint),
("sh_addralign", c_ulonglong),
("sh_entsize", c_ulonglong)
]
""" This class parses the ELF """
class ELF(object):
def __init__(self, binary):
self.__binary = bytearray(binary)
self.__ElfHeader = None
self.__shdr_l = []
self.__phdr_l = []
self.__setHeaderElf()
self.__setShdr()
self.__setPhdr()
""" Parse ELF header """
def __setHeaderElf(self):
e_ident = self.__binary[:15]
ei_class = e_ident[ELFFlags.EI_CLASS]
ei_data = e_ident[ELFFlags.EI_DATA]
if ei_class != ELFFlags.ELFCLASS32 and ei_class != ELFFlags.ELFCLASS64:
print("[Error] ELF.__setHeaderElf() - Bad Arch size")
return None
if ei_data != ELFFlags.ELFDATA2LSB and ei_data != ELFFlags.ELFDATA2MSB:
print("[Error] ELF.__setHeaderElf() - Bad architecture endian")
return None
if ei_class == ELFFlags.ELFCLASS32:
if ei_data == ELFFlags.ELFDATA2LSB: self.__ElfHeader = Elf32_Ehdr_LSB.from_buffer_copy(self.__binary)
elif ei_data == ELFFlags.ELFDATA2MSB: self.__ElfHeader = Elf32_Ehdr_MSB.from_buffer_copy(self.__binary)
elif ei_class == ELFFlags.ELFCLASS64:
if ei_data == ELFFlags.ELFDATA2LSB: self.__ElfHeader = Elf64_Ehdr_LSB.from_buffer_copy(self.__binary)
elif ei_data == ELFFlags.ELFDATA2MSB: self.__ElfHeader = Elf64_Ehdr_MSB.from_buffer_copy(self.__binary)
self.getArch() # Check if architecture is supported
""" Parse Section header """
def __setShdr(self):
shdr_num = self.__ElfHeader.e_shnum
base = self.__binary[self.__ElfHeader.e_shoff:]
shdr_l = []
e_ident = self.__binary[:15]
ei_data = e_ident[ELFFlags.EI_DATA]
for i in range(shdr_num):
if self.getArchMode() == CS_MODE_32:
if ei_data == ELFFlags.ELFDATA2LSB: shdr = Elf32_Shdr_LSB.from_buffer_copy(base)
elif ei_data == ELFFlags.ELFDATA2MSB: shdr = Elf32_Shdr_MSB.from_buffer_copy(base)
elif self.getArchMode() == CS_MODE_64:
if ei_data == ELFFlags.ELFDATA2LSB: shdr = Elf64_Shdr_LSB.from_buffer_copy(base)
elif ei_data == ELFFlags.ELFDATA2MSB: shdr = Elf64_Shdr_MSB.from_buffer_copy(base)
self.__shdr_l.append(shdr)
base = base[self.__ElfHeader.e_shentsize:]
# setup name from the strings table
if self.__ElfHeader.e_shstrndx != 0:
string_table = bytes(self.__binary[(self.__shdr_l[self.__ElfHeader.e_shstrndx].sh_offset):])
for i in range(shdr_num):
self.__shdr_l[i].str_name = string_table[self.__shdr_l[i].sh_name:].split(b'\x00')[0].decode('utf8')
""" Parse Program header """
def __setPhdr(self):
pdhr_num = self.__ElfHeader.e_phnum
base = self.__binary[self.__ElfHeader.e_phoff:]
phdr_l = []
e_ident = self.__binary[:15]
ei_data = e_ident[ELFFlags.EI_DATA]
for i in range(pdhr_num):
if self.getArchMode() == CS_MODE_32:
if ei_data == ELFFlags.ELFDATA2LSB: phdr = Elf32_Phdr_LSB.from_buffer_copy(base)
elif ei_data == ELFFlags.ELFDATA2MSB: phdr = Elf32_Phdr_MSB.from_buffer_copy(base)
elif self.getArchMode() == CS_MODE_64:
if ei_data == ELFFlags.ELFDATA2LSB: phdr = Elf64_Phdr_LSB.from_buffer_copy(base)
elif ei_data == ELFFlags.ELFDATA2MSB: phdr = Elf64_Phdr_MSB.from_buffer_copy(base)
self.__phdr_l.append(phdr)
base = base[self.__ElfHeader.e_phentsize:]
def getEntryPoint(self):
return self.__e_entry
def getExecSections(self):
ret = []
for segment in self.__phdr_l:
if segment.p_flags & 0x1:
ret += [{
"offset" : segment.p_offset,
"size" : segment.p_memsz,
"vaddr" : segment.p_vaddr,
"opcodes" : bytes(self.__binary[segment.p_offset:segment.p_offset+segment.p_memsz])
}]
return ret
def getDataSections(self):
ret = []
for section in self.__shdr_l:
if not (section.sh_flags & 0x4) and (section.sh_flags & 0x2):
ret += [{
"name" : section.str_name,
"offset" : section.sh_offset,
"size" : section.sh_size,
"vaddr" : section.sh_addr,
"opcodes" : bytes(self.__binary[section.sh_offset:section.sh_offset+section.sh_size])
}]
return ret
def getArch(self):
if self.__ElfHeader.e_machine == ELFFlags.EM_386 or self.__ElfHeader.e_machine == ELFFlags.EM_X86_64:
return CS_ARCH_X86
elif self.__ElfHeader.e_machine == ELFFlags.EM_ARM:
return CS_ARCH_ARM
elif self.__ElfHeader.e_machine == ELFFlags.EM_ARM64:
return CS_ARCH_ARM64
elif self.__ElfHeader.e_machine == ELFFlags.EM_MIPS:
return CS_ARCH_MIPS
elif self.__ElfHeader.e_machine == ELFFlags.EM_PowerPC:
return CS_ARCH_PPC
elif self.__ElfHeader.e_machine == ELFFlags.EM_SPARCv8p:
return CS_ARCH_SPARC
else:
print("[Error] ELF.getArch() - Architecture not supported")
return None
def getArchMode(self):
if self.__ElfHeader.e_ident[ELFFlags.EI_CLASS] == ELFFlags.ELFCLASS32:
return CS_MODE_32
elif self.__ElfHeader.e_ident[ELFFlags.EI_CLASS] == ELFFlags.ELFCLASS64:
return CS_MODE_64
else:
print("[Error] ELF.getArchMode() - Bad Arch size")
return None
def getEndian(self):
if self.__ElfHeader.e_ident[ELFFlags.EI_DATA] == ELFFlags.ELFDATA2LSB:
return 0
if self.__ElfHeader.e_ident[ELFFlags.EI_DATA] == ELFFlags.ELFDATA2MSB:
return CS_MODE_BIG_ENDIAN
print("[Error] ELF.getEndian() - Bad Endianness")
return None
def getFormat(self):
return "ELF"

View File

@ -0,0 +1,211 @@
## -*- coding: utf-8 -*-
##
## Jonathan Salwan - 2014-05-12 - ROPgadget tool
##
## http://twitter.com/JonathanSalwan
## http://shell-storm.org/project/ROPgadget/
##
from capstone import *
from ctypes import *
class MACH_HEADER(Structure):
_fields_ = [
("magic", c_uint),
("cputype", c_uint),
("cpusubtype", c_uint),
("filetype", c_uint),
("ncmds", c_uint),
("sizeofcmds", c_uint),
("flags", c_uint)
]
class LOAD_COMMAND(Structure):
_fields_ = [
("cmd", c_uint),
("cmdsize", c_uint)
]
class SEGMENT_COMMAND(Structure):
_fields_ = [
("cmd", c_uint),
("cmdsize", c_uint),
("segname", c_ubyte * 16),
("vmaddr", c_uint),
("vmsize", c_uint),
("fileoff", c_uint),
("filesize", c_uint),
("maxprot", c_uint),
("initprot", c_uint),
("nsects", c_uint),
("flags", c_uint)
]
class SEGMENT_COMMAND64(Structure):
_fields_ = [
("cmd", c_uint),
("cmdsize", c_uint),
("segname", c_ubyte * 16),
("vmaddr", c_ulonglong),
("vmsize", c_ulonglong),
("fileoff", c_ulonglong),
("filesize", c_ulonglong),
("maxprot", c_uint),
("initprot", c_uint),
("nsects", c_uint),
("flags", c_uint)
]
class SECTION(Structure):
_fields_ = [
("sectname", c_ubyte * 16),
("segname", c_ubyte * 16),
("addr", c_uint),
("size", c_uint),
("offset", c_uint),
("align", c_uint),
("reloff", c_uint),
("nreloc", c_uint),
("flags", c_uint),
("reserved1", c_uint),
("reserved2", c_uint)
]
class SECTION64(Structure):
_fields_ = [
("sectname", c_ubyte * 16),
("segname", c_ubyte * 16),
("addr", c_ulonglong),
("size", c_ulonglong),
("offset", c_uint),
("align", c_uint),
("reloff", c_uint),
("nreloc", c_uint),
("flags", c_uint),
("reserved1", c_uint),
("reserved2", c_uint)
]
class MACHOFlags(object):
CPU_TYPE_I386 = 0x7
CPU_TYPE_X86_64 = (CPU_TYPE_I386 | 0x1000000)
CPU_TYPE_MIPS = 0x8
CPU_TYPE_ARM = 12
CPU_TYPE_ARM64 = (CPU_TYPE_ARM | 0x1000000)
CPU_TYPE_SPARC = 14
CPU_TYPE_POWERPC = 18
CPU_TYPE_POWERPC64 = (CPU_TYPE_POWERPC | 0x1000000)
LC_SEGMENT = 0x1
LC_SEGMENT_64 = 0x19
S_ATTR_SOME_INSTRUCTIONS = 0x00000400
S_ATTR_PURE_INSTRUCTIONS = 0x80000000
""" This class parses the Mach-O """
class MACHO(object):
def __init__(self, binary):
self.__binary = bytearray(binary)
self.__machHeader = None
self.__rawLoadCmd = None
self.__sections_l = []
self.__setHeader()
self.__setLoadCmd()
def __setHeader(self):
self.__machHeader = MACH_HEADER.from_buffer_copy(self.__binary)
if self.getArchMode() == CS_MODE_32:
self.__rawLoadCmd = self.__binary[28:28+self.__machHeader.sizeofcmds]
elif self.getArchMode() == CS_MODE_64:
self.__rawLoadCmd = self.__binary[32:32+self.__machHeader.sizeofcmds]
def __setLoadCmd(self):
base = self.__rawLoadCmd
for i in range(self.__machHeader.ncmds):
command = LOAD_COMMAND.from_buffer_copy(base)
if command.cmd == MACHOFlags.LC_SEGMENT:
segment = SEGMENT_COMMAND.from_buffer_copy(base)
self.__setSections(segment, base[56:], 32)
elif command.cmd == MACHOFlags.LC_SEGMENT_64:
segment = SEGMENT_COMMAND64.from_buffer_copy(base)
self.__setSections(segment, base[72:], 64)
base = base[command.cmdsize:]
def __setSections(self, segment, base, sizeHeader):
for i in range(segment.nsects):
if sizeHeader == 32:
section = SECTION.from_buffer_copy(base)
section.offset = segment.fileoff + section.addr - segment.vmaddr
base = base[68:]
self.__sections_l += [section]
elif sizeHeader == 64:
section = SECTION64.from_buffer_copy(base)
section.offset = segment.fileoff + section.addr - segment.vmaddr
base = base[80:]
self.__sections_l += [section]
def getEntryPoint(self):
for section in self.__sections_l:
if section.sectname[0:6] == "__text":
return section.addr
def getExecSections(self):
ret = []
for section in self.__sections_l:
if section.flags & MACHOFlags.S_ATTR_SOME_INSTRUCTIONS or section.flags & MACHOFlags.S_ATTR_PURE_INSTRUCTIONS:
ret += [{
"name" : section.sectname,
"offset" : section.offset,
"size" : section.size,
"vaddr" : section.addr,
"opcodes" : bytes(self.__binary[section.offset:section.offset+section.size])
}]
return ret
def getDataSections(self):
ret = []
for section in self.__sections_l:
if not section.flags & MACHOFlags.S_ATTR_SOME_INSTRUCTIONS and not section.flags & MACHOFlags.S_ATTR_PURE_INSTRUCTIONS:
ret += [{
"name" : section.sectname,
"offset" : section.offset,
"size" : section.size,
"vaddr" : section.addr,
"opcodes" : bytes(self.__binary[section.offset:section.offset+section.size])
}]
return ret
def getArch(self):
if self.__machHeader.cputype == MACHOFlags.CPU_TYPE_I386 or self.__machHeader.cputype == MACHOFlags.CPU_TYPE_X86_64:
return CS_ARCH_X86
if self.__machHeader.cputype == MACHOFlags.CPU_TYPE_ARM:
return CS_ARCH_ARM
if self.__machHeader.cputype == MACHOFlags.CPU_TYPE_ARM64:
return CS_ARCH_ARM64
if self.__machHeader.cputype == MACHOFlags.CPU_TYPE_MIPS:
return CS_ARCH_MIPS
else:
print("[Error] MACHO.getArch() - Architecture not supported")
return None
def getArchMode(self):
if self.__machHeader.magic == 0xfeedface:
return CS_MODE_32
elif self.__machHeader.magic == 0xfeedfacf:
return CS_MODE_64
else:
print("[Error] MACHO.getArchMode() - Bad Arch size")
return None
pass
def getEndian(self):
# TODO: Support other endianness
return 0
def getFormat(self):
return "Mach-O"

View File

@ -0,0 +1,233 @@
## -*- coding: utf-8 -*-
##
## Jonathan Salwan - 2014-05-12 - ROPgadget tool
##
## http://twitter.com/JonathanSalwan
## http://shell-storm.org/project/ROPgadget/
##
from capstone import *
from ctypes import *
from struct import unpack
from binascii import unhexlify
class PEFlags(object):
IMAGE_MACHINE_INTEL_386 = 0x014c
IMAGE_MACHINE_AMD_8664 = 0x8664
IMAGE_FILE_MACHINE_ARM = 0x1c0
IMAGE_FILE_MACHINE_ARMV7 = 0x1c4
IMAGE_NT_OPTIONAL_HDR32_MAGIC = 0x10b
IMAGE_NT_OPTIONAL_HDR64_MAGIC = 0x20b
IMAGE_SIZEOF_SHORT_NAME = 0x8
class IMAGE_FILE_HEADER(Structure):
_fields_ = [
("Magic", c_uint),
("Machine", c_ushort),
("NumberOfSections", c_ushort),
("TimeDateStamp", c_uint),
("PointerToSymbolTable", c_uint),
("NumberOfSymbols", c_uint),
("SizeOfOptionalHeader", c_ushort),
("Characteristics", c_ushort)
]
class IMAGE_OPTIONAL_HEADER(Structure):
_fields_ = [
("Magic", c_ushort),
("MajorLinkerVersion", c_ubyte),
("MinorLinkerVersion", c_ubyte),
("SizeOfCode", c_uint),
("SizeOfInitializedData", c_uint),
("SizeOfUninitializedData", c_uint),
("AddressOfEntryPoint", c_uint),
("BaseOfCode", c_uint),
("BaseOfData", c_uint),
("ImageBase", c_uint),
("SectionAlignment", c_uint),
("FileAlignment", c_uint),
("MajorOperatingSystemVersion", c_ushort),
("MinorOperatingSystemVersion", c_ushort),
("MajorImageVersion", c_ushort),
("MinorImageVersion", c_ushort),
("MajorSubsystemVersion", c_ushort),
("MinorSubsystemVersion", c_ushort),
("Win32VersionValue", c_uint),
("SizeOfImage", c_uint),
("SizeOfHeaders", c_uint),
("CheckSum", c_uint),
("Subsystem", c_ushort),
("DllCharacteristics", c_ushort),
("SizeOfStackReserve", c_uint),
("SizeOfStackCommit", c_uint),
("SizeOfHeapReserve", c_uint),
("SizeOfHeapCommit", c_uint),
("LoaderFlags", c_uint),
("NumberOfRvaAndSizes", c_uint)
]
class IMAGE_OPTIONAL_HEADER64(Structure):
_fields_ = [
("Magic", c_ushort),
("MajorLinkerVersion", c_ubyte),
("MinorLinkerVersion", c_ubyte),
("SizeOfCode", c_uint),
("SizeOfInitializedData", c_uint),
("SizeOfUninitializedData", c_uint),
("AddressOfEntryPoint", c_uint),
("BaseOfCode", c_uint),
("ImageBase", c_ulonglong),
("SectionAlignment", c_uint),
("FileAlignment", c_uint),
("MajorOperatingSystemVersion", c_ushort),
("MinorOperatingSystemVersion", c_ushort),
("MajorImageVersion", c_ushort),
("MinorImageVersion", c_ushort),
("MajorSubsystemVersion", c_ushort),
("MinorSubsystemVersion", c_ushort),
("Win32VersionValue", c_uint),
("SizeOfImage", c_uint),
("SizeOfHeaders", c_uint),
("CheckSum", c_uint),
("Subsystem", c_ushort),
("DllCharacteristics", c_ushort),
("SizeOfStackReserve", c_ulonglong),
("SizeOfStackCommit", c_ulonglong),
("SizeOfHeapReserve", c_ulonglong),
("SizeOfHeapCommit", c_ulonglong),
("LoaderFlags", c_uint),
("NumberOfRvaAndSizes", c_uint)
]
class IMAGE_NT_HEADERS(Structure):
_fields_ = [
("Signature", c_uint),
("FileHeader", IMAGE_FILE_HEADER),
("OptionalHeader", IMAGE_OPTIONAL_HEADER)
]
class IMAGE_NT_HEADERS64(Structure):
_fields_ = [
("Signature", c_uint),
("FileHeader", IMAGE_FILE_HEADER),
("OptionalHeader", IMAGE_OPTIONAL_HEADER64)
]
class IMAGE_SECTION_HEADER(Structure):
_fields_ = [
("Name", c_ubyte * PEFlags.IMAGE_SIZEOF_SHORT_NAME),
("PhysicalAddress", c_uint),
("VirtualAddress", c_uint),
("SizeOfRawData", c_uint),
("PointerToRawData", c_uint),
("PointerToRelocations", c_uint),
("PointerToLinenumbers", c_uint),
("NumberOfRelocations", c_ushort),
("NumberOfLinenumbers", c_ushort),
("Characteristics", c_uint)
]
""" This class parses the PE format """
class PE(object):
def __init__(self, binary):
self.__binary = bytearray(binary)
self.__PEOffset = 0x00000000
self.__IMAGE_FILE_HEADER = None
self.__IMAGE_OPTIONAL_HEADER = None
self.__sections_l = []
self.__getPEOffset()
self.__parsePEHeader()
self.__parseOptHeader()
self.__parseSections()
def __getPEOffset(self):
self.__PEOffset = unpack("<I", bytes(self.__binary[60:64]))[0]
if self.__binary[self.__PEOffset:self.__PEOffset+4] != unhexlify(b"50450000"):
print("[Error] PE.__getPEOffset() - Bad PE signature")
return None
def __parsePEHeader(self):
PEheader = self.__binary[self.__PEOffset:]
self.__IMAGE_FILE_HEADER = IMAGE_FILE_HEADER.from_buffer_copy(PEheader)
def __parseOptHeader(self):
PEoptHeader = self.__binary[self.__PEOffset+24:self.__PEOffset+24+self.__IMAGE_FILE_HEADER.SizeOfOptionalHeader]
if unpack("<H", bytes(PEoptHeader[0:2]))[0] == PEFlags.IMAGE_NT_OPTIONAL_HDR32_MAGIC:
self.__IMAGE_OPTIONAL_HEADER = IMAGE_OPTIONAL_HEADER.from_buffer_copy(PEoptHeader)
elif unpack("<H", bytes(PEoptHeader[0:2]))[0] == PEFlags.IMAGE_NT_OPTIONAL_HDR64_MAGIC:
self.__IMAGE_OPTIONAL_HEADER = IMAGE_OPTIONAL_HEADER64.from_buffer_copy(PEoptHeader)
else:
print("[Error] PE.__parseOptHeader - Bad size header")
return None
def __parseSections(self):
baseSections = self.__PEOffset+24+self.__IMAGE_FILE_HEADER.SizeOfOptionalHeader
sizeSections = self.__IMAGE_FILE_HEADER.NumberOfSections * sizeof(IMAGE_SECTION_HEADER)
base = self.__binary[baseSections:baseSections+sizeSections]
for i in range(self.__IMAGE_FILE_HEADER.NumberOfSections):
sec = IMAGE_SECTION_HEADER.from_buffer_copy(base)
base = base[sizeof(IMAGE_SECTION_HEADER):]
self.__sections_l += [sec]
return 0
def getEntryPoint(self):
return self.__IMAGE_OPTIONAL_HEADER.ImageBase + self.__IMAGE_OPTIONAL_HEADER.AddressOfEntryPoint
def getDataSections(self):
ret = []
for section in self.__sections_l:
if section.Characteristics & 0x80000000:
ret += [{
"name" : section.Name,
"offset" : section.PointerToRawData,
"size" : section.SizeOfRawData,
"vaddr" : section.VirtualAddress + self.__IMAGE_OPTIONAL_HEADER.ImageBase,
"opcodes" : bytes(self.__binary[section.PointerToRawData:section.PointerToRawData+section.SizeOfRawData])
}]
return ret
def getExecSections(self):
ret = []
for section in self.__sections_l:
if section.Characteristics & 0x20000000:
ret += [{
"name" : section.Name,
"offset" : section.PointerToRawData,
"size" : section.SizeOfRawData,
"vaddr" : section.VirtualAddress + self.__IMAGE_OPTIONAL_HEADER.ImageBase,
"opcodes" : bytes(self.__binary[section.PointerToRawData:section.PointerToRawData+section.SizeOfRawData])
}]
return ret
def getArch(self):
if self.__IMAGE_FILE_HEADER.Machine == PEFlags.IMAGE_MACHINE_INTEL_386 or self.__IMAGE_FILE_HEADER.Machine == PEFlags.IMAGE_MACHINE_AMD_8664:
return CS_ARCH_X86
if self.__IMAGE_FILE_HEADER.Machine == PEFlags.IMAGE_FILE_MACHINE_ARM or self.__IMAGE_FILE_HEADER.Machine == PEFlags.IMAGE_FILE_MACHINE_ARMV7:
return CS_ARCH_ARM
else:
print("[Error] PE.getArch() - Bad Arch")
return None
def getArchMode(self):
if self.__IMAGE_OPTIONAL_HEADER.Magic == PEFlags.IMAGE_NT_OPTIONAL_HDR32_MAGIC:
return CS_MODE_32
elif self.__IMAGE_OPTIONAL_HEADER.Magic == PEFlags.IMAGE_NT_OPTIONAL_HDR64_MAGIC:
return CS_MODE_64
else:
print("[Error] PE.getArch() - Bad arch size")
return None
def getEndian(self):
# PE is little-endian only
return 0
def getFormat(self):
return "PE"

View File

@ -0,0 +1,72 @@
## -*- coding: utf-8 -*-
##
## Jonathan Salwan - 2014-05-12
##
## http://shell-storm.org
## http://twitter.com/JonathanSalwan
##
from capstone import *
class Raw(object):
def __init__(self, binary, arch, mode, endian):
self.__binary = bytearray(binary)
self.__arch = arch
self.__mode = mode
self.__endian = endian
def getEntryPoint(self):
return 0x0
def getExecSections(self):
return [{"name": "raw", "offset": 0x0, "size": len(self.__binary), "vaddr": 0x0, "opcodes": bytes(self.__binary)}]
def getDataSections(self):
return []
def getArch(self):
arch = {
"x86": CS_ARCH_X86,
"arm": CS_ARCH_ARM,
"arm64": CS_ARCH_ARM64,
"sparc": CS_ARCH_SPARC,
"mips": CS_ARCH_MIPS,
"ppc": CS_ARCH_PPC
}
try:
ret = arch[self.__arch]
except:
print("[Error] Raw.getArch() - Architecture not supported. Only supported: x86 arm arm64 sparc mips ppc")
return None
return ret
def getArchMode(self):
mode = {
"32": CS_MODE_32,
"64": CS_MODE_64,
"arm": CS_MODE_ARM,
"thumb": CS_MODE_THUMB
}
try:
ret = mode[self.__mode]
except:
print("[Error] Raw.getArchMode() - Mode not supported. Only supported: 32 64 arm thumb")
return None
return ret
def getEndian(self):
if self.getArch() == CS_ARCH_X86:
return 0
endian ={
"little": 0,
"big": CS_MODE_BIG_ENDIAN
}
try:
ret = endian[self.__endian]
except:
print("[Error] Raw.getArchEndian() - Endianness not supported. Only supported: little big")
return None
return ret
def getFormat(self):
return "Raw"

View File

@ -0,0 +1,107 @@
## -*- coding: utf-8 -*-
##
## Christoffer Brodd-Reijer - 2014-07-20 - ROPgadget tool
##
## http://twitter.com/ephracis
## http://shell-storm.org/project/ROPgadget/
##
import sys
from capstone import *
from ctypes import *
from binascii import *
from ropgadget.loaders.macho import *
class FAT_HEADER(BigEndianStructure):
_fields_ = [
("magic", c_uint),
("nfat_arch", c_uint)
]
class FAT_ARC(BigEndianStructure):
_fields_ = [
("cputype", c_uint),
("cpusubtype", c_uint),
("offset", c_uint),
("size", c_uint),
("align", c_uint)
]
class MACHOFlags(object):
CPU_TYPE_I386 = 0x7
CPU_TYPE_X86_64 = (CPU_TYPE_I386 | 0x1000000)
CPU_TYPE_MIPS = 0x8
CPU_TYPE_ARM = 12
CPU_TYPE_SPARC = 14
CPU_TYPE_POWERPC = 18
CPU_TYPE_POWERPC64 = (CPU_TYPE_POWERPC | 0x1000000)
LC_SEGMENT = 0x1
LC_SEGMENT_64 = 0x19
S_ATTR_SOME_INSTRUCTIONS = 0x00000400
S_ATTR_PURE_INSTRUCTIONS = 0x80000000
""" This class parses the Universal binary """
class UNIVERSAL(object):
def __init__(self, binary):
self.__binary = bytearray(binary)
self.__machoBinaries = []
self.__fatHeader = None
self.__rawLoadCmd = None
self.__sections_l = []
self.__setHeader()
self.__setBinaries()
def __setHeader(self):
self.__fatHeader = FAT_HEADER.from_buffer_copy(self.__binary)
def __setBinaries(self):
offset = 8
for i in xrange(self.__fatHeader.nfat_arch):
header = FAT_ARC.from_buffer_copy(self.__binary[offset:])
rawBinary = self.__binary[header.offset:header.offset+header.size]
if rawBinary[:4] == unhexlify(b"cefaedfe") or rawBinary[:4] == unhexlify(b"cffaedfe"):
self.__machoBinaries.append(MACHO(rawBinary))
else:
print("[Error] Binary #"+str(i+1)+" in Universal binary has an unsupported format")
offset += sizeof(header)
def getExecSections(self):
ret = []
for binary in self.__machoBinaries:
ret += binary.getExecSections()
return ret
def getDataSections(self):
ret = []
for binary in self.__machoBinaries:
ret += binary.getDataSections()
return ret
def getFormat(self):
return "Universal"
# TODO: These three will just return whatever is in the first binary.
# Perhaps the rest of ROPgadget should support loading multiple binaries?
def getEntryPoint(self):
for binary in self.__machoBinaries:
return binary.getEntryPoint()
def getArch(self):
for binary in self.__machoBinaries:
return binary.getArch()
def getArchMode(self):
for binary in self.__machoBinaries:
return binary.getArchMode()
def getEndian(self):
for binary in self.__machoBinaries:
return binary.getEndian()
if sys.version_info.major == 3:
xrange = range

View File

@ -0,0 +1,145 @@
## -*- coding: utf-8 -*-
##
## Jonathan Salwan - 2014-05-17 - ROPgadget tool
##
## http://twitter.com/JonathanSalwan
## http://shell-storm.org/project/ROPgadget/
##
import re
import codecs
from capstone import *
from struct import pack
class Options(object):
def __init__(self, options, binary, gadgets):
self.__options = options
self.__gadgets = gadgets
self.__binary = binary
if options.only: self.__onlyOption()
if options.range: self.__rangeOption()
if options.re: self.__reOption()
if options.badbytes: self.__deleteBadBytes()
if options.callPreceded: self.__removeNonCallPreceded()
def __onlyOption(self):
new = []
if not self.__options.only:
return
only = self.__options.only.split("|")
if not len(only):
return
for gadget in self.__gadgets:
flag = 0
insts = gadget["gadget"].split(" ; ")
for ins in insts:
if ins.split(" ")[0] not in only:
flag = 1
break
if not flag:
new += [gadget]
self.__gadgets = new
def __rangeOption(self):
new = []
rangeS = int(self.__options.range.split('-')[0], 16)
rangeE = int(self.__options.range.split('-')[1], 16)
if rangeS == 0 and rangeE == 0:
return
for gadget in self.__gadgets:
vaddr = gadget["vaddr"]
if vaddr >= rangeS and vaddr <= rangeE:
new += [gadget]
self.__gadgets = new
def __reOption(self):
new = []
re_strs = []
if not self.__options.re:
return
if '|' in self.__options.re:
re_strs = self.__options.re.split(' | ')
if 1 == len(re_strs):
re_strs = self.__options.re.split('|')
else:
re_strs.append(self.__options.re)
patterns = []
for __re_str in re_strs:
pattern = re.compile(__re_str)
patterns.append(pattern)
for gadget in self.__gadgets:
flag = 1
insts = gadget["gadget"].split(" ; ")
for pattern in patterns:
for ins in insts:
res = pattern.search(ins)
if res:
flag = 1
break
else:
flag = 0
if not flag:
break
if flag:
new += [gadget]
self.__gadgets = new
def __removeNonCallPreceded(self):
def __isGadgetCallPreceded(gadget):
# Given a gadget, determine if the bytes immediately preceding are a call instruction
prevBytes = gadget["prev"]
# TODO: Improve / Semantically document each of these cases.
callPrecededExpressions = [
"\xe8[\x00-\xff][\x00-\xff][\x00-\xff][\x00-\xff]$",
"\xe8[\x00-\xff][\x00-\xff][\x00-\xff][\x00-\xff][\x00-\xff][\x00-\xff][\x00-\xff][\x00-\xff]$",
"\xff[\x00-\xff]$",
"\xff[\x00-\xff][\x00-\xff]$",
"\xff[\x00-\xff][\x00-\xff][\x00-\xff][\x00-\xff]$"
"\xff[\x00-\xff][\x00-\xff][\x00-\xff][\x00-\xff][\x00-\xff][\x00-\xff][\x00-\xff][\x00-\xff]$"
]
return bool(reduce(lambda x,y: x or y, map(lambda x: re.search(x, prevBytes), callPrecededExpressions)))
arch = self.__binary.getArch()
if arch == CS_ARCH_X86:
initial_length = len(self.__gadgets)
self.__gadgets = filter(__isGadgetCallPreceded, self.__gadgets)
print("Options().removeNonCallPreceded(): Filtered out {} gadgets.".format(initial_length - len(self.__gadgets)))
else:
print("Options().removeNonCallPreceded(): Unsupported architecture.")
def __deleteBadBytes(self):
archMode = self.__binary.getArchMode()
if not self.__options.badbytes:
return
new = []
#Filter out empty badbytes (i.e if badbytes was set to 00|ff| there's an empty badbyte after the last '|')
#and convert each one to the corresponding byte
bbytes = []
for bb in self.__options.badbytes.split("|"):
if '-' in bb:
rng = bb.split('-')
low = ord(codecs.decode(rng[0], "hex"))
high = ord(codecs.decode(rng[1], "hex"))
for i in range(low, high):
bbytes.append(chr(i))
else:
bbytes.append(codecs.decode(bb.encode("ascii"), "hex"))
archMode = self.__binary.getArchMode()
for gadget in self.__gadgets:
gadAddr = pack("<L", gadget["vaddr"]) if archMode == CS_MODE_32 else pack("<Q", gadget["vaddr"])
try:
for x in bbytes:
if x in gadAddr: raise
new += [gadget]
except:
pass
self.__gadgets = new
def getGadgets(self):
return self.__gadgets

View File

@ -0,0 +1,22 @@
## -*- coding: utf-8 -*-
##
## Jonathan Salwan - 2014-05-17 - ROPgadget tool
##
## http://twitter.com/JonathanSalwan
## http://shell-storm.org/project/ROPgadget/
##
def deleteDuplicateGadgets(currentGadgets):
gadgets_content_set = set()
unique_gadgets = []
for gadget in currentGadgets:
gad = gadget["gadget"]
if gad in gadgets_content_set:
continue
gadgets_content_set.add(gad)
unique_gadgets += [gadget]
return unique_gadgets
def alphaSortgadgets(currentGadgets):
return sorted(currentGadgets, key=lambda key : key["gadget"])

View File

@ -0,0 +1,10 @@
## -*- coding: utf-8 -*-
##
## Jonathan Salwan - 2014-05-13
##
## http://shell-storm.org
## http://twitter.com/JonathanSalwan
##
import ropgadget.ropchain.ropmaker
import ropgadget.ropchain.arch

View File

@ -0,0 +1,11 @@
#!/usr/bin/env python2
## -*- coding: utf-8 -*-
##
## Jonathan Salwan - 2014-05-13
##
## http://shell-storm.org
## http://twitter.com/JonathanSalwan
##
import ropgadget.ropchain.arch.ropmakerx86
import ropgadget.ropchain.arch.ropmakerx64

View File

@ -0,0 +1,225 @@
#!/usr/bin/env python2
## -*- coding: utf-8 -*-
##
## Jonathan Salwan - 2014-05-13
## Florian Meier - 2014-08-31 - The 64b ROP chain generation
##
## http://shell-storm.org
## http://twitter.com/JonathanSalwan
##
import re
from capstone import *
class ROPMakerX64(object):
def __init__(self, binary, gadgets, liboffset=0x0):
self.__binary = binary
self.__gadgets = gadgets
# If it's a library, we have the option to add an offset to the addresses
self.__liboffset = liboffset
self.__generate()
def __lookingForWrite4Where(self, gadgetsAlreadyTested):
for gadget in self.__gadgets:
if gadget in gadgetsAlreadyTested:
continue
f = gadget["gadget"].split(" ; ")[0]
regex = re.search("mov .* ptr \[(?P<dst>([(rax)|(rbx)|(rcx)|(rdx)|(rsi)|(rdi)|(r9)|(r10)|(r11)|(r12)|(r13)|(r14)|(r15)]{3}))\], (?P<src>([(rax)|(rbx)|(rcx)|(rdx)|(rsi)|(rdi)|(r9)|(r10)|(r11)|(r12)|(r13)|(r14)|(r15)]{3}))$", f)
if regex:
lg = gadget["gadget"].split(" ; ")[1:]
try:
for g in lg:
if g.split()[0] != "pop" and g.split()[0] != "ret":
raise
# we need this to filterout 'ret' instructions with an offset like 'ret 0x6', because they ruin the stack pointer
if g != "ret":
if g.split()[0] == "ret" and g.split()[1] != "":
raise
print("\t[+] Gadget found: 0x%x %s" %(gadget["vaddr"], gadget["gadget"]))
return [gadget, regex.group("dst"), regex.group("src")]
except:
continue
return None
def __lookingForSomeThing(self, something):
for gadget in self.__gadgets:
lg = gadget["gadget"].split(" ; ")
if lg[0] == something:
try:
for g in lg[1:]:
if g.split()[0] != "pop" and g.split()[0] != "ret":
raise
if g != "ret":
# we need this to filterout 'ret' instructions with an offset like 'ret 0x6', because they ruin the stack pointer
if g.split()[0] == "ret" and g.split()[1] != "":
raise
print("\t[+] Gadget found: 0x%x %s" %(gadget["vaddr"], gadget["gadget"]))
return gadget
except:
continue
return None
def __padding(self, gadget, regAlreadSetted):
lg = gadget["gadget"].split(" ; ")
for g in lg[1:]:
if g.split()[0] == "pop":
reg = g.split()[1]
try:
print("\tp += pack('<Q', 0x%016x) # padding without overwrite %s" %(regAlreadSetted[reg], reg))
except KeyError:
print("\tp += pack('<Q', 0x4141414141414141) # padding")
def __buildRopChain(self, write4where, popDst, popSrc, xorSrc, xorRax, incRax, popRdi, popRsi, popRdx, syscall):
sects = self.__binary.getDataSections()
dataAddr = None
for s in sects:
if s["name"] == ".data":
dataAddr = s["vaddr"] + self.__liboffset
if dataAddr is None:
print("\n[-] Error - Can't find a writable section")
return
print("\t#!/usr/bin/env python2")
print("\t# execve generated by ROPgadget\n")
print("\tfrom struct import pack\n")
print("\t# Padding goes here")
print("\tp = ''\n")
print("\tp += pack('<Q', 0x%016x) # %s" %(popDst["vaddr"], popDst["gadget"]))
print("\tp += pack('<Q', 0x%016x) # @ .data" %(dataAddr))
self.__padding(popDst, {})
print("\tp += pack('<Q', 0x%016x) # %s" %(popSrc["vaddr"], popSrc["gadget"]))
print("\tp += '/bin//sh'")
self.__padding(popSrc, {popDst["gadget"].split()[1]: dataAddr}) # Don't overwrite reg dst
print("\tp += pack('<Q', 0x%016x) # %s" %(write4where["vaddr"], write4where["gadget"]))
self.__padding(write4where, {})
print("\tp += pack('<Q', 0x%016x) # %s" %(popDst["vaddr"], popDst["gadget"]))
print("\tp += pack('<Q', 0x%016x) # @ .data + 8" %(dataAddr + 8))
self.__padding(popDst, {})
print("\tp += pack('<Q', 0x%016x) # %s" %(xorSrc["vaddr"], xorSrc["gadget"]))
self.__padding(xorSrc, {})
print("\tp += pack('<Q', 0x%016x) # %s" %(write4where["vaddr"], write4where["gadget"]))
self.__padding(write4where, {})
print("\tp += pack('<Q', 0x%016x) # %s" %(popRdi["vaddr"], popRdi["gadget"]))
print("\tp += pack('<Q', 0x%016x) # @ .data" %(dataAddr))
self.__padding(popRdi, {})
print("\tp += pack('<Q', 0x%016x) # %s" %(popRsi["vaddr"], popRsi["gadget"]))
print("\tp += pack('<Q', 0x%016x) # @ .data + 8" %(dataAddr + 8))
self.__padding(popRsi, {"rdi": dataAddr}) # Don't overwrite rdi
print("\tp += pack('<Q', 0x%016x) # %s" %(popRdx["vaddr"], popRdx["gadget"]))
print("\tp += pack('<Q', 0x%016x) # @ .data + 8" %(dataAddr + 8))
self.__padding(popRdx, {"rdi": dataAddr, "rsi": dataAddr + 8}) # Don't overwrite rdi and rsi
print("\tp += pack('<Q', 0x%016x) # %s" %(xorRax["vaddr"], xorRax["gadget"]))
self.__padding(xorRax, {"rdi": dataAddr, "rsi": dataAddr + 8}) # Don't overwrite rdi and rsi
for i in range(59):
print("\tp += pack('<Q', 0x%016x) # %s" %(incRax["vaddr"], incRax["gadget"]))
self.__padding(incRax, {"rdi": dataAddr, "rsi": dataAddr + 8}) # Don't overwrite rdi and rsi
print("\tp += pack('<Q', 0x%016x) # %s" %(syscall["vaddr"], syscall["gadget"]))
def __generate(self):
# To find the smaller gadget
self.__gadgets.reverse()
print("\nROP chain generation\n===========================================================")
print("\n- Step 1 -- Write-what-where gadgets\n")
gadgetsAlreadyTested = []
while True:
write4where = self.__lookingForWrite4Where(gadgetsAlreadyTested)
if not write4where:
print("\t[-] Can't find the 'mov qword ptr [r64], r64' gadget")
return
popDst = self.__lookingForSomeThing("pop %s" %(write4where[1]))
if not popDst:
print("\t[-] Can't find the 'pop %s' gadget. Try with another 'mov [reg], reg'\n" %(write4where[1]))
gadgetsAlreadyTested += [write4where[0]]
continue
popSrc = self.__lookingForSomeThing("pop %s" %(write4where[2]))
if not popSrc:
print("\t[-] Can't find the 'pop %s' gadget. Try with another 'mov [reg], reg'\n" %(write4where[2]))
gadgetsAlreadyTested += [write4where[0]]
continue
xorSrc = self.__lookingForSomeThing("xor %s, %s" %(write4where[2], write4where[2]))
if not xorSrc:
print("\t[-] Can't find the 'xor %s, %s' gadget. Try with another 'mov [reg], reg'\n" %(write4where[2], write4where[2]))
gadgetsAlreadyTested += [write4where[0]]
continue
else:
break
print("\n- Step 2 -- Init syscall number gadgets\n")
xorRax = self.__lookingForSomeThing("xor rax, rax")
if not xorRax:
print("\t[-] Can't find the 'xor rax, rax' instruction")
return
incRax = self.__lookingForSomeThing("inc rax")
incEax = self.__lookingForSomeThing("inc eax")
incAx = self.__lookingForSomeThing("inc al")
addRax = self.__lookingForSomeThing("add rax, 1")
addEax = self.__lookingForSomeThing("add eax, 1")
addAx = self.__lookingForSomeThing("add al, 1")
instr = [incRax, incEax, incAx, addRax, addEax, addAx]
if all(v is None for v in instr):
print("\t[-] Can't find the 'inc rax' or 'add rax, 1' instruction")
return
for i in instr:
if i is not None:
incRax = i
break
print("\n- Step 3 -- Init syscall arguments gadgets\n")
popRdi = self.__lookingForSomeThing("pop rdi")
if not popRdi:
print("\t[-] Can't find the 'pop rdi' instruction")
return
popRsi = self.__lookingForSomeThing("pop rsi")
if not popRsi:
print("\t[-] Can't find the 'pop rsi' instruction")
return
popRdx = self.__lookingForSomeThing("pop rdx")
if not popRdx:
print("\t[-] Can't find the 'pop rdx' instruction")
return
print("\n- Step 4 -- Syscall gadget\n")
syscall = self.__lookingForSomeThing("syscall")
if not syscall:
print("\t[-] Can't find the 'syscall' instruction")
return
print("\n- Step 5 -- Build the ROP chain\n")
self.__buildRopChain(write4where[0], popDst, popSrc, xorSrc, xorRax, incRax, popRdi, popRsi, popRdx, syscall)

View File

@ -0,0 +1,223 @@
#!/usr/bin/env python2
## -*- coding: utf-8 -*-
##
## Jonathan Salwan - 2014-05-13
##
## http://shell-storm.org
## http://twitter.com/JonathanSalwan
##
import re
from capstone import *
class ROPMakerX86(object):
def __init__(self, binary, gadgets, liboffset=0x0):
self.__binary = binary
self.__gadgets = gadgets
# If it's a library, we have the option to add an offset to the addresses
self.__liboffset = liboffset
self.__generate()
def __lookingForWrite4Where(self, gadgetsAlreadyTested):
for gadget in self.__gadgets:
if gadget in gadgetsAlreadyTested:
continue
f = gadget["gadget"].split(" ; ")[0]
# regex -> mov dword ptr [r32], r32
regex = re.search("mov dword ptr \[(?P<dst>([(eax)|(ebx)|(ecx)|(edx)|(esi)|(edi)]{3}))\], (?P<src>([(eax)|(ebx)|(ecx)|(edx)|(esi)|(edi)]{3}))$", f)
if regex:
lg = gadget["gadget"].split(" ; ")[1:]
try:
for g in lg:
if g.split()[0] != "pop" and g.split()[0] != "ret":
raise
# we need this to filterout 'ret' instructions with an offset like 'ret 0x6', because they ruin the stack pointer
if g != "ret":
if g.split()[0] == "ret" and g.split()[1] != "":
raise
print("\t[+] Gadget found: 0x%x %s" %(gadget["vaddr"], gadget["gadget"]))
return [gadget, regex.group("dst"), regex.group("src")]
except:
continue
return None
def __lookingForSomeThing(self, something):
for gadget in self.__gadgets:
lg = gadget["gadget"].split(" ; ")
if lg[0] == something:
try:
for g in lg[1:]:
if g.split()[0] != "pop" and g.split()[0] != "ret":
raise
# we need this to filterout 'ret' instructions with an offset like 'ret 0x6', because they ruin the stack pointer
if g != "ret":
if g.split()[0] == "ret" and g.split()[1] != "":
raise
print("\t[+] Gadget found: 0x%x %s" %(gadget["vaddr"], gadget["gadget"]))
return gadget
except:
continue
return None
def __padding(self, gadget, regAlreadSetted):
lg = gadget["gadget"].split(" ; ")
for g in lg[1:]:
if g.split()[0] == "pop":
reg = g.split()[1]
try:
print("\tp += pack('<I', 0x%08x) # padding without overwrite %s" %(regAlreadSetted[reg], reg))
except KeyError:
print("\tp += pack('<I', 0x41414141) # padding")
def __buildRopChain(self, write4where, popDst, popSrc, xorSrc, xorEax, incEax, popEbx, popEcx, popEdx, syscall):
sects = self.__binary.getDataSections()
dataAddr = None
for s in sects:
if s["name"] == ".data":
dataAddr = s["vaddr"] + self.__liboffset
if dataAddr == None:
print("\n[-] Error - Can't find a writable section")
return
print("\t#!/usr/bin/env python2")
print("\t# execve generated by ROPgadget\n" )
print("\tfrom struct import pack\n")
print("\t# Padding goes here")
print("\tp = ''\n")
print("\tp += pack('<I', 0x%08x) # %s" %(popDst["vaddr"], popDst["gadget"]))
print("\tp += pack('<I', 0x%08x) # @ .data" %(dataAddr))
self.__padding(popDst, {})
print("\tp += pack('<I', 0x%08x) # %s" %(popSrc["vaddr"], popSrc["gadget"]))
print("\tp += '/bin'")
self.__padding(popSrc, {popDst["gadget"].split()[1]: dataAddr}) # Don't overwrite reg dst
print("\tp += pack('<I', 0x%08x) # %s" %(write4where["vaddr"], write4where["gadget"]))
self.__padding(write4where, {})
print("\tp += pack('<I', 0x%08x) # %s" %(popDst["vaddr"], popDst["gadget"]))
print("\tp += pack('<I', 0x%08x) # @ .data + 4" %(dataAddr + 4))
self.__padding(popDst, {})
print("\tp += pack('<I', 0x%08x) # %s" %(popSrc["vaddr"], popSrc["gadget"]))
print("\tp += '//sh'")
self.__padding(popSrc, {popDst["gadget"].split()[1]: dataAddr + 4}) # Don't overwrite reg dst
print("\tp += pack('<I', 0x%08x) # %s" %(write4where["vaddr"], write4where["gadget"]))
self.__padding(write4where, {})
print("\tp += pack('<I', 0x%08x) # %s" %(popDst["vaddr"], popDst["gadget"]))
print("\tp += pack('<I', 0x%08x) # @ .data + 8" %(dataAddr + 8))
self.__padding(popDst, {})
print("\tp += pack('<I', 0x%08x) # %s" %(xorSrc["vaddr"], xorSrc["gadget"]))
self.__padding(xorSrc, {})
print("\tp += pack('<I', 0x%08x) # %s" %(write4where["vaddr"], write4where["gadget"]))
self.__padding(write4where, {})
print("\tp += pack('<I', 0x%08x) # %s" %(popEbx["vaddr"], popEbx["gadget"]))
print("\tp += pack('<I', 0x%08x) # @ .data" %(dataAddr))
self.__padding(popEbx, {})
print("\tp += pack('<I', 0x%08x) # %s" %(popEcx["vaddr"], popEcx["gadget"]))
print("\tp += pack('<I', 0x%08x) # @ .data + 8" %(dataAddr + 8))
self.__padding(popEcx, {"ebx": dataAddr}) # Don't overwrite ebx
print("\tp += pack('<I', 0x%08x) # %s" %(popEdx["vaddr"], popEdx["gadget"]))
print("\tp += pack('<I', 0x%08x) # @ .data + 8" %(dataAddr + 8))
self.__padding(popEdx, {"ebx": dataAddr, "ecx": dataAddr + 8}) # Don't overwrite ebx and ecx
print("\tp += pack('<I', 0x%08x) # %s" %(xorEax["vaddr"], xorEax["gadget"]))
self.__padding(xorEax, {"ebx": dataAddr, "ecx": dataAddr + 8}) # Don't overwrite ebx and ecx
for i in range(11):
print("\tp += pack('<I', 0x%08x) # %s" %(incEax["vaddr"], incEax["gadget"]))
self.__padding(incEax, {"ebx": dataAddr, "ecx": dataAddr + 8}) # Don't overwrite ebx and ecx
print("\tp += pack('<I', 0x%08x) # %s" %(syscall["vaddr"], syscall["gadget"]))
def __generate(self):
# To find the smaller gadget
self.__gadgets.reverse()
print("\nROP chain generation\n===========================================================")
print("\n- Step 1 -- Write-what-where gadgets\n")
gadgetsAlreadyTested = []
while True:
write4where = self.__lookingForWrite4Where(gadgetsAlreadyTested)
if not write4where:
print("\t[-] Can't find the 'mov dword ptr [r32], r32' gadget")
return
popDst = self.__lookingForSomeThing("pop %s" %(write4where[1]))
if not popDst:
print("\t[-] Can't find the 'pop %s' gadget. Try with another 'mov [reg], reg'\n" %(write4where[1]))
gadgetsAlreadyTested += [write4where[0]]
continue
popSrc = self.__lookingForSomeThing("pop %s" %(write4where[2]))
if not popSrc:
print("\t[-] Can't find the 'pop %s' gadget. Try with another 'mov [reg], reg'\n" %(write4where[2]))
gadgetsAlreadyTested += [write4where[0]]
continue
xorSrc = self.__lookingForSomeThing("xor %s, %s" %(write4where[2], write4where[2]))
if not xorSrc:
print("\t[-] Can't find the 'xor %s, %s' gadget. Try with another 'mov [r], r'\n" %(write4where[2], write4where[2]))
gadgetsAlreadyTested += [write4where[0]]
continue
else:
break
print("\n- Step 2 -- Init syscall number gadgets\n")
xorEax = self.__lookingForSomeThing("xor eax, eax")
if not xorEax:
print("\t[-] Can't find the 'xor eax, eax' instruction")
return
incEax = self.__lookingForSomeThing("inc eax")
if not incEax:
print("\t[-] Can't find the 'inc eax' instruction")
return
print("\n- Step 3 -- Init syscall arguments gadgets\n")
popEbx = self.__lookingForSomeThing("pop ebx")
if not popEbx:
print("\t[-] Can't find the 'pop ebx' instruction")
return
popEcx = self.__lookingForSomeThing("pop ecx")
if not popEcx:
print("\t[-] Can't find the 'pop ecx' instruction")
return
popEdx = self.__lookingForSomeThing("pop edx")
if not popEdx:
print("\t[-] Can't find the 'pop edx' instruction")
return
print("\n- Step 4 -- Syscall gadget\n")
syscall = self.__lookingForSomeThing("int 0x80")
if not syscall:
print("\t[-] Can't find the 'syscall' instruction")
return
print("\n- Step 5 -- Build the ROP chain\n")
self.__buildRopChain(write4where[0], popDst, popSrc, xorSrc, xorEax, incEax, popEbx, popEcx, popEdx, syscall)

View File

@ -0,0 +1,35 @@
## -*- coding: utf-8 -*-
##
## Jonathan Salwan - 2014-05-13
##
## http://shell-storm.org
## http://twitter.com/JonathanSalwan
##
from capstone import *
from ropgadget.ropchain.arch.ropmakerx86 import *
from ropgadget.ropchain.arch.ropmakerx64 import *
class ROPMaker(object):
def __init__(self, binary, gadgets, offset):
self.__binary = binary
self.__gadgets = gadgets
self.__offset = offset
self.__handlerArch()
def __handlerArch(self):
if self.__binary.getArch() == CS_ARCH_X86 \
and self.__binary.getArchMode() == CS_MODE_32 \
and self.__binary.getFormat() == "ELF":
ROPMakerX86(self.__binary, self.__gadgets, self.__offset)
elif self.__binary.getArch() == CS_ARCH_X86 \
and self.__binary.getArchMode() == CS_MODE_64 \
and self.__binary.getFormat() == "ELF":
ROPMakerX64(self.__binary, self.__gadgets, self.__offset)
else:
print("\n[Error] ROPMaker.__handlerArch - Arch not supported yet for the rop chain generation")

View File

@ -0,0 +1,38 @@
## -*- coding: utf-8 -*-
##
## Jonathan Salwan - 2014-05-12 - ROPgadget tool
##
## http://twitter.com/JonathanSalwan
## http://shell-storm.org/project/ROPgadget/
##
import re
try:
import httplib
except ImportError:
import http.client as httplib
from ropgadget.version import *
class UpdateAlert(object):
@staticmethod
def checkUpdate():
try:
conn = httplib.HTTPSConnection("raw.githubusercontent.com", 443)
conn.request("GET", "/JonathanSalwan/ROPgadget/master/ropgadget/version.py")
except:
print("Can't connect to raw.githubusercontent.com")
return
d = conn.getresponse().read()
majorVersion = re.search("MAJOR_VERSION.+=.+(?P<value>[\d])", d).group("value")
minorVersion = re.search("MINOR_VERSION.+=.+(?P<value>[\d])", d).group("value")
webVersion = int("%s%s" %(majorVersion, minorVersion))
curVersion = int("%s%s" %(MAJOR_VERSION, MINOR_VERSION))
if webVersion > curVersion:
print("The version %s.%s is available. Currently, you use the version %d.%d." %(majorVersion, minorVersion, MAJOR_VERSION, MINOR_VERSION))
else:
print("Your version is up-to-date.")

View File

@ -0,0 +1,11 @@
## -*- coding: utf-8 -*-
##
## Jonathan Salwan - 2014-05-12 - ROPgadget tool
##
## http://twitter.com/JonathanSalwan
## http://shell-storm.org/project/ROPgadget/
##
MAJOR_VERSION = 6
MINOR_VERSION = 3
PYROPGADGET_VERSION = "ROPgadget v%d.%d" %(MAJOR_VERSION, MINOR_VERSION)