diff --git a/ROPgadget/.github/workflows/main.yml b/ROPgadget/.github/workflows/main.yml
new file mode 100644
index 0000000..d87c8fb
--- /dev/null
+++ b/ROPgadget/.github/workflows/main.yml
@@ -0,0 +1,31 @@
+name: CI
+
+on:
+ push:
+ branches:
+ - master
+ pull_request:
+
+jobs:
+ build:
+
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: actions/checkout@v2
+ - name: Build
+ run: |
+ python2 -m pip install --upgrade setuptools wheel
+ python3 -m pip install --upgrade setuptools wheel
+ python2 setup.py sdist bdist_wheel
+ python3 setup.py sdist bdist_wheel
+ - name: Install
+ run: |
+ python2 -m pip install dist/ROPGadget*py2*.whl
+ python3 -m pip install dist/ROPGadget*py3*.whl
+ - name: Run tests
+ run: |
+ cd test-suite-binaries
+ ./test.sh
+ ./test.sh python2
+ cd ..
diff --git a/ROPgadget/.gitignore b/ROPgadget/.gitignore
new file mode 100644
index 0000000..c4db969
--- /dev/null
+++ b/ROPgadget/.gitignore
@@ -0,0 +1,4 @@
+*.pyc
+build
+dist
+ROPGadget.egg-info
diff --git a/ROPgadget/AUTHORS b/ROPgadget/AUTHORS
new file mode 100644
index 0000000..8e36c76
--- /dev/null
+++ b/ROPgadget/AUTHORS
@@ -0,0 +1,42 @@
+
+ROPgadget project (>= v5.0)
+===================================================
+
+Authors:
+
+* Jonathan Salwan
+
+
+Contributors:
+
+* hugsy - Has added the --offset option
+* Francisco Falcon - Has fixed the --badbytes option and added the count/loaddb/save2db console features
+* Kevin Hamacher - Added some functionality for using ROPgadget as library. Also added support for x86(_64) jmp {r,e}sp/call {r,e}sp instructions
+* Florian Meier - Added the 64b ROP chain generation
+* Álvaro Felipe Melchor (increase performance)
+* Sascha Schirra (features, python3, bugs fix)
+* Stephen Edwards (increase performance)
+* Mikhail Davidov (features)
+* penguin-wwy (features)
+
+
+
+ROPgadget initial project (<= v4.0.3)
+===================================================
+
+Authors:
+
+* Jonathan Salwan
+* Allan Wirth
+
+
+Contributors:
+
+* Hellman (Bug Fix)
+* Axel "0vercl0k" Souchet (Bug Fix)
+* k3rensk1 (Bug repport)
+* brianairb (Bug Fix)
+* cao (Bug Fix)
+* dark-rose (Made searching for gadgets faster)
+* Dennis Semakin (Bug Fix)
+
diff --git a/ROPgadget/LICENSE_BSD.txt b/ROPgadget/LICENSE_BSD.txt
new file mode 100644
index 0000000..e52c765
--- /dev/null
+++ b/ROPgadget/LICENSE_BSD.txt
@@ -0,0 +1,27 @@
+This is the software license for the ROPgadget project.
+
+Copyright (c) 2016. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+* Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+* Neither the name of the developers nor the names of its
+ contributors may be used to endorse or promote products derived from this
+ software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
diff --git a/ROPgadget/README.md b/ROPgadget/README.md
new file mode 100644
index 0000000..ec20899
--- /dev/null
+++ b/ROPgadget/README.md
@@ -0,0 +1,114 @@
+ROPgadget Tool
+================
+
+This tool lets you search your gadgets on your binaries to facilitate your ROP exploitation.
+ROPgadget supports ELF/PE/Mach-O format on x86, x64, ARM, ARM64, PowerPC, SPARC and MIPS
+architectures. Since the version 5, ROPgadget has a new core which is written in Python
+using Capstone disassembly framework for the gadgets search engine - The older version can
+be found in the Archives directory but it will not be maintained.
+
+Install
+-------
+
+If you want to use ROPgadget, you have to install [Capstone](http://www.capstone-engine.org/) first.
+
+For the Capstone's installation on nix machine:
+
+ $ sudo pip install capstone
+
+Capstone supports multi-platforms (windows, ios, android, cygwin...). For the cross-compilation,
+please refer to the https://github.com/aquynh/capstone/blob/master/COMPILE.TXT file.
+
+After Capstone is installed, ROPgadget can be used as a standalone tool:
+
+ $ ROPgadget.py
+
+Or installed into the Python site-packages library, and executed from $PATH.
+
+ $ python setup.py install
+ $ ROPgadget
+
+Or installed from PyPi
+
+ $ pip install ropgadget
+ $ ROPgadget
+
+Usage
+-----
+
+ usage: ROPgadget.py [-h] [-v] [-c] [--binary ] [--opcode ]
+ [--string ] [--memstr ] [--depth ]
+ [--only ] [--filter ] [--range ]
+ [--badbytes ] [--rawArch ] [--rawMode ]
+ [--rawEndian ] [--re ] [--offset ]
+ [--ropchain] [--thumb] [--console] [--norop] [--nojop]
+ [--callPreceded] [--nosys] [--multibr] [--all] [--noinstr]
+ [--dump]
+
+ optional arguments:
+ -h, --help show this help message and exit
+ -v, --version Display the ROPgadget's version
+ -c, --checkUpdate Checks if a new version is available
+ --binary Specify a binary filename to analyze
+ --opcode Search opcode in executable segment
+ --string Search string in readable segment
+ --memstr Search each byte in all readable segment
+ --depth Depth for search engine (default 10)
+ --only Only show specific instructions
+ --filter Suppress specific instructions
+ --range Search between two addresses (0x...-0x...)
+ --badbytes Rejects specific bytes in the gadget's address
+ --rawArch Specify an arch for a raw file
+ --rawMode Specify a mode for a raw file
+ --rawEndian Specify an endianness for a raw file
+ --re Regular expression
+ --offset Specify an offset for gadget addresses
+ --ropchain Enable the ROP chain generation
+ --thumb Use the thumb mode for the search engine (ARM only)
+ --console Use an interactive console for search engine
+ --norop Disable ROP search engine
+ --nojop Disable JOP search engine
+ --callPreceded Only show gadgets which are call-preceded
+ --nosys Disable SYS search engine
+ --multibr Enable multiple branch gadgets
+ --all Disables the removal of duplicate gadgets
+ --noinstr Disable the gadget instructions console printing
+ --dump Outputs the gadget bytes
+
+
+How can I contribute ?
+----------------------
+
+- Use Z3 to solve the ROP chain
+- Add system gadgets for PPC, Sparc, ARM64 (Gadgets.addSYSGadgets())
+- Manage big endian in Mach-O format like the ELF classe.
+- Everything you think is cool :)
+
+Bugs/Patches/Contact
+--------------------
+
+Please report bugs, submit pull requests, etc. on github at https://github.com/JonathanSalwan/ROPgadget
+The offical page is on shell-storm.org at http://shell-storm.org/project/ROPgadget/
+
+License
+-------
+
+See COPYING and the license header on all source files. For the files in the dependencies/ there are
+individual licenses in each folder.
+
+
+Screenshots
+-----------
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ROPgadget/ROPgadget.py b/ROPgadget/ROPgadget.py
new file mode 100755
index 0000000..777f2d5
--- /dev/null
+++ b/ROPgadget/ROPgadget.py
@@ -0,0 +1,12 @@
+#!/usr/bin/env python
+## -*- coding: utf-8 -*-
+##
+## Jonathan Salwan - 2014-05-12 - ROPgadget tool
+##
+## http://twitter.com/JonathanSalwan
+## http://shell-storm.org/project/ROPgadget/
+##
+
+import ropgadget
+
+ropgadget.main()
diff --git a/ROPgadget/ropgadget/__init__.py b/ROPgadget/ropgadget/__init__.py
new file mode 100644
index 0000000..2201b59
--- /dev/null
+++ b/ROPgadget/ropgadget/__init__.py
@@ -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)
diff --git a/ROPgadget/ropgadget/args.py b/ROPgadget/ropgadget/args.py
new file mode 100644
index 0000000..1bb53b0
--- /dev/null
+++ b/ROPgadget/ropgadget/args.py
@@ -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="", help="Specify a binary filename to analyze")
+ parser.add_argument("--opcode", type=str, metavar="", help="Search opcode in executable segment")
+ parser.add_argument("--string", type=str, metavar="", help="Search string in readable segment")
+ parser.add_argument("--memstr", type=str, metavar="", help="Search each byte in all readable segment")
+ parser.add_argument("--depth", type=int, metavar="", default=10, help="Depth for search engine (default 10)")
+ parser.add_argument("--only", type=str, metavar="", help="Only show specific instructions")
+ parser.add_argument("--filter", type=str, metavar="", help="Suppress specific mnemonics")
+ parser.add_argument("--range", type=str, metavar="", default="0x0-0x0", help="Search between two addresses (0x...-0x...)")
+ parser.add_argument("--badbytes", type=str, metavar="", help="Rejects specific bytes in the gadget's address")
+ parser.add_argument("--rawArch", type=str, metavar="", help="Specify an arch for a raw file")
+ parser.add_argument("--rawMode", type=str, metavar="", help="Specify a mode for a raw file")
+ parser.add_argument("--rawEndian", type=str, metavar="", help="Specify an endianness for a raw file")
+ parser.add_argument("--re", type=str, metavar="", help="Regular expression")
+ parser.add_argument("--offset", type=str, metavar="", 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= can't be used together")
+
+ if self.__args.noinstr and self.__args.re:
+ raise ValueError("[Error] --noinstr and --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
diff --git a/ROPgadget/ropgadget/binary.py b/ROPgadget/ropgadget/binary.py
new file mode 100644
index 0000000..b40e0fe
--- /dev/null
+++ b/ROPgadget/ropgadget/binary.py
@@ -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()
diff --git a/ROPgadget/ropgadget/core.py b/ROPgadget/ropgadget/core.py
new file mode 100644
index 0000000..6cebb95
--- /dev/null
+++ b/ROPgadget/ropgadget/core.py
@@ -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 -- 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 -- 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 -- ")
+ 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 -- 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 - 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 - 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 - 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 - 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 - 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 - 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 - 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 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 - 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")
diff --git a/ROPgadget/ropgadget/gadgets.py b/ROPgadget/ropgadget/gadgets.py
new file mode 100644
index 0000000..07c4ec7
--- /dev/null
+++ b/ROPgadget/ropgadget/gadgets.py
@@ -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
+ [b"\xcb", 1, 1], # retf
+ [b"\xca[\x00-\xff]{2}", 3, 1], # retf
+ # MPX
+ [b"\xf2\xc3", 2, 1], # ret
+ [b"\xf2\xc2[\x00-\xff]{2}", 4, 1], # ret
+ ]
+
+ 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
+
diff --git a/ROPgadget/ropgadget/loaders/__init__.py b/ROPgadget/ropgadget/loaders/__init__.py
new file mode 100644
index 0000000..98666c2
--- /dev/null
+++ b/ROPgadget/ropgadget/loaders/__init__.py
@@ -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
diff --git a/ROPgadget/ropgadget/loaders/elf.py b/ROPgadget/ropgadget/loaders/elf.py
new file mode 100644
index 0000000..8f267fb
--- /dev/null
+++ b/ROPgadget/ropgadget/loaders/elf.py
@@ -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"
diff --git a/ROPgadget/ropgadget/loaders/macho.py b/ROPgadget/ropgadget/loaders/macho.py
new file mode 100644
index 0000000..27c52bd
--- /dev/null
+++ b/ROPgadget/ropgadget/loaders/macho.py
@@ -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"
diff --git a/ROPgadget/ropgadget/loaders/pe.py b/ROPgadget/ropgadget/loaders/pe.py
new file mode 100644
index 0000000..42c6fd8
--- /dev/null
+++ b/ROPgadget/ropgadget/loaders/pe.py
@@ -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("= 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("([(rax)|(rbx)|(rcx)|(rdx)|(rsi)|(rdi)|(r9)|(r10)|(r11)|(r12)|(r13)|(r14)|(r15)]{3}))\], (?P([(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(' mov dword ptr [r32], r32
+ regex = re.search("mov dword ptr \[(?P([(eax)|(ebx)|(ecx)|(edx)|(esi)|(edi)]{3}))\], (?P([(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('[\d])", d).group("value")
+ minorVersion = re.search("MINOR_VERSION.+=.+(?P[\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.")
+
diff --git a/ROPgadget/ropgadget/version.py b/ROPgadget/ropgadget/version.py
new file mode 100644
index 0000000..16821ac
--- /dev/null
+++ b/ROPgadget/ropgadget/version.py
@@ -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)
diff --git a/ROPgadget/scripts/ROPgadget b/ROPgadget/scripts/ROPgadget
new file mode 100755
index 0000000..777f2d5
--- /dev/null
+++ b/ROPgadget/scripts/ROPgadget
@@ -0,0 +1,12 @@
+#!/usr/bin/env python
+## -*- coding: utf-8 -*-
+##
+## Jonathan Salwan - 2014-05-12 - ROPgadget tool
+##
+## http://twitter.com/JonathanSalwan
+## http://shell-storm.org/project/ROPgadget/
+##
+
+import ropgadget
+
+ropgadget.main()
diff --git a/ROPgadget/setup.py b/ROPgadget/setup.py
new file mode 100644
index 0000000..4a095f7
--- /dev/null
+++ b/ROPgadget/setup.py
@@ -0,0 +1,67 @@
+#!/usr/bin/env python
+
+from setuptools import setup
+import os
+
+package_name = "ROPGadget"
+package_dir = "ropgadget"
+package_description = """
+This tool lets you search your gadgets on your binaries to facilitate your ROP exploitation.
+ROPgadget supports ELF, PE and Mach-O format on x86, x64, ARM, ARM64, PowerPC, SPARC and MIPS architectures.
+http://www.shell-storm.org/project/ROPgadget/
+""".strip()
+
+
+def fullsplit(path, result=None):
+ """
+ Split a pathname into components (the opposite of os.path.join) in a
+ platform-neutral way.
+ """
+ if result is None:
+ result = []
+ head, tail = os.path.split(path)
+ if head == '':
+ return [tail] + result
+ if head == path:
+ return result
+ return fullsplit(head, [tail] + result)
+
+# Compile the list of packages available, because distutils doesn't have
+# an easy way to do this.
+packages, data_files = [], []
+root_dir = os.path.dirname(__file__)
+if root_dir != '':
+ os.chdir(root_dir)
+
+for dirpath, dirnames, filenames in os.walk(package_dir):
+ # Ignore dirnames that start with '.'
+ for i, dirname in enumerate(dirnames):
+ if dirname.startswith('.'): del dirnames[i]
+ if '__init__.py' in filenames:
+ packages.append('.'.join(fullsplit(dirpath)))
+ elif filenames:
+ data_files.append([dirpath, [os.path.join(dirpath, f) for f in filenames]])
+
+version = "6.3"
+
+setup(
+ name = package_name,
+ version = version,
+ description = package_description,
+ packages = packages,
+ license = "BSD",
+ author = "Jonathan Salwan",
+ author_email = "jonathan.salwan@gmail.com",
+ url = "https://github.com/JonathanSalwan/ROPgadget",
+ scripts = ['scripts/ROPgadget'],
+ install_requires = ['capstone'],
+ classifiers = [
+ 'Topic :: Security',
+ 'Environment :: Console',
+ 'Operating System :: OS Independent',
+ 'License :: OSI Approved :: BSD License',
+ 'Programming Language :: Python :: 2.7',
+ 'Programming Language :: Python :: 3',
+ 'Intended Audience :: Developers'
+ ]
+)
diff --git a/ROPgadget/test-suite-binaries/UNIVERSAL-x86-x64-libSystem.B.dylib b/ROPgadget/test-suite-binaries/UNIVERSAL-x86-x64-libSystem.B.dylib
new file mode 100644
index 0000000..adbbf1f
Binary files /dev/null and b/ROPgadget/test-suite-binaries/UNIVERSAL-x86-x64-libSystem.B.dylib differ
diff --git a/ROPgadget/test-suite-binaries/elf-ARM64-bash b/ROPgadget/test-suite-binaries/elf-ARM64-bash
new file mode 100644
index 0000000..5bffdf7
Binary files /dev/null and b/ROPgadget/test-suite-binaries/elf-ARM64-bash differ
diff --git a/ROPgadget/test-suite-binaries/elf-ARMv7-ls b/ROPgadget/test-suite-binaries/elf-ARMv7-ls
new file mode 100644
index 0000000..3a2573f
Binary files /dev/null and b/ROPgadget/test-suite-binaries/elf-ARMv7-ls differ
diff --git a/ROPgadget/test-suite-binaries/elf-FreeBSD-x86 b/ROPgadget/test-suite-binaries/elf-FreeBSD-x86
new file mode 100644
index 0000000..4d13e98
Binary files /dev/null and b/ROPgadget/test-suite-binaries/elf-FreeBSD-x86 differ
diff --git a/ROPgadget/test-suite-binaries/elf-Linux-x64 b/ROPgadget/test-suite-binaries/elf-Linux-x64
new file mode 100644
index 0000000..7db51f5
Binary files /dev/null and b/ROPgadget/test-suite-binaries/elf-Linux-x64 differ
diff --git a/ROPgadget/test-suite-binaries/elf-Linux-x86 b/ROPgadget/test-suite-binaries/elf-Linux-x86
new file mode 100644
index 0000000..78b6959
Binary files /dev/null and b/ROPgadget/test-suite-binaries/elf-Linux-x86 differ
diff --git a/ROPgadget/test-suite-binaries/elf-Linux-x86-NDH-chall b/ROPgadget/test-suite-binaries/elf-Linux-x86-NDH-chall
new file mode 100644
index 0000000..6b3d280
Binary files /dev/null and b/ROPgadget/test-suite-binaries/elf-Linux-x86-NDH-chall differ
diff --git a/ROPgadget/test-suite-binaries/elf-Mips-Defcon-20-pwn100 b/ROPgadget/test-suite-binaries/elf-Mips-Defcon-20-pwn100
new file mode 100644
index 0000000..3fc5532
Binary files /dev/null and b/ROPgadget/test-suite-binaries/elf-Mips-Defcon-20-pwn100 differ
diff --git a/ROPgadget/test-suite-binaries/elf-PowerPC-bash b/ROPgadget/test-suite-binaries/elf-PowerPC-bash
new file mode 100644
index 0000000..d443085
Binary files /dev/null and b/ROPgadget/test-suite-binaries/elf-PowerPC-bash differ
diff --git a/ROPgadget/test-suite-binaries/elf-SparcV8-bash b/ROPgadget/test-suite-binaries/elf-SparcV8-bash
new file mode 100644
index 0000000..501038f
Binary files /dev/null and b/ROPgadget/test-suite-binaries/elf-SparcV8-bash differ
diff --git a/ROPgadget/test-suite-binaries/elf-x64-bash-v4.1.5.1 b/ROPgadget/test-suite-binaries/elf-x64-bash-v4.1.5.1
new file mode 100644
index 0000000..0d861f2
Binary files /dev/null and b/ROPgadget/test-suite-binaries/elf-x64-bash-v4.1.5.1 differ
diff --git a/ROPgadget/test-suite-binaries/elf-x86-bash-v4.1.5.1 b/ROPgadget/test-suite-binaries/elf-x86-bash-v4.1.5.1
new file mode 100644
index 0000000..a3a4bac
Binary files /dev/null and b/ROPgadget/test-suite-binaries/elf-x86-bash-v4.1.5.1 differ
diff --git a/ROPgadget/test-suite-binaries/macho-x64-ls b/ROPgadget/test-suite-binaries/macho-x64-ls
new file mode 100644
index 0000000..d80548d
Binary files /dev/null and b/ROPgadget/test-suite-binaries/macho-x64-ls differ
diff --git a/ROPgadget/test-suite-binaries/macho-x86-ls b/ROPgadget/test-suite-binaries/macho-x86-ls
new file mode 100644
index 0000000..e33a51e
Binary files /dev/null and b/ROPgadget/test-suite-binaries/macho-x86-ls differ
diff --git a/ROPgadget/test-suite-binaries/pe-Windows-ARMv7-Thumb2LE-HelloWorld b/ROPgadget/test-suite-binaries/pe-Windows-ARMv7-Thumb2LE-HelloWorld
new file mode 100644
index 0000000..dd9a51b
Binary files /dev/null and b/ROPgadget/test-suite-binaries/pe-Windows-ARMv7-Thumb2LE-HelloWorld differ
diff --git a/ROPgadget/test-suite-binaries/pe-x64-cmd-v6.1.7601 b/ROPgadget/test-suite-binaries/pe-x64-cmd-v6.1.7601
new file mode 100644
index 0000000..dca94f4
Binary files /dev/null and b/ROPgadget/test-suite-binaries/pe-x64-cmd-v6.1.7601 differ
diff --git a/ROPgadget/test-suite-binaries/pe-x86-cmd-v6.1.7600 b/ROPgadget/test-suite-binaries/pe-x86-cmd-v6.1.7600
new file mode 100644
index 0000000..9dc724d
Binary files /dev/null and b/ROPgadget/test-suite-binaries/pe-x86-cmd-v6.1.7600 differ
diff --git a/ROPgadget/test-suite-binaries/raw-x86.raw b/ROPgadget/test-suite-binaries/raw-x86.raw
new file mode 100644
index 0000000..84baa4c
--- /dev/null
+++ b/ROPgadget/test-suite-binaries/raw-x86.raw
@@ -0,0 +1 @@
+1ɉHHL$1
\ No newline at end of file
diff --git a/ROPgadget/test-suite-binaries/ref_output.bz2 b/ROPgadget/test-suite-binaries/ref_output.bz2
new file mode 100644
index 0000000..b366286
Binary files /dev/null and b/ROPgadget/test-suite-binaries/ref_output.bz2 differ
diff --git a/ROPgadget/test-suite-binaries/test.sh b/ROPgadget/test-suite-binaries/test.sh
new file mode 100755
index 0000000..8fb5b11
--- /dev/null
+++ b/ROPgadget/test-suite-binaries/test.sh
@@ -0,0 +1,61 @@
+#!/bin/bash
+
+export PYTHONPATH=../
+if [ "$#" == "1" ]
+then
+ RUN="python2 ../ROPgadget.py"
+else
+ RUN="python3 ../ROPgadget.py"
+fi
+
+rm -rf test_output
+
+FILES=`ls | sort -f`
+for f in $FILES
+do
+ if [ "$f" != "test.sh" ] && [ "$f" != "ref_output.bz2" ] && [ "$f" != "test_output" ]
+ then
+ echo "RUN $f" | tee -a ./test_output
+ if [ "$f" == "raw-x86.raw" ]
+ then
+ $RUN --rawArch=x86 --rawMode=32 --depth 5 --binary $f 1>> ./test_output
+ else
+ $RUN --depth 5 --binary $f 1>> ./test_output
+ fi
+ fi
+done
+
+echo "RUN elf-Linux-x86 --ropchain" | tee -a ./test_output
+$RUN --binary ./elf-Linux-x86 --ropchain 1>> ./test_output
+echo "RUN elf-Linux-x86 --depth 3" | tee -a ./test_output
+$RUN --binary ./elf-Linux-x86 --depth 3 1>> ./test_output
+echo "RUN elf-Linux-x86 --string \"main\"" | tee -a ./test_output
+$RUN --binary ./elf-Linux-x86 --string "main" 1>> ./test_output
+echo "RUN elf-Linux-x86 --string \"m..n\"" | tee -a ./test_output
+$RUN --binary ./elf-Linux-x86 --string "m..n" 1>> ./test_output
+echo "RUN elf-Linux-x86 --opcode c9c3" | tee -a ./test_output
+$RUN --binary ./elf-Linux-x86 --opcode c9c3 1>> ./test_output
+echo "RUN elf-Linux-x86 --only \"mov|ret\"" | tee -a ./test_output
+$RUN --binary ./elf-Linux-x86 --only "mov|ret" 1>> ./test_output
+echo "RUN elf-Linux-x86 --only \"mov|pop|xor|ret\"" | tee -a ./test_output
+$RUN --binary ./elf-Linux-x86 --only "mov|pop|xor|ret" 1>> ./test_output
+echo "RUN elf-Linux-x86 --filter \"xchg|add|sub|cmov.*\"" | tee -a ./test_output
+$RUN --binary ./elf-Linux-x86 --filter "xchg|add|sub|cmov.*" 1>> ./test_output
+echo "RUN elf-Linux-x86 --norop --nosys" | tee -a ./test_output
+$RUN --binary ./elf-Linux-x86 --norop --nosys 1>> ./test_output
+echo "RUN elf-Linux-x86 --range 0x08041000-0x08042000" | tee -a ./test_output
+$RUN --binary ./elf-Linux-x86 --range 0x08041000-0x08042000 1>> ./test_output
+echo "RUN elf-Linux-x86 --string main --range 0x080c9aaa-0x080c9aba" | tee -a ./test_output
+$RUN --binary ./elf-Linux-x86 --string main --range 0x080c9aaa-0x080c9aba 1>> ./test_output
+echo "RUN elf-Linux-x86 --memstr \"/bin/sh\"" | tee -a ./test_output
+$RUN --binary ./elf-Linux-x86 --memstr "/bin/sh" 1>> ./test_output
+echo "RUN elf-Linux-x86 --badbytes \"00|01-1f|7f|42\"" | tee -a ./test_output
+$RUN --binary ./elf-Linux-x86 --badbytes "00|01-1f|7f|42" 1>> ./test_output
+echo "RUN Linux_lib64.so --offset 0xdeadbeef00000000" | tee -a ./test_output
+$RUN --binary ./Linux_lib64.so --offset 0xdeadbeef00000000 1>> ./test_output
+echo "RUN elf-ARMv7-ls --depth 5" | tee -a ./test_output
+$RUN --binary ./elf-ARMv7-ls --depth 5 1>> ./test_output
+echo "RUN elf-ARM64-bash --depth 5" | tee -a ./test_output
+$RUN --binary ./elf-ARM64-bash --depth 5 1>> ./test_output
+
+diff test_output <(bunzip2 --stdout ref_output.bz2) 1>&2