include ROPGadget
This commit is contained in:
parent
688bb5a1be
commit
5f8099dde0
31
ROPgadget/.github/workflows/main.yml
vendored
Normal file
31
ROPgadget/.github/workflows/main.yml
vendored
Normal file
@ -0,0 +1,31 @@
|
||||
name: CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Build
|
||||
run: |
|
||||
python2 -m pip install --upgrade setuptools wheel
|
||||
python3 -m pip install --upgrade setuptools wheel
|
||||
python2 setup.py sdist bdist_wheel
|
||||
python3 setup.py sdist bdist_wheel
|
||||
- name: Install
|
||||
run: |
|
||||
python2 -m pip install dist/ROPGadget*py2*.whl
|
||||
python3 -m pip install dist/ROPGadget*py3*.whl
|
||||
- name: Run tests
|
||||
run: |
|
||||
cd test-suite-binaries
|
||||
./test.sh
|
||||
./test.sh python2
|
||||
cd ..
|
4
ROPgadget/.gitignore
vendored
Normal file
4
ROPgadget/.gitignore
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
*.pyc
|
||||
build
|
||||
dist
|
||||
ROPGadget.egg-info
|
42
ROPgadget/AUTHORS
Normal file
42
ROPgadget/AUTHORS
Normal file
@ -0,0 +1,42 @@
|
||||
|
||||
ROPgadget project (>= v5.0)
|
||||
===================================================
|
||||
|
||||
Authors:
|
||||
|
||||
* Jonathan Salwan
|
||||
|
||||
|
||||
Contributors:
|
||||
|
||||
* hugsy - Has added the --offset option
|
||||
* Francisco Falcon - Has fixed the --badbytes option and added the count/loaddb/save2db console features
|
||||
* Kevin Hamacher - Added some functionality for using ROPgadget as library. Also added support for x86(_64) jmp {r,e}sp/call {r,e}sp instructions
|
||||
* Florian Meier - Added the 64b ROP chain generation
|
||||
* Álvaro Felipe Melchor (increase performance)
|
||||
* Sascha Schirra (features, python3, bugs fix)
|
||||
* Stephen Edwards (increase performance)
|
||||
* Mikhail Davidov (features)
|
||||
* penguin-wwy (features)
|
||||
|
||||
|
||||
|
||||
ROPgadget initial project (<= v4.0.3)
|
||||
===================================================
|
||||
|
||||
Authors:
|
||||
|
||||
* Jonathan Salwan
|
||||
* Allan Wirth
|
||||
|
||||
|
||||
Contributors:
|
||||
|
||||
* Hellman (Bug Fix)
|
||||
* Axel "0vercl0k" Souchet (Bug Fix)
|
||||
* k3rensk1 (Bug repport)
|
||||
* brianairb (Bug Fix)
|
||||
* cao (Bug Fix)
|
||||
* dark-rose (Made searching for gadgets faster)
|
||||
* Dennis Semakin (Bug Fix)
|
||||
|
27
ROPgadget/LICENSE_BSD.txt
Normal file
27
ROPgadget/LICENSE_BSD.txt
Normal file
@ -0,0 +1,27 @@
|
||||
This is the software license for the ROPgadget project.
|
||||
|
||||
Copyright (c) 2016. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
* Neither the name of the developers nor the names of its
|
||||
contributors may be used to endorse or promote products derived from this
|
||||
software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
114
ROPgadget/README.md
Normal file
114
ROPgadget/README.md
Normal file
@ -0,0 +1,114 @@
|
||||
ROPgadget Tool
|
||||
================
|
||||
|
||||
This tool lets you search your gadgets on your binaries to facilitate your ROP exploitation.
|
||||
ROPgadget supports ELF/PE/Mach-O format on x86, x64, ARM, ARM64, PowerPC, SPARC and MIPS
|
||||
architectures. Since the version 5, ROPgadget has a new core which is written in Python
|
||||
using Capstone disassembly framework for the gadgets search engine - The older version can
|
||||
be found in the Archives directory but it will not be maintained.
|
||||
|
||||
Install
|
||||
-------
|
||||
|
||||
If you want to use ROPgadget, you have to install [Capstone](http://www.capstone-engine.org/) first.
|
||||
|
||||
For the Capstone's installation on nix machine:
|
||||
|
||||
$ sudo pip install capstone
|
||||
|
||||
Capstone supports multi-platforms (windows, ios, android, cygwin...). For the cross-compilation,
|
||||
please refer to the https://github.com/aquynh/capstone/blob/master/COMPILE.TXT file.
|
||||
|
||||
After Capstone is installed, ROPgadget can be used as a standalone tool:
|
||||
|
||||
$ ROPgadget.py
|
||||
|
||||
Or installed into the Python site-packages library, and executed from $PATH.
|
||||
|
||||
$ python setup.py install
|
||||
$ ROPgadget
|
||||
|
||||
Or installed from PyPi
|
||||
|
||||
$ pip install ropgadget
|
||||
$ ROPgadget
|
||||
|
||||
Usage
|
||||
-----
|
||||
|
||||
usage: ROPgadget.py [-h] [-v] [-c] [--binary <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]
|
||||
|
||||
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 instructions
|
||||
--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
|
||||
--rawMode <mode> Specify a mode for a raw file
|
||||
--rawEndian <endian> Specify an endianness for a raw file
|
||||
--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
|
||||
|
||||
|
||||
How can I contribute ?
|
||||
----------------------
|
||||
|
||||
- Use Z3 to solve the ROP chain
|
||||
- Add system gadgets for PPC, Sparc, ARM64 (Gadgets.addSYSGadgets())
|
||||
- Manage big endian in Mach-O format like the ELF classe.
|
||||
- Everything you think is cool :)
|
||||
|
||||
Bugs/Patches/Contact
|
||||
--------------------
|
||||
|
||||
Please report bugs, submit pull requests, etc. on github at https://github.com/JonathanSalwan/ROPgadget
|
||||
The offical page is on shell-storm.org at http://shell-storm.org/project/ROPgadget/
|
||||
|
||||
License
|
||||
-------
|
||||
|
||||
See COPYING and the license header on all source files. For the files in the dependencies/ there are
|
||||
individual licenses in each folder.</p>
|
||||
|
||||
|
||||
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>
|
||||
|
12
ROPgadget/ROPgadget.py
Executable file
12
ROPgadget/ROPgadget.py
Executable file
@ -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()
|
29
ROPgadget/ropgadget/__init__.py
Normal file
29
ROPgadget/ropgadget/__init__.py
Normal file
@ -0,0 +1,29 @@
|
||||
## -*- coding: utf-8 -*-
|
||||
##
|
||||
## Jonathan Salwan - 2014-05-12 - ROPgadget tool
|
||||
##
|
||||
## http://twitter.com/JonathanSalwan
|
||||
## http://shell-storm.org/project/ROPgadget/
|
||||
##
|
||||
|
||||
import ropgadget.args
|
||||
import ropgadget.binary
|
||||
import ropgadget.core
|
||||
import ropgadget.gadgets
|
||||
import ropgadget.options
|
||||
import ropgadget.rgutils
|
||||
import ropgadget.updateAlert
|
||||
import ropgadget.version
|
||||
import ropgadget.loaders
|
||||
import ropgadget.ropchain
|
||||
|
||||
def main():
|
||||
import sys
|
||||
from ropgadget.args import Args
|
||||
from ropgadget.core import Core
|
||||
try:
|
||||
args = Args()
|
||||
except ValueError as e:
|
||||
print(e)
|
||||
sys.exit(-1)
|
||||
sys.exit(0 if Core(args.getArgs()).analyze() else 1)
|
138
ROPgadget/ropgadget/args.py
Normal file
138
ROPgadget/ropgadget/args.py
Normal file
@ -0,0 +1,138 @@
|
||||
## -*- coding: utf-8 -*-
|
||||
##
|
||||
## Jonathan Salwan - 2014-05-12 - ROPgadget tool
|
||||
##
|
||||
## http://twitter.com/JonathanSalwan
|
||||
## http://shell-storm.org/project/ROPgadget/
|
||||
##
|
||||
|
||||
import argparse
|
||||
import sys
|
||||
|
||||
from ropgadget.updateAlert import UpdateAlert
|
||||
from ropgadget.version import *
|
||||
|
||||
class Args(object):
|
||||
def __init__(self, arguments=None):
|
||||
self.__args = None
|
||||
custom_arguments_provided = True
|
||||
|
||||
# If no custom arguments are provided, use the program arguments
|
||||
if not arguments:
|
||||
arguments = sys.argv[1:]
|
||||
custom_arguments_provided = False
|
||||
|
||||
|
||||
self.__parse(arguments, custom_arguments_provided)
|
||||
|
||||
def __parse(self, arguments, custom_arguments_provided=False):
|
||||
parser = argparse.ArgumentParser(formatter_class=argparse.RawDescriptionHelpFormatter,
|
||||
description="""description:
|
||||
ROPgadget lets you search your gadgets on a binary. It supports several
|
||||
file formats and architectures and uses the Capstone disassembler for
|
||||
the search engine.
|
||||
|
||||
formats supported:
|
||||
- ELF
|
||||
- PE
|
||||
- Mach-O
|
||||
- Raw
|
||||
|
||||
architectures supported:
|
||||
- x86
|
||||
- x86-64
|
||||
- ARM
|
||||
- ARM64
|
||||
- MIPS
|
||||
- PowerPC
|
||||
- Sparc
|
||||
""",
|
||||
epilog="""examples:
|
||||
ROPgadget.py --binary ./test-suite-binaries/elf-Linux-x86
|
||||
ROPgadget.py --binary ./test-suite-binaries/elf-Linux-x86 --ropchain
|
||||
ROPgadget.py --binary ./test-suite-binaries/elf-Linux-x86 --depth 3
|
||||
ROPgadget.py --binary ./test-suite-binaries/elf-Linux-x86 --string "main"
|
||||
ROPgadget.py --binary ./test-suite-binaries/elf-Linux-x86 --string "m..n"
|
||||
ROPgadget.py --binary ./test-suite-binaries/elf-Linux-x86 --opcode c9c3
|
||||
ROPgadget.py --binary ./test-suite-binaries/elf-Linux-x86 --only "mov|ret"
|
||||
ROPgadget.py --binary ./test-suite-binaries/elf-Linux-x86 --only "mov|pop|xor|ret"
|
||||
ROPgadget.py --binary ./test-suite-binaries/elf-Linux-x86 --filter "xchg|add|sub|cmov.*"
|
||||
ROPgadget.py --binary ./test-suite-binaries/elf-Linux-x86 --norop --nosys
|
||||
ROPgadget.py --binary ./test-suite-binaries/elf-Linux-x86 --range 0x08041000-0x08042000
|
||||
ROPgadget.py --binary ./test-suite-binaries/elf-Linux-x86 --string main --range 0x080c9aaa-0x080c9aba
|
||||
ROPgadget.py --binary ./test-suite-binaries/elf-Linux-x86 --memstr "/bin/sh"
|
||||
ROPgadget.py --binary ./test-suite-binaries/elf-Linux-x86 --console
|
||||
ROPgadget.py --binary ./test-suite-binaries/elf-Linux-x86 --badbytes "00|01-1f|7f|42"
|
||||
ROPgadget.py --binary ./test-suite-binaries/Linux_lib64.so --offset 0xdeadbeef00000000
|
||||
ROPgadget.py --binary ./test-suite-binaries/elf-ARMv7-ls --depth 5
|
||||
ROPgadget.py --binary ./test-suite-binaries/elf-ARM64-bash --depth 5
|
||||
ROPgadget.py --binary ./test-suite-binaries/raw-x86.raw --rawArch=x86 --rawMode=32""")
|
||||
|
||||
parser.add_argument("-v", "--version", action="store_true", help="Display the ROPgadget's version")
|
||||
parser.add_argument("-c", "--checkUpdate", action="store_true", help="Checks if a new version is available")
|
||||
parser.add_argument("--binary", type=str, metavar="<binary>", help="Specify a binary filename to analyze")
|
||||
parser.add_argument("--opcode", type=str, metavar="<opcodes>", help="Search opcode in executable segment")
|
||||
parser.add_argument("--string", type=str, metavar="<string>", help="Search string in readable segment")
|
||||
parser.add_argument("--memstr", type=str, metavar="<string>", help="Search each byte in all readable segment")
|
||||
parser.add_argument("--depth", type=int, metavar="<nbyte>", default=10, help="Depth for search engine (default 10)")
|
||||
parser.add_argument("--only", type=str, metavar="<key>", help="Only show specific instructions")
|
||||
parser.add_argument("--filter", type=str, metavar="<key>", help="Suppress specific mnemonics")
|
||||
parser.add_argument("--range", type=str, metavar="<start-end>", default="0x0-0x0", help="Search between two addresses (0x...-0x...)")
|
||||
parser.add_argument("--badbytes", type=str, metavar="<byte>", help="Rejects specific bytes in the gadget's address")
|
||||
parser.add_argument("--rawArch", type=str, metavar="<arch>", help="Specify an arch for a raw file")
|
||||
parser.add_argument("--rawMode", type=str, metavar="<mode>", help="Specify a mode for a raw file")
|
||||
parser.add_argument("--rawEndian", type=str, metavar="<endian>", help="Specify an endianness for a raw file")
|
||||
parser.add_argument("--re", type=str, metavar="<re>", help="Regular expression")
|
||||
parser.add_argument("--offset", type=str, metavar="<hexaddr>", help="Specify an offset for gadget addresses")
|
||||
parser.add_argument("--ropchain", action="store_true", help="Enable the ROP chain generation")
|
||||
parser.add_argument("--thumb" , action="store_true", help="Use the thumb mode for the search engine (ARM only)")
|
||||
parser.add_argument("--console", action="store_true", help="Use an interactive console for search engine")
|
||||
parser.add_argument("--norop", action="store_true", help="Disable ROP search engine")
|
||||
parser.add_argument("--nojop", action="store_true", help="Disable JOP search engine")
|
||||
parser.add_argument("--callPreceded", action="store_true", help="Only show gadgets which are call-preceded")
|
||||
parser.add_argument("--nosys", action="store_true", help="Disable SYS search engine")
|
||||
parser.add_argument("--multibr", action="store_true", help="Enable multiple branch gadgets")
|
||||
parser.add_argument("--all", action="store_true", help="Disables the removal of duplicate gadgets")
|
||||
parser.add_argument("--noinstr", action="store_true", help="Disable the gadget instructions console printing")
|
||||
parser.add_argument("--dump", action="store_true", help="Outputs the gadget bytes")
|
||||
parser.add_argument("--silent", action="store_true", help="Disables printing of gadgets during analysis")
|
||||
|
||||
self.__args = parser.parse_args(arguments)
|
||||
|
||||
if self.__args.noinstr and self.__args.only:
|
||||
raise ValueError("[Error] --noinstr and --only=<key> can't be used together")
|
||||
|
||||
if self.__args.noinstr and self.__args.re:
|
||||
raise ValueError("[Error] --noinstr and --re=<re> can't be used together")
|
||||
|
||||
if self.__args.version:
|
||||
self.__printVersion()
|
||||
sys.exit(0)
|
||||
|
||||
elif self.__args.checkUpdate:
|
||||
UpdateAlert().checkUpdate()
|
||||
sys.exit(0)
|
||||
|
||||
elif self.__args.depth < 2:
|
||||
raise ValueError("[Error] The depth must be >= 2")
|
||||
|
||||
elif not custom_arguments_provided and not self.__args.binary and not self.__args.console:
|
||||
raise ValueError("[Error] Need a binary filename (--binary/--console or --help)")
|
||||
|
||||
elif self.__args.range:
|
||||
try:
|
||||
rangeS = int(self.__args.range.split('-')[0], 16)
|
||||
rangeE = int(self.__args.range.split('-')[1], 16)
|
||||
except:
|
||||
raise ValueError("[Error] A range must be set in hexadecimal. Ex: 0x08041000-0x08042000")
|
||||
if rangeS > rangeE:
|
||||
raise ValueError("[Error] The start value must be greater than end value")
|
||||
|
||||
def __printVersion(self):
|
||||
print("Version: %s" %(PYROPGADGET_VERSION))
|
||||
print("Author: Jonathan Salwan" )
|
||||
print("Author page: https://twitter.com/JonathanSalwan" )
|
||||
print("Project page: http://shell-storm.org/project/ROPgadget/" )
|
||||
|
||||
def getArgs(self):
|
||||
return self.__args
|
72
ROPgadget/ropgadget/binary.py
Normal file
72
ROPgadget/ropgadget/binary.py
Normal file
@ -0,0 +1,72 @@
|
||||
## -*- coding: utf-8 -*-
|
||||
##
|
||||
## Jonathan Salwan - 2014-05-12 - ROPgadget tool
|
||||
##
|
||||
## http://twitter.com/JonathanSalwan
|
||||
## http://shell-storm.org/project/ROPgadget/
|
||||
##
|
||||
|
||||
from ropgadget.loaders.elf import *
|
||||
from ropgadget.loaders.pe import *
|
||||
from ropgadget.loaders.raw import *
|
||||
from ropgadget.loaders.macho import *
|
||||
from ropgadget.loaders.universal import *
|
||||
from binascii import unhexlify
|
||||
|
||||
class Binary(object):
|
||||
def __init__(self, options):
|
||||
self.__fileName = options.binary
|
||||
self.__rawBinary = None
|
||||
self.__binary = None
|
||||
|
||||
try:
|
||||
fd = open(self.__fileName, "rb")
|
||||
self.__rawBinary = fd.read()
|
||||
fd.close()
|
||||
except:
|
||||
print("[Error] Can't open the binary or binary not found")
|
||||
return None
|
||||
|
||||
if options.rawArch and options.rawMode:
|
||||
self.__binary = Raw(self.__rawBinary, options.rawArch, options.rawMode, options.rawEndian)
|
||||
elif self.__rawBinary[:4] == unhexlify(b"7f454c46"):
|
||||
self.__binary = ELF(self.__rawBinary)
|
||||
elif self.__rawBinary[:2] == unhexlify(b"4d5a"):
|
||||
self.__binary = PE(self.__rawBinary)
|
||||
elif self.__rawBinary[:4] == unhexlify(b"cafebabe"):
|
||||
self.__binary = UNIVERSAL(self.__rawBinary)
|
||||
elif self.__rawBinary[:4] == unhexlify(b"cefaedfe") or self.__rawBinary[:4] == unhexlify(b"cffaedfe"):
|
||||
self.__binary = MACHO(self.__rawBinary)
|
||||
else:
|
||||
print("[Error] Binary format not supported")
|
||||
return None
|
||||
|
||||
def getFileName(self):
|
||||
return self.__fileName
|
||||
|
||||
def getRawBinary(self):
|
||||
return self.__rawBinary
|
||||
|
||||
def getBinary(self):
|
||||
return self.__binary
|
||||
|
||||
def getEntryPoint(self):
|
||||
return self.__binary.getEntryPoint()
|
||||
|
||||
def getDataSections(self):
|
||||
return self.__binary.getDataSections()
|
||||
|
||||
def getExecSections(self):
|
||||
return self.__binary.getExecSections()
|
||||
|
||||
def getArch(self):
|
||||
return self.__binary.getArch()
|
||||
|
||||
def getArchMode(self):
|
||||
return self.__binary.getArchMode()
|
||||
|
||||
def getEndian(self):
|
||||
return self.__binary.getEndian()
|
||||
|
||||
def getFormat(self):
|
||||
return self.__binary.getFormat()
|
652
ROPgadget/ropgadget/core.py
Normal file
652
ROPgadget/ropgadget/core.py
Normal file
@ -0,0 +1,652 @@
|
||||
## -*- coding: utf-8 -*-
|
||||
##
|
||||
## Jonathan Salwan - 2014-05-17 - ROPgadget tool
|
||||
##
|
||||
## http://twitter.com/JonathanSalwan
|
||||
## http://shell-storm.org/project/ROPgadget/
|
||||
##
|
||||
|
||||
import cmd
|
||||
import os
|
||||
import re
|
||||
import codecs
|
||||
import ropgadget.rgutils as rgutils
|
||||
import binascii
|
||||
|
||||
from ropgadget.binary import Binary
|
||||
from capstone import CS_MODE_32
|
||||
from ropgadget.gadgets import Gadgets
|
||||
from ropgadget.options import Options
|
||||
from ropgadget.ropchain.ropmaker import ROPMaker
|
||||
|
||||
class Core(cmd.Cmd):
|
||||
def __init__(self, options):
|
||||
cmd.Cmd.__init__(self)
|
||||
self.__options = options
|
||||
self.__binary = None
|
||||
self.__gadgets = []
|
||||
self.__offset = 0
|
||||
self.prompt = '(ROPgadget)> '
|
||||
|
||||
|
||||
def __checksBeforeManipulations(self):
|
||||
if self.__binary == None or self.__binary.getBinary() == None or self.__binary.getArch() == None or self.__binary.getArchMode() == None or self.__binary.getEndian() == None:
|
||||
return False
|
||||
return True
|
||||
|
||||
def _sectionInRange(self, section):
|
||||
"""
|
||||
given a section and a range, edit the section so that all opcodes are within the range
|
||||
"""
|
||||
if self.__options.range == "0x0-0x0":
|
||||
return section
|
||||
|
||||
rangeStart, rangeEnd = map(lambda x:int(x, 16), self.__options.range.split('-'))
|
||||
|
||||
sectionStart = section['vaddr']
|
||||
sectionEnd = sectionStart + section['size']
|
||||
|
||||
opcodes = section['opcodes']
|
||||
if rangeEnd < sectionStart or rangeStart > sectionEnd:
|
||||
return None
|
||||
if rangeStart > sectionStart:
|
||||
diff = rangeStart - sectionStart
|
||||
opcodes = opcodes[diff:]
|
||||
section['vaddr'] += diff
|
||||
section['offset'] += diff
|
||||
section['size'] -= diff
|
||||
if rangeEnd < sectionEnd:
|
||||
diff = sectionEnd - rangeEnd
|
||||
opcodes = opcodes[:-diff]
|
||||
section['size'] -= diff
|
||||
|
||||
if not section['size']:
|
||||
return None
|
||||
section['opcodes'] = opcodes
|
||||
return section
|
||||
|
||||
def __getGadgets(self):
|
||||
if self.__checksBeforeManipulations() == False:
|
||||
return False
|
||||
|
||||
G = Gadgets(self.__binary, self.__options, self.__offset)
|
||||
execSections = self.__binary.getExecSections()
|
||||
|
||||
# Find ROP/JOP/SYS gadgets
|
||||
self.__gadgets = []
|
||||
for section in execSections:
|
||||
section = self._sectionInRange(section)
|
||||
if not section: continue
|
||||
if not self.__options.norop: self.__gadgets += G.addROPGadgets(section)
|
||||
if not self.__options.nojop: self.__gadgets += G.addJOPGadgets(section)
|
||||
if not self.__options.nosys: self.__gadgets += G.addSYSGadgets(section)
|
||||
|
||||
# Delete duplicate gadgets
|
||||
if not self.__options.all and not self.__options.noinstr:
|
||||
self.__gadgets = rgutils.deleteDuplicateGadgets(self.__gadgets)
|
||||
|
||||
# Applicate some Options
|
||||
self.__gadgets = Options(self.__options, self.__binary, self.__gadgets).getGadgets()
|
||||
|
||||
# Sorted alphabetically
|
||||
if not self.__options.noinstr:
|
||||
self.__gadgets = rgutils.alphaSortgadgets(self.__gadgets)
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def __lookingForGadgets(self):
|
||||
|
||||
if self.__checksBeforeManipulations() == False:
|
||||
return False
|
||||
|
||||
if self.__options.silent:
|
||||
return True
|
||||
|
||||
arch = self.__binary.getArchMode()
|
||||
print("Gadgets information\n============================================================")
|
||||
for gadget in self.__gadgets:
|
||||
vaddr = gadget["vaddr"]
|
||||
insts = gadget.get("gadget", "")
|
||||
bytesStr = " // " + binascii.hexlify(gadget["bytes"]).decode('utf8') if self.__options.dump else ""
|
||||
|
||||
print(("0x%08x" %(vaddr) if arch == CS_MODE_32 else "0x%016x" %(vaddr)) +
|
||||
(" : %s" %(insts) if insts else "") + bytesStr)
|
||||
|
||||
print("\nUnique gadgets found: %d" %(len(self.__gadgets)))
|
||||
return True
|
||||
|
||||
|
||||
def __lookingForAString(self, string):
|
||||
|
||||
if self.__checksBeforeManipulations() == False:
|
||||
return False
|
||||
|
||||
if self.__options.silent:
|
||||
return True
|
||||
|
||||
dataSections = self.__binary.getDataSections()
|
||||
arch = self.__binary.getArchMode()
|
||||
print("Strings information\n============================================================")
|
||||
for section in dataSections:
|
||||
section = self._sectionInRange(section)
|
||||
if not section: continue
|
||||
allRef = [m.start() for m in re.finditer(string.encode(), section["opcodes"])]
|
||||
for ref in allRef:
|
||||
vaddr = self.__offset + section["vaddr"] + ref
|
||||
match = section["opcodes"][ref:ref+len(string)]
|
||||
print(("0x%08x" %(vaddr) if arch == CS_MODE_32 else "0x%016x" %(vaddr)) + " : %s" %(match.decode()))
|
||||
return True
|
||||
|
||||
|
||||
def __lookingForOpcodes(self, opcodes):
|
||||
import binascii
|
||||
|
||||
if self.__checksBeforeManipulations() == False:
|
||||
return False
|
||||
|
||||
if self.__options.silent:
|
||||
return True
|
||||
|
||||
execSections = self.__binary.getExecSections()
|
||||
arch = self.__binary.getArchMode()
|
||||
print("Opcodes information\n============================================================")
|
||||
for section in execSections:
|
||||
section = self._sectionInRange(section)
|
||||
if not section: continue
|
||||
allRef = [m.start() for m in re.finditer(re.escape(binascii.unhexlify(opcodes)), section["opcodes"])]
|
||||
for ref in allRef:
|
||||
vaddr = self.__offset + section["vaddr"] + ref
|
||||
print(("0x%08x" %(vaddr) if arch == CS_MODE_32 else "0x%016x" %(vaddr)) + " : %s" %(opcodes))
|
||||
return True
|
||||
|
||||
|
||||
def __lookingForMemStr(self, memstr):
|
||||
if self.__checksBeforeManipulations() == False:
|
||||
return False
|
||||
|
||||
if self.__options.silent:
|
||||
return True
|
||||
|
||||
sections = self.__binary.getExecSections()
|
||||
sections += self.__binary.getDataSections()
|
||||
arch = self.__binary.getArchMode()
|
||||
print("Memory bytes information\n=======================================================")
|
||||
chars = list(memstr)
|
||||
for char in chars:
|
||||
try:
|
||||
for section in sections:
|
||||
section = self._sectionInRange(section)
|
||||
if not section: continue
|
||||
allRef = [m.start() for m in re.finditer(char.encode('utf-8'), section["opcodes"])]
|
||||
for ref in allRef:
|
||||
vaddr = self.__offset + section["vaddr"] + ref
|
||||
print(("0x%08x" %(vaddr) if arch == CS_MODE_32 else "0x%016x" %(vaddr)) + " : '%c'" %(char))
|
||||
raise
|
||||
except:
|
||||
pass
|
||||
return True
|
||||
|
||||
|
||||
def analyze(self):
|
||||
|
||||
try:
|
||||
self.__offset = int(self.__options.offset, 16) if self.__options.offset else 0
|
||||
except ValueError:
|
||||
print("[Error] The offset must be in hexadecimal")
|
||||
return False
|
||||
|
||||
if self.__options.console:
|
||||
if self.__options.binary:
|
||||
self.__binary = Binary(self.__options)
|
||||
if self.__checksBeforeManipulations() == False:
|
||||
return False
|
||||
self.cmdloop()
|
||||
return True
|
||||
|
||||
self.__binary = Binary(self.__options)
|
||||
if self.__checksBeforeManipulations() == False:
|
||||
return False
|
||||
|
||||
if self.__options.string: return self.__lookingForAString(self.__options.string)
|
||||
elif self.__options.opcode: return self.__lookingForOpcodes(self.__options.opcode)
|
||||
elif self.__options.memstr: return self.__lookingForMemStr(self.__options.memstr)
|
||||
else:
|
||||
self.__getGadgets()
|
||||
self.__lookingForGadgets()
|
||||
if self.__options.ropchain:
|
||||
ROPMaker(self.__binary, self.__gadgets, self.__offset)
|
||||
return True
|
||||
|
||||
|
||||
def gadgets(self):
|
||||
return self.__gadgets
|
||||
|
||||
|
||||
|
||||
|
||||
# Console methods ============================================
|
||||
|
||||
def do_binary(self, s, silent=False):
|
||||
# Do not split the filename with spaces since it might contain
|
||||
# whitespaces
|
||||
if len(s) == 0:
|
||||
if not silent:
|
||||
return self.help_binary()
|
||||
return False
|
||||
|
||||
binary = s
|
||||
|
||||
self.__options.binary = binary
|
||||
self.__binary = Binary(self.__options)
|
||||
if self.__checksBeforeManipulations() == False:
|
||||
return False
|
||||
|
||||
if not silent:
|
||||
print("[+] Binary loaded")
|
||||
|
||||
|
||||
def help_binary(self):
|
||||
print("Syntax: binary <file> -- Load a binary")
|
||||
return False
|
||||
|
||||
|
||||
def do_EOF(self, s, silent=False):
|
||||
return self.do_quit(s, silent)
|
||||
|
||||
def do_quit(self, s, silent=False):
|
||||
return True
|
||||
|
||||
|
||||
def help_quit(self):
|
||||
print("Syntax: quit -- Terminates the application")
|
||||
return False
|
||||
|
||||
|
||||
def do_load(self, s, silent=False):
|
||||
|
||||
if self.__binary == None:
|
||||
if not silent:
|
||||
print("[-] No binary loaded.")
|
||||
return False
|
||||
|
||||
if not silent:
|
||||
print("[+] Loading gadgets, please wait...")
|
||||
self.__getGadgets()
|
||||
|
||||
if not silent:
|
||||
print("[+] Gadgets loaded !")
|
||||
|
||||
|
||||
def help_load(self):
|
||||
print("Syntax: load -- Load all gadgets")
|
||||
return False
|
||||
|
||||
|
||||
def do_display(self, s, silent=False):
|
||||
self.__lookingForGadgets()
|
||||
|
||||
|
||||
def help_display(self):
|
||||
print("Syntax: display -- Display all gadgets loaded")
|
||||
return False
|
||||
|
||||
|
||||
def do_depth(self, s, silent=False):
|
||||
try:
|
||||
depth = int(s.split()[0])
|
||||
except:
|
||||
if not silent:
|
||||
return self.help_depth()
|
||||
return False
|
||||
if depth <= 0:
|
||||
if not silent:
|
||||
print("[-] The depth value must be > 0")
|
||||
return False
|
||||
self.__options.depth = int(depth)
|
||||
|
||||
if not silent:
|
||||
print("[+] Depth updated. You have to reload gadgets")
|
||||
|
||||
|
||||
def help_depth(self):
|
||||
print("Syntax: depth <value> -- Set the depth search engine")
|
||||
return False
|
||||
|
||||
|
||||
def do_badbytes(self, s, silent=False):
|
||||
try:
|
||||
bb = s.split()[0]
|
||||
except:
|
||||
if not silent:
|
||||
return self.help_badbytes()
|
||||
else:
|
||||
return False
|
||||
self.__options.badbytes = bb
|
||||
|
||||
if not silent:
|
||||
print("[+] Bad bytes updated. You have to reload gadgets")
|
||||
|
||||
|
||||
def help_badbytes(self):
|
||||
print("Syntax: badbytes <badbyte1|badbyte2...> -- ")
|
||||
return False
|
||||
|
||||
|
||||
def __withK(self, listK, gadget):
|
||||
if len(listK) == 0:
|
||||
return True
|
||||
for a in listK:
|
||||
if a not in gadget:
|
||||
return False
|
||||
return True
|
||||
|
||||
def __withoutK(self, listK, gadget):
|
||||
for a in listK:
|
||||
if a in gadget:
|
||||
return False
|
||||
return True
|
||||
|
||||
def do_search(self, s, silent=False):
|
||||
args = s.split()
|
||||
if not len(args):
|
||||
return self.help_search()
|
||||
withK, withoutK = [], []
|
||||
for a in args:
|
||||
if a[0:1] == "!":
|
||||
withoutK += [a[1:]]
|
||||
else:
|
||||
withK += [a]
|
||||
if self.__checksBeforeManipulations() == False:
|
||||
if not silent:
|
||||
print("[-] You have to load a binary")
|
||||
return False
|
||||
arch = self.__binary.getArchMode()
|
||||
for gadget in self.__gadgets:
|
||||
vaddr = gadget["vaddr"]
|
||||
insts = gadget["gadget"]
|
||||
if self.__withK(withK, insts) and self.__withoutK(withoutK, insts):
|
||||
# What to do if silent = True?
|
||||
print(("0x%08x" %(vaddr) if arch == CS_MODE_32 else "0x%016x" %(vaddr)) + " : %s" %(insts))
|
||||
|
||||
|
||||
def help_search(self):
|
||||
print("Syntax: search <keyword1 keyword2 keyword3...> -- Filter with or without keywords")
|
||||
print("keyword = with")
|
||||
print("!keyword = without")
|
||||
return False
|
||||
|
||||
|
||||
def count(self):
|
||||
return len(self.__gadgets)
|
||||
|
||||
def do_count(self, s, silent=False):
|
||||
if not silent:
|
||||
print("[+] %d loaded gadgets." % self.count())
|
||||
|
||||
|
||||
def help_count(self):
|
||||
print("Shows the number of loaded gadgets.")
|
||||
return False
|
||||
|
||||
|
||||
def do_filter(self, s, silent=False):
|
||||
try:
|
||||
self.__options.filter = s.split()[0]
|
||||
except:
|
||||
if not silent:
|
||||
return self.help_filter()
|
||||
return False
|
||||
|
||||
if not silent:
|
||||
print("[+] Filter setted. You have to reload gadgets")
|
||||
|
||||
|
||||
def help_filter(self):
|
||||
print("Syntax: filter <filter1|filter2|...> - Suppress specific mnemonics")
|
||||
return False
|
||||
|
||||
|
||||
def do_only(self, s, silent=False):
|
||||
try:
|
||||
if s.lower() == "none":
|
||||
self.__options.only = None
|
||||
else:
|
||||
self.__options.only = s.split()[0]
|
||||
except:
|
||||
if not silent:
|
||||
return self.help_only()
|
||||
return False
|
||||
|
||||
if not silent:
|
||||
print("[+] Only setted. You have to reload gadgets")
|
||||
|
||||
|
||||
def help_only(self):
|
||||
print("Syntax: only <only1|only2|...> - Only show specific instructions")
|
||||
return False
|
||||
|
||||
|
||||
def do_range(self, s, silent=False):
|
||||
try:
|
||||
rangeS = int(s.split('-')[0], 16)
|
||||
rangeE = int(s.split('-')[1], 16)
|
||||
self.__options.range = s.split()[0]
|
||||
except:
|
||||
if not silent:
|
||||
return self.help_range()
|
||||
return False
|
||||
|
||||
if rangeS > rangeE:
|
||||
if not silent:
|
||||
print("[-] The start value must be greater than the end value")
|
||||
return False
|
||||
|
||||
if not silent:
|
||||
print("[+] Range setted. You have to reload gadgets")
|
||||
|
||||
|
||||
def help_range(self):
|
||||
print("Syntax: range <start-and> - Search between two addresses (0x...-0x...)")
|
||||
return False
|
||||
|
||||
|
||||
def do_settings(self, s, silent=False):
|
||||
print("All: %s" %(self.__options.all))
|
||||
print("Badbytes: %s" %(self.__options.badbytes))
|
||||
print("Binary: %s" %(self.__options.binary))
|
||||
print("Depth: %s" %(self.__options.depth))
|
||||
print("Filter: %s" %(self.__options.filter))
|
||||
print("Memstr: %s" %(self.__options.memstr))
|
||||
print("MultiBr: %s" %(self.__options.multibr))
|
||||
print("NoJOP: %s" %(self.__options.nojop))
|
||||
print("NoROP: %s" %(self.__options.norop))
|
||||
print("NoSYS: %s" %(self.__options.nosys))
|
||||
print("Offset: %s" %(self.__options.offset))
|
||||
print("Only: %s" %(self.__options.only))
|
||||
print("Opcode: %s" %(self.__options.opcode))
|
||||
print("ROPchain: %s" %(self.__options.ropchain))
|
||||
print("Range: %s" %(self.__options.range))
|
||||
print("RawArch: %s" %(self.__options.rawArch))
|
||||
print("RawMode: %s" %(self.__options.rawMode))
|
||||
print("RawEndian: %s" %(self.__options.rawEndian))
|
||||
print("Re: %s" %(self.__options.re))
|
||||
print("String: %s" %(self.__options.string))
|
||||
print("Thumb: %s" %(self.__options.thumb))
|
||||
|
||||
def help_settings(self):
|
||||
print("Display setting's environment")
|
||||
return False
|
||||
|
||||
|
||||
def do_nojop(self, s, silent=False):
|
||||
try:
|
||||
arg = s.split()[0]
|
||||
except:
|
||||
return self.help_nojop()
|
||||
|
||||
if arg == "enable":
|
||||
self.__options.nojop = True
|
||||
if not silent:
|
||||
print("[+] NoJOP enable. You have to reload gadgets")
|
||||
|
||||
elif arg == "disable":
|
||||
self.__options.nojop = False
|
||||
if not silent:
|
||||
print("[+] NoJOP disable. You have to reload gadgets")
|
||||
|
||||
else:
|
||||
if not silent:
|
||||
return self.help_nojop()
|
||||
return False
|
||||
|
||||
|
||||
def help_nojop(self):
|
||||
print("Syntax: nojop <enable|disable> - Disable JOP search engin")
|
||||
return False
|
||||
|
||||
|
||||
def do_norop(self, s, silent=False):
|
||||
try:
|
||||
arg = s.split()[0]
|
||||
except:
|
||||
return self.help_norop()
|
||||
|
||||
if arg == "enable":
|
||||
self.__options.norop = True
|
||||
if not silent:
|
||||
print("[+] NoROP enable. You have to reload gadgets")
|
||||
|
||||
elif arg == "disable":
|
||||
self.__options.norop = False
|
||||
if not silent:
|
||||
print("[+] NoROP disable. You have to reload gadgets")
|
||||
|
||||
else:
|
||||
if not silent:
|
||||
return self.help_norop()
|
||||
return False
|
||||
|
||||
|
||||
def help_norop(self):
|
||||
print("Syntax: norop <enable|disable> - Disable ROP search engin")
|
||||
return False
|
||||
|
||||
|
||||
def do_nosys(self, s, silent=False):
|
||||
try:
|
||||
arg = s.split()[0]
|
||||
except:
|
||||
return self.help_nosys()
|
||||
|
||||
if arg == "enable":
|
||||
self.__options.nosys = True
|
||||
if not silent:
|
||||
print("[+] NoSYS enable. You have to reload gadgets")
|
||||
|
||||
elif arg == "disable":
|
||||
self.__options.nosys = False
|
||||
if not silent:
|
||||
print("[+] NoSYS disable. You have to reload gadgets")
|
||||
|
||||
else:
|
||||
if not silent:
|
||||
return self.help_nosys()
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def help_nosys(self):
|
||||
print("Syntax: nosys <enable|disable> - Disable SYS search engin")
|
||||
return False
|
||||
|
||||
|
||||
def do_thumb(self, s, silent=False):
|
||||
try:
|
||||
arg = s.split()[0]
|
||||
except:
|
||||
return self.help_thumb()
|
||||
|
||||
if arg == "enable":
|
||||
self.__options.thumb = True
|
||||
if not silent:
|
||||
print("[+] Thumb enable. You have to reload gadgets")
|
||||
|
||||
elif arg == "disable":
|
||||
self.__options.thumb = False
|
||||
if not silent:
|
||||
print("[+] Thumb disable. You have to reload gadgets")
|
||||
|
||||
else:
|
||||
if not silent:
|
||||
return self.help_thumb()
|
||||
return False
|
||||
|
||||
|
||||
def help_thumb(self):
|
||||
print("Syntax: thumb <enable|disable> - Use the thumb mode for the search engine (ARM only)")
|
||||
return False
|
||||
|
||||
|
||||
def do_all(self, s, silent=False):
|
||||
if s == "enable":
|
||||
self.__options.all = True
|
||||
if not silent:
|
||||
print("[+] Showing all gadgets enabled. You have to reload gadgets")
|
||||
|
||||
elif s == "disable":
|
||||
self.__options.all = False
|
||||
if not silent:
|
||||
print("[+] Showing all gadgets disabled. You have to reload gadgets")
|
||||
|
||||
else:
|
||||
if not silent:
|
||||
return self.help_all()
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def help_multibr(self):
|
||||
print("Syntax: multibr <enable|disable> - Enable/Disable multiple branch gadgets")
|
||||
return False
|
||||
|
||||
|
||||
def do_multibr(self, s, silent=False):
|
||||
if s == "enable":
|
||||
self.__options.multibr = True
|
||||
if not silent:
|
||||
print("[+] Multiple branch gadgets enabled. You have to reload gadgets")
|
||||
|
||||
elif s == "disable":
|
||||
self.__options.multibr = False
|
||||
if not silent:
|
||||
print("[+] Multiple branch gadgets disabled. You have to reload gadgets")
|
||||
|
||||
else:
|
||||
if not silent:
|
||||
return self.help_all()
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def help_all(self):
|
||||
print("Syntax: all <enable|disable - Show all gadgets (disable removing duplicate gadgets)")
|
||||
return False
|
||||
|
||||
|
||||
def help_re(self):
|
||||
print("Syntax: re <pattern1 | pattern2 |...> - Regular expression")
|
||||
return False
|
||||
|
||||
|
||||
def do_re(self, s, silent=False):
|
||||
if s.lower() == 'none':
|
||||
self.__options.re = None
|
||||
elif s == "":
|
||||
self.help_re()
|
||||
silent = True
|
||||
else:
|
||||
self.__options.re = s
|
||||
|
||||
if not silent:
|
||||
print("[+] Re setted. You have to reload gadgets")
|
358
ROPgadget/ropgadget/gadgets.py
Normal file
358
ROPgadget/ropgadget/gadgets.py
Normal file
@ -0,0 +1,358 @@
|
||||
## -*- coding: utf-8 -*-
|
||||
##
|
||||
## Jonathan Salwan - 2014-05-12 - ROPgadget tool
|
||||
##
|
||||
## http://twitter.com/JonathanSalwan
|
||||
## http://shell-storm.org/project/ROPgadget/
|
||||
##
|
||||
|
||||
import re
|
||||
from capstone import *
|
||||
|
||||
|
||||
class Gadgets(object):
|
||||
def __init__(self, binary, options, offset):
|
||||
self.__binary = binary
|
||||
self.__options = options
|
||||
self.__offset = offset
|
||||
self.__arch = self.__binary.getArch()
|
||||
|
||||
re_str = ""
|
||||
if self.__arch == CS_ARCH_X86:
|
||||
re_str = "db|int3"
|
||||
elif self.__arch == CS_ARCH_ARM64:
|
||||
re_str = "brk|smc|hvc"
|
||||
if self.__options.filter:
|
||||
if re_str:
|
||||
re_str += "|"
|
||||
re_str += self.__options.filter
|
||||
|
||||
self.__filterRE = re.compile("({})$".format(re_str)) if re_str else None
|
||||
|
||||
def __passCleanX86(self, decodes):
|
||||
br = ["ret", "retf", "int", "sysenter", "jmp", "call", "syscall"]
|
||||
|
||||
if decodes[-1][2] not in br:
|
||||
return True
|
||||
if not self.__options.multibr and any(mnemonic in br for _, _, mnemonic, _ in decodes[:-1]):
|
||||
return True
|
||||
if any("ret" in mnemonic for _, _, mnemonic, _ in decodes[:-1]):
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def __gadgetsFinding(self, section, gadgets, arch, mode):
|
||||
|
||||
PREV_BYTES = 9 # Number of bytes prior to the gadget to store.
|
||||
|
||||
opcodes = section["opcodes"]
|
||||
sec_vaddr = section["vaddr"]
|
||||
|
||||
ret = []
|
||||
md = Cs(arch, mode)
|
||||
for gad_op, gad_size, gad_align in gadgets:
|
||||
allRefRet = [m.start() for m in re.finditer(gad_op, opcodes)]
|
||||
for ref in allRefRet:
|
||||
end = ref + gad_size
|
||||
for i in range(self.__options.depth):
|
||||
start = ref - (i * gad_align)
|
||||
if (sec_vaddr+start) % gad_align == 0:
|
||||
code = opcodes[start:end]
|
||||
decodes = md.disasm_lite(code, sec_vaddr+ref)
|
||||
decodes = list(decodes)
|
||||
if sum(size for _, size, _, _ in decodes) != i*gad_align + gad_size:
|
||||
# We've read less instructions than planned so something went wrong
|
||||
continue
|
||||
if self.passClean(decodes):
|
||||
continue
|
||||
off = self.__offset
|
||||
vaddr = off+sec_vaddr+start
|
||||
g = {"vaddr" : vaddr}
|
||||
if not self.__options.noinstr:
|
||||
g["gadget"] = " ; ".join("{}{}{}".format(mnemonic, " " if op_str else "", op_str)
|
||||
for _, _, mnemonic, op_str in decodes).replace(" ", " ")
|
||||
if self.__options.callPreceded:
|
||||
prevBytesAddr = max(sec_vaddr, vaddr - PREV_BYTES)
|
||||
g["prev"] = opcodes[prevBytesAddr-sec_vaddr:vaddr-sec_vaddr]
|
||||
if self.__options.dump:
|
||||
g["bytes"] = code
|
||||
ret.append(g)
|
||||
return ret
|
||||
|
||||
def addROPGadgets(self, section):
|
||||
|
||||
arch = self.__binary.getArch()
|
||||
arch_mode = self.__binary.getArchMode()
|
||||
arch_endian = self.__binary.getEndian()
|
||||
|
||||
if arch == CS_ARCH_X86:
|
||||
gadgets = [
|
||||
[b"\xc3", 1, 1], # ret
|
||||
[b"\xc2[\x00-\xff]{2}", 3, 1], # ret <imm>
|
||||
[b"\xcb", 1, 1], # retf
|
||||
[b"\xca[\x00-\xff]{2}", 3, 1], # retf <imm>
|
||||
# MPX
|
||||
[b"\xf2\xc3", 2, 1], # ret
|
||||
[b"\xf2\xc2[\x00-\xff]{2}", 4, 1], # ret <imm>
|
||||
]
|
||||
|
||||
elif arch == CS_ARCH_MIPS: gadgets = [] # MIPS doesn't contains RET instruction set. Only JOP gadgets
|
||||
elif arch == CS_ARCH_PPC:
|
||||
if arch_endian == CS_MODE_BIG_ENDIAN:
|
||||
gadgets = [
|
||||
[b"\x4e\x80\x00\x20", 4, 4] # blr
|
||||
]
|
||||
else:
|
||||
gadgets = [
|
||||
[b"\x20\x00\x80\x4e", 4, 4] # blr
|
||||
]
|
||||
|
||||
elif arch == CS_ARCH_SPARC:
|
||||
if arch_endian == CS_MODE_BIG_ENDIAN:
|
||||
gadgets = [
|
||||
[b"\x81\xc3\xe0\x08", 4, 4], # retl
|
||||
[b"\x81\xc7\xe0\x08", 4, 4], # ret
|
||||
[b"\x81\xe8\x00\x00", 4, 4] # restore
|
||||
]
|
||||
else:
|
||||
gadgets = [
|
||||
[b"\x08\xe0\xc3\x81", 4, 4], # retl
|
||||
[b"\x08\xe0\xc7\x81", 4, 4], # ret
|
||||
[b"\x00\x00\xe8\x81", 4, 4] # restore
|
||||
]
|
||||
arch_mode = 0
|
||||
|
||||
elif arch == CS_ARCH_ARM: gadgets = [] # ARM doesn't contains RET instruction set. Only JOP gadgets
|
||||
elif arch == CS_ARCH_ARM64:
|
||||
if arch_endian == CS_MODE_BIG_ENDIAN:
|
||||
gadgets = [
|
||||
[b"\xd6\x5f\x03\xc0", 4, 4] # ret
|
||||
]
|
||||
else:
|
||||
gadgets = [
|
||||
[b"\xc0\x03\x5f\xd6", 4, 4] # ret
|
||||
]
|
||||
arch_mode = CS_MODE_ARM
|
||||
|
||||
else:
|
||||
print("Gadgets().addROPGadgets() - Architecture not supported")
|
||||
return None
|
||||
|
||||
if len(gadgets) > 0 :
|
||||
return self.__gadgetsFinding(section, gadgets, arch, arch_mode + arch_endian)
|
||||
return gadgets
|
||||
|
||||
|
||||
def addJOPGadgets(self, section):
|
||||
arch = self.__binary.getArch()
|
||||
arch_mode = self.__binary.getArchMode()
|
||||
arch_endian = self.__binary.getEndian()
|
||||
|
||||
|
||||
|
||||
if arch == CS_ARCH_X86:
|
||||
# we start with x86 and x64 common sequences operating on registers
|
||||
gadgets = [
|
||||
# call/jmp reg
|
||||
# d0-d7=call,e0-e7=jmp
|
||||
# x86: 0=eax,1=ecx,2=edx,3=ebx,4=esp,5=ebp,6=esi,7=edi
|
||||
# x64: 0=rax,1=rcx,2=rdx,3=rbx,4=rsp,5=rbp,6=rsi,7=rdi
|
||||
[b"\xff[\xd0-\xd7\xe0-\xe7]", 2, 1],
|
||||
|
||||
# call/jmp [reg]
|
||||
# 10-17=call,20-27=jmp
|
||||
# x86: 0=eax,1=ecx,2=edx,3=ebx, 6=esi,7=edi
|
||||
# x64: 0=rax,1=rcx,2=rdx,3=rbx, 6=rsi,7=rdi
|
||||
[b"\xff[\x10-\x13\x16-\x17\x20-\x23\x26-\x27]", 2, 1],
|
||||
# call/jmp [reg]
|
||||
# 14=call,24=jmp
|
||||
# x86: esp
|
||||
# x64: rsp
|
||||
[b"\xff[\x14\x24]\x24", 3, 1],
|
||||
|
||||
# call/jmp [reg + offset], -0x80 <= offset <= 0x7f
|
||||
# 50-57=call,60-67=jmp
|
||||
# x86: 0=eax,1=ecx,2=edx,3=ebx, 5=ebp,6=esi,7=edi
|
||||
# x64: 0=rax,1=rcx,2=rdx,3=rbx, 5=rbp,6=rsi,7=rdi
|
||||
[b"\xff[\x50-\x53\x55-\x57\x60-\x63\x65-\x67][\x00-\xff]", 3, 1],
|
||||
# call/jmp [reg + offset], -0x80 <= offset <= 0x7f
|
||||
# 54=call,64=jmp
|
||||
# x86: esp
|
||||
# x64: rsp
|
||||
[b"\xff[\x54\x64]\x24[\x00-\xff]", 4, 1],
|
||||
|
||||
# call/jmp [reg + offset], -0x80000000 <= offset <= 0x7fffffff
|
||||
# 90-97=call,a0-a7=jmp
|
||||
# x86: 0=eax,1=ecx,2=edx,3=ebx, 5=ebp,6=esi,7=edi
|
||||
# x64: 0=rax,1=rcx,2=rdx,3=rbx, 5=rbp,6=rsi,7=rdi
|
||||
[b"\xff[\x90-\x93\x95-\x97\xa0-\xa3\xa5-\xa7][\x00-\xff]{4}", 6, 1],
|
||||
# call/jmp [reg + offset], -0x80000000 <= offset <= 0x7fffffff
|
||||
# 94=call,a4=jmp
|
||||
# x86: esp
|
||||
# x64: rsp
|
||||
[b"\xff[\x94\xa4]\x24[\x00-\xff]{4}", 7, 1]
|
||||
]
|
||||
# in x64, by adding 41 before a sequence with
|
||||
# 0=rax,1=rcx,2=rdx,3=rbx,4=rsp,5=rbp,6=rsi,7=rdi
|
||||
# we convert it to the same sequence with
|
||||
# 0= r8,1= r9,2=r10,3=r11,4=r12,5=r13,6=r14,7=r15
|
||||
if arch_mode == CS_MODE_64:
|
||||
gadgets += [(b"\x41" + op, size + 1, align) for (op, size, align) in gadgets]
|
||||
# finally, add extra sequences common to x86 and x64
|
||||
gadgets += [
|
||||
[b"\xeb[\x00-\xff]", 2, 1], # jmp offset
|
||||
[b"\xe9[\x00-\xff]{4}", 5, 1], # jmp offset
|
||||
# MPX
|
||||
[b"\xf2\xff[\x20\x21\x22\x23\x26\x27]{1}", 3, 1], # jmp [reg]
|
||||
[b"\xf2\xff[\xe0\xe1\xe2\xe3\xe4\xe6\xe7]{1}", 3, 1], # jmp [reg]
|
||||
[b"\xf2\xff[\x10\x11\x12\x13\x16\x17]{1}", 3, 1], # jmp [reg]
|
||||
[b"\xf2\xff[\xd0\xd1\xd2\xd3\xd4\xd6\xd7]{1}", 3, 1] # call [reg]
|
||||
]
|
||||
|
||||
|
||||
elif arch == CS_ARCH_MIPS:
|
||||
if arch_endian == CS_MODE_BIG_ENDIAN:
|
||||
gadgets = [
|
||||
[b"\x00[\x40\x60\x80\xa0\xc0\xe0]\xf8\x09[\x00-\xff]{4}", 8, 4], # jalr $v[0-1]|$a[0-3]
|
||||
[b"[\x01\x02][\x00\x20\x40\x60\x80\xa0\xc0\xe0]\xf8\x09[\x00-\xff]{4}", 8, 4], # jalr $t[0-7]|$s[0-7]
|
||||
[b"\x03[\x00\x20\xc0\xe0]\xf8\x09[\x00-\xff]{4}", 8, 4], # jalr $t[8-9]|$s8|$ra
|
||||
[b"\x00[\x40\x60\x80\xa0\xc0\xe0]\x00\x08[\x00-\xff]{4}", 8, 4], # jr $v[0-1]|$a[0-3]
|
||||
[b"[\x01\x02][\x00\x20\x40\x60\x80\xa0\xc0\xe0]\x00\x08[\x00-\xff]{4}", 8, 4], # jr $t[0-7]|$s[0-7]
|
||||
[b"\x03[\x00\x20\xc0\xe0]\x00\x08[\x00-\xff]{4}", 8, 4], # jr $t[8-9]|$s8|$ra
|
||||
[b"[\x0c-\x0f][\x00-\xff]{7}", 8, 4], # jal addr
|
||||
[b"[\x08-\x0b][\x00-\xff]{7}", 8, 4] # j addr
|
||||
]
|
||||
else:
|
||||
gadgets = [
|
||||
[b"\x09\xf8[\x40\x60\x80\xa0\xc0\xe0]\x00[\x00-\xff]{4}", 8, 4], # jalr $v[0-1]|$a[0-3]
|
||||
[b"\x09\xf8[\x00\x20\x40\x60\x80\xa0\xc0\xe0][\x01\x02][\x00-\xff]{4}", 8, 4], # jalr $t[0-7]|$s[0-7]
|
||||
[b"\x09\xf8[\x00\x20\xc0\xe0]\x03[\x00-\xff]{4}", 8, 4], # jalr $t[8-9]|$s8|$ra
|
||||
[b"\x08\x00[\x40\x60\x80\xa0\xc0\xe0]\x00[\x00-\xff]{4}", 8, 4], # jr $v[0-1]|$a[0-3]
|
||||
[b"\x08\x00[\x00\x20\x40\x60\x80\xa0\xc0\xe0][\x01\x02][\x00-\xff]{4}", 8, 4], # jr $t[0-7]|$s[0-7]
|
||||
[b"\x08\x00[\x00\x20\xc0\xe0]\x03[\x00-\xff]{4}", 8, 4], # jr $t[8-9]|$s8|$ra
|
||||
[b"[\x00-\xff]{3}[\x0c-\x0f][\x00-\xff]{4}", 8, 4], # jal addr
|
||||
[b"[\x00-\xff]{3}[\x08-\x0b][\x00-\xff]{4}", 8, 4] # j addr
|
||||
]
|
||||
elif arch == CS_ARCH_PPC: gadgets = [] # PPC architecture doesn't contains reg branch instruction
|
||||
elif arch == CS_ARCH_SPARC:
|
||||
if arch_endian == CS_MODE_BIG_ENDIAN:
|
||||
gadgets = [
|
||||
[b"\x81\xc0[\x00\x40\x80\xc0]{1}\x00", 4, 4] # jmp %g[0-3]
|
||||
]
|
||||
else:
|
||||
gadgets = [
|
||||
[b"\x00[\x00\x40\x80\xc0]{1}\xc0\x81", 4, 4] # jmp %g[0-3]
|
||||
]
|
||||
arch_mode = 0
|
||||
elif arch == CS_ARCH_ARM64:
|
||||
if arch_endian == CS_MODE_BIG_ENDIAN:
|
||||
gadgets = [
|
||||
[b"\xd6[\x1f\x5f]{1}[\x00-\x03]{1}[\x00\x20\x40\x60\x80\xa0\xc0\xe0]{1}", 4, 4], # br reg
|
||||
[b"\xd6\?[\x00-\x03]{1}[\x00\x20\x40\x60\x80\xa0\xc0\xe0]{1}", 4, 4] # blr reg
|
||||
]
|
||||
else:
|
||||
gadgets = [
|
||||
[b"[\x00\x20\x40\x60\x80\xa0\xc0\xe0]{1}[\x00-\x03]{1}[\x1f\x5f]{1}\xd6", 4, 4], # br reg
|
||||
[b"[\x00\x20\x40\x60\x80\xa0\xc0\xe0]{1}[\x00-\x03]{1}\?\xd6", 4, 4] # blr reg
|
||||
]
|
||||
arch_mode = CS_MODE_ARM
|
||||
elif arch == CS_ARCH_ARM:
|
||||
if self.__options.thumb or self.__options.rawMode == "thumb":
|
||||
if arch_endian == CS_MODE_BIG_ENDIAN:
|
||||
gadgets = [
|
||||
[b"\x47[\x00\x08\x10\x18\x20\x28\x30\x38\x40\x48\x70]{1}", 2, 2], # bx reg
|
||||
[b"\x47[\x80\x88\x90\x98\xa0\xa8\xb0\xb8\xc0\xc8\xf0]{1}", 2, 2], # blx reg
|
||||
[b"\xbd[\x00-\xff]{1}", 2, 2] # pop {,pc}
|
||||
]
|
||||
else:
|
||||
gadgets = [
|
||||
[b"[\x00\x08\x10\x18\x20\x28\x30\x38\x40\x48\x70]{1}\x47", 2, 2], # bx reg
|
||||
[b"[\x80\x88\x90\x98\xa0\xa8\xb0\xb8\xc0\xc8\xf0]{1}\x47", 2, 2], # blx reg
|
||||
[b"[\x00-\xff]{1}\xbd", 2, 2] # pop {,pc}
|
||||
]
|
||||
arch_mode = CS_MODE_THUMB
|
||||
else:
|
||||
if arch_endian == CS_MODE_BIG_ENDIAN:
|
||||
gadgets = [
|
||||
[b"\xe1\x2f\xff[\x10-\x19\x1e]{1}", 4, 4], # bx reg
|
||||
[b"\xe1\x2f\xff[\x30-\x39\x3e]{1}", 4, 4], # blx reg
|
||||
[b"[\xe8\xe9][\x10-\x1e\x30-\x3e\x50-\x5e\x70-\x7e\x90-\x9e\xb0-\xbe\xd0-\xde\xf0-\xfe][\x80-\xff][\x00-\xff]", 4, 4] # ldm {,pc}
|
||||
]
|
||||
else:
|
||||
gadgets = [
|
||||
[b"[\x10-\x19\x1e]{1}\xff\x2f\xe1", 4, 4], # bx reg
|
||||
[b"[\x30-\x39\x3e]{1}\xff\x2f\xe1", 4, 4], # blx reg
|
||||
[b"[\x00-\xff][\x80-\xff][\x10-\x1e\x30-\x3e\x50-\x5e\x70-\x7e\x90-\x9e\xb0-\xbe\xd0-\xde\xf0-\xfe][\xe8\xe9]", 4, 4] # ldm {,pc}
|
||||
]
|
||||
arch_mode = CS_MODE_ARM
|
||||
else:
|
||||
print("Gadgets().addJOPGadgets() - Architecture not supported")
|
||||
return None
|
||||
|
||||
if len(gadgets) > 0 :
|
||||
return self.__gadgetsFinding(section, gadgets, arch, arch_mode + arch_endian)
|
||||
return gadgets
|
||||
|
||||
def addSYSGadgets(self, section):
|
||||
|
||||
arch = self.__binary.getArch()
|
||||
arch_mode = self.__binary.getArchMode()
|
||||
arch_endian = self.__binary.getEndian()
|
||||
|
||||
if arch == CS_ARCH_X86:
|
||||
gadgets = [
|
||||
[b"\xcd\x80", 2, 1], # int 0x80
|
||||
[b"\x0f\x34", 2, 1], # sysenter
|
||||
[b"\x0f\x05", 2, 1], # syscall
|
||||
[b"\x65\xff\x15\x10\x00\x00\x00", 7, 1], # call DWORD PTR gs:0x10
|
||||
[b"\xcd\x80\xc3", 3, 1], # int 0x80 ; ret
|
||||
[b"\x0f\x34\xc3", 3, 1], # sysenter ; ret
|
||||
[b"\x0f\x05\xc3", 3, 1], # syscall ; ret
|
||||
[b"\x65\xff\x15\x10\x00\x00\x00\xc3", 8, 1], # call DWORD PTR gs:0x10 ; ret
|
||||
]
|
||||
|
||||
elif arch == CS_ARCH_MIPS:
|
||||
if arch_endian == CS_MODE_BIG_ENDIAN:
|
||||
gadgets = [
|
||||
[b"\x00\x00\x00\x0c", 4, 4] # syscall
|
||||
]
|
||||
else:
|
||||
gadgets = [
|
||||
[b"\x0c\x00\x00\x00", 4, 4] # syscall
|
||||
]
|
||||
elif arch == CS_ARCH_PPC: gadgets = [] # TODO (sc inst)
|
||||
elif arch == CS_ARCH_SPARC: gadgets = [] # TODO (ta inst)
|
||||
elif arch == CS_ARCH_ARM64: gadgets = [] # TODO
|
||||
elif arch == CS_ARCH_ARM:
|
||||
if self.__options.thumb or self.__options.rawMode == "thumb":
|
||||
gadgets = [
|
||||
[b"\x00-\xff]{1}\xef", 2, 2] # FIXME: svc
|
||||
]
|
||||
arch_mode = CS_MODE_THUMB
|
||||
else:
|
||||
gadgets = [
|
||||
[b"\x00-\xff]{3}\xef", 4, 4] # FIXME: svc
|
||||
]
|
||||
arch_mode = CS_MODE_ARM
|
||||
else:
|
||||
print("Gadgets().addSYSGadgets() - Architecture not supported")
|
||||
return None
|
||||
|
||||
if len(gadgets) > 0 :
|
||||
return self.__gadgetsFinding(section, gadgets, arch, arch_mode + arch_endian)
|
||||
return []
|
||||
|
||||
|
||||
def passClean(self, decodes):
|
||||
|
||||
if not decodes:
|
||||
return True
|
||||
|
||||
if self.__arch == CS_ARCH_X86 and self.__passCleanX86(decodes):
|
||||
return True
|
||||
|
||||
if self.__filterRE and any(self.__filterRE.match(mnemonic) for _, _, mnemonic, _ in decodes):
|
||||
return True
|
||||
|
||||
return False
|
||||
|
12
ROPgadget/ropgadget/loaders/__init__.py
Normal file
12
ROPgadget/ropgadget/loaders/__init__.py
Normal file
@ -0,0 +1,12 @@
|
||||
## -*- coding: utf-8 -*-
|
||||
##
|
||||
## Jonathan Salwan - 2014-05-12 - ROPgadget tool
|
||||
##
|
||||
## http://twitter.com/JonathanSalwan
|
||||
## http://shell-storm.org/project/ROPgadget/
|
||||
##
|
||||
|
||||
import ropgadget.loaders.elf
|
||||
import ropgadget.loaders.macho
|
||||
import ropgadget.loaders.pe
|
||||
import ropgadget.loaders.raw
|
350
ROPgadget/ropgadget/loaders/elf.py
Normal file
350
ROPgadget/ropgadget/loaders/elf.py
Normal file
@ -0,0 +1,350 @@
|
||||
## -*- coding: utf-8 -*-
|
||||
##
|
||||
## Jonathan Salwan - 2014-05-12 - ROPgadget tool
|
||||
##
|
||||
## http://twitter.com/JonathanSalwan
|
||||
## http://shell-storm.org/project/ROPgadget/
|
||||
##
|
||||
|
||||
from capstone import *
|
||||
from ctypes import *
|
||||
from struct import unpack
|
||||
|
||||
class ELFFlags(object):
|
||||
ELFCLASS32 = 0x01
|
||||
ELFCLASS64 = 0x02
|
||||
EI_CLASS = 0x04
|
||||
EI_DATA = 0x05
|
||||
ELFDATA2LSB = 0x01
|
||||
ELFDATA2MSB = 0x02
|
||||
EM_386 = 0x03
|
||||
EM_X86_64 = 0x3e
|
||||
EM_ARM = 0x28
|
||||
EM_MIPS = 0x08
|
||||
EM_SPARCv8p = 0x12
|
||||
EM_PowerPC = 0x14
|
||||
EM_ARM64 = 0xb7
|
||||
|
||||
class Elf32_Ehdr_LSB(LittleEndianStructure):
|
||||
_fields_ = [
|
||||
("e_ident", c_ubyte * 16),
|
||||
("e_type", c_ushort),
|
||||
("e_machine", c_ushort),
|
||||
("e_version", c_uint),
|
||||
("e_entry", c_uint),
|
||||
("e_phoff", c_uint),
|
||||
("e_shoff", c_uint),
|
||||
("e_flags", c_uint),
|
||||
("e_ehsize", c_ushort),
|
||||
("e_phentsize", c_ushort),
|
||||
("e_phnum", c_ushort),
|
||||
("e_shentsize", c_ushort),
|
||||
("e_shnum", c_ushort),
|
||||
("e_shstrndx", c_ushort)
|
||||
]
|
||||
|
||||
class Elf64_Ehdr_LSB(LittleEndianStructure):
|
||||
_fields_ = [
|
||||
("e_ident", c_ubyte * 16),
|
||||
("e_type", c_ushort),
|
||||
("e_machine", c_ushort),
|
||||
("e_version", c_uint),
|
||||
("e_entry", c_ulonglong),
|
||||
("e_phoff", c_ulonglong),
|
||||
("e_shoff", c_ulonglong),
|
||||
("e_flags", c_uint),
|
||||
("e_ehsize", c_ushort),
|
||||
("e_phentsize", c_ushort),
|
||||
("e_phnum", c_ushort),
|
||||
("e_shentsize", c_ushort),
|
||||
("e_shnum", c_ushort),
|
||||
("e_shstrndx", c_ushort)
|
||||
]
|
||||
|
||||
class Elf32_Phdr_LSB(LittleEndianStructure):
|
||||
_fields_ = [
|
||||
("p_type", c_uint),
|
||||
("p_offset", c_uint),
|
||||
("p_vaddr", c_uint),
|
||||
("p_paddr", c_uint),
|
||||
("p_filesz", c_uint),
|
||||
("p_memsz", c_uint),
|
||||
("p_flags", c_uint),
|
||||
("p_align", c_uint)
|
||||
]
|
||||
|
||||
class Elf64_Phdr_LSB(LittleEndianStructure):
|
||||
_fields_ = [
|
||||
("p_type", c_uint),
|
||||
("p_flags", c_uint),
|
||||
("p_offset", c_ulonglong),
|
||||
("p_vaddr", c_ulonglong),
|
||||
("p_paddr", c_ulonglong),
|
||||
("p_filesz", c_ulonglong),
|
||||
("p_memsz", c_ulonglong),
|
||||
("p_align", c_ulonglong)
|
||||
]
|
||||
|
||||
class Elf32_Shdr_LSB(LittleEndianStructure):
|
||||
_fields_ = [
|
||||
("sh_name", c_uint),
|
||||
("sh_type", c_uint),
|
||||
("sh_flags", c_uint),
|
||||
("sh_addr", c_uint),
|
||||
("sh_offset", c_uint),
|
||||
("sh_size", c_uint),
|
||||
("sh_link", c_uint),
|
||||
("sh_info", c_uint),
|
||||
("sh_addralign", c_uint),
|
||||
("sh_entsize", c_uint)
|
||||
]
|
||||
|
||||
class Elf64_Shdr_LSB(LittleEndianStructure):
|
||||
_fields_ = [
|
||||
("sh_name", c_uint),
|
||||
("sh_type", c_uint),
|
||||
("sh_flags", c_ulonglong),
|
||||
("sh_addr", c_ulonglong),
|
||||
("sh_offset", c_ulonglong),
|
||||
("sh_size", c_ulonglong),
|
||||
("sh_link", c_uint),
|
||||
("sh_info", c_uint),
|
||||
("sh_addralign", c_ulonglong),
|
||||
("sh_entsize", c_ulonglong)
|
||||
]
|
||||
|
||||
class Elf32_Ehdr_MSB(BigEndianStructure):
|
||||
_fields_ = [
|
||||
("e_ident", c_ubyte * 16),
|
||||
("e_type", c_ushort),
|
||||
("e_machine", c_ushort),
|
||||
("e_version", c_uint),
|
||||
("e_entry", c_uint),
|
||||
("e_phoff", c_uint),
|
||||
("e_shoff", c_uint),
|
||||
("e_flags", c_uint),
|
||||
("e_ehsize", c_ushort),
|
||||
("e_phentsize", c_ushort),
|
||||
("e_phnum", c_ushort),
|
||||
("e_shentsize", c_ushort),
|
||||
("e_shnum", c_ushort),
|
||||
("e_shstrndx", c_ushort)
|
||||
]
|
||||
|
||||
class Elf64_Ehdr_MSB(BigEndianStructure):
|
||||
_fields_ = [
|
||||
("e_ident", c_ubyte * 16),
|
||||
("e_type", c_ushort),
|
||||
("e_machine", c_ushort),
|
||||
("e_version", c_uint),
|
||||
("e_entry", c_ulonglong),
|
||||
("e_phoff", c_ulonglong),
|
||||
("e_shoff", c_ulonglong),
|
||||
("e_flags", c_uint),
|
||||
("e_ehsize", c_ushort),
|
||||
("e_phentsize", c_ushort),
|
||||
("e_phnum", c_ushort),
|
||||
("e_shentsize", c_ushort),
|
||||
("e_shnum", c_ushort),
|
||||
("e_shstrndx", c_ushort)
|
||||
]
|
||||
|
||||
class Elf32_Phdr_MSB(BigEndianStructure):
|
||||
_fields_ = [
|
||||
("p_type", c_uint),
|
||||
("p_offset", c_uint),
|
||||
("p_vaddr", c_uint),
|
||||
("p_paddr", c_uint),
|
||||
("p_filesz", c_uint),
|
||||
("p_memsz", c_uint),
|
||||
("p_flags", c_uint),
|
||||
("p_align", c_uint)
|
||||
]
|
||||
|
||||
class Elf64_Phdr_MSB(BigEndianStructure):
|
||||
_fields_ = [
|
||||
("p_type", c_uint),
|
||||
("p_flags", c_uint),
|
||||
("p_offset", c_ulonglong),
|
||||
("p_vaddr", c_ulonglong),
|
||||
("p_paddr", c_ulonglong),
|
||||
("p_filesz", c_ulonglong),
|
||||
("p_memsz", c_ulonglong),
|
||||
("p_align", c_ulonglong)
|
||||
]
|
||||
|
||||
class Elf32_Shdr_MSB(BigEndianStructure):
|
||||
_fields_ = [
|
||||
("sh_name", c_uint),
|
||||
("sh_type", c_uint),
|
||||
("sh_flags", c_uint),
|
||||
("sh_addr", c_uint),
|
||||
("sh_offset", c_uint),
|
||||
("sh_size", c_uint),
|
||||
("sh_link", c_uint),
|
||||
("sh_info", c_uint),
|
||||
("sh_addralign", c_uint),
|
||||
("sh_entsize", c_uint)
|
||||
]
|
||||
|
||||
class Elf64_Shdr_MSB(BigEndianStructure):
|
||||
_fields_ = [
|
||||
("sh_name", c_uint),
|
||||
("sh_type", c_uint),
|
||||
("sh_flags", c_ulonglong),
|
||||
("sh_addr", c_ulonglong),
|
||||
("sh_offset", c_ulonglong),
|
||||
("sh_size", c_ulonglong),
|
||||
("sh_link", c_uint),
|
||||
("sh_info", c_uint),
|
||||
("sh_addralign", c_ulonglong),
|
||||
("sh_entsize", c_ulonglong)
|
||||
]
|
||||
|
||||
""" This class parses the ELF """
|
||||
class ELF(object):
|
||||
def __init__(self, binary):
|
||||
self.__binary = bytearray(binary)
|
||||
self.__ElfHeader = None
|
||||
self.__shdr_l = []
|
||||
self.__phdr_l = []
|
||||
|
||||
self.__setHeaderElf()
|
||||
self.__setShdr()
|
||||
self.__setPhdr()
|
||||
|
||||
""" Parse ELF header """
|
||||
def __setHeaderElf(self):
|
||||
e_ident = self.__binary[:15]
|
||||
|
||||
ei_class = e_ident[ELFFlags.EI_CLASS]
|
||||
ei_data = e_ident[ELFFlags.EI_DATA]
|
||||
|
||||
if ei_class != ELFFlags.ELFCLASS32 and ei_class != ELFFlags.ELFCLASS64:
|
||||
print("[Error] ELF.__setHeaderElf() - Bad Arch size")
|
||||
return None
|
||||
|
||||
if ei_data != ELFFlags.ELFDATA2LSB and ei_data != ELFFlags.ELFDATA2MSB:
|
||||
print("[Error] ELF.__setHeaderElf() - Bad architecture endian")
|
||||
return None
|
||||
|
||||
if ei_class == ELFFlags.ELFCLASS32:
|
||||
if ei_data == ELFFlags.ELFDATA2LSB: self.__ElfHeader = Elf32_Ehdr_LSB.from_buffer_copy(self.__binary)
|
||||
elif ei_data == ELFFlags.ELFDATA2MSB: self.__ElfHeader = Elf32_Ehdr_MSB.from_buffer_copy(self.__binary)
|
||||
elif ei_class == ELFFlags.ELFCLASS64:
|
||||
if ei_data == ELFFlags.ELFDATA2LSB: self.__ElfHeader = Elf64_Ehdr_LSB.from_buffer_copy(self.__binary)
|
||||
elif ei_data == ELFFlags.ELFDATA2MSB: self.__ElfHeader = Elf64_Ehdr_MSB.from_buffer_copy(self.__binary)
|
||||
|
||||
self.getArch() # Check if architecture is supported
|
||||
|
||||
""" Parse Section header """
|
||||
def __setShdr(self):
|
||||
shdr_num = self.__ElfHeader.e_shnum
|
||||
base = self.__binary[self.__ElfHeader.e_shoff:]
|
||||
shdr_l = []
|
||||
|
||||
e_ident = self.__binary[:15]
|
||||
ei_data = e_ident[ELFFlags.EI_DATA]
|
||||
|
||||
for i in range(shdr_num):
|
||||
|
||||
if self.getArchMode() == CS_MODE_32:
|
||||
if ei_data == ELFFlags.ELFDATA2LSB: shdr = Elf32_Shdr_LSB.from_buffer_copy(base)
|
||||
elif ei_data == ELFFlags.ELFDATA2MSB: shdr = Elf32_Shdr_MSB.from_buffer_copy(base)
|
||||
elif self.getArchMode() == CS_MODE_64:
|
||||
if ei_data == ELFFlags.ELFDATA2LSB: shdr = Elf64_Shdr_LSB.from_buffer_copy(base)
|
||||
elif ei_data == ELFFlags.ELFDATA2MSB: shdr = Elf64_Shdr_MSB.from_buffer_copy(base)
|
||||
|
||||
self.__shdr_l.append(shdr)
|
||||
base = base[self.__ElfHeader.e_shentsize:]
|
||||
|
||||
# setup name from the strings table
|
||||
if self.__ElfHeader.e_shstrndx != 0:
|
||||
string_table = bytes(self.__binary[(self.__shdr_l[self.__ElfHeader.e_shstrndx].sh_offset):])
|
||||
for i in range(shdr_num):
|
||||
self.__shdr_l[i].str_name = string_table[self.__shdr_l[i].sh_name:].split(b'\x00')[0].decode('utf8')
|
||||
|
||||
""" Parse Program header """
|
||||
def __setPhdr(self):
|
||||
pdhr_num = self.__ElfHeader.e_phnum
|
||||
base = self.__binary[self.__ElfHeader.e_phoff:]
|
||||
phdr_l = []
|
||||
|
||||
e_ident = self.__binary[:15]
|
||||
ei_data = e_ident[ELFFlags.EI_DATA]
|
||||
|
||||
for i in range(pdhr_num):
|
||||
if self.getArchMode() == CS_MODE_32:
|
||||
if ei_data == ELFFlags.ELFDATA2LSB: phdr = Elf32_Phdr_LSB.from_buffer_copy(base)
|
||||
elif ei_data == ELFFlags.ELFDATA2MSB: phdr = Elf32_Phdr_MSB.from_buffer_copy(base)
|
||||
elif self.getArchMode() == CS_MODE_64:
|
||||
if ei_data == ELFFlags.ELFDATA2LSB: phdr = Elf64_Phdr_LSB.from_buffer_copy(base)
|
||||
elif ei_data == ELFFlags.ELFDATA2MSB: phdr = Elf64_Phdr_MSB.from_buffer_copy(base)
|
||||
|
||||
self.__phdr_l.append(phdr)
|
||||
base = base[self.__ElfHeader.e_phentsize:]
|
||||
|
||||
def getEntryPoint(self):
|
||||
return self.__e_entry
|
||||
|
||||
def getExecSections(self):
|
||||
ret = []
|
||||
for segment in self.__phdr_l:
|
||||
if segment.p_flags & 0x1:
|
||||
ret += [{
|
||||
"offset" : segment.p_offset,
|
||||
"size" : segment.p_memsz,
|
||||
"vaddr" : segment.p_vaddr,
|
||||
"opcodes" : bytes(self.__binary[segment.p_offset:segment.p_offset+segment.p_memsz])
|
||||
}]
|
||||
return ret
|
||||
|
||||
def getDataSections(self):
|
||||
ret = []
|
||||
for section in self.__shdr_l:
|
||||
if not (section.sh_flags & 0x4) and (section.sh_flags & 0x2):
|
||||
ret += [{
|
||||
"name" : section.str_name,
|
||||
"offset" : section.sh_offset,
|
||||
"size" : section.sh_size,
|
||||
"vaddr" : section.sh_addr,
|
||||
"opcodes" : bytes(self.__binary[section.sh_offset:section.sh_offset+section.sh_size])
|
||||
}]
|
||||
return ret
|
||||
|
||||
def getArch(self):
|
||||
if self.__ElfHeader.e_machine == ELFFlags.EM_386 or self.__ElfHeader.e_machine == ELFFlags.EM_X86_64:
|
||||
return CS_ARCH_X86
|
||||
elif self.__ElfHeader.e_machine == ELFFlags.EM_ARM:
|
||||
return CS_ARCH_ARM
|
||||
elif self.__ElfHeader.e_machine == ELFFlags.EM_ARM64:
|
||||
return CS_ARCH_ARM64
|
||||
elif self.__ElfHeader.e_machine == ELFFlags.EM_MIPS:
|
||||
return CS_ARCH_MIPS
|
||||
elif self.__ElfHeader.e_machine == ELFFlags.EM_PowerPC:
|
||||
return CS_ARCH_PPC
|
||||
elif self.__ElfHeader.e_machine == ELFFlags.EM_SPARCv8p:
|
||||
return CS_ARCH_SPARC
|
||||
else:
|
||||
print("[Error] ELF.getArch() - Architecture not supported")
|
||||
return None
|
||||
|
||||
def getArchMode(self):
|
||||
if self.__ElfHeader.e_ident[ELFFlags.EI_CLASS] == ELFFlags.ELFCLASS32:
|
||||
return CS_MODE_32
|
||||
elif self.__ElfHeader.e_ident[ELFFlags.EI_CLASS] == ELFFlags.ELFCLASS64:
|
||||
return CS_MODE_64
|
||||
else:
|
||||
print("[Error] ELF.getArchMode() - Bad Arch size")
|
||||
return None
|
||||
|
||||
def getEndian(self):
|
||||
if self.__ElfHeader.e_ident[ELFFlags.EI_DATA] == ELFFlags.ELFDATA2LSB:
|
||||
return 0
|
||||
if self.__ElfHeader.e_ident[ELFFlags.EI_DATA] == ELFFlags.ELFDATA2MSB:
|
||||
return CS_MODE_BIG_ENDIAN
|
||||
print("[Error] ELF.getEndian() - Bad Endianness")
|
||||
return None
|
||||
|
||||
def getFormat(self):
|
||||
return "ELF"
|
211
ROPgadget/ropgadget/loaders/macho.py
Normal file
211
ROPgadget/ropgadget/loaders/macho.py
Normal file
@ -0,0 +1,211 @@
|
||||
## -*- coding: utf-8 -*-
|
||||
##
|
||||
## Jonathan Salwan - 2014-05-12 - ROPgadget tool
|
||||
##
|
||||
## http://twitter.com/JonathanSalwan
|
||||
## http://shell-storm.org/project/ROPgadget/
|
||||
##
|
||||
|
||||
from capstone import *
|
||||
from ctypes import *
|
||||
|
||||
class MACH_HEADER(Structure):
|
||||
_fields_ = [
|
||||
("magic", c_uint),
|
||||
("cputype", c_uint),
|
||||
("cpusubtype", c_uint),
|
||||
("filetype", c_uint),
|
||||
("ncmds", c_uint),
|
||||
("sizeofcmds", c_uint),
|
||||
("flags", c_uint)
|
||||
]
|
||||
|
||||
class LOAD_COMMAND(Structure):
|
||||
_fields_ = [
|
||||
("cmd", c_uint),
|
||||
("cmdsize", c_uint)
|
||||
]
|
||||
|
||||
class SEGMENT_COMMAND(Structure):
|
||||
_fields_ = [
|
||||
("cmd", c_uint),
|
||||
("cmdsize", c_uint),
|
||||
("segname", c_ubyte * 16),
|
||||
("vmaddr", c_uint),
|
||||
("vmsize", c_uint),
|
||||
("fileoff", c_uint),
|
||||
("filesize", c_uint),
|
||||
("maxprot", c_uint),
|
||||
("initprot", c_uint),
|
||||
("nsects", c_uint),
|
||||
("flags", c_uint)
|
||||
]
|
||||
|
||||
class SEGMENT_COMMAND64(Structure):
|
||||
_fields_ = [
|
||||
("cmd", c_uint),
|
||||
("cmdsize", c_uint),
|
||||
("segname", c_ubyte * 16),
|
||||
("vmaddr", c_ulonglong),
|
||||
("vmsize", c_ulonglong),
|
||||
("fileoff", c_ulonglong),
|
||||
("filesize", c_ulonglong),
|
||||
("maxprot", c_uint),
|
||||
("initprot", c_uint),
|
||||
("nsects", c_uint),
|
||||
("flags", c_uint)
|
||||
]
|
||||
|
||||
class SECTION(Structure):
|
||||
_fields_ = [
|
||||
("sectname", c_ubyte * 16),
|
||||
("segname", c_ubyte * 16),
|
||||
("addr", c_uint),
|
||||
("size", c_uint),
|
||||
("offset", c_uint),
|
||||
("align", c_uint),
|
||||
("reloff", c_uint),
|
||||
("nreloc", c_uint),
|
||||
("flags", c_uint),
|
||||
("reserved1", c_uint),
|
||||
("reserved2", c_uint)
|
||||
]
|
||||
|
||||
class SECTION64(Structure):
|
||||
_fields_ = [
|
||||
("sectname", c_ubyte * 16),
|
||||
("segname", c_ubyte * 16),
|
||||
("addr", c_ulonglong),
|
||||
("size", c_ulonglong),
|
||||
("offset", c_uint),
|
||||
("align", c_uint),
|
||||
("reloff", c_uint),
|
||||
("nreloc", c_uint),
|
||||
("flags", c_uint),
|
||||
("reserved1", c_uint),
|
||||
("reserved2", c_uint)
|
||||
]
|
||||
|
||||
class MACHOFlags(object):
|
||||
CPU_TYPE_I386 = 0x7
|
||||
CPU_TYPE_X86_64 = (CPU_TYPE_I386 | 0x1000000)
|
||||
CPU_TYPE_MIPS = 0x8
|
||||
CPU_TYPE_ARM = 12
|
||||
CPU_TYPE_ARM64 = (CPU_TYPE_ARM | 0x1000000)
|
||||
CPU_TYPE_SPARC = 14
|
||||
CPU_TYPE_POWERPC = 18
|
||||
CPU_TYPE_POWERPC64 = (CPU_TYPE_POWERPC | 0x1000000)
|
||||
LC_SEGMENT = 0x1
|
||||
LC_SEGMENT_64 = 0x19
|
||||
S_ATTR_SOME_INSTRUCTIONS = 0x00000400
|
||||
S_ATTR_PURE_INSTRUCTIONS = 0x80000000
|
||||
|
||||
""" This class parses the Mach-O """
|
||||
class MACHO(object):
|
||||
def __init__(self, binary):
|
||||
self.__binary = bytearray(binary)
|
||||
|
||||
self.__machHeader = None
|
||||
self.__rawLoadCmd = None
|
||||
self.__sections_l = []
|
||||
|
||||
self.__setHeader()
|
||||
self.__setLoadCmd()
|
||||
|
||||
def __setHeader(self):
|
||||
self.__machHeader = MACH_HEADER.from_buffer_copy(self.__binary)
|
||||
|
||||
if self.getArchMode() == CS_MODE_32:
|
||||
self.__rawLoadCmd = self.__binary[28:28+self.__machHeader.sizeofcmds]
|
||||
|
||||
elif self.getArchMode() == CS_MODE_64:
|
||||
self.__rawLoadCmd = self.__binary[32:32+self.__machHeader.sizeofcmds]
|
||||
|
||||
def __setLoadCmd(self):
|
||||
base = self.__rawLoadCmd
|
||||
for i in range(self.__machHeader.ncmds):
|
||||
command = LOAD_COMMAND.from_buffer_copy(base)
|
||||
|
||||
if command.cmd == MACHOFlags.LC_SEGMENT:
|
||||
segment = SEGMENT_COMMAND.from_buffer_copy(base)
|
||||
self.__setSections(segment, base[56:], 32)
|
||||
|
||||
elif command.cmd == MACHOFlags.LC_SEGMENT_64:
|
||||
segment = SEGMENT_COMMAND64.from_buffer_copy(base)
|
||||
self.__setSections(segment, base[72:], 64)
|
||||
|
||||
base = base[command.cmdsize:]
|
||||
|
||||
def __setSections(self, segment, base, sizeHeader):
|
||||
for i in range(segment.nsects):
|
||||
if sizeHeader == 32:
|
||||
section = SECTION.from_buffer_copy(base)
|
||||
section.offset = segment.fileoff + section.addr - segment.vmaddr
|
||||
base = base[68:]
|
||||
self.__sections_l += [section]
|
||||
elif sizeHeader == 64:
|
||||
section = SECTION64.from_buffer_copy(base)
|
||||
section.offset = segment.fileoff + section.addr - segment.vmaddr
|
||||
base = base[80:]
|
||||
self.__sections_l += [section]
|
||||
|
||||
def getEntryPoint(self):
|
||||
for section in self.__sections_l:
|
||||
if section.sectname[0:6] == "__text":
|
||||
return section.addr
|
||||
|
||||
def getExecSections(self):
|
||||
ret = []
|
||||
for section in self.__sections_l:
|
||||
if section.flags & MACHOFlags.S_ATTR_SOME_INSTRUCTIONS or section.flags & MACHOFlags.S_ATTR_PURE_INSTRUCTIONS:
|
||||
ret += [{
|
||||
"name" : section.sectname,
|
||||
"offset" : section.offset,
|
||||
"size" : section.size,
|
||||
"vaddr" : section.addr,
|
||||
"opcodes" : bytes(self.__binary[section.offset:section.offset+section.size])
|
||||
}]
|
||||
return ret
|
||||
|
||||
def getDataSections(self):
|
||||
ret = []
|
||||
for section in self.__sections_l:
|
||||
if not section.flags & MACHOFlags.S_ATTR_SOME_INSTRUCTIONS and not section.flags & MACHOFlags.S_ATTR_PURE_INSTRUCTIONS:
|
||||
ret += [{
|
||||
"name" : section.sectname,
|
||||
"offset" : section.offset,
|
||||
"size" : section.size,
|
||||
"vaddr" : section.addr,
|
||||
"opcodes" : bytes(self.__binary[section.offset:section.offset+section.size])
|
||||
}]
|
||||
return ret
|
||||
|
||||
def getArch(self):
|
||||
if self.__machHeader.cputype == MACHOFlags.CPU_TYPE_I386 or self.__machHeader.cputype == MACHOFlags.CPU_TYPE_X86_64:
|
||||
return CS_ARCH_X86
|
||||
if self.__machHeader.cputype == MACHOFlags.CPU_TYPE_ARM:
|
||||
return CS_ARCH_ARM
|
||||
if self.__machHeader.cputype == MACHOFlags.CPU_TYPE_ARM64:
|
||||
return CS_ARCH_ARM64
|
||||
if self.__machHeader.cputype == MACHOFlags.CPU_TYPE_MIPS:
|
||||
return CS_ARCH_MIPS
|
||||
else:
|
||||
print("[Error] MACHO.getArch() - Architecture not supported")
|
||||
return None
|
||||
|
||||
def getArchMode(self):
|
||||
if self.__machHeader.magic == 0xfeedface:
|
||||
return CS_MODE_32
|
||||
elif self.__machHeader.magic == 0xfeedfacf:
|
||||
return CS_MODE_64
|
||||
else:
|
||||
print("[Error] MACHO.getArchMode() - Bad Arch size")
|
||||
return None
|
||||
pass
|
||||
|
||||
def getEndian(self):
|
||||
# TODO: Support other endianness
|
||||
return 0
|
||||
|
||||
def getFormat(self):
|
||||
return "Mach-O"
|
233
ROPgadget/ropgadget/loaders/pe.py
Normal file
233
ROPgadget/ropgadget/loaders/pe.py
Normal file
@ -0,0 +1,233 @@
|
||||
## -*- coding: utf-8 -*-
|
||||
##
|
||||
## Jonathan Salwan - 2014-05-12 - ROPgadget tool
|
||||
##
|
||||
## http://twitter.com/JonathanSalwan
|
||||
## http://shell-storm.org/project/ROPgadget/
|
||||
##
|
||||
|
||||
from capstone import *
|
||||
from ctypes import *
|
||||
from struct import unpack
|
||||
from binascii import unhexlify
|
||||
|
||||
class PEFlags(object):
|
||||
IMAGE_MACHINE_INTEL_386 = 0x014c
|
||||
IMAGE_MACHINE_AMD_8664 = 0x8664
|
||||
IMAGE_FILE_MACHINE_ARM = 0x1c0
|
||||
IMAGE_FILE_MACHINE_ARMV7 = 0x1c4
|
||||
IMAGE_NT_OPTIONAL_HDR32_MAGIC = 0x10b
|
||||
IMAGE_NT_OPTIONAL_HDR64_MAGIC = 0x20b
|
||||
IMAGE_SIZEOF_SHORT_NAME = 0x8
|
||||
|
||||
class IMAGE_FILE_HEADER(Structure):
|
||||
_fields_ = [
|
||||
("Magic", c_uint),
|
||||
("Machine", c_ushort),
|
||||
("NumberOfSections", c_ushort),
|
||||
("TimeDateStamp", c_uint),
|
||||
("PointerToSymbolTable", c_uint),
|
||||
("NumberOfSymbols", c_uint),
|
||||
("SizeOfOptionalHeader", c_ushort),
|
||||
("Characteristics", c_ushort)
|
||||
]
|
||||
|
||||
class IMAGE_OPTIONAL_HEADER(Structure):
|
||||
_fields_ = [
|
||||
("Magic", c_ushort),
|
||||
("MajorLinkerVersion", c_ubyte),
|
||||
("MinorLinkerVersion", c_ubyte),
|
||||
("SizeOfCode", c_uint),
|
||||
("SizeOfInitializedData", c_uint),
|
||||
("SizeOfUninitializedData", c_uint),
|
||||
("AddressOfEntryPoint", c_uint),
|
||||
("BaseOfCode", c_uint),
|
||||
("BaseOfData", c_uint),
|
||||
("ImageBase", c_uint),
|
||||
("SectionAlignment", c_uint),
|
||||
("FileAlignment", c_uint),
|
||||
("MajorOperatingSystemVersion", c_ushort),
|
||||
("MinorOperatingSystemVersion", c_ushort),
|
||||
("MajorImageVersion", c_ushort),
|
||||
("MinorImageVersion", c_ushort),
|
||||
("MajorSubsystemVersion", c_ushort),
|
||||
("MinorSubsystemVersion", c_ushort),
|
||||
("Win32VersionValue", c_uint),
|
||||
("SizeOfImage", c_uint),
|
||||
("SizeOfHeaders", c_uint),
|
||||
("CheckSum", c_uint),
|
||||
("Subsystem", c_ushort),
|
||||
("DllCharacteristics", c_ushort),
|
||||
("SizeOfStackReserve", c_uint),
|
||||
("SizeOfStackCommit", c_uint),
|
||||
("SizeOfHeapReserve", c_uint),
|
||||
("SizeOfHeapCommit", c_uint),
|
||||
("LoaderFlags", c_uint),
|
||||
("NumberOfRvaAndSizes", c_uint)
|
||||
]
|
||||
|
||||
class IMAGE_OPTIONAL_HEADER64(Structure):
|
||||
_fields_ = [
|
||||
("Magic", c_ushort),
|
||||
("MajorLinkerVersion", c_ubyte),
|
||||
("MinorLinkerVersion", c_ubyte),
|
||||
("SizeOfCode", c_uint),
|
||||
("SizeOfInitializedData", c_uint),
|
||||
("SizeOfUninitializedData", c_uint),
|
||||
("AddressOfEntryPoint", c_uint),
|
||||
("BaseOfCode", c_uint),
|
||||
("ImageBase", c_ulonglong),
|
||||
("SectionAlignment", c_uint),
|
||||
("FileAlignment", c_uint),
|
||||
("MajorOperatingSystemVersion", c_ushort),
|
||||
("MinorOperatingSystemVersion", c_ushort),
|
||||
("MajorImageVersion", c_ushort),
|
||||
("MinorImageVersion", c_ushort),
|
||||
("MajorSubsystemVersion", c_ushort),
|
||||
("MinorSubsystemVersion", c_ushort),
|
||||
("Win32VersionValue", c_uint),
|
||||
("SizeOfImage", c_uint),
|
||||
("SizeOfHeaders", c_uint),
|
||||
("CheckSum", c_uint),
|
||||
("Subsystem", c_ushort),
|
||||
("DllCharacteristics", c_ushort),
|
||||
("SizeOfStackReserve", c_ulonglong),
|
||||
("SizeOfStackCommit", c_ulonglong),
|
||||
("SizeOfHeapReserve", c_ulonglong),
|
||||
("SizeOfHeapCommit", c_ulonglong),
|
||||
("LoaderFlags", c_uint),
|
||||
("NumberOfRvaAndSizes", c_uint)
|
||||
]
|
||||
|
||||
class IMAGE_NT_HEADERS(Structure):
|
||||
_fields_ = [
|
||||
("Signature", c_uint),
|
||||
("FileHeader", IMAGE_FILE_HEADER),
|
||||
("OptionalHeader", IMAGE_OPTIONAL_HEADER)
|
||||
]
|
||||
|
||||
class IMAGE_NT_HEADERS64(Structure):
|
||||
_fields_ = [
|
||||
("Signature", c_uint),
|
||||
("FileHeader", IMAGE_FILE_HEADER),
|
||||
("OptionalHeader", IMAGE_OPTIONAL_HEADER64)
|
||||
]
|
||||
|
||||
class IMAGE_SECTION_HEADER(Structure):
|
||||
_fields_ = [
|
||||
("Name", c_ubyte * PEFlags.IMAGE_SIZEOF_SHORT_NAME),
|
||||
("PhysicalAddress", c_uint),
|
||||
("VirtualAddress", c_uint),
|
||||
("SizeOfRawData", c_uint),
|
||||
("PointerToRawData", c_uint),
|
||||
("PointerToRelocations", c_uint),
|
||||
("PointerToLinenumbers", c_uint),
|
||||
("NumberOfRelocations", c_ushort),
|
||||
("NumberOfLinenumbers", c_ushort),
|
||||
("Characteristics", c_uint)
|
||||
]
|
||||
|
||||
""" This class parses the PE format """
|
||||
class PE(object):
|
||||
def __init__(self, binary):
|
||||
self.__binary = bytearray(binary)
|
||||
|
||||
self.__PEOffset = 0x00000000
|
||||
self.__IMAGE_FILE_HEADER = None
|
||||
self.__IMAGE_OPTIONAL_HEADER = None
|
||||
|
||||
self.__sections_l = []
|
||||
|
||||
self.__getPEOffset()
|
||||
self.__parsePEHeader()
|
||||
self.__parseOptHeader()
|
||||
self.__parseSections()
|
||||
|
||||
def __getPEOffset(self):
|
||||
self.__PEOffset = unpack("<I", bytes(self.__binary[60:64]))[0]
|
||||
if self.__binary[self.__PEOffset:self.__PEOffset+4] != unhexlify(b"50450000"):
|
||||
print("[Error] PE.__getPEOffset() - Bad PE signature")
|
||||
return None
|
||||
|
||||
def __parsePEHeader(self):
|
||||
PEheader = self.__binary[self.__PEOffset:]
|
||||
self.__IMAGE_FILE_HEADER = IMAGE_FILE_HEADER.from_buffer_copy(PEheader)
|
||||
|
||||
def __parseOptHeader(self):
|
||||
PEoptHeader = self.__binary[self.__PEOffset+24:self.__PEOffset+24+self.__IMAGE_FILE_HEADER.SizeOfOptionalHeader]
|
||||
|
||||
if unpack("<H", bytes(PEoptHeader[0:2]))[0] == PEFlags.IMAGE_NT_OPTIONAL_HDR32_MAGIC:
|
||||
self.__IMAGE_OPTIONAL_HEADER = IMAGE_OPTIONAL_HEADER.from_buffer_copy(PEoptHeader)
|
||||
|
||||
elif unpack("<H", bytes(PEoptHeader[0:2]))[0] == PEFlags.IMAGE_NT_OPTIONAL_HDR64_MAGIC:
|
||||
self.__IMAGE_OPTIONAL_HEADER = IMAGE_OPTIONAL_HEADER64.from_buffer_copy(PEoptHeader)
|
||||
|
||||
else:
|
||||
print("[Error] PE.__parseOptHeader - Bad size header")
|
||||
return None
|
||||
|
||||
def __parseSections(self):
|
||||
baseSections = self.__PEOffset+24+self.__IMAGE_FILE_HEADER.SizeOfOptionalHeader
|
||||
sizeSections = self.__IMAGE_FILE_HEADER.NumberOfSections * sizeof(IMAGE_SECTION_HEADER)
|
||||
base = self.__binary[baseSections:baseSections+sizeSections]
|
||||
|
||||
for i in range(self.__IMAGE_FILE_HEADER.NumberOfSections):
|
||||
sec = IMAGE_SECTION_HEADER.from_buffer_copy(base)
|
||||
base = base[sizeof(IMAGE_SECTION_HEADER):]
|
||||
self.__sections_l += [sec]
|
||||
|
||||
return 0
|
||||
|
||||
def getEntryPoint(self):
|
||||
return self.__IMAGE_OPTIONAL_HEADER.ImageBase + self.__IMAGE_OPTIONAL_HEADER.AddressOfEntryPoint
|
||||
|
||||
def getDataSections(self):
|
||||
ret = []
|
||||
for section in self.__sections_l:
|
||||
if section.Characteristics & 0x80000000:
|
||||
ret += [{
|
||||
"name" : section.Name,
|
||||
"offset" : section.PointerToRawData,
|
||||
"size" : section.SizeOfRawData,
|
||||
"vaddr" : section.VirtualAddress + self.__IMAGE_OPTIONAL_HEADER.ImageBase,
|
||||
"opcodes" : bytes(self.__binary[section.PointerToRawData:section.PointerToRawData+section.SizeOfRawData])
|
||||
}]
|
||||
return ret
|
||||
|
||||
def getExecSections(self):
|
||||
ret = []
|
||||
for section in self.__sections_l:
|
||||
if section.Characteristics & 0x20000000:
|
||||
ret += [{
|
||||
"name" : section.Name,
|
||||
"offset" : section.PointerToRawData,
|
||||
"size" : section.SizeOfRawData,
|
||||
"vaddr" : section.VirtualAddress + self.__IMAGE_OPTIONAL_HEADER.ImageBase,
|
||||
"opcodes" : bytes(self.__binary[section.PointerToRawData:section.PointerToRawData+section.SizeOfRawData])
|
||||
}]
|
||||
return ret
|
||||
|
||||
def getArch(self):
|
||||
if self.__IMAGE_FILE_HEADER.Machine == PEFlags.IMAGE_MACHINE_INTEL_386 or self.__IMAGE_FILE_HEADER.Machine == PEFlags.IMAGE_MACHINE_AMD_8664:
|
||||
return CS_ARCH_X86
|
||||
if self.__IMAGE_FILE_HEADER.Machine == PEFlags.IMAGE_FILE_MACHINE_ARM or self.__IMAGE_FILE_HEADER.Machine == PEFlags.IMAGE_FILE_MACHINE_ARMV7:
|
||||
return CS_ARCH_ARM
|
||||
else:
|
||||
print("[Error] PE.getArch() - Bad Arch")
|
||||
return None
|
||||
|
||||
def getArchMode(self):
|
||||
if self.__IMAGE_OPTIONAL_HEADER.Magic == PEFlags.IMAGE_NT_OPTIONAL_HDR32_MAGIC:
|
||||
return CS_MODE_32
|
||||
elif self.__IMAGE_OPTIONAL_HEADER.Magic == PEFlags.IMAGE_NT_OPTIONAL_HDR64_MAGIC:
|
||||
return CS_MODE_64
|
||||
else:
|
||||
print("[Error] PE.getArch() - Bad arch size")
|
||||
return None
|
||||
|
||||
def getEndian(self):
|
||||
# PE is little-endian only
|
||||
return 0
|
||||
|
||||
def getFormat(self):
|
||||
return "PE"
|
72
ROPgadget/ropgadget/loaders/raw.py
Normal file
72
ROPgadget/ropgadget/loaders/raw.py
Normal file
@ -0,0 +1,72 @@
|
||||
## -*- coding: utf-8 -*-
|
||||
##
|
||||
## Jonathan Salwan - 2014-05-12
|
||||
##
|
||||
## http://shell-storm.org
|
||||
## http://twitter.com/JonathanSalwan
|
||||
##
|
||||
|
||||
from capstone import *
|
||||
|
||||
class Raw(object):
|
||||
def __init__(self, binary, arch, mode, endian):
|
||||
self.__binary = bytearray(binary)
|
||||
self.__arch = arch
|
||||
self.__mode = mode
|
||||
self.__endian = endian
|
||||
|
||||
def getEntryPoint(self):
|
||||
return 0x0
|
||||
|
||||
def getExecSections(self):
|
||||
return [{"name": "raw", "offset": 0x0, "size": len(self.__binary), "vaddr": 0x0, "opcodes": bytes(self.__binary)}]
|
||||
|
||||
def getDataSections(self):
|
||||
return []
|
||||
|
||||
def getArch(self):
|
||||
arch = {
|
||||
"x86": CS_ARCH_X86,
|
||||
"arm": CS_ARCH_ARM,
|
||||
"arm64": CS_ARCH_ARM64,
|
||||
"sparc": CS_ARCH_SPARC,
|
||||
"mips": CS_ARCH_MIPS,
|
||||
"ppc": CS_ARCH_PPC
|
||||
}
|
||||
try:
|
||||
ret = arch[self.__arch]
|
||||
except:
|
||||
print("[Error] Raw.getArch() - Architecture not supported. Only supported: x86 arm arm64 sparc mips ppc")
|
||||
return None
|
||||
return ret
|
||||
|
||||
def getArchMode(self):
|
||||
mode = {
|
||||
"32": CS_MODE_32,
|
||||
"64": CS_MODE_64,
|
||||
"arm": CS_MODE_ARM,
|
||||
"thumb": CS_MODE_THUMB
|
||||
}
|
||||
try:
|
||||
ret = mode[self.__mode]
|
||||
except:
|
||||
print("[Error] Raw.getArchMode() - Mode not supported. Only supported: 32 64 arm thumb")
|
||||
return None
|
||||
return ret
|
||||
|
||||
def getEndian(self):
|
||||
if self.getArch() == CS_ARCH_X86:
|
||||
return 0
|
||||
endian ={
|
||||
"little": 0,
|
||||
"big": CS_MODE_BIG_ENDIAN
|
||||
}
|
||||
try:
|
||||
ret = endian[self.__endian]
|
||||
except:
|
||||
print("[Error] Raw.getArchEndian() - Endianness not supported. Only supported: little big")
|
||||
return None
|
||||
return ret
|
||||
|
||||
def getFormat(self):
|
||||
return "Raw"
|
107
ROPgadget/ropgadget/loaders/universal.py
Normal file
107
ROPgadget/ropgadget/loaders/universal.py
Normal file
@ -0,0 +1,107 @@
|
||||
## -*- coding: utf-8 -*-
|
||||
##
|
||||
## Christoffer Brodd-Reijer - 2014-07-20 - ROPgadget tool
|
||||
##
|
||||
## http://twitter.com/ephracis
|
||||
## http://shell-storm.org/project/ROPgadget/
|
||||
##
|
||||
|
||||
import sys
|
||||
|
||||
from capstone import *
|
||||
from ctypes import *
|
||||
from binascii import *
|
||||
from ropgadget.loaders.macho import *
|
||||
|
||||
|
||||
class FAT_HEADER(BigEndianStructure):
|
||||
_fields_ = [
|
||||
("magic", c_uint),
|
||||
("nfat_arch", c_uint)
|
||||
]
|
||||
|
||||
class FAT_ARC(BigEndianStructure):
|
||||
_fields_ = [
|
||||
("cputype", c_uint),
|
||||
("cpusubtype", c_uint),
|
||||
("offset", c_uint),
|
||||
("size", c_uint),
|
||||
("align", c_uint)
|
||||
]
|
||||
|
||||
class MACHOFlags(object):
|
||||
CPU_TYPE_I386 = 0x7
|
||||
CPU_TYPE_X86_64 = (CPU_TYPE_I386 | 0x1000000)
|
||||
CPU_TYPE_MIPS = 0x8
|
||||
CPU_TYPE_ARM = 12
|
||||
CPU_TYPE_SPARC = 14
|
||||
CPU_TYPE_POWERPC = 18
|
||||
CPU_TYPE_POWERPC64 = (CPU_TYPE_POWERPC | 0x1000000)
|
||||
LC_SEGMENT = 0x1
|
||||
LC_SEGMENT_64 = 0x19
|
||||
S_ATTR_SOME_INSTRUCTIONS = 0x00000400
|
||||
S_ATTR_PURE_INSTRUCTIONS = 0x80000000
|
||||
|
||||
""" This class parses the Universal binary """
|
||||
class UNIVERSAL(object):
|
||||
def __init__(self, binary):
|
||||
self.__binary = bytearray(binary)
|
||||
self.__machoBinaries = []
|
||||
|
||||
self.__fatHeader = None
|
||||
self.__rawLoadCmd = None
|
||||
self.__sections_l = []
|
||||
|
||||
self.__setHeader()
|
||||
self.__setBinaries()
|
||||
|
||||
def __setHeader(self):
|
||||
self.__fatHeader = FAT_HEADER.from_buffer_copy(self.__binary)
|
||||
|
||||
def __setBinaries(self):
|
||||
offset = 8
|
||||
for i in xrange(self.__fatHeader.nfat_arch):
|
||||
header = FAT_ARC.from_buffer_copy(self.__binary[offset:])
|
||||
rawBinary = self.__binary[header.offset:header.offset+header.size]
|
||||
if rawBinary[:4] == unhexlify(b"cefaedfe") or rawBinary[:4] == unhexlify(b"cffaedfe"):
|
||||
self.__machoBinaries.append(MACHO(rawBinary))
|
||||
else:
|
||||
print("[Error] Binary #"+str(i+1)+" in Universal binary has an unsupported format")
|
||||
offset += sizeof(header)
|
||||
|
||||
def getExecSections(self):
|
||||
ret = []
|
||||
for binary in self.__machoBinaries:
|
||||
ret += binary.getExecSections()
|
||||
return ret
|
||||
|
||||
def getDataSections(self):
|
||||
ret = []
|
||||
for binary in self.__machoBinaries:
|
||||
ret += binary.getDataSections()
|
||||
return ret
|
||||
|
||||
def getFormat(self):
|
||||
return "Universal"
|
||||
|
||||
# TODO: These three will just return whatever is in the first binary.
|
||||
# Perhaps the rest of ROPgadget should support loading multiple binaries?
|
||||
def getEntryPoint(self):
|
||||
for binary in self.__machoBinaries:
|
||||
return binary.getEntryPoint()
|
||||
|
||||
def getArch(self):
|
||||
for binary in self.__machoBinaries:
|
||||
return binary.getArch()
|
||||
|
||||
def getArchMode(self):
|
||||
for binary in self.__machoBinaries:
|
||||
return binary.getArchMode()
|
||||
|
||||
def getEndian(self):
|
||||
for binary in self.__machoBinaries:
|
||||
return binary.getEndian()
|
||||
|
||||
|
||||
if sys.version_info.major == 3:
|
||||
xrange = range
|
145
ROPgadget/ropgadget/options.py
Normal file
145
ROPgadget/ropgadget/options.py
Normal file
@ -0,0 +1,145 @@
|
||||
## -*- coding: utf-8 -*-
|
||||
##
|
||||
## Jonathan Salwan - 2014-05-17 - ROPgadget tool
|
||||
##
|
||||
## http://twitter.com/JonathanSalwan
|
||||
## http://shell-storm.org/project/ROPgadget/
|
||||
##
|
||||
|
||||
import re
|
||||
import codecs
|
||||
from capstone import *
|
||||
from struct import pack
|
||||
|
||||
class Options(object):
|
||||
def __init__(self, options, binary, gadgets):
|
||||
self.__options = options
|
||||
self.__gadgets = gadgets
|
||||
self.__binary = binary
|
||||
|
||||
if options.only: self.__onlyOption()
|
||||
if options.range: self.__rangeOption()
|
||||
if options.re: self.__reOption()
|
||||
if options.badbytes: self.__deleteBadBytes()
|
||||
if options.callPreceded: self.__removeNonCallPreceded()
|
||||
|
||||
def __onlyOption(self):
|
||||
new = []
|
||||
if not self.__options.only:
|
||||
return
|
||||
only = self.__options.only.split("|")
|
||||
if not len(only):
|
||||
return
|
||||
for gadget in self.__gadgets:
|
||||
flag = 0
|
||||
insts = gadget["gadget"].split(" ; ")
|
||||
for ins in insts:
|
||||
if ins.split(" ")[0] not in only:
|
||||
flag = 1
|
||||
break
|
||||
if not flag:
|
||||
new += [gadget]
|
||||
self.__gadgets = new
|
||||
|
||||
def __rangeOption(self):
|
||||
new = []
|
||||
rangeS = int(self.__options.range.split('-')[0], 16)
|
||||
rangeE = int(self.__options.range.split('-')[1], 16)
|
||||
if rangeS == 0 and rangeE == 0:
|
||||
return
|
||||
for gadget in self.__gadgets:
|
||||
vaddr = gadget["vaddr"]
|
||||
if vaddr >= rangeS and vaddr <= rangeE:
|
||||
new += [gadget]
|
||||
self.__gadgets = new
|
||||
|
||||
def __reOption(self):
|
||||
new = []
|
||||
re_strs = []
|
||||
|
||||
if not self.__options.re:
|
||||
return
|
||||
|
||||
if '|' in self.__options.re:
|
||||
re_strs = self.__options.re.split(' | ')
|
||||
if 1 == len(re_strs):
|
||||
re_strs = self.__options.re.split('|')
|
||||
else:
|
||||
re_strs.append(self.__options.re)
|
||||
|
||||
patterns = []
|
||||
for __re_str in re_strs:
|
||||
pattern = re.compile(__re_str)
|
||||
patterns.append(pattern)
|
||||
|
||||
for gadget in self.__gadgets:
|
||||
flag = 1
|
||||
insts = gadget["gadget"].split(" ; ")
|
||||
for pattern in patterns:
|
||||
for ins in insts:
|
||||
res = pattern.search(ins)
|
||||
if res:
|
||||
flag = 1
|
||||
break
|
||||
else:
|
||||
flag = 0
|
||||
if not flag:
|
||||
break
|
||||
if flag:
|
||||
new += [gadget]
|
||||
self.__gadgets = new
|
||||
|
||||
def __removeNonCallPreceded(self):
|
||||
def __isGadgetCallPreceded(gadget):
|
||||
# Given a gadget, determine if the bytes immediately preceding are a call instruction
|
||||
prevBytes = gadget["prev"]
|
||||
# TODO: Improve / Semantically document each of these cases.
|
||||
callPrecededExpressions = [
|
||||
"\xe8[\x00-\xff][\x00-\xff][\x00-\xff][\x00-\xff]$",
|
||||
"\xe8[\x00-\xff][\x00-\xff][\x00-\xff][\x00-\xff][\x00-\xff][\x00-\xff][\x00-\xff][\x00-\xff]$",
|
||||
"\xff[\x00-\xff]$",
|
||||
"\xff[\x00-\xff][\x00-\xff]$",
|
||||
"\xff[\x00-\xff][\x00-\xff][\x00-\xff][\x00-\xff]$"
|
||||
"\xff[\x00-\xff][\x00-\xff][\x00-\xff][\x00-\xff][\x00-\xff][\x00-\xff][\x00-\xff][\x00-\xff]$"
|
||||
]
|
||||
return bool(reduce(lambda x,y: x or y, map(lambda x: re.search(x, prevBytes), callPrecededExpressions)))
|
||||
arch = self.__binary.getArch()
|
||||
if arch == CS_ARCH_X86:
|
||||
initial_length = len(self.__gadgets)
|
||||
self.__gadgets = filter(__isGadgetCallPreceded, self.__gadgets)
|
||||
print("Options().removeNonCallPreceded(): Filtered out {} gadgets.".format(initial_length - len(self.__gadgets)))
|
||||
else:
|
||||
print("Options().removeNonCallPreceded(): Unsupported architecture.")
|
||||
|
||||
def __deleteBadBytes(self):
|
||||
archMode = self.__binary.getArchMode()
|
||||
if not self.__options.badbytes:
|
||||
return
|
||||
new = []
|
||||
#Filter out empty badbytes (i.e if badbytes was set to 00|ff| there's an empty badbyte after the last '|')
|
||||
#and convert each one to the corresponding byte
|
||||
bbytes = []
|
||||
for bb in self.__options.badbytes.split("|"):
|
||||
if '-' in bb:
|
||||
rng = bb.split('-')
|
||||
low = ord(codecs.decode(rng[0], "hex"))
|
||||
high = ord(codecs.decode(rng[1], "hex"))
|
||||
for i in range(low, high):
|
||||
bbytes.append(chr(i))
|
||||
else:
|
||||
bbytes.append(codecs.decode(bb.encode("ascii"), "hex"))
|
||||
|
||||
archMode = self.__binary.getArchMode()
|
||||
for gadget in self.__gadgets:
|
||||
gadAddr = pack("<L", gadget["vaddr"]) if archMode == CS_MODE_32 else pack("<Q", gadget["vaddr"])
|
||||
try:
|
||||
for x in bbytes:
|
||||
if x in gadAddr: raise
|
||||
new += [gadget]
|
||||
except:
|
||||
pass
|
||||
self.__gadgets = new
|
||||
|
||||
def getGadgets(self):
|
||||
return self.__gadgets
|
||||
|
22
ROPgadget/ropgadget/rgutils.py
Normal file
22
ROPgadget/ropgadget/rgutils.py
Normal file
@ -0,0 +1,22 @@
|
||||
## -*- coding: utf-8 -*-
|
||||
##
|
||||
## Jonathan Salwan - 2014-05-17 - ROPgadget tool
|
||||
##
|
||||
## http://twitter.com/JonathanSalwan
|
||||
## http://shell-storm.org/project/ROPgadget/
|
||||
##
|
||||
|
||||
def deleteDuplicateGadgets(currentGadgets):
|
||||
gadgets_content_set = set()
|
||||
unique_gadgets = []
|
||||
for gadget in currentGadgets:
|
||||
gad = gadget["gadget"]
|
||||
if gad in gadgets_content_set:
|
||||
continue
|
||||
gadgets_content_set.add(gad)
|
||||
unique_gadgets += [gadget]
|
||||
return unique_gadgets
|
||||
|
||||
def alphaSortgadgets(currentGadgets):
|
||||
return sorted(currentGadgets, key=lambda key : key["gadget"])
|
||||
|
10
ROPgadget/ropgadget/ropchain/__init__.py
Normal file
10
ROPgadget/ropgadget/ropchain/__init__.py
Normal file
@ -0,0 +1,10 @@
|
||||
## -*- coding: utf-8 -*-
|
||||
##
|
||||
## Jonathan Salwan - 2014-05-13
|
||||
##
|
||||
## http://shell-storm.org
|
||||
## http://twitter.com/JonathanSalwan
|
||||
##
|
||||
|
||||
import ropgadget.ropchain.ropmaker
|
||||
import ropgadget.ropchain.arch
|
11
ROPgadget/ropgadget/ropchain/arch/__init__.py
Normal file
11
ROPgadget/ropgadget/ropchain/arch/__init__.py
Normal file
@ -0,0 +1,11 @@
|
||||
#!/usr/bin/env python2
|
||||
## -*- coding: utf-8 -*-
|
||||
##
|
||||
## Jonathan Salwan - 2014-05-13
|
||||
##
|
||||
## http://shell-storm.org
|
||||
## http://twitter.com/JonathanSalwan
|
||||
##
|
||||
|
||||
import ropgadget.ropchain.arch.ropmakerx86
|
||||
import ropgadget.ropchain.arch.ropmakerx64
|
225
ROPgadget/ropgadget/ropchain/arch/ropmakerx64.py
Normal file
225
ROPgadget/ropgadget/ropchain/arch/ropmakerx64.py
Normal file
@ -0,0 +1,225 @@
|
||||
#!/usr/bin/env python2
|
||||
## -*- coding: utf-8 -*-
|
||||
##
|
||||
## Jonathan Salwan - 2014-05-13
|
||||
## Florian Meier - 2014-08-31 - The 64b ROP chain generation
|
||||
##
|
||||
## http://shell-storm.org
|
||||
## http://twitter.com/JonathanSalwan
|
||||
##
|
||||
|
||||
import re
|
||||
from capstone import *
|
||||
|
||||
|
||||
|
||||
class ROPMakerX64(object):
|
||||
def __init__(self, binary, gadgets, liboffset=0x0):
|
||||
self.__binary = binary
|
||||
self.__gadgets = gadgets
|
||||
|
||||
# If it's a library, we have the option to add an offset to the addresses
|
||||
self.__liboffset = liboffset
|
||||
|
||||
self.__generate()
|
||||
|
||||
|
||||
def __lookingForWrite4Where(self, gadgetsAlreadyTested):
|
||||
for gadget in self.__gadgets:
|
||||
if gadget in gadgetsAlreadyTested:
|
||||
continue
|
||||
f = gadget["gadget"].split(" ; ")[0]
|
||||
regex = re.search("mov .* ptr \[(?P<dst>([(rax)|(rbx)|(rcx)|(rdx)|(rsi)|(rdi)|(r9)|(r10)|(r11)|(r12)|(r13)|(r14)|(r15)]{3}))\], (?P<src>([(rax)|(rbx)|(rcx)|(rdx)|(rsi)|(rdi)|(r9)|(r10)|(r11)|(r12)|(r13)|(r14)|(r15)]{3}))$", f)
|
||||
if regex:
|
||||
lg = gadget["gadget"].split(" ; ")[1:]
|
||||
try:
|
||||
for g in lg:
|
||||
if g.split()[0] != "pop" and g.split()[0] != "ret":
|
||||
raise
|
||||
# we need this to filterout 'ret' instructions with an offset like 'ret 0x6', because they ruin the stack pointer
|
||||
if g != "ret":
|
||||
if g.split()[0] == "ret" and g.split()[1] != "":
|
||||
raise
|
||||
print("\t[+] Gadget found: 0x%x %s" %(gadget["vaddr"], gadget["gadget"]))
|
||||
return [gadget, regex.group("dst"), regex.group("src")]
|
||||
except:
|
||||
continue
|
||||
return None
|
||||
|
||||
def __lookingForSomeThing(self, something):
|
||||
for gadget in self.__gadgets:
|
||||
lg = gadget["gadget"].split(" ; ")
|
||||
if lg[0] == something:
|
||||
try:
|
||||
for g in lg[1:]:
|
||||
if g.split()[0] != "pop" and g.split()[0] != "ret":
|
||||
raise
|
||||
if g != "ret":
|
||||
# we need this to filterout 'ret' instructions with an offset like 'ret 0x6', because they ruin the stack pointer
|
||||
if g.split()[0] == "ret" and g.split()[1] != "":
|
||||
raise
|
||||
print("\t[+] Gadget found: 0x%x %s" %(gadget["vaddr"], gadget["gadget"]))
|
||||
return gadget
|
||||
except:
|
||||
continue
|
||||
return None
|
||||
|
||||
def __padding(self, gadget, regAlreadSetted):
|
||||
lg = gadget["gadget"].split(" ; ")
|
||||
for g in lg[1:]:
|
||||
if g.split()[0] == "pop":
|
||||
reg = g.split()[1]
|
||||
try:
|
||||
print("\tp += pack('<Q', 0x%016x) # padding without overwrite %s" %(regAlreadSetted[reg], reg))
|
||||
except KeyError:
|
||||
print("\tp += pack('<Q', 0x4141414141414141) # padding")
|
||||
|
||||
def __buildRopChain(self, write4where, popDst, popSrc, xorSrc, xorRax, incRax, popRdi, popRsi, popRdx, syscall):
|
||||
|
||||
sects = self.__binary.getDataSections()
|
||||
dataAddr = None
|
||||
for s in sects:
|
||||
if s["name"] == ".data":
|
||||
dataAddr = s["vaddr"] + self.__liboffset
|
||||
if dataAddr is None:
|
||||
print("\n[-] Error - Can't find a writable section")
|
||||
return
|
||||
|
||||
print("\t#!/usr/bin/env python2")
|
||||
print("\t# execve generated by ROPgadget\n")
|
||||
print("\tfrom struct import pack\n")
|
||||
|
||||
print("\t# Padding goes here")
|
||||
print("\tp = ''\n")
|
||||
|
||||
print("\tp += pack('<Q', 0x%016x) # %s" %(popDst["vaddr"], popDst["gadget"]))
|
||||
print("\tp += pack('<Q', 0x%016x) # @ .data" %(dataAddr))
|
||||
self.__padding(popDst, {})
|
||||
|
||||
print("\tp += pack('<Q', 0x%016x) # %s" %(popSrc["vaddr"], popSrc["gadget"]))
|
||||
print("\tp += '/bin//sh'")
|
||||
self.__padding(popSrc, {popDst["gadget"].split()[1]: dataAddr}) # Don't overwrite reg dst
|
||||
|
||||
print("\tp += pack('<Q', 0x%016x) # %s" %(write4where["vaddr"], write4where["gadget"]))
|
||||
self.__padding(write4where, {})
|
||||
|
||||
print("\tp += pack('<Q', 0x%016x) # %s" %(popDst["vaddr"], popDst["gadget"]))
|
||||
print("\tp += pack('<Q', 0x%016x) # @ .data + 8" %(dataAddr + 8))
|
||||
self.__padding(popDst, {})
|
||||
|
||||
print("\tp += pack('<Q', 0x%016x) # %s" %(xorSrc["vaddr"], xorSrc["gadget"]))
|
||||
self.__padding(xorSrc, {})
|
||||
|
||||
print("\tp += pack('<Q', 0x%016x) # %s" %(write4where["vaddr"], write4where["gadget"]))
|
||||
self.__padding(write4where, {})
|
||||
|
||||
print("\tp += pack('<Q', 0x%016x) # %s" %(popRdi["vaddr"], popRdi["gadget"]))
|
||||
print("\tp += pack('<Q', 0x%016x) # @ .data" %(dataAddr))
|
||||
self.__padding(popRdi, {})
|
||||
|
||||
print("\tp += pack('<Q', 0x%016x) # %s" %(popRsi["vaddr"], popRsi["gadget"]))
|
||||
print("\tp += pack('<Q', 0x%016x) # @ .data + 8" %(dataAddr + 8))
|
||||
self.__padding(popRsi, {"rdi": dataAddr}) # Don't overwrite rdi
|
||||
|
||||
print("\tp += pack('<Q', 0x%016x) # %s" %(popRdx["vaddr"], popRdx["gadget"]))
|
||||
print("\tp += pack('<Q', 0x%016x) # @ .data + 8" %(dataAddr + 8))
|
||||
self.__padding(popRdx, {"rdi": dataAddr, "rsi": dataAddr + 8}) # Don't overwrite rdi and rsi
|
||||
|
||||
print("\tp += pack('<Q', 0x%016x) # %s" %(xorRax["vaddr"], xorRax["gadget"]))
|
||||
self.__padding(xorRax, {"rdi": dataAddr, "rsi": dataAddr + 8}) # Don't overwrite rdi and rsi
|
||||
|
||||
for i in range(59):
|
||||
print("\tp += pack('<Q', 0x%016x) # %s" %(incRax["vaddr"], incRax["gadget"]))
|
||||
self.__padding(incRax, {"rdi": dataAddr, "rsi": dataAddr + 8}) # Don't overwrite rdi and rsi
|
||||
|
||||
print("\tp += pack('<Q', 0x%016x) # %s" %(syscall["vaddr"], syscall["gadget"]))
|
||||
|
||||
def __generate(self):
|
||||
|
||||
# To find the smaller gadget
|
||||
self.__gadgets.reverse()
|
||||
|
||||
print("\nROP chain generation\n===========================================================")
|
||||
|
||||
print("\n- Step 1 -- Write-what-where gadgets\n")
|
||||
|
||||
gadgetsAlreadyTested = []
|
||||
while True:
|
||||
write4where = self.__lookingForWrite4Where(gadgetsAlreadyTested)
|
||||
if not write4where:
|
||||
print("\t[-] Can't find the 'mov qword ptr [r64], r64' gadget")
|
||||
return
|
||||
|
||||
popDst = self.__lookingForSomeThing("pop %s" %(write4where[1]))
|
||||
if not popDst:
|
||||
print("\t[-] Can't find the 'pop %s' gadget. Try with another 'mov [reg], reg'\n" %(write4where[1]))
|
||||
gadgetsAlreadyTested += [write4where[0]]
|
||||
continue
|
||||
|
||||
popSrc = self.__lookingForSomeThing("pop %s" %(write4where[2]))
|
||||
if not popSrc:
|
||||
print("\t[-] Can't find the 'pop %s' gadget. Try with another 'mov [reg], reg'\n" %(write4where[2]))
|
||||
gadgetsAlreadyTested += [write4where[0]]
|
||||
continue
|
||||
|
||||
xorSrc = self.__lookingForSomeThing("xor %s, %s" %(write4where[2], write4where[2]))
|
||||
if not xorSrc:
|
||||
print("\t[-] Can't find the 'xor %s, %s' gadget. Try with another 'mov [reg], reg'\n" %(write4where[2], write4where[2]))
|
||||
gadgetsAlreadyTested += [write4where[0]]
|
||||
continue
|
||||
else:
|
||||
break
|
||||
|
||||
print("\n- Step 2 -- Init syscall number gadgets\n")
|
||||
|
||||
xorRax = self.__lookingForSomeThing("xor rax, rax")
|
||||
if not xorRax:
|
||||
print("\t[-] Can't find the 'xor rax, rax' instruction")
|
||||
return
|
||||
|
||||
incRax = self.__lookingForSomeThing("inc rax")
|
||||
incEax = self.__lookingForSomeThing("inc eax")
|
||||
incAx = self.__lookingForSomeThing("inc al")
|
||||
addRax = self.__lookingForSomeThing("add rax, 1")
|
||||
addEax = self.__lookingForSomeThing("add eax, 1")
|
||||
addAx = self.__lookingForSomeThing("add al, 1")
|
||||
|
||||
instr = [incRax, incEax, incAx, addRax, addEax, addAx]
|
||||
|
||||
if all(v is None for v in instr):
|
||||
print("\t[-] Can't find the 'inc rax' or 'add rax, 1' instruction")
|
||||
return
|
||||
|
||||
for i in instr:
|
||||
if i is not None:
|
||||
incRax = i
|
||||
break
|
||||
|
||||
print("\n- Step 3 -- Init syscall arguments gadgets\n")
|
||||
|
||||
popRdi = self.__lookingForSomeThing("pop rdi")
|
||||
if not popRdi:
|
||||
print("\t[-] Can't find the 'pop rdi' instruction")
|
||||
return
|
||||
|
||||
popRsi = self.__lookingForSomeThing("pop rsi")
|
||||
if not popRsi:
|
||||
print("\t[-] Can't find the 'pop rsi' instruction")
|
||||
return
|
||||
|
||||
popRdx = self.__lookingForSomeThing("pop rdx")
|
||||
if not popRdx:
|
||||
print("\t[-] Can't find the 'pop rdx' instruction")
|
||||
return
|
||||
|
||||
print("\n- Step 4 -- Syscall gadget\n")
|
||||
|
||||
syscall = self.__lookingForSomeThing("syscall")
|
||||
if not syscall:
|
||||
print("\t[-] Can't find the 'syscall' instruction")
|
||||
return
|
||||
|
||||
print("\n- Step 5 -- Build the ROP chain\n")
|
||||
|
||||
self.__buildRopChain(write4where[0], popDst, popSrc, xorSrc, xorRax, incRax, popRdi, popRsi, popRdx, syscall)
|
||||
|
223
ROPgadget/ropgadget/ropchain/arch/ropmakerx86.py
Normal file
223
ROPgadget/ropgadget/ropchain/arch/ropmakerx86.py
Normal file
@ -0,0 +1,223 @@
|
||||
#!/usr/bin/env python2
|
||||
## -*- coding: utf-8 -*-
|
||||
##
|
||||
## Jonathan Salwan - 2014-05-13
|
||||
##
|
||||
## http://shell-storm.org
|
||||
## http://twitter.com/JonathanSalwan
|
||||
##
|
||||
|
||||
import re
|
||||
from capstone import *
|
||||
|
||||
|
||||
|
||||
class ROPMakerX86(object):
|
||||
def __init__(self, binary, gadgets, liboffset=0x0):
|
||||
self.__binary = binary
|
||||
self.__gadgets = gadgets
|
||||
|
||||
# If it's a library, we have the option to add an offset to the addresses
|
||||
self.__liboffset = liboffset
|
||||
|
||||
self.__generate()
|
||||
|
||||
|
||||
def __lookingForWrite4Where(self, gadgetsAlreadyTested):
|
||||
for gadget in self.__gadgets:
|
||||
if gadget in gadgetsAlreadyTested:
|
||||
continue
|
||||
f = gadget["gadget"].split(" ; ")[0]
|
||||
# regex -> mov dword ptr [r32], r32
|
||||
regex = re.search("mov dword ptr \[(?P<dst>([(eax)|(ebx)|(ecx)|(edx)|(esi)|(edi)]{3}))\], (?P<src>([(eax)|(ebx)|(ecx)|(edx)|(esi)|(edi)]{3}))$", f)
|
||||
if regex:
|
||||
lg = gadget["gadget"].split(" ; ")[1:]
|
||||
try:
|
||||
for g in lg:
|
||||
if g.split()[0] != "pop" and g.split()[0] != "ret":
|
||||
raise
|
||||
# we need this to filterout 'ret' instructions with an offset like 'ret 0x6', because they ruin the stack pointer
|
||||
if g != "ret":
|
||||
if g.split()[0] == "ret" and g.split()[1] != "":
|
||||
raise
|
||||
print("\t[+] Gadget found: 0x%x %s" %(gadget["vaddr"], gadget["gadget"]))
|
||||
return [gadget, regex.group("dst"), regex.group("src")]
|
||||
except:
|
||||
continue
|
||||
return None
|
||||
|
||||
def __lookingForSomeThing(self, something):
|
||||
for gadget in self.__gadgets:
|
||||
lg = gadget["gadget"].split(" ; ")
|
||||
if lg[0] == something:
|
||||
try:
|
||||
for g in lg[1:]:
|
||||
if g.split()[0] != "pop" and g.split()[0] != "ret":
|
||||
raise
|
||||
# we need this to filterout 'ret' instructions with an offset like 'ret 0x6', because they ruin the stack pointer
|
||||
if g != "ret":
|
||||
if g.split()[0] == "ret" and g.split()[1] != "":
|
||||
raise
|
||||
print("\t[+] Gadget found: 0x%x %s" %(gadget["vaddr"], gadget["gadget"]))
|
||||
return gadget
|
||||
except:
|
||||
continue
|
||||
return None
|
||||
|
||||
def __padding(self, gadget, regAlreadSetted):
|
||||
lg = gadget["gadget"].split(" ; ")
|
||||
for g in lg[1:]:
|
||||
if g.split()[0] == "pop":
|
||||
reg = g.split()[1]
|
||||
try:
|
||||
print("\tp += pack('<I', 0x%08x) # padding without overwrite %s" %(regAlreadSetted[reg], reg))
|
||||
except KeyError:
|
||||
print("\tp += pack('<I', 0x41414141) # padding")
|
||||
|
||||
def __buildRopChain(self, write4where, popDst, popSrc, xorSrc, xorEax, incEax, popEbx, popEcx, popEdx, syscall):
|
||||
|
||||
sects = self.__binary.getDataSections()
|
||||
dataAddr = None
|
||||
for s in sects:
|
||||
if s["name"] == ".data":
|
||||
dataAddr = s["vaddr"] + self.__liboffset
|
||||
if dataAddr == None:
|
||||
print("\n[-] Error - Can't find a writable section")
|
||||
return
|
||||
|
||||
print("\t#!/usr/bin/env python2")
|
||||
print("\t# execve generated by ROPgadget\n" )
|
||||
print("\tfrom struct import pack\n")
|
||||
|
||||
print("\t# Padding goes here")
|
||||
print("\tp = ''\n")
|
||||
|
||||
print("\tp += pack('<I', 0x%08x) # %s" %(popDst["vaddr"], popDst["gadget"]))
|
||||
print("\tp += pack('<I', 0x%08x) # @ .data" %(dataAddr))
|
||||
self.__padding(popDst, {})
|
||||
|
||||
print("\tp += pack('<I', 0x%08x) # %s" %(popSrc["vaddr"], popSrc["gadget"]))
|
||||
print("\tp += '/bin'")
|
||||
self.__padding(popSrc, {popDst["gadget"].split()[1]: dataAddr}) # Don't overwrite reg dst
|
||||
|
||||
print("\tp += pack('<I', 0x%08x) # %s" %(write4where["vaddr"], write4where["gadget"]))
|
||||
self.__padding(write4where, {})
|
||||
|
||||
print("\tp += pack('<I', 0x%08x) # %s" %(popDst["vaddr"], popDst["gadget"]))
|
||||
print("\tp += pack('<I', 0x%08x) # @ .data + 4" %(dataAddr + 4))
|
||||
self.__padding(popDst, {})
|
||||
|
||||
print("\tp += pack('<I', 0x%08x) # %s" %(popSrc["vaddr"], popSrc["gadget"]))
|
||||
print("\tp += '//sh'")
|
||||
self.__padding(popSrc, {popDst["gadget"].split()[1]: dataAddr + 4}) # Don't overwrite reg dst
|
||||
|
||||
print("\tp += pack('<I', 0x%08x) # %s" %(write4where["vaddr"], write4where["gadget"]))
|
||||
self.__padding(write4where, {})
|
||||
|
||||
print("\tp += pack('<I', 0x%08x) # %s" %(popDst["vaddr"], popDst["gadget"]))
|
||||
print("\tp += pack('<I', 0x%08x) # @ .data + 8" %(dataAddr + 8))
|
||||
self.__padding(popDst, {})
|
||||
|
||||
print("\tp += pack('<I', 0x%08x) # %s" %(xorSrc["vaddr"], xorSrc["gadget"]))
|
||||
self.__padding(xorSrc, {})
|
||||
|
||||
print("\tp += pack('<I', 0x%08x) # %s" %(write4where["vaddr"], write4where["gadget"]))
|
||||
self.__padding(write4where, {})
|
||||
|
||||
print("\tp += pack('<I', 0x%08x) # %s" %(popEbx["vaddr"], popEbx["gadget"]))
|
||||
print("\tp += pack('<I', 0x%08x) # @ .data" %(dataAddr))
|
||||
self.__padding(popEbx, {})
|
||||
|
||||
print("\tp += pack('<I', 0x%08x) # %s" %(popEcx["vaddr"], popEcx["gadget"]))
|
||||
print("\tp += pack('<I', 0x%08x) # @ .data + 8" %(dataAddr + 8))
|
||||
self.__padding(popEcx, {"ebx": dataAddr}) # Don't overwrite ebx
|
||||
|
||||
print("\tp += pack('<I', 0x%08x) # %s" %(popEdx["vaddr"], popEdx["gadget"]))
|
||||
print("\tp += pack('<I', 0x%08x) # @ .data + 8" %(dataAddr + 8))
|
||||
self.__padding(popEdx, {"ebx": dataAddr, "ecx": dataAddr + 8}) # Don't overwrite ebx and ecx
|
||||
|
||||
print("\tp += pack('<I', 0x%08x) # %s" %(xorEax["vaddr"], xorEax["gadget"]))
|
||||
self.__padding(xorEax, {"ebx": dataAddr, "ecx": dataAddr + 8}) # Don't overwrite ebx and ecx
|
||||
|
||||
for i in range(11):
|
||||
print("\tp += pack('<I', 0x%08x) # %s" %(incEax["vaddr"], incEax["gadget"]))
|
||||
self.__padding(incEax, {"ebx": dataAddr, "ecx": dataAddr + 8}) # Don't overwrite ebx and ecx
|
||||
|
||||
print("\tp += pack('<I', 0x%08x) # %s" %(syscall["vaddr"], syscall["gadget"]))
|
||||
|
||||
def __generate(self):
|
||||
|
||||
# To find the smaller gadget
|
||||
self.__gadgets.reverse()
|
||||
|
||||
print("\nROP chain generation\n===========================================================")
|
||||
|
||||
print("\n- Step 1 -- Write-what-where gadgets\n")
|
||||
|
||||
gadgetsAlreadyTested = []
|
||||
while True:
|
||||
write4where = self.__lookingForWrite4Where(gadgetsAlreadyTested)
|
||||
if not write4where:
|
||||
print("\t[-] Can't find the 'mov dword ptr [r32], r32' gadget")
|
||||
return
|
||||
|
||||
popDst = self.__lookingForSomeThing("pop %s" %(write4where[1]))
|
||||
if not popDst:
|
||||
print("\t[-] Can't find the 'pop %s' gadget. Try with another 'mov [reg], reg'\n" %(write4where[1]))
|
||||
gadgetsAlreadyTested += [write4where[0]]
|
||||
continue
|
||||
|
||||
popSrc = self.__lookingForSomeThing("pop %s" %(write4where[2]))
|
||||
if not popSrc:
|
||||
print("\t[-] Can't find the 'pop %s' gadget. Try with another 'mov [reg], reg'\n" %(write4where[2]))
|
||||
gadgetsAlreadyTested += [write4where[0]]
|
||||
continue
|
||||
|
||||
xorSrc = self.__lookingForSomeThing("xor %s, %s" %(write4where[2], write4where[2]))
|
||||
if not xorSrc:
|
||||
print("\t[-] Can't find the 'xor %s, %s' gadget. Try with another 'mov [r], r'\n" %(write4where[2], write4where[2]))
|
||||
gadgetsAlreadyTested += [write4where[0]]
|
||||
continue
|
||||
else:
|
||||
break
|
||||
|
||||
print("\n- Step 2 -- Init syscall number gadgets\n")
|
||||
|
||||
xorEax = self.__lookingForSomeThing("xor eax, eax")
|
||||
if not xorEax:
|
||||
print("\t[-] Can't find the 'xor eax, eax' instruction")
|
||||
return
|
||||
|
||||
incEax = self.__lookingForSomeThing("inc eax")
|
||||
if not incEax:
|
||||
print("\t[-] Can't find the 'inc eax' instruction")
|
||||
return
|
||||
|
||||
print("\n- Step 3 -- Init syscall arguments gadgets\n")
|
||||
|
||||
popEbx = self.__lookingForSomeThing("pop ebx")
|
||||
if not popEbx:
|
||||
print("\t[-] Can't find the 'pop ebx' instruction")
|
||||
return
|
||||
|
||||
popEcx = self.__lookingForSomeThing("pop ecx")
|
||||
if not popEcx:
|
||||
print("\t[-] Can't find the 'pop ecx' instruction")
|
||||
return
|
||||
|
||||
popEdx = self.__lookingForSomeThing("pop edx")
|
||||
if not popEdx:
|
||||
print("\t[-] Can't find the 'pop edx' instruction")
|
||||
return
|
||||
|
||||
print("\n- Step 4 -- Syscall gadget\n")
|
||||
|
||||
syscall = self.__lookingForSomeThing("int 0x80")
|
||||
if not syscall:
|
||||
print("\t[-] Can't find the 'syscall' instruction")
|
||||
return
|
||||
|
||||
print("\n- Step 5 -- Build the ROP chain\n")
|
||||
|
||||
self.__buildRopChain(write4where[0], popDst, popSrc, xorSrc, xorEax, incEax, popEbx, popEcx, popEdx, syscall)
|
||||
|
35
ROPgadget/ropgadget/ropchain/ropmaker.py
Normal file
35
ROPgadget/ropgadget/ropchain/ropmaker.py
Normal file
@ -0,0 +1,35 @@
|
||||
## -*- coding: utf-8 -*-
|
||||
##
|
||||
## Jonathan Salwan - 2014-05-13
|
||||
##
|
||||
## http://shell-storm.org
|
||||
## http://twitter.com/JonathanSalwan
|
||||
##
|
||||
|
||||
from capstone import *
|
||||
from ropgadget.ropchain.arch.ropmakerx86 import *
|
||||
from ropgadget.ropchain.arch.ropmakerx64 import *
|
||||
|
||||
class ROPMaker(object):
|
||||
def __init__(self, binary, gadgets, offset):
|
||||
self.__binary = binary
|
||||
self.__gadgets = gadgets
|
||||
self.__offset = offset
|
||||
|
||||
self.__handlerArch()
|
||||
|
||||
def __handlerArch(self):
|
||||
|
||||
if self.__binary.getArch() == CS_ARCH_X86 \
|
||||
and self.__binary.getArchMode() == CS_MODE_32 \
|
||||
and self.__binary.getFormat() == "ELF":
|
||||
ROPMakerX86(self.__binary, self.__gadgets, self.__offset)
|
||||
|
||||
elif self.__binary.getArch() == CS_ARCH_X86 \
|
||||
and self.__binary.getArchMode() == CS_MODE_64 \
|
||||
and self.__binary.getFormat() == "ELF":
|
||||
ROPMakerX64(self.__binary, self.__gadgets, self.__offset)
|
||||
|
||||
else:
|
||||
print("\n[Error] ROPMaker.__handlerArch - Arch not supported yet for the rop chain generation")
|
||||
|
38
ROPgadget/ropgadget/updateAlert.py
Normal file
38
ROPgadget/ropgadget/updateAlert.py
Normal file
@ -0,0 +1,38 @@
|
||||
## -*- coding: utf-8 -*-
|
||||
##
|
||||
## Jonathan Salwan - 2014-05-12 - ROPgadget tool
|
||||
##
|
||||
## http://twitter.com/JonathanSalwan
|
||||
## http://shell-storm.org/project/ROPgadget/
|
||||
##
|
||||
|
||||
import re
|
||||
try:
|
||||
import httplib
|
||||
except ImportError:
|
||||
import http.client as httplib
|
||||
|
||||
|
||||
from ropgadget.version import *
|
||||
|
||||
|
||||
class UpdateAlert(object):
|
||||
|
||||
@staticmethod
|
||||
def checkUpdate():
|
||||
try:
|
||||
conn = httplib.HTTPSConnection("raw.githubusercontent.com", 443)
|
||||
conn.request("GET", "/JonathanSalwan/ROPgadget/master/ropgadget/version.py")
|
||||
except:
|
||||
print("Can't connect to raw.githubusercontent.com")
|
||||
return
|
||||
d = conn.getresponse().read()
|
||||
majorVersion = re.search("MAJOR_VERSION.+=.+(?P<value>[\d])", d).group("value")
|
||||
minorVersion = re.search("MINOR_VERSION.+=.+(?P<value>[\d])", d).group("value")
|
||||
webVersion = int("%s%s" %(majorVersion, minorVersion))
|
||||
curVersion = int("%s%s" %(MAJOR_VERSION, MINOR_VERSION))
|
||||
if webVersion > curVersion:
|
||||
print("The version %s.%s is available. Currently, you use the version %d.%d." %(majorVersion, minorVersion, MAJOR_VERSION, MINOR_VERSION))
|
||||
else:
|
||||
print("Your version is up-to-date.")
|
||||
|
11
ROPgadget/ropgadget/version.py
Normal file
11
ROPgadget/ropgadget/version.py
Normal file
@ -0,0 +1,11 @@
|
||||
## -*- coding: utf-8 -*-
|
||||
##
|
||||
## Jonathan Salwan - 2014-05-12 - ROPgadget tool
|
||||
##
|
||||
## http://twitter.com/JonathanSalwan
|
||||
## http://shell-storm.org/project/ROPgadget/
|
||||
##
|
||||
|
||||
MAJOR_VERSION = 6
|
||||
MINOR_VERSION = 3
|
||||
PYROPGADGET_VERSION = "ROPgadget v%d.%d" %(MAJOR_VERSION, MINOR_VERSION)
|
12
ROPgadget/scripts/ROPgadget
Executable file
12
ROPgadget/scripts/ROPgadget
Executable file
@ -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()
|
67
ROPgadget/setup.py
Normal file
67
ROPgadget/setup.py
Normal file
@ -0,0 +1,67 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
from setuptools import setup
|
||||
import os
|
||||
|
||||
package_name = "ROPGadget"
|
||||
package_dir = "ropgadget"
|
||||
package_description = """
|
||||
This tool lets you search your gadgets on your binaries to facilitate your ROP exploitation.
|
||||
ROPgadget supports ELF, PE and Mach-O format on x86, x64, ARM, ARM64, PowerPC, SPARC and MIPS architectures.
|
||||
http://www.shell-storm.org/project/ROPgadget/
|
||||
""".strip()
|
||||
|
||||
|
||||
def fullsplit(path, result=None):
|
||||
"""
|
||||
Split a pathname into components (the opposite of os.path.join) in a
|
||||
platform-neutral way.
|
||||
"""
|
||||
if result is None:
|
||||
result = []
|
||||
head, tail = os.path.split(path)
|
||||
if head == '':
|
||||
return [tail] + result
|
||||
if head == path:
|
||||
return result
|
||||
return fullsplit(head, [tail] + result)
|
||||
|
||||
# Compile the list of packages available, because distutils doesn't have
|
||||
# an easy way to do this.
|
||||
packages, data_files = [], []
|
||||
root_dir = os.path.dirname(__file__)
|
||||
if root_dir != '':
|
||||
os.chdir(root_dir)
|
||||
|
||||
for dirpath, dirnames, filenames in os.walk(package_dir):
|
||||
# Ignore dirnames that start with '.'
|
||||
for i, dirname in enumerate(dirnames):
|
||||
if dirname.startswith('.'): del dirnames[i]
|
||||
if '__init__.py' in filenames:
|
||||
packages.append('.'.join(fullsplit(dirpath)))
|
||||
elif filenames:
|
||||
data_files.append([dirpath, [os.path.join(dirpath, f) for f in filenames]])
|
||||
|
||||
version = "6.3"
|
||||
|
||||
setup(
|
||||
name = package_name,
|
||||
version = version,
|
||||
description = package_description,
|
||||
packages = packages,
|
||||
license = "BSD",
|
||||
author = "Jonathan Salwan",
|
||||
author_email = "jonathan.salwan@gmail.com",
|
||||
url = "https://github.com/JonathanSalwan/ROPgadget",
|
||||
scripts = ['scripts/ROPgadget'],
|
||||
install_requires = ['capstone'],
|
||||
classifiers = [
|
||||
'Topic :: Security',
|
||||
'Environment :: Console',
|
||||
'Operating System :: OS Independent',
|
||||
'License :: OSI Approved :: BSD License',
|
||||
'Programming Language :: Python :: 2.7',
|
||||
'Programming Language :: Python :: 3',
|
||||
'Intended Audience :: Developers'
|
||||
]
|
||||
)
|
Binary file not shown.
BIN
ROPgadget/test-suite-binaries/elf-ARM64-bash
Normal file
BIN
ROPgadget/test-suite-binaries/elf-ARM64-bash
Normal file
Binary file not shown.
BIN
ROPgadget/test-suite-binaries/elf-ARMv7-ls
Normal file
BIN
ROPgadget/test-suite-binaries/elf-ARMv7-ls
Normal file
Binary file not shown.
BIN
ROPgadget/test-suite-binaries/elf-FreeBSD-x86
Normal file
BIN
ROPgadget/test-suite-binaries/elf-FreeBSD-x86
Normal file
Binary file not shown.
BIN
ROPgadget/test-suite-binaries/elf-Linux-x64
Normal file
BIN
ROPgadget/test-suite-binaries/elf-Linux-x64
Normal file
Binary file not shown.
BIN
ROPgadget/test-suite-binaries/elf-Linux-x86
Normal file
BIN
ROPgadget/test-suite-binaries/elf-Linux-x86
Normal file
Binary file not shown.
BIN
ROPgadget/test-suite-binaries/elf-Linux-x86-NDH-chall
Normal file
BIN
ROPgadget/test-suite-binaries/elf-Linux-x86-NDH-chall
Normal file
Binary file not shown.
BIN
ROPgadget/test-suite-binaries/elf-Mips-Defcon-20-pwn100
Normal file
BIN
ROPgadget/test-suite-binaries/elf-Mips-Defcon-20-pwn100
Normal file
Binary file not shown.
BIN
ROPgadget/test-suite-binaries/elf-PowerPC-bash
Normal file
BIN
ROPgadget/test-suite-binaries/elf-PowerPC-bash
Normal file
Binary file not shown.
BIN
ROPgadget/test-suite-binaries/elf-SparcV8-bash
Normal file
BIN
ROPgadget/test-suite-binaries/elf-SparcV8-bash
Normal file
Binary file not shown.
BIN
ROPgadget/test-suite-binaries/elf-x64-bash-v4.1.5.1
Normal file
BIN
ROPgadget/test-suite-binaries/elf-x64-bash-v4.1.5.1
Normal file
Binary file not shown.
BIN
ROPgadget/test-suite-binaries/elf-x86-bash-v4.1.5.1
Normal file
BIN
ROPgadget/test-suite-binaries/elf-x86-bash-v4.1.5.1
Normal file
Binary file not shown.
BIN
ROPgadget/test-suite-binaries/macho-x64-ls
Normal file
BIN
ROPgadget/test-suite-binaries/macho-x64-ls
Normal file
Binary file not shown.
BIN
ROPgadget/test-suite-binaries/macho-x86-ls
Normal file
BIN
ROPgadget/test-suite-binaries/macho-x86-ls
Normal file
Binary file not shown.
Binary file not shown.
BIN
ROPgadget/test-suite-binaries/pe-x64-cmd-v6.1.7601
Normal file
BIN
ROPgadget/test-suite-binaries/pe-x64-cmd-v6.1.7601
Normal file
Binary file not shown.
BIN
ROPgadget/test-suite-binaries/pe-x86-cmd-v6.1.7600
Normal file
BIN
ROPgadget/test-suite-binaries/pe-x86-cmd-v6.1.7600
Normal file
Binary file not shown.
1
ROPgadget/test-suite-binaries/raw-x86.raw
Normal file
1
ROPgadget/test-suite-binaries/raw-x86.raw
Normal file
@ -0,0 +1 @@
|
||||
1и┴H┴┴HL$┴1юц
|
BIN
ROPgadget/test-suite-binaries/ref_output.bz2
Normal file
BIN
ROPgadget/test-suite-binaries/ref_output.bz2
Normal file
Binary file not shown.
61
ROPgadget/test-suite-binaries/test.sh
Executable file
61
ROPgadget/test-suite-binaries/test.sh
Executable file
@ -0,0 +1,61 @@
|
||||
#!/bin/bash
|
||||
|
||||
export PYTHONPATH=../
|
||||
if [ "$#" == "1" ]
|
||||
then
|
||||
RUN="python2 ../ROPgadget.py"
|
||||
else
|
||||
RUN="python3 ../ROPgadget.py"
|
||||
fi
|
||||
|
||||
rm -rf test_output
|
||||
|
||||
FILES=`ls | sort -f`
|
||||
for f in $FILES
|
||||
do
|
||||
if [ "$f" != "test.sh" ] && [ "$f" != "ref_output.bz2" ] && [ "$f" != "test_output" ]
|
||||
then
|
||||
echo "RUN $f" | tee -a ./test_output
|
||||
if [ "$f" == "raw-x86.raw" ]
|
||||
then
|
||||
$RUN --rawArch=x86 --rawMode=32 --depth 5 --binary $f 1>> ./test_output
|
||||
else
|
||||
$RUN --depth 5 --binary $f 1>> ./test_output
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
echo "RUN elf-Linux-x86 --ropchain" | tee -a ./test_output
|
||||
$RUN --binary ./elf-Linux-x86 --ropchain 1>> ./test_output
|
||||
echo "RUN elf-Linux-x86 --depth 3" | tee -a ./test_output
|
||||
$RUN --binary ./elf-Linux-x86 --depth 3 1>> ./test_output
|
||||
echo "RUN elf-Linux-x86 --string \"main\"" | tee -a ./test_output
|
||||
$RUN --binary ./elf-Linux-x86 --string "main" 1>> ./test_output
|
||||
echo "RUN elf-Linux-x86 --string \"m..n\"" | tee -a ./test_output
|
||||
$RUN --binary ./elf-Linux-x86 --string "m..n" 1>> ./test_output
|
||||
echo "RUN elf-Linux-x86 --opcode c9c3" | tee -a ./test_output
|
||||
$RUN --binary ./elf-Linux-x86 --opcode c9c3 1>> ./test_output
|
||||
echo "RUN elf-Linux-x86 --only \"mov|ret\"" | tee -a ./test_output
|
||||
$RUN --binary ./elf-Linux-x86 --only "mov|ret" 1>> ./test_output
|
||||
echo "RUN elf-Linux-x86 --only \"mov|pop|xor|ret\"" | tee -a ./test_output
|
||||
$RUN --binary ./elf-Linux-x86 --only "mov|pop|xor|ret" 1>> ./test_output
|
||||
echo "RUN elf-Linux-x86 --filter \"xchg|add|sub|cmov.*\"" | tee -a ./test_output
|
||||
$RUN --binary ./elf-Linux-x86 --filter "xchg|add|sub|cmov.*" 1>> ./test_output
|
||||
echo "RUN elf-Linux-x86 --norop --nosys" | tee -a ./test_output
|
||||
$RUN --binary ./elf-Linux-x86 --norop --nosys 1>> ./test_output
|
||||
echo "RUN elf-Linux-x86 --range 0x08041000-0x08042000" | tee -a ./test_output
|
||||
$RUN --binary ./elf-Linux-x86 --range 0x08041000-0x08042000 1>> ./test_output
|
||||
echo "RUN elf-Linux-x86 --string main --range 0x080c9aaa-0x080c9aba" | tee -a ./test_output
|
||||
$RUN --binary ./elf-Linux-x86 --string main --range 0x080c9aaa-0x080c9aba 1>> ./test_output
|
||||
echo "RUN elf-Linux-x86 --memstr \"/bin/sh\"" | tee -a ./test_output
|
||||
$RUN --binary ./elf-Linux-x86 --memstr "/bin/sh" 1>> ./test_output
|
||||
echo "RUN elf-Linux-x86 --badbytes \"00|01-1f|7f|42\"" | tee -a ./test_output
|
||||
$RUN --binary ./elf-Linux-x86 --badbytes "00|01-1f|7f|42" 1>> ./test_output
|
||||
echo "RUN Linux_lib64.so --offset 0xdeadbeef00000000" | tee -a ./test_output
|
||||
$RUN --binary ./Linux_lib64.so --offset 0xdeadbeef00000000 1>> ./test_output
|
||||
echo "RUN elf-ARMv7-ls --depth 5" | tee -a ./test_output
|
||||
$RUN --binary ./elf-ARMv7-ls --depth 5 1>> ./test_output
|
||||
echo "RUN elf-ARM64-bash --depth 5" | tee -a ./test_output
|
||||
$RUN --binary ./elf-ARM64-bash --depth 5 1>> ./test_output
|
||||
|
||||
diff test_output <(bunzip2 --stdout ref_output.bz2) 1>&2
|
Loading…
Reference in New Issue
Block a user