:sparkles ajout du conteneur et de certains fichiers

rop2
Lucas Evard 2 years ago
parent d0e48acb8d
commit 4cbcd36c74

@ -0,0 +1,21 @@
#include <stdio.h>
void secretFunction()
{
printf("Congratulations!\n");
printf("You have entered in the secret function!\n");
}
void echo()
{
char buffer[20];
printf("Enter some text:\n");
scanf("%s", buffer);
printf("You entered: %s\n", buffer);
}
int main()
{
echo();
return 0;
}

@ -0,0 +1,19 @@
FROM ubuntu:latest
RUN apt-get update && \
apt install -y python3 gcc musl-dev python3-pip && \
python3 -m pip install ROPgadget && \
python3 -m pip install capstone
COPY Bufferoverflow /root/Bufferoverflow
COPY ROPgadget /root/ROPgadget
WORKDIR /root/Bufferoverflow
RUN gcc main.c -o binaire -fno-stack-protector
WORKDIR /root
ENTRYPOINT ["/bin/bash"]
#python3 ROPgadget/ROPgadget.py --binary Bufferoverflow/binaire

@ -0,0 +1,4 @@
*.pyc
build
dist
ROPGadget.egg-info

@ -0,0 +1,46 @@
ROPgadget project (>= v5.0)
===================================================
Authors:
* Jonathan Salwan
* Alexey Vishnyakov
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)
* Alexey Nurmukhametov (increase performance)
* Mario Haustein (PowerPC for MachO binaries)
* pkubaj (PowerPC 64-bit)
* 0xMirasio (RISC-V 64 and Compressed)
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)

@ -0,0 +1,27 @@
This is the software license for the ROPgadget project.
Copyright (c) 2016-2023. 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.

@ -0,0 +1,160 @@
ROPgadget Tool
==============
This tool lets you search your gadgets on your binaries to facilitate your ROP
exploitation. ROPgadget supports ELF/PE/Mach-O/Raw formats on x86, x64, ARM,
ARM64, PowerPC, SPARC, MIPS, RISC-V 64, and RISC-V Compressed architectures.
Install
-------
The easiest way is installing ROPgadget from PyPi:
$ sudo apt install python3-pip
$ sudo -H python3 -m pip install ROPgadget
$ ROPgadget --help
Alternatively you can install ROPgadget from source.
You have to install [Capstone](http://www.capstone-engine.org/) first.
For the Capstone's installation on nix machine:
$ sudo apt install python3-pip
$ sudo -H python3 -m pip install capstone
Capstone supports multi-platforms (windows, ios, android, cygwin...). For the cross-compilation,
please refer to the https://github.com/capstone-engine/capstone/blob/master/COMPILE.TXT file.
After Capstone is installed, ROPgadget can be used as a standalone tool:
$ python3 ROPgadget.py --help
Or installed into the Python site-packages library, and executed from $PATH.
$ sudo -H python3 setup.py install
$ ROPgadget --help
Usage
-----
usage: ROPgadget.py [-h] [-v] [-c] [--binary <binary>] [--opcode <opcodes>]
[--string <string>] [--memstr <string>] [--depth <nbyte>]
[--only <key>] [--filter <key>] [--range <start-end>]
[--badbytes <byte>] [--rawArch <arch>] [--rawMode <mode>]
[--rawEndian <endian>] [--re <re>] [--offset <hexaddr>]
[--ropchain] [--thumb] [--console] [--norop] [--nojop]
[--callPreceded] [--nosys] [--multibr] [--all] [--noinstr]
[--dump] [--silent] [--align ALIGN] [--mipsrop <rtype>]
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
- RISC-V 64
- RISC-V Compressed
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 <binary> Specify a binary filename to analyze
--opcode <opcodes> Search opcode in executable segment
--string <string> Search string in readable segment
--memstr <string> Search each byte in all readable segment
--depth <nbyte> Depth for search engine (default 10)
--only <key> Only show specific instructions
--filter <key> Suppress specific mnemonics
--range <start-end> Search between two addresses (0x...-0x...)
--badbytes <byte> Rejects specific bytes in the gadget's address
--rawArch <arch> Specify an arch for a raw file
x86|arm|arm64|sparc|mips|ppc|riscv
--rawMode <mode> Specify a mode for a raw file 32|64|arm|thumb
--rawEndian <endian> Specify an endianness for a raw file little|big
--re <re> Regular expression
--offset <hexaddr> 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
--silent Disables printing of gadgets during analysis
--align ALIGN Align gadgets addresses (in bytes)
--mipsrop <rtype> MIPS useful gadgets finder
stackfinder|system|tails|lia0|registers
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
ROPgadget.py --binary ./test-suite-binaries/elf-Linux-RISCV_64 --depth 8
How can I contribute ?
----------------------
- Add system gadgets for PPC, Sparc, ARM64 (Gadgets.addSYSGadgets()).
- Support RISC-V 32-bit.
- Handle bad bytes in data during ROP chain generation.
- Manage big endian in Mach-O format like the ELF class.
- Everything you think is cool :)
Bugs/Patches/Contact
--------------------
Please, report bugs, submit pull requests, etc. on GitHub at https://github.com/JonathanSalwan/ROPgadget
License
-------
See LICENSE_BSD.txt and the license header on all source files.
Screenshots
-----------
<img src="http://shell-storm.org/project/ROPgadget/x64.png" alt="x64"></img>
<img src="http://shell-storm.org/project/ROPgadget/arm.png" alt="ARM"></img>
<img src="http://shell-storm.org/project/ROPgadget/sparc.png" alt="Sparc"></img>
<img src="http://shell-storm.org/project/ROPgadget/mips.png" alt="MIPS"></img>
<img src="http://shell-storm.org/project/ROPgadget/ppc.png" alt="PowerPC"></img>
<img src="http://shell-storm.org/project/ROPgadget/ropchain.png" alt="ROP chain"></img>

@ -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()

@ -0,0 +1,30 @@
## -*- 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.loaders
import ropgadget.options
import ropgadget.rgutils
import ropgadget.ropchain
import ropgadget.updateAlert
import ropgadget.version
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)

@ -0,0 +1,161 @@
## -*- 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
- RISC-V 64
- RISC-V Compressed
""",
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
ROPgadget.py --binary ./test-suite-binaries/elf-Linux-RISCV_64 --depth 8
""")
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 x86|arm|arm64|sparc|mips|ppc|riscv")
parser.add_argument("--rawMode", type=str, metavar="<mode>", help="Specify a mode for a raw file 32|64|arm|thumb")
parser.add_argument("--rawEndian", type=str, metavar="<endian>", help="Specify an endianness for a raw file little|big")
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")
parser.add_argument("--align", type=int, help="Align gadgets addresses (in bytes)")
parser.add_argument("--mipsrop", type=str, metavar="<rtype>", help="MIPS useful gadgets finder stackfinder|system|tails|lia0|registers")
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.thumb and self.__args.rawMode and self.__args.rawMode != "thumb":
raise ValueError("[Error] --rawMode is conflicting with --thumb")
if not self.__args.rawArch and self.__args.rawMode:
raise ValueError("[Error] Specify --rawArch")
if not self.__args.rawArch and self.__args.rawEndian:
raise ValueError("[Error] Specify --rawArch")
rawMode = "thumb" if self.__args.thumb else self.__args.rawMode
if self.__args.rawArch and not rawMode:
raise ValueError("[Error] Specify --rawMode")
if self.__args.rawArch and not self.__args.rawEndian and self.__args.rawArch != "x86":
raise ValueError("[Error] Specify --rawEndian")
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

@ -0,0 +1,80 @@
## -*- coding: utf-8 -*-
##
## Jonathan Salwan - 2014-05-12 - ROPgadget tool
##
## http://twitter.com/JonathanSalwan
## http://shell-storm.org/project/ROPgadget/
##
from binascii import unhexlify
from ropgadget.loaders.elf import *
from ropgadget.loaders.macho import *
from ropgadget.loaders.pe import *
from ropgadget.loaders.raw import *
from ropgadget.loaders.universal import *
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:
self.__binary = Raw(
self.__rawBinary,
options.rawArch,
"thumb" if options.thumb else 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") or \
self.__rawBinary[:4] == unhexlify(b"feedface") or self.__rawBinary[:4] == unhexlify(b"feedfacf"):
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()

@ -0,0 +1,653 @@
## -*- coding: utf-8 -*-
##
## Jonathan Salwan - 2014-05-17 - ROPgadget tool
##
## http://twitter.com/JonathanSalwan
## http://shell-storm.org/project/ROPgadget/
##
import binascii
import cmd
import re
import string
from capstone import CS_MODE_32
import ropgadget.rgutils as rgutils
from ropgadget.binary import Binary
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 is None or self.__binary.getBinary() is None or self.__binary.getArch() is None or self.__binary.getArchMode() is None or self.__binary.getEndian() is 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 not self.__checksBeforeManipulations():
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 not self.__checksBeforeManipulations():
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", "")
insts = " : {}".format(insts) if insts else ""
bytesStr = " // " + binascii.hexlify(gadget["bytes"]).decode('utf8') if self.__options.dump else ""
print("0x{{0:0{}x}}{{1}}{{2}}".format(8 if arch == CS_MODE_32 else 16).format(vaddr, insts, bytesStr))
print("\nUnique gadgets found: %d" % (len(self.__gadgets)))
return True
def __lookingForMIPSgadgets(self, mips_option):
if not self.__checksBeforeManipulations():
return False
if self.__options.silent:
return True
arch = self.__binary.getArchMode()
if mips_option == 'stackfinder':
mipsFindRegex = [r'addiu .*, \$sp']
elif mips_option == 'system':
mipsFindRegex = [r'addiu \$a0, \$sp']
elif mips_option == 'tails':
mipsFindRegex = [r'lw \$t[0-9], 0x[0-9a-z]{0,4}\(\$s[0-9]', r'move \$t9, \$(s|a|v)']
elif mips_option == 'lia0':
mipsFindRegex = [r'li \$a0']
elif mips_option == 'registers':
mipsFindRegex = [r'lw \$ra, 0x[0-9a-z]{0,4}\(\$sp']
else:
print("Unrecognized option " + mips_option)
print("Accepted options stackfinder|system|tails|lia0|registers")
return False
print("MIPS ROP (" + mips_option + ")\n============================================================")
self.__getGadgets()
gadget_counter = 0
for gadget in self.__gadgets:
vaddr = gadget["vaddr"]
insts = gadget.get("gadget", "")
insts = " : {}".format(insts) if insts else ""
bytesStr = " // " + binascii.hexlify(gadget["bytes"]).decode('utf8') if self.__options.dump else ""
for thisRegex in mipsFindRegex:
toFind = re.findall(thisRegex, insts)
if toFind:
print("0x{{0:0{}x}}{{1}}{{2}}".format(8 if arch == CS_MODE_32 else 16).format(vaddr, insts, bytesStr))
gadget_counter += 1
print("\nUnique gadgets found: %d" % gadget_counter)
return True
def __lookingForAString(self, s):
if not self.__checksBeforeManipulations():
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(s.encode(), section["opcodes"])]
for ref in allRef:
vaddr = self.__offset + section["vaddr"] + ref
match = section["opcodes"][ref:ref + len(s)]
printable = string.printable.encode()
match = "".join((chr(m) if isinstance(m, int) else m) if m in printable else "." for m in match)
print("0x{{0:0{}x}} : {{1}}".format(8 if arch == CS_MODE_32 else 16).format(vaddr, match))
return True
def __lookingForOpcodes(self, opcodes):
if not self.__checksBeforeManipulations():
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{{0:0{}x}} : {{1}}".format(8 if arch == CS_MODE_32 else 16).format(vaddr, opcodes))
return True
def __lookingForMemStr(self, memstr):
if not self.__checksBeforeManipulations():
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{{0:0{}x}} : '{{1}}'".format(8 if arch == CS_MODE_32 else 16).format(vaddr, 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 not self.__checksBeforeManipulations():
return False
self.cmdloop()
return True
self.__binary = Binary(self.__options)
if not self.__checksBeforeManipulations():
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)
elif self.__options.mipsrop:
return self.__lookingForMIPSgadgets(self.__options.mipsrop)
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 not s:
if not silent:
return self.help_binary()
return False
binary = s
self.__options.binary = binary
self.__binary = Binary(self.__options)
if not self.__checksBeforeManipulations():
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 is 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 not listK:
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] == "!":
withoutK += [a[1:]]
else:
withK += [a]
if not self.__checksBeforeManipulations():
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{{0:0{}x}} : {{1}}".format(8 if arch == CS_MODE_32 else 16).format(vaddr, 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)
print("Mipsrop: %s" % self.__options.mipsrop)
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")

@ -0,0 +1,412 @@
## -*- 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", "repz ret", "retf", "int", "sysenter", "jmp", "notrack jmp", "call", "notrack 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:
if self.__options.align:
gad_align = self.__options.align
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 + start)
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 have RET instructions. 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 have RET instructions. 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
elif arch == CS_ARCH_RISCV:
if arch_endian == CS_MODE_BIG_ENDIAN:
gadgets = [
[b"\x80\x82", 2, 1], # c.ret
]
else:
gadgets = [
[b"\x82\x80", 2, 1], # c.ret
]
arch_mode = CS_MODE_RISCV64 | CS_MODE_RISCVC
else:
print("Gadgets().addROPGadgets() - Architecture not supported")
return None
if gadgets:
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 doesn't have reg branch instructions
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 # noqa: W605 # FIXME: \?
]
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 # noqa: W605 # FIXME: \?
]
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
elif arch == CS_ARCH_RISCV:
if arch_endian == CS_MODE_BIG_ENDIAN:
gadgets = [
#32 bits encoded register
[b"[\x00-\xff]{2}[\x00-\xff][\x67\x6f\xe7\xef]",4 , 1],
[b"[\x00-\xff]{2}[\x00-\xff][\x63\xe3]", 4 , 1],
#16bits encoded register
[b"[\xa0-\xff]{1}[\xfd\xf9\xf5\xf1\xed\xe9\xe5\xe1\xdd\xd9\xd5\xd1\xcd\xc9\xc5\xc1\xbd\xb9\xb5\xb1\xad\xa9\xa5\xa1]", 2, 1], # c.j | c.beqz | c.bnez
[b"[\xa0-\xff]{1}[\x0d\x09\x05\x01\x1d\x19\x15\x11\x2d\x29\x25\x21\x3d\x39\x35\x31\x4d\x49\x45\x41\x5d\x59\x55\x51]", 2, 1], # c.j | c.beqz | c.bnez
[b"[\xa0-\xff]{1}[\x6d\x69\x65\x61\x7d\x79\x75\x71\x8d\x89\x85\x81\x9d\x99\x95\x91]", 2, 1], # c.j | c.beqz| c.bnez
[b"[\x81-\x8f]{1}[\x02\x82]", 2, 1], #c.jr register
[b"[\x91-\x9f]{1}[\x02\x82]", 2, 1], #c.jalr register
]
else:
gadgets = [
#32 bits encoded register
[b"[\x67\x6f\xe7\xef][\x00-\xff][\x00-\xff]{2}" , 4, 1], #jalr/j/jal register, offset
[b"[\x63\xe3][\x00-\xff][\x00-\xff]{2}" , 4, 1], #branch register, offset
#16 bits encoded register
[b"[\xfd\xf9\xf5\xf1\xed\xe9\xe5\xe1\xdd\xd9\xd5\xd1\xcd\xc9\xc5\xc1\xbd\xb9\xb5\xb1\xad\xa9\xa5\xa1][\xa0-\xff]{1}", 2, 1], # c.j | c.beqz | c.bnez
[b"[\x0d\x09\x05\x01\x1d\x19\x15\x11\x2d\x29\x25\x21\x3d\x39\x35\x31\x4d\x49\x45\x41\x5d\x59\x55\x51][\xa0-\xff]{1}", 2, 1], # c.j | c.beqz | c.bnez
[b"[\x6d\x69\x65\x61\x7d\x79\x75\x71\x8d\x89\x85\x81\x9d\x99\x95\x91][\xa0-\xff]{1}", 2, 1], # c.j | c.beqz| c.bnez
[b"[\x02\x82][\x81-\x8f]{1}", 2, 1], #c.jr register
[b"[\x02\x82][\x91-\x9f]{1}", 2, 1], #c.jalr register
]
arch_mode = CS_MODE_RISCV64 | CS_MODE_RISCVC
else:
print("Gadgets().addJOPGadgets() - Architecture not supported")
return None
if gadgets:
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
elif arch == CS_ARCH_RISCV:
if arch_endian == CS_MODE_BIG_ENDIAN:
gadgets = [
[b"\x00\x00\x00\x73", 4, 2] # syscall
]
else:
gadgets = [
[b"\x73\x00\x00\x00", 4, 2] # syscall
]
arch_mode = CS_MODE_RISCV64 | CS_MODE_RISCVC
else:
print("Gadgets().addSYSGadgets() - Architecture not supported")
return None
if gadgets:
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

@ -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

@ -0,0 +1,366 @@
## -*- coding: utf-8 -*-
##
## Jonathan Salwan - 2014-05-12 - ROPgadget tool
##
## http://twitter.com/JonathanSalwan
## http://shell-storm.org/project/ROPgadget/
##
from ctypes import *
from capstone import *
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_PPC64 = 0x15
EM_ARM64 = 0xb7
EM_RISCV = 0xf3
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),
]
class ELF(object):
"""This class parses the ELF."""
def __init__(self, binary):
self.__binary = bytearray(binary)
self.__ElfHeader = None
self.__shdr_l = []
self.__phdr_l = []
self.__setHeaderElf()
self.__setShdr()
self.__setPhdr()
def __setHeaderElf(self):
"""Parse ELF header."""
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
def __setShdr(self):
"""Parse Section header."""
shdr_num = self.__ElfHeader.e_shnum
base = self.__binary[self.__ElfHeader.e_shoff:]
self.__shdr_l = []
e_ident = self.__binary[:15]
ei_data = e_ident[ELFFlags.EI_DATA]
for _ 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')
def __setPhdr(self):
"""Parse Program header."""
pdhr_num = self.__ElfHeader.e_phnum
base = self.__binary[self.__ElfHeader.e_phoff:]
self.__phdr_l = []
e_ident = self.__binary[:15]
ei_data = e_ident[ELFFlags.EI_DATA]
for _ 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 or self.__ElfHeader.e_machine == ELFFlags.EM_PPC64:
return CS_ARCH_PPC
elif self.__ElfHeader.e_machine == ELFFlags.EM_SPARCv8p:
return CS_ARCH_SPARC
elif self.__ElfHeader.e_machine == ELFFlags.EM_RISCV:
return CS_ARCH_RISCV
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
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"

@ -0,0 +1,329 @@
## -*- coding: utf-8 -*-
##
## Jonathan Salwan - 2014-05-12 - ROPgadget tool
##
## http://twitter.com/JonathanSalwan
## http://shell-storm.org/project/ROPgadget/
##
from ctypes import *
from capstone import *
class MACH_HEADER_LE(LittleEndianStructure):
_fields_ = [
("magic", c_uint),
("cputype", c_uint),
("cpusubtype", c_uint),
("filetype", c_uint),
("ncmds", c_uint),
("sizeofcmds", c_uint),
("flags", c_uint),
]
class MACH_HEADER_BE(BigEndianStructure):
_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_LE(LittleEndianStructure):
_fields_ = [
("cmd", c_uint),
("cmdsize", c_uint),
]
class LOAD_COMMAND_BE(BigEndianStructure):
_fields_ = [
("cmd", c_uint),
("cmdsize", c_uint),
]
class SEGMENT_COMMAND_LE(LittleEndianStructure):
_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_COMMAND_BE(BigEndianStructure):
_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_LE(LittleEndianStructure):
_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 SEGMENT_COMMAND64_BE(BigEndianStructure):
_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_LE(LittleEndianStructure):
_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 SECTION_BE(BigEndianStructure):
_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_LE(LittleEndianStructure):
_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 SECTION64_BE(BigEndianStructure):
_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
class MACHO(object):
"""This class parses the Mach-O."""
def __init__(self, binary):
self.__binary = bytearray(binary)
self.__machHeader = None
self.__endianness = None
self.__rawLoadCmd = None
self.__sections_l = []
self.__setEndianness()
self.__setHeader()
self.__setLoadCmd()
def __setEndianness(self):
magic = self.__binary[0] << 24 | \
self.__binary[1] << 16 | \
self.__binary[2] << 8 | \
self.__binary[3]
if magic == 0xfeedface or magic == 0xfeedfacf:
self.__endianness = CS_MODE_BIG_ENDIAN
else:
self.__endianness = 0
def __setHeader(self):
if self.__endianness == CS_MODE_BIG_ENDIAN:
self.__machHeader = MACH_HEADER_BE.from_buffer_copy(self.__binary)
else:
self.__machHeader = MACH_HEADER_LE.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 _ in range(self.__machHeader.ncmds):
if self.__endianness == CS_MODE_BIG_ENDIAN:
command = LOAD_COMMAND_BE.from_buffer_copy(base)
else:
command = LOAD_COMMAND_LE.from_buffer_copy(base)
if command.cmd == MACHOFlags.LC_SEGMENT:
if self.__endianness == CS_MODE_BIG_ENDIAN:
segment = SEGMENT_COMMAND_BE.from_buffer_copy(base)
else:
segment = SEGMENT_COMMAND_LE.from_buffer_copy(base)
self.__setSections(segment, base[56:], 32)
elif command.cmd == MACHOFlags.LC_SEGMENT_64:
if self.__endianness == CS_MODE_BIG_ENDIAN:
segment = SEGMENT_COMMAND64_BE.from_buffer_copy(base)
else:
segment = SEGMENT_COMMAND64_LE.from_buffer_copy(base)
self.__setSections(segment, base[72:], 64)
base = base[command.cmdsize:]
def __setSections(self, segment, base, sizeHeader):
for _ in range(segment.nsects):
if sizeHeader == 32:
if self.__endianness == CS_MODE_BIG_ENDIAN:
section = SECTION_BE.from_buffer_copy(base)
else:
section = SECTION_LE.from_buffer_copy(base)
section.offset = segment.fileoff + section.addr - segment.vmaddr
base = base[68:]
self.__sections_l += [section]
elif sizeHeader == 64:
if self.__endianness == CS_MODE_BIG_ENDIAN:
section = SECTION64_BE.from_buffer_copy(base)
else:
section = SECTION64_LE.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
if self.__machHeader.cputype == MACHOFlags.CPU_TYPE_POWERPC or self.__machHeader.cputype == MACHOFlags.CPU_TYPE_POWERPC64:
return CS_ARCH_PPC
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
print("[Error] MACHO.getArchMode() - Bad Arch size")
return None
def getEndian(self):
if self.__endianness is None:
print("[Error] MACHO.getEndian() - Unable to determine endianness")
return self.__endianness
def getFormat(self):
return "Mach-O"

@ -0,0 +1,241 @@
## -*- coding: utf-8 -*-
##
## Jonathan Salwan - 2014-05-12 - ROPgadget tool
##
## http://twitter.com/JonathanSalwan
## http://shell-storm.org/project/ROPgadget/
##
from binascii import unhexlify
from ctypes import *
from struct import unpack
from capstone import *
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(LittleEndianStructure):
_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(LittleEndianStructure):
_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(LittleEndianStructure):
_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(LittleEndianStructure):
_fields_ = [
("Signature", c_uint),
("FileHeader", IMAGE_FILE_HEADER),
("OptionalHeader", IMAGE_OPTIONAL_HEADER),
]
class IMAGE_NT_HEADERS64(LittleEndianStructure):
_fields_ = [
("Signature", c_uint),
("FileHeader", IMAGE_FILE_HEADER),
("OptionalHeader", IMAGE_OPTIONAL_HEADER64),
]
class IMAGE_SECTION_HEADER(LittleEndianStructure):
_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),
]
class PE(object):
"""This class parses the PE format."""
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 _ 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
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
print("[Error] PE.getArch() - Bad arch size")
return None
def getEndian(self):
# PE is little-endian only
return 0
def getFormat(self):
return "PE"

@ -0,0 +1,75 @@
## -*- 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,
"riscv" : CS_ARCH_RISCV,
}
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,
"riscv": CS_MODE_RISCV64 | CS_MODE_RISCVC,
}
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"

@ -0,0 +1,112 @@
## -*- coding: utf-8 -*-
##
## Christoffer Brodd-Reijer - 2014-07-20 - ROPgadget tool
##
## http://twitter.com/ephracis
## http://shell-storm.org/project/ROPgadget/
##
import sys
from binascii import *
from ctypes import *
from capstone 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
class UNIVERSAL(object):
"""This class parses the Universal binary."""
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

@ -0,0 +1,148 @@
## -*- coding: utf-8 -*-
##
## Jonathan Salwan - 2014-05-17 - ROPgadget tool
##
## http://twitter.com/JonathanSalwan
## http://shell-storm.org/project/ROPgadget/
##
import codecs
import re
from struct import pack
from capstone import *
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 rangeS <= 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 len(re_strs) == 1:
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):
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"))
bbytes += bytes(bytearray(i for i in range(low, high + 1)))
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"])
for x in bbytes:
if x in gadAddr:
break
else:
new += [gadget]
self.__gadgets = new
def getGadgets(self):
return self.__gadgets

@ -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"])

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

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

@ -0,0 +1,221 @@
#!/usr/bin/env python3
## -*- 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
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("#!/usr/bin/env python3")
print("# execve generated by ROPgadget\n")
print("from struct import pack\n")
print("# Padding goes here")
print("p = b''\n")
print("p += pack('<Q', 0x%016x) # %s" % (popDst["vaddr"], popDst["gadget"]))
print("p += pack('<Q', 0x%016x) # @ .data" % dataAddr)
self.__padding(popDst, {})
print("p += pack('<Q', 0x%016x) # %s" % (popSrc["vaddr"], popSrc["gadget"]))
print("p += b'/bin//sh'")
self.__padding(popSrc, {popDst["gadget"].split()[1]: dataAddr}) # Don't overwrite reg dst
print("p += pack('<Q', 0x%016x) # %s" % (write4where["vaddr"], write4where["gadget"]))
self.__padding(write4where, {})
print("p += pack('<Q', 0x%016x) # %s" % (popDst["vaddr"], popDst["gadget"]))
print("p += pack('<Q', 0x%016x) # @ .data + 8" % (dataAddr + 8))
self.__padding(popDst, {})
print("p += pack('<Q', 0x%016x) # %s" % (xorSrc["vaddr"], xorSrc["gadget"]))
self.__padding(xorSrc, {})
print("p += pack('<Q', 0x%016x) # %s" % (write4where["vaddr"], write4where["gadget"]))
self.__padding(write4where, {})
print("p += pack('<Q', 0x%016x) # %s" % (popRdi["vaddr"], popRdi["gadget"]))
print("p += pack('<Q', 0x%016x) # @ .data" % dataAddr)
self.__padding(popRdi, {})
print("p += pack('<Q', 0x%016x) # %s" % (popRsi["vaddr"], popRsi["gadget"]))
print("p += pack('<Q', 0x%016x) # @ .data + 8" % (dataAddr + 8))
self.__padding(popRsi, {"rdi": dataAddr}) # Don't overwrite rdi
print("p += pack('<Q', 0x%016x) # %s" % (popRdx["vaddr"], popRdx["gadget"]))
print("p += pack('<Q', 0x%016x) # @ .data + 8" % (dataAddr + 8))
self.__padding(popRdx, {"rdi": dataAddr, "rsi": dataAddr + 8}) # Don't overwrite rdi and rsi
print("p += pack('<Q', 0x%016x) # %s" % (xorRax["vaddr"], xorRax["gadget"]))
self.__padding(xorRax, {"rdi": dataAddr, "rsi": dataAddr + 8}) # Don't overwrite rdi and rsi
for _ in range(59):
print("p += pack('<Q', 0x%016x) # %s" % (incRax["vaddr"], incRax["gadget"]))
self.__padding(incRax, {"rdi": dataAddr, "rsi": dataAddr + 8}) # Don't overwrite rdi and rsi
print("p += 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)

@ -0,0 +1,219 @@
#!/usr/bin/env python3
## -*- coding: utf-8 -*-
##
## Jonathan Salwan - 2014-05-13
##
## http://shell-storm.org
## http://twitter.com/JonathanSalwan
##
import re
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 is None:
print("\n[-] Error - Can't find a writable section")
return
print("#!/usr/bin/env python3")
print("# execve generated by ROPgadget\n")
print("from struct import pack\n")
print("# Padding goes here")
print("p = b''\n")
print("p += pack('<I', 0x%08x) # %s" % (popDst["vaddr"], popDst["gadget"]))
print("p += pack('<I', 0x%08x) # @ .data" % dataAddr)
self.__padding(popDst, {})
print("p += pack('<I', 0x%08x) # %s" % (popSrc["vaddr"], popSrc["gadget"]))
print("p += b'/bin'")
self.__padding(popSrc, {popDst["gadget"].split()[1]: dataAddr}) # Don't overwrite reg dst
print("p += pack('<I', 0x%08x) # %s" % (write4where["vaddr"], write4where["gadget"]))
self.__padding(write4where, {})
print("p += pack('<I', 0x%08x) # %s" % (popDst["vaddr"], popDst["gadget"]))
print("p += pack('<I', 0x%08x) # @ .data + 4" % (dataAddr + 4))
self.__padding(popDst, {})
print("p += pack('<I', 0x%08x) # %s" % (popSrc["vaddr"], popSrc["gadget"]))
print("p += b'//sh'")
self.__padding(popSrc, {popDst["gadget"].split()[1]: dataAddr + 4}) # Don't overwrite reg dst
print("p += pack('<I', 0x%08x) # %s" % (write4where["vaddr"], write4where["gadget"]))
self.__padding(write4where, {})
print("p += pack('<I', 0x%08x) # %s" % (popDst["vaddr"], popDst["gadget"]))
print("p += pack('<I', 0x%08x) # @ .data + 8" % (dataAddr + 8))
self.__padding(popDst, {})
print("p += pack('<I', 0x%08x) # %s" % (xorSrc["vaddr"], xorSrc["gadget"]))
self.__padding(xorSrc, {})
print("p += pack('<I', 0x%08x) # %s" % (write4where["vaddr"], write4where["gadget"]))
self.__padding(write4where, {})
print("p += pack('<I', 0x%08x) # %s" % (popEbx["vaddr"], popEbx["gadget"]))
print("p += pack('<I', 0x%08x) # @ .data" % dataAddr)
self.__padding(popEbx, {})
print("p += pack('<I', 0x%08x) # %s" % (popEcx["vaddr"], popEcx["gadget"]))
print("p += pack('<I', 0x%08x) # @ .data + 8" % (dataAddr + 8))
self.__padding(popEcx, {"ebx": dataAddr}) # Don't overwrite ebx
print("p += pack('<I', 0x%08x) # %s" % (popEdx["vaddr"], popEdx["gadget"]))
print("p += pack('<I', 0x%08x) # @ .data + 8" % (dataAddr + 8))
self.__padding(popEdx, {"ebx": dataAddr, "ecx": dataAddr + 8}) # Don't overwrite ebx and ecx
print("p += pack('<I', 0x%08x) # %s" % (xorEax["vaddr"], xorEax["gadget"]))
self.__padding(xorEax, {"ebx": dataAddr, "ecx": dataAddr + 8}) # Don't overwrite ebx and ecx
for _ in range(11):
print("p += pack('<I', 0x%08x) # %s" % (incEax["vaddr"], incEax["gadget"]))
self.__padding(incEax, {"ebx": dataAddr, "ecx": dataAddr + 8}) # Don't overwrite ebx and ecx
print("p += 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)

@ -0,0 +1,40 @@
## -*- coding: utf-8 -*-
##
## Jonathan Salwan - 2014-05-13
##
## http://shell-storm.org
## http://twitter.com/JonathanSalwan
##
from capstone import *
from ropgadget.ropchain.arch.ropmakerx64 import *
from ropgadget.ropchain.arch.ropmakerx86 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")

@ -0,0 +1,37 @@
## -*- 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().decode()
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.")

@ -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 = 7
MINOR_VERSION = 4
PYROPGADGET_VERSION = "ROPgadget v%d.%d" % (MAJOR_VERSION, MINOR_VERSION)

@ -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()

@ -0,0 +1,85 @@
# All configuration for plugins and other utils is defined here.
# Read more about `setup.cfg`:
# https://docs.python.org/3/distutils/configfile.html
# === Linter configuration ===
# You can reuse this configuration in your own projects.
# See: https://wemake-python-stylegui.de/en/latest/pages/usage/integrations/nitpick.html
[flake8]
# Base flake8 configuration:
# https://flake8.pycqa.org/en/latest/user/configuration.html
format = wemake
show-source = True
statistics = False
doctests = True
# Plugins:
max-complexity = 6
max-line-length = 100
# Self settings:
max-imports = 17
# Excluding some directories:
exclude =
.git
__pycache__
.venv
.eggs
*.egg
dist
# Exclude some checks globally:
ignore = B001, C901, D100, D101, D102, D103, D104, D107, D205, D400, E221, E241,
E251, E266, E271, E272, E722, F403, F405, I004, N802, N803, N806, P101,
Q000, W503, W504, WPS110, WPS111, WPS112, WPS122, WPS202, WPS204, WPS210,
WPS212, WPS213, WPS214, WPS220, WPS221, WPS222, WPS223, WPS226, WPS229,
WPS231, WPS232, WPS301, WPS323, WPS336, WPS337, WPS338, WPS341, WPS347,
WPS412, WPS420, WPS421, WPS430, WPS432, WPS433, WPS440, WPS504, WPS514,
WPS515, WPS602, WPS605
per-file-ignores =
ROPgadget.py: WPS102
ropgadget/__init__.py: F401
ropgadget/args.py: E501, WPS317, WPS318
ropgadget/binary.py: E501
ropgadget/core.py: E501, I001, S110, WPS125, WPS503, WPS513, WPS609
ropgadget/gadgets.py: C812, E126, E261, E501, E800, WPS318, WPS319, WPS513
ropgadget/loaders/__init__.py: F401
ropgadget/loaders/elf.py: E126, E203, E222, E501, E701, N801, WPS114,
WPS115, WPS120, WPS318, WPS339
ropgadget/loaders/macho.py: E126, E203, E222, E501, N801, WPS114, WPS115,
WPS120, WPS318, WPS339, WPS349
ropgadget/loaders/pe.py: E126, E203, E222, E501, N801, WPS114, WPS115,
WPS120, WPS318, WPS339, WPS349
ropgadget/loaders/raw.py: E126, E222, E501, WPS318
ropgadget/loaders/universal.py: E126, E501, N801, WPS114, WPS115, WPS120,
WPS318, WPS328, WPS339, WPS519
ropgadget/options.py: E501, S110
ropgadget/ropchain/__init__.py: F401
ropgadget/ropchain/arch/__init__.py: F401
ropgadget/ropchain/arch/ropmakerx64.py: E501, S112, W605, WPS211, WPS327,
WPS503
ropgadget/ropchain/arch/ropmakerx86.py: E501, S112, W605, WPS211, WPS327,
WPS503
ropgadget/ropchain/ropmaker.py: E501, N400
ropgadget/updateAlert.py: E501, I001, I003, S309, W605, WPS102, WPS301
setup.py: E501
[isort]
# isort configuration:
# https://github.com/timothycrosley/isort/wiki/isort-Settings
include_trailing_comma = true
use_parentheses = true
# See https://github.com/timothycrosley/isort#multi-line-output-modes
multi_line_output = 3
# Is the same as 80 in flake8:
line_length = 100
[darglint]
# darglint configuration:
# https://github.com/terrencepreilly/darglint
strictness = long

@ -0,0 +1,71 @@
#!/usr/bin/env python
import os
from setuptools import setup
package_name = "ROPGadget"
package_dir = "ropgadget"
package_description = "This tool lets you search your gadgets on your binaries to facilitate your ROP exploitation."
long_description = """
ROPgadget supports ELF, PE, Mach-O, and Raw formats on x86, x64, ARM, ARM64, PowerPC, SPARC, MIPS, RISC-V 64, and RISC-V Compressed architectures.
https://github.com/JonathanSalwan/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 = "7.4"
setup(
name = package_name,
version = version,
description = package_description,
long_description = long_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>=5.0.1'],
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',
],
)

@ -0,0 +1 @@
1и┴H┴H L$1юц

@ -0,0 +1,69 @@
#!/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 elf-Linux-x86 --offset 5555e000 --badbytes \"00-20|80-ff\"" | tee -a ./test_output
$RUN --binary ./elf-Linux-x86 --offset 5555e000 --badbytes "00-20|80-ff" 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
echo "RUN elf-PPC64-bash --depth 5" | tee -a ./test_output
$RUN --binary ./elf-PPC64-bash --depth 5 1>> ./test_output
echo "RUN elf-Linux-RISCV_64 --depth 8" | tee -a ./test_output
$RUN --binary ./elf-Linux-RISCV_64 --depth 8 1>> ./test_output
echo "RUN elf-Linux-RISCV_32 --depth 8" | tee -a ./test_output
$RUN --binary ./elf-Linux-RISCV_32 --depth 8 1>> ./test_output
diff test_output <(bunzip2 --stdout ref_output.bz2) 1>&2

@ -0,0 +1,2 @@
Combien de gadgets possède le binaire nommé "binaire" dans le dossier Bufferoverflow ?
Loading…
Cancel
Save