├── .github └── workflows │ └── main.yml ├── .gitignore ├── AUTHORS ├── LICENSE_BSD.txt ├── README.md ├── ROPgadget.py ├── ropgadget ├── __init__.py ├── args.py ├── binary.py ├── core.py ├── gadgets.py ├── loaders │ ├── __init__.py │ ├── elf.py │ ├── macho.py │ ├── pe.py │ ├── raw.py │ └── universal.py ├── options.py ├── rgutils.py ├── ropchain │ ├── __init__.py │ ├── arch │ │ ├── __init__.py │ │ ├── ropmakerx64.py │ │ └── ropmakerx86.py │ └── ropmaker.py ├── updateAlert.py └── version.py ├── scripts └── ROPgadget ├── setup.cfg ├── setup.py └── test-suite-binaries ├── .gitignore ├── Linux_lib32.so ├── Linux_lib64.so ├── UNIVERSAL-x86-x64-libSystem.B.dylib ├── core ├── elf-ARM64-bash ├── elf-ARMv7-ls ├── elf-FreeBSD-x86 ├── elf-Linux-RISCV_32 ├── elf-Linux-RISCV_64 ├── elf-Linux-x64 ├── elf-Linux-x86 ├── elf-Linux-x86-NDH-chall ├── elf-Mips-Defcon-20-pwn100 ├── elf-PPC64-bash ├── elf-PowerPC-bash ├── elf-SparcV8-bash ├── elf-x64-bash-v4.1.5.1 ├── elf-x86-bash-v4.1.5.1 ├── macho-ppc-openssl ├── macho-x64-ls ├── macho-x86-ls ├── pe-Windows-ARMv7-Thumb2LE-HelloWorld ├── pe-x64-cmd-v6.1.7601 ├── pe-x86-cmd-v6.1.7600 ├── raw-x86.raw ├── ref_output.bz2 └── test.sh /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | pull_request: 6 | 7 | jobs: 8 | build: 9 | 10 | runs-on: ubuntu-22.04 11 | 12 | steps: 13 | - uses: actions/checkout@v2 14 | # - name: Python code style linter 15 | # - uses: wemake-services/wemake-python-styleguide@0.16.0 16 | - name: Build 17 | run: | 18 | sudo apt-get -y install python2 19 | wget https://bootstrap.pypa.io/pip/2.7/get-pip.py 20 | python2 get-pip.py 21 | rm get-pip.py 22 | python2 -m pip install --upgrade setuptools wheel importlib_metadata packaging 23 | python3 -m pip install --upgrade setuptools wheel importlib_metadata packaging 24 | python2 setup.py sdist bdist_wheel 25 | python3 setup.py sdist bdist_wheel 26 | - name: Install 27 | run: | 28 | python2 -m pip install dist/ROPGadget*py2*.whl 29 | python3 -m pip install dist/ropgadget*py3*.whl 30 | - name: Run tests 31 | run: | 32 | cd test-suite-binaries 33 | ./test.sh 34 | ./test.sh python2 35 | cd .. 36 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | build 3 | dist 4 | ROPGadget.egg-info 5 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | 2 | ROPgadget project (>= v5.0) 3 | =================================================== 4 | 5 | Authors: 6 | 7 | * Jonathan Salwan 8 | * Alexey Vishnyakov 9 | 10 | 11 | Contributors: 12 | 13 | * hugsy - Has added the --offset option 14 | * Francisco Falcon - Has fixed the --badbytes option and added the count/loaddb/save2db console features 15 | * 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 16 | * Florian Meier - Added the 64b ROP chain generation 17 | * Álvaro Felipe Melchor (increase performance) 18 | * Sascha Schirra (features, python3, bugs fix) 19 | * Stephen Edwards (increase performance) 20 | * Mikhail Davidov (features) 21 | * penguin-wwy (features) 22 | * Alexey Nurmukhametov (increase performance) 23 | * Mario Haustein (PowerPC for MachO binaries) 24 | * pkubaj (PowerPC 64-bit) 25 | * 0xMirasio (RISC-V 64 and Compressed) 26 | 27 | 28 | 29 | ROPgadget initial project (<= v4.0.3) 30 | =================================================== 31 | 32 | Authors: 33 | 34 | * Jonathan Salwan 35 | * Allan Wirth 36 | 37 | 38 | Contributors: 39 | 40 | * Hellman (Bug Fix) 41 | * Axel "0vercl0k" Souchet (Bug Fix) 42 | * k3rensk1 (Bug repport) 43 | * brianairb (Bug Fix) 44 | * cao (Bug Fix) 45 | * dark-rose (Made searching for gadgets faster) 46 | * Dennis Semakin (Bug Fix) 47 | -------------------------------------------------------------------------------- /LICENSE_BSD.txt: -------------------------------------------------------------------------------- 1 | This is the software license for the ROPgadget project. 2 | 3 | Copyright (c) 2016-2023. All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 8 | * Redistributions of source code must retain the above copyright notice, 9 | this list of conditions and the following disclaimer. 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | * Neither the name of the developers nor the names of its 14 | contributors may be used to endorse or promote products derived from this 15 | software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE 21 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27 | POSSIBILITY OF SUCH DAMAGE. 28 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ROPgadget Tool 2 | ============== 3 | 4 | This tool lets you search your gadgets on your binaries to facilitate your ROP 5 | exploitation. ROPgadget supports ELF/PE/Mach-O/Raw formats on x86, x64, ARM, 6 | ARM64, PowerPC, SPARC, MIPS, RISC-V 64, and RISC-V Compressed architectures. 7 | 8 | Install 9 | ------- 10 | 11 | The easiest way is installing ROPgadget from PyPi: 12 | 13 | $ sudo apt install python3-pip 14 | $ sudo -H python3 -m pip install ROPgadget 15 | $ ROPgadget --help 16 | 17 | Alternatively you can install ROPgadget from source. 18 | You have to install [Capstone](http://www.capstone-engine.org/) first. 19 | 20 | For the Capstone's installation on nix machine: 21 | 22 | $ sudo apt install python3-pip 23 | $ sudo -H python3 -m pip install capstone 24 | 25 | Capstone supports multi-platforms (windows, ios, android, cygwin...). For the cross-compilation, 26 | please refer to the https://github.com/capstone-engine/capstone/blob/master/COMPILE.TXT file. 27 | 28 | After Capstone is installed, ROPgadget can be used as a standalone tool: 29 | 30 | $ python3 ROPgadget.py --help 31 | 32 | Or installed into the Python site-packages library, and executed from $PATH. 33 | 34 | $ sudo -H python3 setup.py install 35 | $ ROPgadget --help 36 | 37 | Usage 38 | ----- 39 | 40 | usage: ROPgadget.py [-h] [-v] [-c] [--binary ] [--opcode ] 41 | [--string ] [--memstr ] [--depth ] 42 | [--only ] [--filter ] [--range ] 43 | [--badbytes ] [--rawArch ] [--rawMode ] 44 | [--rawEndian ] [--re ] [--offset ] 45 | [--ropchain] [--thumb] [--console] [--norop] [--nojop] 46 | [--callPreceded] [--nosys] [--multibr] [--all] [--noinstr] 47 | [--dump] [--silent] [--align ALIGN] [--mipsrop ] 48 | 49 | description: 50 | ROPgadget lets you search your gadgets on a binary. It supports several 51 | file formats and architectures and uses the Capstone disassembler for 52 | the search engine. 53 | 54 | formats supported: 55 | - ELF 56 | - PE 57 | - Mach-O 58 | - Raw 59 | 60 | architectures supported: 61 | - x86 62 | - x86-64 63 | - ARM 64 | - ARM64 65 | - MIPS 66 | - PowerPC 67 | - Sparc 68 | - RISC-V 64 69 | - RISC-V Compressed 70 | 71 | optional arguments: 72 | -h, --help show this help message and exit 73 | -v, --version Display the ROPgadget's version 74 | -c, --checkUpdate Checks if a new version is available 75 | --binary Specify a binary filename to analyze 76 | --opcode Search opcode in executable segment 77 | --string Search string in readable segment 78 | --memstr Search each byte in all readable segment 79 | --depth Depth for search engine (default 10) 80 | --only Only show specific instructions 81 | --filter Suppress specific mnemonics 82 | --range Search between two addresses (0x...-0x...) 83 | --badbytes Rejects specific bytes in the gadget's address 84 | --rawArch Specify an arch for a raw file 85 | x86|arm|arm64|sparc|mips|ppc|riscv 86 | --rawMode Specify a mode for a raw file 32|64|arm|thumb 87 | --rawEndian Specify an endianness for a raw file little|big 88 | --re Regular expression 89 | --offset Specify an offset for gadget addresses 90 | --ropchain Enable the ROP chain generation 91 | --thumb Use the thumb mode for the search engine (ARM only) 92 | --console Use an interactive console for search engine 93 | --norop Disable ROP search engine 94 | --nojop Disable JOP search engine 95 | --callPreceded Only show gadgets which are call-preceded 96 | --nosys Disable SYS search engine 97 | --multibr Enable multiple branch gadgets 98 | --all Disables the removal of duplicate gadgets 99 | --noinstr Disable the gadget instructions console printing 100 | --dump Outputs the gadget bytes 101 | --silent Disables printing of gadgets during analysis 102 | --align ALIGN Align gadgets addresses (in bytes) 103 | --mipsrop MIPS useful gadgets finder 104 | stackfinder|system|tails|lia0|registers 105 | 106 | examples: 107 | ROPgadget.py --binary ./test-suite-binaries/elf-Linux-x86 108 | ROPgadget.py --binary ./test-suite-binaries/elf-Linux-x86 --ropchain 109 | ROPgadget.py --binary ./test-suite-binaries/elf-Linux-x86 --depth 3 110 | ROPgadget.py --binary ./test-suite-binaries/elf-Linux-x86 --string "main" 111 | ROPgadget.py --binary ./test-suite-binaries/elf-Linux-x86 --string "m..n" 112 | ROPgadget.py --binary ./test-suite-binaries/elf-Linux-x86 --opcode c9c3 113 | ROPgadget.py --binary ./test-suite-binaries/elf-Linux-x86 --only "mov|ret" 114 | ROPgadget.py --binary ./test-suite-binaries/elf-Linux-x86 --only "mov|pop|xor|ret" 115 | ROPgadget.py --binary ./test-suite-binaries/elf-Linux-x86 --filter "xchg|add|sub|cmov.*" 116 | ROPgadget.py --binary ./test-suite-binaries/elf-Linux-x86 --norop --nosys 117 | ROPgadget.py --binary ./test-suite-binaries/elf-Linux-x86 --range 0x08041000-0x08042000 118 | ROPgadget.py --binary ./test-suite-binaries/elf-Linux-x86 --string main --range 0x080c9aaa-0x080c9aba 119 | ROPgadget.py --binary ./test-suite-binaries/elf-Linux-x86 --memstr "/bin/sh" 120 | ROPgadget.py --binary ./test-suite-binaries/elf-Linux-x86 --console 121 | ROPgadget.py --binary ./test-suite-binaries/elf-Linux-x86 --badbytes "00|01-1f|7f|42" 122 | ROPgadget.py --binary ./test-suite-binaries/Linux_lib64.so --offset 0xdeadbeef00000000 123 | ROPgadget.py --binary ./test-suite-binaries/elf-ARMv7-ls --depth 5 124 | ROPgadget.py --binary ./test-suite-binaries/elf-ARM64-bash --depth 5 125 | ROPgadget.py --binary ./test-suite-binaries/raw-x86.raw --rawArch=x86 --rawMode=32 126 | ROPgadget.py --binary ./test-suite-binaries/elf-Linux-RISCV_64 --depth 8 127 | 128 | How can I contribute ? 129 | ---------------------- 130 | 131 | - Add system gadgets for PPC, Sparc, ARM64 (Gadgets.addSYSGadgets()). 132 | - Support RISC-V 32-bit. 133 | - Handle bad bytes in data during ROP chain generation. 134 | - Manage big endian in Mach-O format like the ELF class. 135 | - Everything you think is cool :) 136 | 137 | Bugs/Patches/Contact 138 | -------------------- 139 | 140 | Please, report bugs, submit pull requests, etc. on GitHub at https://github.com/JonathanSalwan/ROPgadget 141 | 142 | License 143 | ------- 144 | 145 | See LICENSE_BSD.txt and the license header on all source files. 146 | 147 | Screenshots 148 | ----------- 149 | 150 | x64 151 | 152 | ARM 153 | 154 | Sparc 155 | 156 | MIPS 157 | 158 | PowerPC 159 | 160 | ROP chain 161 | -------------------------------------------------------------------------------- /ROPgadget.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ## -*- coding: utf-8 -*- 3 | ## 4 | ## Jonathan Salwan - 2014-05-12 - ROPgadget tool 5 | ## 6 | ## http://twitter.com/JonathanSalwan 7 | ## http://shell-storm.org/project/ROPgadget/ 8 | ## 9 | 10 | import ropgadget 11 | 12 | ropgadget.main() 13 | -------------------------------------------------------------------------------- /ropgadget/__init__.py: -------------------------------------------------------------------------------- 1 | ## -*- coding: utf-8 -*- 2 | ## 3 | ## Jonathan Salwan - 2014-05-12 - ROPgadget tool 4 | ## 5 | ## http://twitter.com/JonathanSalwan 6 | ## http://shell-storm.org/project/ROPgadget/ 7 | ## 8 | 9 | import ropgadget.args 10 | import ropgadget.binary 11 | import ropgadget.core 12 | import ropgadget.gadgets 13 | import ropgadget.loaders 14 | import ropgadget.options 15 | import ropgadget.rgutils 16 | import ropgadget.ropchain 17 | import ropgadget.updateAlert 18 | import ropgadget.version 19 | 20 | 21 | def main(): 22 | import sys 23 | from ropgadget.args import Args 24 | from ropgadget.core import Core 25 | try: 26 | args = Args() 27 | except ValueError as e: 28 | print(e) 29 | sys.exit(-1) 30 | sys.exit(0 if Core(args.getArgs()).analyze() else 1) 31 | -------------------------------------------------------------------------------- /ropgadget/args.py: -------------------------------------------------------------------------------- 1 | ## -*- coding: utf-8 -*- 2 | ## 3 | ## Jonathan Salwan - 2014-05-12 - ROPgadget tool 4 | ## 5 | ## http://twitter.com/JonathanSalwan 6 | ## http://shell-storm.org/project/ROPgadget/ 7 | ## 8 | 9 | import argparse 10 | import sys 11 | 12 | from ropgadget.updateAlert import UpdateAlert 13 | from ropgadget.version import * 14 | 15 | 16 | class Args(object): 17 | def __init__(self, arguments=None): 18 | self.__args = None 19 | custom_arguments_provided = True 20 | 21 | # If no custom arguments are provided, use the program arguments 22 | if not arguments: 23 | arguments = sys.argv[1:] 24 | custom_arguments_provided = False 25 | 26 | self.__parse(arguments, custom_arguments_provided) 27 | 28 | def __parse(self, arguments, custom_arguments_provided=False): 29 | parser = argparse.ArgumentParser(formatter_class=argparse.RawDescriptionHelpFormatter, 30 | description="""description: 31 | ROPgadget lets you search your gadgets on a binary. It supports several 32 | file formats and architectures and uses the Capstone disassembler for 33 | the search engine. 34 | 35 | formats supported: 36 | - ELF 37 | - PE 38 | - Mach-O 39 | - Raw 40 | 41 | architectures supported: 42 | - x86 43 | - x86-64 44 | - ARM 45 | - ARM64 46 | - MIPS 47 | - PowerPC 48 | - Sparc 49 | - RISC-V 64 50 | - RISC-V Compressed 51 | """, 52 | epilog="""examples: 53 | ROPgadget.py --binary ./test-suite-binaries/elf-Linux-x86 54 | ROPgadget.py --binary ./test-suite-binaries/elf-Linux-x86 --ropchain 55 | ROPgadget.py --binary ./test-suite-binaries/elf-Linux-x86 --depth 3 56 | ROPgadget.py --binary ./test-suite-binaries/elf-Linux-x86 --string "main" 57 | ROPgadget.py --binary ./test-suite-binaries/elf-Linux-x86 --string "m..n" 58 | ROPgadget.py --binary ./test-suite-binaries/elf-Linux-x86 --opcode c9c3 59 | ROPgadget.py --binary ./test-suite-binaries/elf-Linux-x86 --only "mov|ret" 60 | ROPgadget.py --binary ./test-suite-binaries/elf-Linux-x86 --only "mov|pop|xor|ret" 61 | ROPgadget.py --binary ./test-suite-binaries/elf-Linux-x86 --filter "xchg|add|sub|cmov.*" 62 | ROPgadget.py --binary ./test-suite-binaries/elf-Linux-x86 --norop --nosys 63 | ROPgadget.py --binary ./test-suite-binaries/elf-Linux-x86 --range 0x08041000-0x08042000 64 | ROPgadget.py --binary ./test-suite-binaries/elf-Linux-x86 --string main --range 0x080c9aaa-0x080c9aba 65 | ROPgadget.py --binary ./test-suite-binaries/elf-Linux-x86 --memstr "/bin/sh" 66 | ROPgadget.py --binary ./test-suite-binaries/elf-Linux-x86 --console 67 | ROPgadget.py --binary ./test-suite-binaries/elf-Linux-x86 --badbytes "00|01-1f|7f|42" 68 | ROPgadget.py --binary ./test-suite-binaries/Linux_lib64.so --offset 0xdeadbeef00000000 69 | ROPgadget.py --binary ./test-suite-binaries/elf-ARMv7-ls --depth 5 70 | ROPgadget.py --binary ./test-suite-binaries/elf-ARM64-bash --depth 5 71 | ROPgadget.py --binary ./test-suite-binaries/raw-x86.raw --rawArch=x86 --rawMode=32 72 | ROPgadget.py --binary ./test-suite-binaries/elf-Linux-RISCV_64 --depth 8 73 | """) 74 | 75 | parser.add_argument("-v", "--version", action="store_true", help="Display the ROPgadget's version") 76 | parser.add_argument("-c", "--checkUpdate", action="store_true", help="Checks if a new version is available") 77 | parser.add_argument("--binary", type=str, metavar="", help="Specify a binary filename to analyze") 78 | parser.add_argument("--opcode", type=str, metavar="", help="Search opcode in executable segment") 79 | parser.add_argument("--string", type=str, metavar="", help="Search string in readable segment") 80 | parser.add_argument("--memstr", type=str, metavar="", help="Search each byte in all readable segment") 81 | parser.add_argument("--depth", type=int, metavar="", default=10, help="Depth for search engine (default 10)") 82 | parser.add_argument("--only", type=str, metavar="", help="Only show specific instructions") 83 | parser.add_argument("--filter", type=str, metavar="", help="Suppress specific mnemonics") 84 | parser.add_argument("--range", type=str, metavar="", default="0x0-0x0", help="Search between two addresses (0x...-0x...)") 85 | parser.add_argument("--badbytes", type=str, metavar="", help="Rejects specific bytes in the gadget's address") 86 | parser.add_argument("--rawArch", type=str, metavar="", help="Specify an arch for a raw file x86|arm|arm64|sparc|mips|ppc|riscv") 87 | parser.add_argument("--rawMode", type=str, metavar="", help="Specify a mode for a raw file 32|64|arm|thumb") 88 | parser.add_argument("--rawEndian", type=str, metavar="", help="Specify an endianness for a raw file little|big") 89 | parser.add_argument("--re", type=str, metavar="", help="Regular expression") 90 | parser.add_argument("--offset", type=str, metavar="", help="Specify an offset for gadget addresses") 91 | parser.add_argument("--ropchain", action="store_true", help="Enable the ROP chain generation") 92 | parser.add_argument("--thumb", action="store_true", help="Use the thumb mode for the search engine (ARM only)") 93 | parser.add_argument("--console", action="store_true", help="Use an interactive console for search engine") 94 | parser.add_argument("--norop", action="store_true", help="Disable ROP search engine") 95 | parser.add_argument("--nojop", action="store_true", help="Disable JOP search engine") 96 | parser.add_argument("--callPreceded", action="store_true", help="Only show gadgets which are call-preceded") 97 | parser.add_argument("--nosys", action="store_true", help="Disable SYS search engine") 98 | parser.add_argument("--multibr", action="store_true", help="Enable multiple branch gadgets") 99 | parser.add_argument("--all", action="store_true", help="Disables the removal of duplicate gadgets") 100 | parser.add_argument("--noinstr", action="store_true", help="Disable the gadget instructions console printing") 101 | parser.add_argument("--dump", action="store_true", help="Outputs the gadget bytes") 102 | parser.add_argument("--silent", action="store_true", help="Disables printing of gadgets during analysis") 103 | parser.add_argument("--align", type=int, help="Align gadgets addresses (in bytes)") 104 | parser.add_argument("--mipsrop", type=str, metavar="", help="MIPS useful gadgets finder stackfinder|system|tails|lia0|registers") 105 | 106 | self.__args = parser.parse_args(arguments) 107 | 108 | if self.__args.noinstr and self.__args.only: 109 | raise ValueError("[Error] --noinstr and --only= can't be used together") 110 | 111 | if self.__args.noinstr and self.__args.re: 112 | raise ValueError("[Error] --noinstr and --re= can't be used together") 113 | 114 | if self.__args.thumb and self.__args.rawMode and self.__args.rawMode != "thumb": 115 | raise ValueError("[Error] --rawMode is conflicting with --thumb") 116 | 117 | if not self.__args.rawArch and self.__args.rawMode: 118 | raise ValueError("[Error] Specify --rawArch") 119 | 120 | if not self.__args.rawArch and self.__args.rawEndian: 121 | raise ValueError("[Error] Specify --rawArch") 122 | 123 | rawMode = "thumb" if self.__args.thumb else self.__args.rawMode 124 | 125 | if self.__args.rawArch and not rawMode: 126 | raise ValueError("[Error] Specify --rawMode") 127 | 128 | if self.__args.rawArch and not self.__args.rawEndian and self.__args.rawArch != "x86": 129 | raise ValueError("[Error] Specify --rawEndian") 130 | 131 | if self.__args.version: 132 | self.__printVersion() 133 | sys.exit(0) 134 | 135 | elif self.__args.checkUpdate: 136 | UpdateAlert().checkUpdate() 137 | sys.exit(0) 138 | 139 | elif self.__args.depth < 2: 140 | raise ValueError("[Error] The depth must be >= 2") 141 | 142 | elif not custom_arguments_provided and not self.__args.binary and not self.__args.console: 143 | raise ValueError("[Error] Need a binary filename (--binary/--console or --help)") 144 | 145 | elif self.__args.range: 146 | try: 147 | rangeS = int(self.__args.range.split('-')[0], 16) 148 | rangeE = int(self.__args.range.split('-')[1], 16) 149 | except: 150 | raise ValueError("[Error] A range must be set in hexadecimal. Ex: 0x08041000-0x08042000") 151 | if rangeS > rangeE: 152 | raise ValueError("[Error] The start value must be greater than end value") 153 | 154 | def __printVersion(self): 155 | print("Version: %s" % (PYROPGADGET_VERSION)) 156 | print("Author: Jonathan Salwan") 157 | print("Author page: https://twitter.com/JonathanSalwan") 158 | print("Project page: http://shell-storm.org/project/ROPgadget/") 159 | 160 | def getArgs(self): 161 | return self.__args 162 | -------------------------------------------------------------------------------- /ropgadget/binary.py: -------------------------------------------------------------------------------- 1 | ## -*- coding: utf-8 -*- 2 | ## 3 | ## Jonathan Salwan - 2014-05-12 - ROPgadget tool 4 | ## 5 | ## http://twitter.com/JonathanSalwan 6 | ## http://shell-storm.org/project/ROPgadget/ 7 | ## 8 | 9 | from binascii import unhexlify 10 | 11 | from ropgadget.loaders.elf import * 12 | from ropgadget.loaders.macho import * 13 | from ropgadget.loaders.pe import * 14 | from ropgadget.loaders.raw import * 15 | from ropgadget.loaders.universal import * 16 | 17 | 18 | class Binary(object): 19 | def __init__(self, options): 20 | self.__fileName = options.binary 21 | self.__rawBinary = None 22 | self.__binary = None 23 | 24 | try: 25 | fd = open(self.__fileName, "rb") 26 | self.__rawBinary = fd.read() 27 | fd.close() 28 | except: 29 | print("[Error] Can't open the binary or binary not found") 30 | return None 31 | 32 | if options.rawArch: 33 | self.__binary = Raw( 34 | self.__rawBinary, 35 | options.rawArch, 36 | "thumb" if options.thumb else options.rawMode, 37 | options.rawEndian, 38 | ) 39 | elif self.__rawBinary[:4] == unhexlify(b"7f454c46"): 40 | self.__binary = ELF(self.__rawBinary) 41 | elif self.__rawBinary[:2] == unhexlify(b"4d5a"): 42 | self.__binary = PE(self.__rawBinary) 43 | elif self.__rawBinary[:4] == unhexlify(b"cafebabe"): 44 | self.__binary = UNIVERSAL(self.__rawBinary) 45 | elif self.__rawBinary[:4] == unhexlify(b"cefaedfe") or self.__rawBinary[:4] == unhexlify(b"cffaedfe") or \ 46 | self.__rawBinary[:4] == unhexlify(b"feedface") or self.__rawBinary[:4] == unhexlify(b"feedfacf"): 47 | self.__binary = MACHO(self.__rawBinary) 48 | else: 49 | print("[Error] Binary format not supported") 50 | return None 51 | 52 | def getFileName(self): 53 | return self.__fileName 54 | 55 | def getRawBinary(self): 56 | return self.__rawBinary 57 | 58 | def getBinary(self): 59 | return self.__binary 60 | 61 | def getEntryPoint(self): 62 | return self.__binary.getEntryPoint() 63 | 64 | def getDataSections(self): 65 | return self.__binary.getDataSections() 66 | 67 | def getExecSections(self): 68 | return self.__binary.getExecSections() 69 | 70 | def getArch(self): 71 | return self.__binary.getArch() 72 | 73 | def getArchMode(self): 74 | return self.__binary.getArchMode() 75 | 76 | def getEndian(self): 77 | return self.__binary.getEndian() 78 | 79 | def getFormat(self): 80 | return self.__binary.getFormat() 81 | -------------------------------------------------------------------------------- /ropgadget/core.py: -------------------------------------------------------------------------------- 1 | ## -*- coding: utf-8 -*- 2 | ## 3 | ## Jonathan Salwan - 2014-05-17 - ROPgadget tool 4 | ## 5 | ## http://twitter.com/JonathanSalwan 6 | ## http://shell-storm.org/project/ROPgadget/ 7 | ## 8 | 9 | import binascii 10 | import cmd 11 | import re 12 | import string 13 | 14 | from capstone import CS_MODE_32 15 | 16 | import ropgadget.rgutils as rgutils 17 | from ropgadget.binary import Binary 18 | from ropgadget.gadgets import Gadgets 19 | from ropgadget.options import Options 20 | from ropgadget.ropchain.ropmaker import ROPMaker 21 | 22 | 23 | class Core(cmd.Cmd): 24 | def __init__(self, options): 25 | cmd.Cmd.__init__(self) 26 | self.__options = options 27 | self.__binary = None 28 | self.__gadgets = [] 29 | self.__offset = 0 30 | self.prompt = '(ROPgadget)> ' 31 | 32 | def __checksBeforeManipulations(self): 33 | if self.__binary is None or self.__binary.getBinary() is None or self.__binary.getArch() is None or self.__binary.getArchMode() is None or self.__binary.getEndian() is None: 34 | return False 35 | return True 36 | 37 | def _sectionInRange(self, section): 38 | """Given a section and a range, edit the section so that all opcodes are within the range""" 39 | if self.__options.range == "0x0-0x0": 40 | return section 41 | 42 | rangeStart, rangeEnd = map(lambda x: int(x, 16), self.__options.range.split('-')) 43 | 44 | sectionStart = section['vaddr'] 45 | sectionEnd = sectionStart + section['size'] 46 | 47 | opcodes = section['opcodes'] 48 | if rangeEnd < sectionStart or rangeStart > sectionEnd: 49 | return None 50 | if rangeStart > sectionStart: 51 | diff = rangeStart - sectionStart 52 | opcodes = opcodes[diff:] 53 | section['vaddr'] += diff 54 | section['offset'] += diff 55 | section['size'] -= diff 56 | if rangeEnd < sectionEnd: 57 | diff = sectionEnd - rangeEnd 58 | opcodes = opcodes[:-diff] 59 | section['size'] -= diff 60 | 61 | if not section['size']: 62 | return None 63 | section['opcodes'] = opcodes 64 | return section 65 | 66 | def __getGadgets(self): 67 | if not self.__checksBeforeManipulations(): 68 | return False 69 | 70 | G = Gadgets(self.__binary, self.__options, self.__offset) 71 | execSections = self.__binary.getExecSections() 72 | 73 | # Find ROP/JOP/SYS gadgets 74 | self.__gadgets = [] 75 | for section in execSections: 76 | section = self._sectionInRange(section) 77 | if not section: 78 | continue 79 | if not self.__options.norop: 80 | self.__gadgets += G.addROPGadgets(section) 81 | if not self.__options.nojop: 82 | self.__gadgets += G.addJOPGadgets(section) 83 | if not self.__options.nosys: 84 | self.__gadgets += G.addSYSGadgets(section) 85 | 86 | # Delete duplicate gadgets 87 | if not self.__options.all and not self.__options.noinstr: 88 | self.__gadgets = rgutils.deleteDuplicateGadgets(self.__gadgets) 89 | 90 | # Applicate some Options 91 | self.__gadgets = Options(self.__options, self.__binary, self.__gadgets).getGadgets() 92 | 93 | # Sorted alphabetically 94 | if not self.__options.noinstr: 95 | self.__gadgets = rgutils.alphaSortgadgets(self.__gadgets) 96 | 97 | return True 98 | 99 | def __lookingForGadgets(self): 100 | if not self.__checksBeforeManipulations(): 101 | return False 102 | 103 | if self.__options.silent: 104 | return True 105 | 106 | arch = self.__binary.getArchMode() 107 | print("Gadgets information\n============================================================") 108 | for gadget in self.__gadgets: 109 | vaddr = gadget["vaddr"] 110 | insts = gadget.get("gadget", "") 111 | insts = " : {}".format(insts) if insts else "" 112 | bytesStr = " // " + binascii.hexlify(gadget["bytes"]).decode('utf8') if self.__options.dump else "" 113 | print("0x{{0:0{}x}}{{1}}{{2}}".format(8 if arch == CS_MODE_32 else 16).format(vaddr, insts, bytesStr)) 114 | 115 | print("\nUnique gadgets found: %d" % (len(self.__gadgets))) 116 | return True 117 | 118 | def __lookingForMIPSgadgets(self, mips_option): 119 | if not self.__checksBeforeManipulations(): 120 | return False 121 | 122 | if self.__options.silent: 123 | return True 124 | 125 | arch = self.__binary.getArchMode() 126 | if mips_option == 'stackfinder': 127 | mipsFindRegex = [r'addiu .*, \$sp'] 128 | elif mips_option == 'system': 129 | mipsFindRegex = [r'addiu \$a0, \$sp'] 130 | elif mips_option == 'tails': 131 | mipsFindRegex = [r'lw \$t[0-9], 0x[0-9a-z]{0,4}\(\$s[0-9]', r'move \$t9, \$(s|a|v)'] 132 | elif mips_option == 'lia0': 133 | mipsFindRegex = [r'li \$a0'] 134 | elif mips_option == 'registers': 135 | mipsFindRegex = [r'lw \$ra, 0x[0-9a-z]{0,4}\(\$sp'] 136 | else: 137 | print("Unrecognized option " + mips_option) 138 | print("Accepted options stackfinder|system|tails|lia0|registers") 139 | return False 140 | 141 | print("MIPS ROP (" + mips_option + ")\n============================================================") 142 | self.__getGadgets() 143 | 144 | gadget_counter = 0 145 | for gadget in self.__gadgets: 146 | vaddr = gadget["vaddr"] 147 | insts = gadget.get("gadget", "") 148 | insts = " : {}".format(insts) if insts else "" 149 | bytesStr = " // " + binascii.hexlify(gadget["bytes"]).decode('utf8') if self.__options.dump else "" 150 | for thisRegex in mipsFindRegex: 151 | toFind = re.findall(thisRegex, insts) 152 | if toFind: 153 | print("0x{{0:0{}x}}{{1}}{{2}}".format(8 if arch == CS_MODE_32 else 16).format(vaddr, insts, bytesStr)) 154 | gadget_counter += 1 155 | 156 | print("\nUnique gadgets found: %d" % gadget_counter) 157 | return True 158 | 159 | def __lookingForAString(self, s): 160 | if not self.__checksBeforeManipulations(): 161 | return False 162 | 163 | if self.__options.silent: 164 | return True 165 | 166 | dataSections = self.__binary.getDataSections() 167 | arch = self.__binary.getArchMode() 168 | print("Strings information\n============================================================") 169 | for section in dataSections: 170 | section = self._sectionInRange(section) 171 | if not section: 172 | continue 173 | allRef = [m.start() for m in re.finditer(s.encode(), section["opcodes"])] 174 | for ref in allRef: 175 | vaddr = self.__offset + section["vaddr"] + ref 176 | match = section["opcodes"][ref:ref + len(s)] 177 | printable = string.printable.encode() 178 | match = "".join((chr(m) if isinstance(m, int) else m) if m in printable else "." for m in match) 179 | print("0x{{0:0{}x}} : {{1}}".format(8 if arch == CS_MODE_32 else 16).format(vaddr, match)) 180 | return True 181 | 182 | def __lookingForOpcodes(self, opcodes): 183 | if not self.__checksBeforeManipulations(): 184 | return False 185 | 186 | if self.__options.silent: 187 | return True 188 | 189 | execSections = self.__binary.getExecSections() 190 | arch = self.__binary.getArchMode() 191 | print("Opcodes information\n============================================================") 192 | for section in execSections: 193 | section = self._sectionInRange(section) 194 | if not section: 195 | continue 196 | allRef = [m.start() for m in re.finditer(re.escape(binascii.unhexlify(opcodes)), section["opcodes"])] 197 | for ref in allRef: 198 | vaddr = self.__offset + section["vaddr"] + ref 199 | print("0x{{0:0{}x}} : {{1}}".format(8 if arch == CS_MODE_32 else 16).format(vaddr, opcodes)) 200 | return True 201 | 202 | def __lookingForMemStr(self, memstr): 203 | if not self.__checksBeforeManipulations(): 204 | return False 205 | 206 | if self.__options.silent: 207 | return True 208 | 209 | sections = self.__binary.getExecSections() 210 | sections += self.__binary.getDataSections() 211 | arch = self.__binary.getArchMode() 212 | print("Memory bytes information\n=======================================================") 213 | chars = list(memstr) 214 | for char in chars: 215 | try: 216 | for section in sections: 217 | section = self._sectionInRange(section) 218 | if not section: 219 | continue 220 | allRef = [m.start() for m in re.finditer(char.encode('utf-8'), section["opcodes"])] 221 | for ref in allRef: 222 | vaddr = self.__offset + section["vaddr"] + ref 223 | print("0x{{0:0{}x}} : '{{1}}'".format(8 if arch == CS_MODE_32 else 16).format(vaddr, char)) 224 | raise 225 | except: 226 | pass 227 | return True 228 | 229 | def analyze(self): 230 | try: 231 | self.__offset = int(self.__options.offset, 16) if self.__options.offset else 0 232 | except ValueError: 233 | print("[Error] The offset must be in hexadecimal") 234 | return False 235 | 236 | if self.__options.console: 237 | if self.__options.binary: 238 | self.__binary = Binary(self.__options) 239 | if not self.__checksBeforeManipulations(): 240 | return False 241 | self.cmdloop() 242 | return True 243 | 244 | self.__binary = Binary(self.__options) 245 | if not self.__checksBeforeManipulations(): 246 | return False 247 | 248 | if self.__options.string: 249 | return self.__lookingForAString(self.__options.string) 250 | elif self.__options.opcode: 251 | return self.__lookingForOpcodes(self.__options.opcode) 252 | elif self.__options.memstr: 253 | return self.__lookingForMemStr(self.__options.memstr) 254 | elif self.__options.mipsrop: 255 | return self.__lookingForMIPSgadgets(self.__options.mipsrop) 256 | else: 257 | self.__getGadgets() 258 | self.__lookingForGadgets() 259 | if self.__options.ropchain: 260 | ROPMaker(self.__binary, self.__gadgets, self.__offset) 261 | return True 262 | 263 | def gadgets(self): 264 | return self.__gadgets 265 | 266 | # Console methods ============================================ 267 | def do_binary(self, s, silent=False): 268 | # Do not split the filename with spaces since it might contain 269 | # whitespaces 270 | if not s: 271 | if not silent: 272 | return self.help_binary() 273 | return False 274 | 275 | binary = s 276 | 277 | self.__options.binary = binary 278 | self.__binary = Binary(self.__options) 279 | if not self.__checksBeforeManipulations(): 280 | return False 281 | 282 | if not silent: 283 | print("[+] Binary loaded") 284 | 285 | def help_binary(self): 286 | print("Syntax: binary -- Load a binary") 287 | return False 288 | 289 | def do_EOF(self, s, silent=False): 290 | return self.do_quit(s, silent) 291 | 292 | def do_quit(self, s, silent=False): 293 | return True 294 | 295 | def help_quit(self): 296 | print("Syntax: quit -- Terminates the application") 297 | return False 298 | 299 | def do_load(self, s, silent=False): 300 | if self.__binary is None: 301 | if not silent: 302 | print("[-] No binary loaded.") 303 | return False 304 | 305 | if not silent: 306 | print("[+] Loading gadgets, please wait...") 307 | self.__getGadgets() 308 | 309 | if not silent: 310 | print("[+] Gadgets loaded !") 311 | 312 | def help_load(self): 313 | print("Syntax: load -- Load all gadgets") 314 | return False 315 | 316 | def do_display(self, s, silent=False): 317 | self.__lookingForGadgets() 318 | 319 | def help_display(self): 320 | print("Syntax: display -- Display all gadgets loaded") 321 | return False 322 | 323 | def do_depth(self, s, silent=False): 324 | try: 325 | depth = int(s.split()[0]) 326 | except: 327 | if not silent: 328 | return self.help_depth() 329 | return False 330 | if depth <= 0: 331 | if not silent: 332 | print("[-] The depth value must be > 0") 333 | return False 334 | self.__options.depth = int(depth) 335 | 336 | if not silent: 337 | print("[+] Depth updated. You have to reload gadgets") 338 | 339 | def help_depth(self): 340 | print("Syntax: depth -- Set the depth search engine") 341 | return False 342 | 343 | def do_badbytes(self, s, silent=False): 344 | try: 345 | bb = s.split()[0] 346 | except: 347 | if not silent: 348 | return self.help_badbytes() 349 | else: 350 | return False 351 | self.__options.badbytes = bb 352 | 353 | if not silent: 354 | print("[+] Bad bytes updated. You have to reload gadgets") 355 | 356 | def help_badbytes(self): 357 | print("Syntax: badbytes -- ") 358 | return False 359 | 360 | def __withK(self, listK, gadget): 361 | if not listK: 362 | return True 363 | for a in listK: 364 | if a not in gadget: 365 | return False 366 | return True 367 | 368 | def __withoutK(self, listK, gadget): 369 | for a in listK: 370 | if a in gadget: 371 | return False 372 | return True 373 | 374 | def do_search(self, s, silent=False): 375 | args = s.split() 376 | if not len(args): 377 | return self.help_search() 378 | withK, withoutK = [], [] 379 | for a in args: 380 | if a[0] == "!": 381 | withoutK += [a[1:]] 382 | else: 383 | withK += [a] 384 | if not self.__checksBeforeManipulations(): 385 | if not silent: 386 | print("[-] You have to load a binary") 387 | return False 388 | arch = self.__binary.getArchMode() 389 | for gadget in self.__gadgets: 390 | vaddr = gadget["vaddr"] 391 | insts = gadget["gadget"] 392 | if self.__withK(withK, insts) and self.__withoutK(withoutK, insts): 393 | # What to do if silent = True? 394 | print("0x{{0:0{}x}} : {{1}}".format(8 if arch == CS_MODE_32 else 16).format(vaddr, insts)) 395 | 396 | def help_search(self): 397 | print("Syntax: search -- Filter with or without keywords") 398 | print("keyword = with") 399 | print("!keyword = without") 400 | return False 401 | 402 | def count(self): 403 | return len(self.__gadgets) 404 | 405 | def do_count(self, s, silent=False): 406 | if not silent: 407 | print("[+] %d loaded gadgets." % self.count()) 408 | 409 | def help_count(self): 410 | print("Shows the number of loaded gadgets.") 411 | return False 412 | 413 | def do_filter(self, s, silent=False): 414 | try: 415 | self.__options.filter = s.split()[0] 416 | except: 417 | if not silent: 418 | return self.help_filter() 419 | return False 420 | 421 | if not silent: 422 | print("[+] Filter setted. You have to reload gadgets") 423 | 424 | def help_filter(self): 425 | print("Syntax: filter - Suppress specific mnemonics") 426 | return False 427 | 428 | def do_only(self, s, silent=False): 429 | try: 430 | if s.lower() == "none": 431 | self.__options.only = None 432 | else: 433 | self.__options.only = s.split()[0] 434 | except: 435 | if not silent: 436 | return self.help_only() 437 | return False 438 | 439 | if not silent: 440 | print("[+] Only setted. You have to reload gadgets") 441 | 442 | def help_only(self): 443 | print("Syntax: only - Only show specific instructions") 444 | return False 445 | 446 | def do_range(self, s, silent=False): 447 | try: 448 | rangeS = int(s.split('-')[0], 16) 449 | rangeE = int(s.split('-')[1], 16) 450 | self.__options.range = s.split()[0] 451 | except: 452 | if not silent: 453 | return self.help_range() 454 | return False 455 | 456 | if rangeS > rangeE: 457 | if not silent: 458 | print("[-] The start value must be greater than the end value") 459 | return False 460 | 461 | if not silent: 462 | print("[+] Range setted. You have to reload gadgets") 463 | 464 | def help_range(self): 465 | print("Syntax: range - Search between two addresses (0x...-0x...)") 466 | return False 467 | 468 | def do_settings(self, s, silent=False): 469 | print("All: %s" % self.__options.all) 470 | print("Badbytes: %s" % self.__options.badbytes) 471 | print("Binary: %s" % self.__options.binary) 472 | print("Depth: %s" % self.__options.depth) 473 | print("Filter: %s" % self.__options.filter) 474 | print("Memstr: %s" % self.__options.memstr) 475 | print("MultiBr: %s" % self.__options.multibr) 476 | print("NoJOP: %s" % self.__options.nojop) 477 | print("NoROP: %s" % self.__options.norop) 478 | print("NoSYS: %s" % self.__options.nosys) 479 | print("Offset: %s" % self.__options.offset) 480 | print("Only: %s" % self.__options.only) 481 | print("Opcode: %s" % self.__options.opcode) 482 | print("ROPchain: %s" % self.__options.ropchain) 483 | print("Range: %s" % self.__options.range) 484 | print("RawArch: %s" % self.__options.rawArch) 485 | print("RawMode: %s" % self.__options.rawMode) 486 | print("RawEndian: %s" % self.__options.rawEndian) 487 | print("Re: %s" % self.__options.re) 488 | print("String: %s" % self.__options.string) 489 | print("Thumb: %s" % self.__options.thumb) 490 | print("Mipsrop: %s" % self.__options.mipsrop) 491 | 492 | def help_settings(self): 493 | print("Display setting's environment") 494 | return False 495 | 496 | def do_nojop(self, s, silent=False): 497 | try: 498 | arg = s.split()[0] 499 | except: 500 | return self.help_nojop() 501 | 502 | if arg == "enable": 503 | self.__options.nojop = True 504 | if not silent: 505 | print("[+] NoJOP enable. You have to reload gadgets") 506 | 507 | elif arg == "disable": 508 | self.__options.nojop = False 509 | if not silent: 510 | print("[+] NoJOP disable. You have to reload gadgets") 511 | 512 | else: 513 | if not silent: 514 | return self.help_nojop() 515 | return False 516 | 517 | def help_nojop(self): 518 | print("Syntax: nojop - Disable JOP search engin") 519 | return False 520 | 521 | def do_norop(self, s, silent=False): 522 | try: 523 | arg = s.split()[0] 524 | except: 525 | return self.help_norop() 526 | 527 | if arg == "enable": 528 | self.__options.norop = True 529 | if not silent: 530 | print("[+] NoROP enable. You have to reload gadgets") 531 | 532 | elif arg == "disable": 533 | self.__options.norop = False 534 | if not silent: 535 | print("[+] NoROP disable. You have to reload gadgets") 536 | 537 | else: 538 | if not silent: 539 | return self.help_norop() 540 | return False 541 | 542 | def help_norop(self): 543 | print("Syntax: norop - Disable ROP search engin") 544 | return False 545 | 546 | def do_nosys(self, s, silent=False): 547 | try: 548 | arg = s.split()[0] 549 | except: 550 | return self.help_nosys() 551 | 552 | if arg == "enable": 553 | self.__options.nosys = True 554 | if not silent: 555 | print("[+] NoSYS enable. You have to reload gadgets") 556 | 557 | elif arg == "disable": 558 | self.__options.nosys = False 559 | if not silent: 560 | print("[+] NoSYS disable. You have to reload gadgets") 561 | 562 | else: 563 | if not silent: 564 | return self.help_nosys() 565 | 566 | return False 567 | 568 | def help_nosys(self): 569 | print("Syntax: nosys - Disable SYS search engin") 570 | return False 571 | 572 | def do_thumb(self, s, silent=False): 573 | try: 574 | arg = s.split()[0] 575 | except: 576 | return self.help_thumb() 577 | 578 | if arg == "enable": 579 | self.__options.thumb = True 580 | if not silent: 581 | print("[+] Thumb enable. You have to reload gadgets") 582 | 583 | elif arg == "disable": 584 | self.__options.thumb = False 585 | if not silent: 586 | print("[+] Thumb disable. You have to reload gadgets") 587 | 588 | else: 589 | if not silent: 590 | return self.help_thumb() 591 | return False 592 | 593 | def help_thumb(self): 594 | print("Syntax: thumb - Use the thumb mode for the search engine (ARM only)") 595 | return False 596 | 597 | def do_all(self, s, silent=False): 598 | if s == "enable": 599 | self.__options.all = True 600 | if not silent: 601 | print("[+] Showing all gadgets enabled. You have to reload gadgets") 602 | 603 | elif s == "disable": 604 | self.__options.all = False 605 | if not silent: 606 | print("[+] Showing all gadgets disabled. You have to reload gadgets") 607 | 608 | else: 609 | if not silent: 610 | return self.help_all() 611 | 612 | return False 613 | 614 | def help_multibr(self): 615 | print("Syntax: multibr - Enable/Disable multiple branch gadgets") 616 | return False 617 | 618 | def do_multibr(self, s, silent=False): 619 | if s == "enable": 620 | self.__options.multibr = True 621 | if not silent: 622 | print("[+] Multiple branch gadgets enabled. You have to reload gadgets") 623 | 624 | elif s == "disable": 625 | self.__options.multibr = False 626 | if not silent: 627 | print("[+] Multiple branch gadgets disabled. You have to reload gadgets") 628 | 629 | else: 630 | if not silent: 631 | return self.help_all() 632 | 633 | return False 634 | 635 | def help_all(self): 636 | print("Syntax: all - Regular expression") 641 | return False 642 | 643 | def do_re(self, s, silent=False): 644 | if s.lower() == 'none': 645 | self.__options.re = None 646 | elif s == "": 647 | self.help_re() 648 | silent = True 649 | else: 650 | self.__options.re = s 651 | 652 | if not silent: 653 | print("[+] Re setted. You have to reload gadgets") 654 | -------------------------------------------------------------------------------- /ropgadget/gadgets.py: -------------------------------------------------------------------------------- 1 | ## -*- coding: utf-8 -*- 2 | ## 3 | ## Jonathan Salwan - 2014-05-12 - ROPgadget tool 4 | ## 5 | ## http://twitter.com/JonathanSalwan 6 | ## http://shell-storm.org/project/ROPgadget/ 7 | ## 8 | 9 | import re 10 | 11 | from capstone import * 12 | 13 | 14 | class Gadgets(object): 15 | def __init__(self, binary, options, offset): 16 | self.__binary = binary 17 | self.__options = options 18 | self.__offset = offset 19 | self.__arch = self.__binary.getArch() 20 | 21 | re_str = "" 22 | if self.__arch == CS_ARCH_X86: 23 | re_str = "db|int3" 24 | elif self.__arch == CS_ARCH_ARM64: 25 | re_str = "brk|smc|hvc" 26 | if self.__options.filter: 27 | if re_str: 28 | re_str += "|" 29 | re_str += self.__options.filter 30 | 31 | self.__filterRE = re.compile("({})$".format(re_str)) if re_str else None 32 | 33 | def __passCleanX86(self, decodes): 34 | br = ["ret", "repz ret", "retf", "int", "sysenter", "jmp", "notrack jmp", "call", "notrack call", "syscall", "iret", "iretd", "iretq", "sysret", "sysretq"] 35 | 36 | if decodes[-1][2] not in br: 37 | return True 38 | if not self.__options.multibr and any(mnemonic in br for _, _, mnemonic, _ in decodes[:-1]): 39 | return True 40 | if any("ret" in mnemonic for _, _, mnemonic, _ in decodes[:-1]): 41 | return True 42 | 43 | return False 44 | 45 | def __gadgetsFinding(self, section, gadgets, arch, mode): 46 | 47 | PREV_BYTES = 9 # Number of bytes prior to the gadget to store. 48 | 49 | opcodes = section["opcodes"] 50 | sec_vaddr = section["vaddr"] 51 | 52 | ret = [] 53 | md = Cs(arch, mode) 54 | for gad_op, gad_size, gad_align in gadgets: 55 | if self.__options.align: 56 | gad_align = self.__options.align 57 | allRefRet = [m.start() for m in re.finditer(gad_op, opcodes)] 58 | for ref in allRefRet: 59 | end = ref + gad_size 60 | for i in range(self.__options.depth): 61 | start = ref - (i * gad_align) 62 | if (sec_vaddr + start) % gad_align == 0: 63 | code = opcodes[start:end] 64 | decodes = md.disasm_lite(code, sec_vaddr + start) 65 | decodes = list(decodes) 66 | if sum(size for _, size, _, _ in decodes) != i * gad_align + gad_size: 67 | # We've read less instructions than planned so something went wrong 68 | continue 69 | if arch == CS_ARCH_RISCV and decodes[-1][1] != gad_size: 70 | # Last disassembled instruction has wrong size! This happens 71 | # e.g. if gad_align == 2 and the last two bytes of a 4-byte 72 | # instruction are also a valid 2-byte instruction. 73 | continue 74 | if self.passClean(decodes): 75 | continue 76 | off = self.__offset 77 | vaddr = off + sec_vaddr + start 78 | g = {"vaddr": vaddr} 79 | if not self.__options.noinstr: 80 | g["gadget"] = " ; ".join("{}{}{}".format(mnemonic, " " if op_str else "", op_str) 81 | for _, _, mnemonic, op_str in decodes).replace(" ", " ") 82 | if self.__options.callPreceded: 83 | prevBytesAddr = max(sec_vaddr, vaddr - PREV_BYTES) 84 | g["prev"] = opcodes[prevBytesAddr - sec_vaddr:vaddr - sec_vaddr] 85 | if self.__options.dump: 86 | g["bytes"] = code 87 | ret.append(g) 88 | return ret 89 | 90 | def addROPGadgets(self, section): 91 | 92 | arch = self.__binary.getArch() 93 | arch_mode = self.__binary.getArchMode() 94 | arch_endian = self.__binary.getEndian() 95 | 96 | if arch == CS_ARCH_X86: 97 | gadgets = [ 98 | [br"\xc3", 1, 1], # ret 99 | [br"\xc2[\x00-\xff]{2}", 3, 1], # ret 100 | [br"\xcb", 1, 1], # retf 101 | [br"\xca[\x00-\xff]{2}", 3, 1], # retf 102 | # MPX 103 | [br"\xf2\xc3", 2, 1], # ret 104 | [br"\xf2\xc2[\x00-\xff]{2}", 4, 1], # ret 105 | ] 106 | 107 | elif arch == CS_ARCH_MIPS: 108 | gadgets = [] # MIPS doesn't have RET instructions. Only JOP gadgets 109 | elif arch == CS_ARCH_PPC: 110 | if arch_endian == CS_MODE_BIG_ENDIAN: 111 | gadgets = [ 112 | [br"\x4e\x80\x00\x20", 4, 4], # blr 113 | [br"\x4e\x80\x00\x21", 4, 4], # blrl 114 | [br"\x4e\x80\x04\x20", 4, 4], # bctr 115 | [br"\x4e\x80\x04\x21", 4, 4], # bctrl 116 | ] 117 | else: 118 | gadgets = [ 119 | [br"\x20\x00\x80\x4e", 4, 4], # blr 120 | [br"\x21\x00\x80\x4e", 4, 4], # blrl 121 | [br"\x20\x04\x80\x4e", 4, 4], # bctr 122 | [br"\x21\x04\x80\x4e", 4, 4], # bctrl 123 | ] 124 | 125 | elif arch == CS_ARCH_SPARC: 126 | if arch_endian == CS_MODE_BIG_ENDIAN: 127 | gadgets = [ 128 | [br"\x81\xc3\xe0\x08", 4, 4], # retl 129 | [br"\x81\xc7\xe0\x08", 4, 4], # ret 130 | [br"\x81\xe8\x00\x00", 4, 4] # restore 131 | ] 132 | else: 133 | gadgets = [ 134 | [br"\x08\xe0\xc3\x81", 4, 4], # retl 135 | [br"\x08\xe0\xc7\x81", 4, 4], # ret 136 | [br"\x00\x00\xe8\x81", 4, 4] # restore 137 | ] 138 | arch_mode = 0 139 | 140 | elif arch == CS_ARCH_ARM: 141 | gadgets = [] # ARM doesn't have RET instructions. Only JOP gadgets 142 | elif arch == CS_ARCH_ARM64: 143 | if arch_endian == CS_MODE_BIG_ENDIAN: 144 | gadgets = [ 145 | [br"\xd6\x5f\x03\xc0", 4, 4] # ret 146 | ] 147 | else: 148 | gadgets = [ 149 | [br"\xc0\x03\x5f\xd6", 4, 4] # ret 150 | ] 151 | arch_mode = CS_MODE_ARM 152 | 153 | elif arch == CS_ARCH_RISCV: 154 | if arch_endian == CS_MODE_BIG_ENDIAN: 155 | gadgets = [ 156 | [br"\x80\x82", 2, 1], # c.ret 157 | ] 158 | else: 159 | gadgets = [ 160 | [br"\x82\x80", 2, 1], # c.ret 161 | ] 162 | arch_mode = CS_MODE_RISCV64 | CS_MODE_RISCVC 163 | 164 | else: 165 | print("Gadgets().addROPGadgets() - Architecture not supported") 166 | return None 167 | 168 | if gadgets: 169 | return self.__gadgetsFinding(section, gadgets, arch, arch_mode + arch_endian) 170 | return gadgets 171 | 172 | def addJOPGadgets(self, section): 173 | arch = self.__binary.getArch() 174 | arch_mode = self.__binary.getArchMode() 175 | arch_endian = self.__binary.getEndian() 176 | 177 | if arch == CS_ARCH_X86: 178 | # we start with x86 and x64 common sequences operating on registers 179 | gadgets = [ 180 | # call/jmp reg 181 | # d0-d7=call,e0-e7=jmp 182 | # x86: 0=eax,1=ecx,2=edx,3=ebx,4=esp,5=ebp,6=esi,7=edi 183 | # x64: 0=rax,1=rcx,2=rdx,3=rbx,4=rsp,5=rbp,6=rsi,7=rdi 184 | [br"\xff[\xd0-\xd7\xe0-\xe7]", 2, 1], 185 | 186 | # call/jmp [reg] 187 | # 10-17=call,20-27=jmp 188 | # x86: 0=eax,1=ecx,2=edx,3=ebx, 6=esi,7=edi 189 | # x64: 0=rax,1=rcx,2=rdx,3=rbx, 6=rsi,7=rdi 190 | [br"\xff[\x10-\x13\x16-\x17\x20-\x23\x26-\x27]", 2, 1], 191 | # call/jmp [reg] 192 | # 14=call,24=jmp 193 | # x86: esp 194 | # x64: rsp 195 | [br"\xff[\x14\x24]\x24", 3, 1], 196 | 197 | # call/jmp [reg + offset], -0x80 <= offset <= 0x7f 198 | # 50-57=call,60-67=jmp 199 | # x86: 0=eax,1=ecx,2=edx,3=ebx, 5=ebp,6=esi,7=edi 200 | # x64: 0=rax,1=rcx,2=rdx,3=rbx, 5=rbp,6=rsi,7=rdi 201 | [br"\xff[\x50-\x53\x55-\x57\x60-\x63\x65-\x67][\x00-\xff]", 3, 1], 202 | # call/jmp [reg + offset], -0x80 <= offset <= 0x7f 203 | # 54=call,64=jmp 204 | # x86: esp 205 | # x64: rsp 206 | [br"\xff[\x54\x64]\x24[\x00-\xff]", 4, 1], 207 | 208 | # call/jmp [reg + offset], -0x80000000 <= offset <= 0x7fffffff 209 | # 90-97=call,a0-a7=jmp 210 | # x86: 0=eax,1=ecx,2=edx,3=ebx, 5=ebp,6=esi,7=edi 211 | # x64: 0=rax,1=rcx,2=rdx,3=rbx, 5=rbp,6=rsi,7=rdi 212 | [br"\xff[\x90-\x93\x95-\x97\xa0-\xa3\xa5-\xa7][\x00-\xff]{4}", 6, 1], 213 | # call/jmp [reg + offset], -0x80000000 <= offset <= 0x7fffffff 214 | # 94=call,a4=jmp 215 | # x86: esp 216 | # x64: rsp 217 | [br"\xff[\x94\xa4]\x24[\x00-\xff]{4}", 7, 1] 218 | ] 219 | # in x64, by adding 41 before a sequence with 220 | # 0=rax,1=rcx,2=rdx,3=rbx,4=rsp,5=rbp,6=rsi,7=rdi 221 | # we convert it to the same sequence with 222 | # 0= r8,1= r9,2=r10,3=r11,4=r12,5=r13,6=r14,7=r15 223 | if arch_mode == CS_MODE_64: 224 | gadgets += [(b"\x41" + op, size + 1, align) for (op, size, align) in gadgets] 225 | # finally, add extra sequences common to x86 and x64 226 | gadgets += [ 227 | [br"\xeb[\x00-\xff]", 2, 1], # jmp offset 228 | [br"\xe9[\x00-\xff]{4}", 5, 1], # jmp offset 229 | # MPX 230 | [br"\xf2\xff[\x20\x21\x22\x23\x26\x27]{1}", 3, 1], # jmp [reg] 231 | [br"\xf2\xff[\xe0\xe1\xe2\xe3\xe4\xe6\xe7]{1}", 3, 1], # jmp [reg] 232 | [br"\xf2\xff[\x10\x11\x12\x13\x16\x17]{1}", 3, 1], # jmp [reg] 233 | [br"\xf2\xff[\xd0\xd1\xd2\xd3\xd4\xd6\xd7]{1}", 3, 1] # call [reg] 234 | ] 235 | elif arch == CS_ARCH_MIPS: 236 | if arch_endian == CS_MODE_BIG_ENDIAN: 237 | gadgets = [ 238 | [br"\x00[\x40\x60\x80\xa0\xc0\xe0]\xf8\x09[\x00-\xff]{4}", 8, 4], # jalr $v[0-1]|$a[0-3] 239 | [br"[\x01\x02][\x00\x20\x40\x60\x80\xa0\xc0\xe0]\xf8\x09[\x00-\xff]{4}", 8, 4], # jalr $t[0-7]|$s[0-7] 240 | [br"\x03[\x00\x20\xc0\xe0]\xf8\x09[\x00-\xff]{4}", 8, 4], # jalr $t[8-9]|$s8|$ra 241 | [br"\x00[\x40\x60\x80\xa0\xc0\xe0]\x00\x08[\x00-\xff]{4}", 8, 4], # jr $v[0-1]|$a[0-3] 242 | [br"[\x01\x02][\x00\x20\x40\x60\x80\xa0\xc0\xe0]\x00\x08[\x00-\xff]{4}", 8, 4], # jr $t[0-7]|$s[0-7] 243 | [br"\x03[\x00\x20\xc0\xe0]\x00\x08[\x00-\xff]{4}", 8, 4], # jr $t[8-9]|$s8|$ra 244 | [br"[\x0c-\x0f][\x00-\xff]{7}", 8, 4], # jal addr 245 | [br"[\x08-\x0b][\x00-\xff]{7}", 8, 4] # j addr 246 | ] 247 | else: 248 | gadgets = [ 249 | [br"\x09\xf8[\x40\x60\x80\xa0\xc0\xe0]\x00[\x00-\xff]{4}", 8, 4], # jalr $v[0-1]|$a[0-3] 250 | [br"\x09\xf8[\x00\x20\x40\x60\x80\xa0\xc0\xe0][\x01\x02][\x00-\xff]{4}", 8, 4], # jalr $t[0-7]|$s[0-7] 251 | [br"\x09\xf8[\x00\x20\xc0\xe0]\x03[\x00-\xff]{4}", 8, 4], # jalr $t[8-9]|$s8|$ra 252 | [br"\x08\x00[\x40\x60\x80\xa0\xc0\xe0]\x00[\x00-\xff]{4}", 8, 4], # jr $v[0-1]|$a[0-3] 253 | [br"\x08\x00[\x00\x20\x40\x60\x80\xa0\xc0\xe0][\x01\x02][\x00-\xff]{4}", 8, 4], # jr $t[0-7]|$s[0-7] 254 | [br"\x08\x00[\x00\x20\xc0\xe0]\x03[\x00-\xff]{4}", 8, 4], # jr $t[8-9]|$s8|$ra 255 | [br"[\x00-\xff]{3}[\x0c-\x0f][\x00-\xff]{4}", 8, 4], # jal addr 256 | [br"[\x00-\xff]{3}[\x08-\x0b][\x00-\xff]{4}", 8, 4] # j addr 257 | ] 258 | elif arch == CS_ARCH_PPC: 259 | if arch_endian == CS_MODE_BIG_ENDIAN: 260 | gadgets = [ 261 | [br"\x48[\x00-\xff]{3}", 4, 4] # bl 262 | ] 263 | else: 264 | gadgets = [ 265 | [br"[\x00-\xff]{3}\x48", 4, 4] # bl 266 | ] 267 | 268 | elif arch == CS_ARCH_SPARC: 269 | if arch_endian == CS_MODE_BIG_ENDIAN: 270 | gadgets = [ 271 | [br"\x81\xc0[\x00\x40\x80\xc0]{1}\x00", 4, 4] # jmp %g[0-3] 272 | ] 273 | else: 274 | gadgets = [ 275 | [br"\x00[\x00\x40\x80\xc0]{1}\xc0\x81", 4, 4] # jmp %g[0-3] 276 | ] 277 | arch_mode = 0 278 | elif arch == CS_ARCH_ARM64: 279 | if arch_endian == CS_MODE_BIG_ENDIAN: 280 | gadgets = [ 281 | [br"\xd6[\x1f\x5f]{1}[\x00-\x03]{1}[\x00\x20\x40\x60\x80\xa0\xc0\xe0]{1}", 4, 4], # br reg 282 | [br"\xd6\x3f[\x00-\x03]{1}[\x00\x20\x40\x60\x80\xa0\xc0\xe0]{1}", 4, 4] # blr reg 283 | ] 284 | else: 285 | gadgets = [ 286 | [br"[\x00\x20\x40\x60\x80\xa0\xc0\xe0]{1}[\x00-\x03]{1}[\x1f\x5f]{1}\xd6", 4, 4], # br reg 287 | [br"[\x00\x20\x40\x60\x80\xa0\xc0\xe0]{1}[\x00-\x03]{1}\x3f\xd6", 4, 4] # blr reg 288 | ] 289 | arch_mode = CS_MODE_ARM 290 | elif arch == CS_ARCH_ARM: 291 | if self.__options.thumb or self.__options.rawMode == "thumb": 292 | if arch_endian == CS_MODE_BIG_ENDIAN: 293 | gadgets = [ 294 | [br"\x47[\x00\x08\x10\x18\x20\x28\x30\x38\x40\x48\x70]{1}", 2, 2], # bx reg 295 | [br"\x47[\x80\x88\x90\x98\xa0\xa8\xb0\xb8\xc0\xc8\xf0]{1}", 2, 2], # blx reg 296 | [br"\xbd[\x00-\xff]{1}", 2, 2], # pop {,pc} 297 | [br"\xe8[\x90-\x9f\xb0-\xbf][\x00-\xff]{4}", 4, 2], # ldm.w reg{!}, {,pc} 298 | [br"\xe9[\x10-\x1f\x30-\x3f][\x00-\xff]{4}", 4, 2] # ldmdb reg{!}, {,pc} 299 | ] 300 | else: 301 | gadgets = [ 302 | [br"[\x00\x08\x10\x18\x20\x28\x30\x38\x40\x48\x70]{1}\x47", 2, 2], # bx reg 303 | [br"[\x80\x88\x90\x98\xa0\xa8\xb0\xb8\xc0\xc8\xf0]{1}\x47", 2, 2], # blx reg 304 | [br"[\x00-\xff]{1}\xbd", 2, 2], # pop {,pc} 305 | [br"[\x90-\x9f\xb0-\xbf]\xe8[\x00-\xff]{4}", 4, 2], # ldm.w reg{!}, {,pc} 306 | [br"[\x10-\x1f\x30-\x3f]\xe9[\x00-\xff]{4}", 4, 2] # ldmdb reg{!}, {,pc} 307 | ] 308 | arch_mode = CS_MODE_THUMB 309 | else: 310 | if arch_endian == CS_MODE_BIG_ENDIAN: 311 | gadgets = [ 312 | [br"\xe1\x2f\xff[\x10-\x19\x1e]{1}", 4, 4], # bx reg 313 | [br"\xe1\x2f\xff[\x30-\x39\x3e]{1}", 4, 4], # blx reg 314 | [br"[\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} 315 | ] 316 | else: 317 | gadgets = [ 318 | [br"[\x10-\x19\x1e]{1}\xff\x2f\xe1", 4, 4], # bx reg 319 | [br"[\x30-\x39\x3e]{1}\xff\x2f\xe1", 4, 4], # blx reg 320 | [br"[\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} 321 | ] 322 | arch_mode = CS_MODE_ARM 323 | elif arch == CS_ARCH_RISCV: 324 | if arch_endian == CS_MODE_BIG_ENDIAN: 325 | gadgets = [ 326 | #32 bits encoded register 327 | [br"[\x00-\xff]{2}[\x00-\xff][\x67\x6f\xe7\xef]",4 , 2], 328 | [br"[\x00-\xff]{2}[\x00-\xff][\x63\xe3]", 4 , 2], 329 | 330 | #16bits encoded register 331 | [br"[\xa0-\xff]{1}[\xfd\xf9\xf5\xf1\xed\xe9\xe5\xe1\xdd\xd9\xd5\xd1\xcd\xc9\xc5\xc1\xbd\xb9\xb5\xb1\xad\xa9\xa5\xa1]", 2, 2], # c.j | c.beqz | c.bnez 332 | [br"[\xa0-\xff]{1}[\x0d\x09\x05\x01\x1d\x19\x15\x11\x2d\x29\x25\x21\x3d\x39\x35\x31\x4d\x49\x45\x41\x5d\x59\x55\x51]", 2, 2], # c.j | c.beqz | c.bnez 333 | [br"[\xa0-\xff]{1}[\x6d\x69\x65\x61\x7d\x79\x75\x71\x8d\x89\x85\x81\x9d\x99\x95\x91]", 2, 2], # c.j | c.beqz| c.bnez 334 | [br"[\x81-\x8f]{1}[\x02\x82]", 2, 2], #c.jr register 335 | [br"[\x91-\x9f]{1}[\x02\x82]", 2, 2], #c.jalr register 336 | 337 | ] 338 | else: 339 | gadgets = [ 340 | #32 bits encoded register 341 | [br"[\x67\x6f\xe7\xef][\x00-\xff][\x00-\xff]{2}" , 4, 2], #jalr/j/jal register, offset 342 | [br"[\x63\xe3][\x00-\xff][\x00-\xff]{2}" , 4, 2], #branch register, offset 343 | 344 | #16 bits encoded register 345 | [br"[\xfd\xf9\xf5\xf1\xed\xe9\xe5\xe1\xdd\xd9\xd5\xd1\xcd\xc9\xc5\xc1\xbd\xb9\xb5\xb1\xad\xa9\xa5\xa1][\xa0-\xff]{1}", 2, 2], # c.j | c.beqz | c.bnez 346 | [br"[\x0d\x09\x05\x01\x1d\x19\x15\x11\x2d\x29\x25\x21\x3d\x39\x35\x31\x4d\x49\x45\x41\x5d\x59\x55\x51][\xa0-\xff]{1}", 2, 2], # c.j | c.beqz | c.bnez 347 | [br"[\x6d\x69\x65\x61\x7d\x79\x75\x71\x8d\x89\x85\x81\x9d\x99\x95\x91][\xa0-\xff]{1}", 2, 2], # c.j | c.beqz| c.bnez 348 | [br"[\x02\x82][\x81-\x8f]{1}", 2, 2], #c.jr register 349 | [br"[\x02\x82][\x91-\x9f]{1}", 2, 2], #c.jalr register 350 | 351 | ] 352 | arch_mode = CS_MODE_RISCV64 | CS_MODE_RISCVC 353 | else: 354 | print("Gadgets().addJOPGadgets() - Architecture not supported") 355 | return None 356 | 357 | if gadgets: 358 | return self.__gadgetsFinding(section, gadgets, arch, arch_mode + arch_endian) 359 | return gadgets 360 | 361 | def addSYSGadgets(self, section): 362 | 363 | arch = self.__binary.getArch() 364 | arch_mode = self.__binary.getArchMode() 365 | arch_endian = self.__binary.getEndian() 366 | 367 | if arch == CS_ARCH_X86: 368 | gadgets = [ 369 | [br"\xcd\x80", 2, 1], # int 0x80 370 | [br"\x0f\x34", 2, 1], # sysenter 371 | [br"\x0f\x05", 2, 1], # syscall 372 | [br"\x65\xff\x15\x10\x00\x00\x00", 7, 1], # call DWORD PTR gs:0x10 373 | [br"\xcd\x80\xc3", 3, 1], # int 0x80 ; ret 374 | [br"\x0f\x34\xc3", 3, 1], # sysenter ; ret 375 | [br"\x0f\x05\xc3", 3, 1], # syscall ; ret 376 | [br"\x65\xff\x15\x10\x00\x00\x00\xc3", 8, 1], # call DWORD PTR gs:0x10 ; ret 377 | [br"\x0f\x07", 2, 1], # sysret 378 | [br"\x48\x0f\x07", 3, 1], # sysret 379 | [br"\xcf", 1, 1], # iret 380 | ] 381 | 382 | elif arch == CS_ARCH_MIPS: 383 | if arch_endian == CS_MODE_BIG_ENDIAN: 384 | gadgets = [ 385 | [br"\x00\x00\x00\x0c", 4, 4] # syscall 386 | ] 387 | else: 388 | gadgets = [ 389 | [br"\x0c\x00\x00\x00", 4, 4] # syscall 390 | ] 391 | elif arch == CS_ARCH_PPC: 392 | if arch_endian == CS_MODE_BIG_ENDIAN: 393 | gadgets = [ 394 | [br"\x44\x00\x00\x02", 4, 4], # sc 395 | [br"\x44\x00\x00\x03", 4, 4] # scv 396 | ] 397 | else: 398 | gadgets = [ 399 | [br"\x02\x00\x00\x44", 4, 4], # sc 400 | [br"\x03\x00\x00\x44", 4, 4] # scv 401 | ] 402 | 403 | elif arch == CS_ARCH_SPARC: 404 | gadgets = [] # TODO (ta inst) 405 | elif arch == CS_ARCH_ARM64: 406 | gadgets = [] # TODO 407 | elif arch == CS_ARCH_ARM: 408 | if self.__options.thumb or self.__options.rawMode == "thumb": 409 | gadgets = [ 410 | [br"\x00-\xff]{1}\xef", 2, 2] # FIXME: svc 411 | ] 412 | arch_mode = CS_MODE_THUMB 413 | else: 414 | gadgets = [ 415 | [br"\x00-\xff]{3}\xef", 4, 4] # FIXME: svc 416 | ] 417 | arch_mode = CS_MODE_ARM 418 | elif arch == CS_ARCH_RISCV: 419 | 420 | if arch_endian == CS_MODE_BIG_ENDIAN: 421 | gadgets = [ 422 | [br"\x00\x00\x00\x73", 4, 2] # syscall 423 | ] 424 | else: 425 | gadgets = [ 426 | [br"\x73\x00\x00\x00", 4, 2] # syscall 427 | ] 428 | 429 | arch_mode = CS_MODE_RISCV64 | CS_MODE_RISCVC 430 | else: 431 | print("Gadgets().addSYSGadgets() - Architecture not supported") 432 | return None 433 | 434 | if gadgets: 435 | return self.__gadgetsFinding(section, gadgets, arch, arch_mode + arch_endian) 436 | return [] 437 | 438 | def passClean(self, decodes): 439 | if not decodes: 440 | return True 441 | 442 | if self.__arch == CS_ARCH_X86 and self.__passCleanX86(decodes): 443 | return True 444 | 445 | if self.__filterRE and any(self.__filterRE.match(mnemonic) for _, _, mnemonic, _ in decodes): 446 | return True 447 | 448 | return False 449 | -------------------------------------------------------------------------------- /ropgadget/loaders/__init__.py: -------------------------------------------------------------------------------- 1 | ## -*- coding: utf-8 -*- 2 | ## 3 | ## Jonathan Salwan - 2014-05-12 - ROPgadget tool 4 | ## 5 | ## http://twitter.com/JonathanSalwan 6 | ## http://shell-storm.org/project/ROPgadget/ 7 | ## 8 | 9 | import ropgadget.loaders.elf 10 | import ropgadget.loaders.macho 11 | import ropgadget.loaders.pe 12 | import ropgadget.loaders.raw 13 | -------------------------------------------------------------------------------- /ropgadget/loaders/elf.py: -------------------------------------------------------------------------------- 1 | ## -*- coding: utf-8 -*- 2 | ## 3 | ## Jonathan Salwan - 2014-05-12 - ROPgadget tool 4 | ## 5 | ## http://twitter.com/JonathanSalwan 6 | ## http://shell-storm.org/project/ROPgadget/ 7 | ## 8 | 9 | from ctypes import * 10 | 11 | from capstone import * 12 | 13 | 14 | class ELFFlags(object): 15 | ELFCLASS32 = 0x01 16 | ELFCLASS64 = 0x02 17 | EI_CLASS = 0x04 18 | EI_DATA = 0x05 19 | ELFDATA2LSB = 0x01 20 | ELFDATA2MSB = 0x02 21 | EM_386 = 0x03 22 | EM_X86_64 = 0x3e 23 | EM_ARM = 0x28 24 | EM_MIPS = 0x08 25 | EM_SPARCv8p = 0x12 26 | EM_PowerPC = 0x14 27 | EM_PPC64 = 0x15 28 | EM_ARM64 = 0xb7 29 | EM_RISCV = 0xf3 30 | 31 | 32 | class Elf32_Ehdr_LSB(LittleEndianStructure): 33 | _fields_ = [ 34 | ("e_ident", c_ubyte * 16), 35 | ("e_type", c_ushort), 36 | ("e_machine", c_ushort), 37 | ("e_version", c_uint), 38 | ("e_entry", c_uint), 39 | ("e_phoff", c_uint), 40 | ("e_shoff", c_uint), 41 | ("e_flags", c_uint), 42 | ("e_ehsize", c_ushort), 43 | ("e_phentsize", c_ushort), 44 | ("e_phnum", c_ushort), 45 | ("e_shentsize", c_ushort), 46 | ("e_shnum", c_ushort), 47 | ("e_shstrndx", c_ushort), 48 | ] 49 | 50 | 51 | class Elf64_Ehdr_LSB(LittleEndianStructure): 52 | _fields_ = [ 53 | ("e_ident", c_ubyte * 16), 54 | ("e_type", c_ushort), 55 | ("e_machine", c_ushort), 56 | ("e_version", c_uint), 57 | ("e_entry", c_ulonglong), 58 | ("e_phoff", c_ulonglong), 59 | ("e_shoff", c_ulonglong), 60 | ("e_flags", c_uint), 61 | ("e_ehsize", c_ushort), 62 | ("e_phentsize", c_ushort), 63 | ("e_phnum", c_ushort), 64 | ("e_shentsize", c_ushort), 65 | ("e_shnum", c_ushort), 66 | ("e_shstrndx", c_ushort), 67 | ] 68 | 69 | 70 | class Elf32_Phdr_LSB(LittleEndianStructure): 71 | _fields_ = [ 72 | ("p_type", c_uint), 73 | ("p_offset", c_uint), 74 | ("p_vaddr", c_uint), 75 | ("p_paddr", c_uint), 76 | ("p_filesz", c_uint), 77 | ("p_memsz", c_uint), 78 | ("p_flags", c_uint), 79 | ("p_align", c_uint), 80 | ] 81 | 82 | 83 | class Elf64_Phdr_LSB(LittleEndianStructure): 84 | _fields_ = [ 85 | ("p_type", c_uint), 86 | ("p_flags", c_uint), 87 | ("p_offset", c_ulonglong), 88 | ("p_vaddr", c_ulonglong), 89 | ("p_paddr", c_ulonglong), 90 | ("p_filesz", c_ulonglong), 91 | ("p_memsz", c_ulonglong), 92 | ("p_align", c_ulonglong), 93 | ] 94 | 95 | 96 | class Elf32_Shdr_LSB(LittleEndianStructure): 97 | _fields_ = [ 98 | ("sh_name", c_uint), 99 | ("sh_type", c_uint), 100 | ("sh_flags", c_uint), 101 | ("sh_addr", c_uint), 102 | ("sh_offset", c_uint), 103 | ("sh_size", c_uint), 104 | ("sh_link", c_uint), 105 | ("sh_info", c_uint), 106 | ("sh_addralign", c_uint), 107 | ("sh_entsize", c_uint), 108 | ] 109 | 110 | 111 | class Elf64_Shdr_LSB(LittleEndianStructure): 112 | _fields_ = [ 113 | ("sh_name", c_uint), 114 | ("sh_type", c_uint), 115 | ("sh_flags", c_ulonglong), 116 | ("sh_addr", c_ulonglong), 117 | ("sh_offset", c_ulonglong), 118 | ("sh_size", c_ulonglong), 119 | ("sh_link", c_uint), 120 | ("sh_info", c_uint), 121 | ("sh_addralign", c_ulonglong), 122 | ("sh_entsize", c_ulonglong), 123 | ] 124 | 125 | 126 | class Elf32_Ehdr_MSB(BigEndianStructure): 127 | _fields_ = [ 128 | ("e_ident", c_ubyte * 16), 129 | ("e_type", c_ushort), 130 | ("e_machine", c_ushort), 131 | ("e_version", c_uint), 132 | ("e_entry", c_uint), 133 | ("e_phoff", c_uint), 134 | ("e_shoff", c_uint), 135 | ("e_flags", c_uint), 136 | ("e_ehsize", c_ushort), 137 | ("e_phentsize", c_ushort), 138 | ("e_phnum", c_ushort), 139 | ("e_shentsize", c_ushort), 140 | ("e_shnum", c_ushort), 141 | ("e_shstrndx", c_ushort), 142 | ] 143 | 144 | 145 | class Elf64_Ehdr_MSB(BigEndianStructure): 146 | _fields_ = [ 147 | ("e_ident", c_ubyte * 16), 148 | ("e_type", c_ushort), 149 | ("e_machine", c_ushort), 150 | ("e_version", c_uint), 151 | ("e_entry", c_ulonglong), 152 | ("e_phoff", c_ulonglong), 153 | ("e_shoff", c_ulonglong), 154 | ("e_flags", c_uint), 155 | ("e_ehsize", c_ushort), 156 | ("e_phentsize", c_ushort), 157 | ("e_phnum", c_ushort), 158 | ("e_shentsize", c_ushort), 159 | ("e_shnum", c_ushort), 160 | ("e_shstrndx", c_ushort), 161 | ] 162 | 163 | 164 | class Elf32_Phdr_MSB(BigEndianStructure): 165 | _fields_ = [ 166 | ("p_type", c_uint), 167 | ("p_offset", c_uint), 168 | ("p_vaddr", c_uint), 169 | ("p_paddr", c_uint), 170 | ("p_filesz", c_uint), 171 | ("p_memsz", c_uint), 172 | ("p_flags", c_uint), 173 | ("p_align", c_uint), 174 | ] 175 | 176 | 177 | class Elf64_Phdr_MSB(BigEndianStructure): 178 | _fields_ = [ 179 | ("p_type", c_uint), 180 | ("p_flags", c_uint), 181 | ("p_offset", c_ulonglong), 182 | ("p_vaddr", c_ulonglong), 183 | ("p_paddr", c_ulonglong), 184 | ("p_filesz", c_ulonglong), 185 | ("p_memsz", c_ulonglong), 186 | ("p_align", c_ulonglong), 187 | ] 188 | 189 | 190 | class Elf32_Shdr_MSB(BigEndianStructure): 191 | _fields_ = [ 192 | ("sh_name", c_uint), 193 | ("sh_type", c_uint), 194 | ("sh_flags", c_uint), 195 | ("sh_addr", c_uint), 196 | ("sh_offset", c_uint), 197 | ("sh_size", c_uint), 198 | ("sh_link", c_uint), 199 | ("sh_info", c_uint), 200 | ("sh_addralign", c_uint), 201 | ("sh_entsize", c_uint), 202 | ] 203 | 204 | 205 | class Elf64_Shdr_MSB(BigEndianStructure): 206 | _fields_ = [ 207 | ("sh_name", c_uint), 208 | ("sh_type", c_uint), 209 | ("sh_flags", c_ulonglong), 210 | ("sh_addr", c_ulonglong), 211 | ("sh_offset", c_ulonglong), 212 | ("sh_size", c_ulonglong), 213 | ("sh_link", c_uint), 214 | ("sh_info", c_uint), 215 | ("sh_addralign", c_ulonglong), 216 | ("sh_entsize", c_ulonglong), 217 | ] 218 | 219 | 220 | class ELF(object): 221 | """This class parses the ELF.""" 222 | 223 | def __init__(self, binary): 224 | self.__binary = bytearray(binary) 225 | self.__ElfHeader = None 226 | self.__shdr_l = [] 227 | self.__phdr_l = [] 228 | 229 | self.__setHeaderElf() 230 | self.__setShdr() 231 | self.__setPhdr() 232 | 233 | def __setHeaderElf(self): 234 | """Parse ELF header.""" 235 | e_ident = self.__binary[:15] 236 | 237 | ei_class = e_ident[ELFFlags.EI_CLASS] 238 | ei_data = e_ident[ELFFlags.EI_DATA] 239 | 240 | if ei_class != ELFFlags.ELFCLASS32 and ei_class != ELFFlags.ELFCLASS64: 241 | print("[Error] ELF.__setHeaderElf() - Bad Arch size") 242 | return None 243 | 244 | if ei_data != ELFFlags.ELFDATA2LSB and ei_data != ELFFlags.ELFDATA2MSB: 245 | print("[Error] ELF.__setHeaderElf() - Bad architecture endian") 246 | return None 247 | 248 | if ei_class == ELFFlags.ELFCLASS32: 249 | if ei_data == ELFFlags.ELFDATA2LSB: self.__ElfHeader = Elf32_Ehdr_LSB.from_buffer_copy(self.__binary) 250 | elif ei_data == ELFFlags.ELFDATA2MSB: self.__ElfHeader = Elf32_Ehdr_MSB.from_buffer_copy(self.__binary) 251 | elif ei_class == ELFFlags.ELFCLASS64: 252 | if ei_data == ELFFlags.ELFDATA2LSB: self.__ElfHeader = Elf64_Ehdr_LSB.from_buffer_copy(self.__binary) 253 | elif ei_data == ELFFlags.ELFDATA2MSB: self.__ElfHeader = Elf64_Ehdr_MSB.from_buffer_copy(self.__binary) 254 | 255 | self.getArch() # Check if architecture is supported 256 | 257 | def __setShdr(self): 258 | """Parse Section header.""" 259 | shdr_num = self.__ElfHeader.e_shnum 260 | base = self.__binary[self.__ElfHeader.e_shoff:] 261 | self.__shdr_l = [] 262 | 263 | e_ident = self.__binary[:15] 264 | ei_data = e_ident[ELFFlags.EI_DATA] 265 | 266 | for _ in range(shdr_num): 267 | if self.getArchMode() == CS_MODE_32: 268 | if ei_data == ELFFlags.ELFDATA2LSB: shdr = Elf32_Shdr_LSB.from_buffer_copy(base) 269 | elif ei_data == ELFFlags.ELFDATA2MSB: shdr = Elf32_Shdr_MSB.from_buffer_copy(base) 270 | elif self.getArchMode() == CS_MODE_64: 271 | if ei_data == ELFFlags.ELFDATA2LSB: shdr = Elf64_Shdr_LSB.from_buffer_copy(base) 272 | elif ei_data == ELFFlags.ELFDATA2MSB: shdr = Elf64_Shdr_MSB.from_buffer_copy(base) 273 | 274 | self.__shdr_l.append(shdr) 275 | base = base[self.__ElfHeader.e_shentsize:] 276 | 277 | # setup name from the strings table 278 | if self.__ElfHeader.e_shstrndx != 0: 279 | string_table = bytes(self.__binary[(self.__shdr_l[self.__ElfHeader.e_shstrndx].sh_offset):]) 280 | for i in range(shdr_num): 281 | self.__shdr_l[i].str_name = string_table[self.__shdr_l[i].sh_name:].split(b'\x00')[0].decode('utf8') 282 | 283 | def __setPhdr(self): 284 | """Parse Program header.""" 285 | pdhr_num = self.__ElfHeader.e_phnum 286 | base = self.__binary[self.__ElfHeader.e_phoff:] 287 | self.__phdr_l = [] 288 | 289 | e_ident = self.__binary[:15] 290 | ei_data = e_ident[ELFFlags.EI_DATA] 291 | 292 | for _ in range(pdhr_num): 293 | if self.getArchMode() == CS_MODE_32: 294 | if ei_data == ELFFlags.ELFDATA2LSB: phdr = Elf32_Phdr_LSB.from_buffer_copy(base) 295 | elif ei_data == ELFFlags.ELFDATA2MSB: phdr = Elf32_Phdr_MSB.from_buffer_copy(base) 296 | elif self.getArchMode() == CS_MODE_64: 297 | if ei_data == ELFFlags.ELFDATA2LSB: phdr = Elf64_Phdr_LSB.from_buffer_copy(base) 298 | elif ei_data == ELFFlags.ELFDATA2MSB: phdr = Elf64_Phdr_MSB.from_buffer_copy(base) 299 | 300 | self.__phdr_l.append(phdr) 301 | base = base[self.__ElfHeader.e_phentsize:] 302 | 303 | def getEntryPoint(self): 304 | return self.__e_entry 305 | 306 | def getExecSections(self): 307 | ret = [] 308 | for segment in self.__phdr_l: 309 | if segment.p_flags & 0x1: 310 | ret += [{ 311 | "offset" : segment.p_offset, 312 | "size" : segment.p_memsz, 313 | "vaddr" : segment.p_vaddr, 314 | "opcodes" : bytes(self.__binary[segment.p_offset:segment.p_offset + segment.p_memsz]), 315 | }] 316 | return ret 317 | 318 | def getDataSections(self): 319 | ret = [] 320 | for section in self.__shdr_l: 321 | if not (section.sh_flags & 0x4) and (section.sh_flags & 0x2): 322 | ret += [{ 323 | "name" : section.str_name, 324 | "offset" : section.sh_offset, 325 | "size" : section.sh_size, 326 | "vaddr" : section.sh_addr, 327 | "opcodes" : bytes(self.__binary[section.sh_offset:section.sh_offset + section.sh_size]), 328 | }] 329 | return ret 330 | 331 | def getArch(self): 332 | if self.__ElfHeader.e_machine == ELFFlags.EM_386 or self.__ElfHeader.e_machine == ELFFlags.EM_X86_64: 333 | return CS_ARCH_X86 334 | elif self.__ElfHeader.e_machine == ELFFlags.EM_ARM: 335 | return CS_ARCH_ARM 336 | elif self.__ElfHeader.e_machine == ELFFlags.EM_ARM64: 337 | return CS_ARCH_ARM64 338 | elif self.__ElfHeader.e_machine == ELFFlags.EM_MIPS: 339 | return CS_ARCH_MIPS 340 | elif self.__ElfHeader.e_machine == ELFFlags.EM_PowerPC or self.__ElfHeader.e_machine == ELFFlags.EM_PPC64: 341 | return CS_ARCH_PPC 342 | elif self.__ElfHeader.e_machine == ELFFlags.EM_SPARCv8p: 343 | return CS_ARCH_SPARC 344 | elif self.__ElfHeader.e_machine == ELFFlags.EM_RISCV: 345 | return CS_ARCH_RISCV 346 | print("[Error] ELF.getArch() - Architecture not supported") 347 | return None 348 | 349 | def getArchMode(self): 350 | if self.__ElfHeader.e_ident[ELFFlags.EI_CLASS] == ELFFlags.ELFCLASS32: 351 | return CS_MODE_32 352 | elif self.__ElfHeader.e_ident[ELFFlags.EI_CLASS] == ELFFlags.ELFCLASS64: 353 | return CS_MODE_64 354 | print("[Error] ELF.getArchMode() - Bad Arch size") 355 | return None 356 | 357 | def getEndian(self): 358 | if self.__ElfHeader.e_ident[ELFFlags.EI_DATA] == ELFFlags.ELFDATA2LSB: 359 | return 0 360 | if self.__ElfHeader.e_ident[ELFFlags.EI_DATA] == ELFFlags.ELFDATA2MSB: 361 | return CS_MODE_BIG_ENDIAN 362 | print("[Error] ELF.getEndian() - Bad Endianness") 363 | return None 364 | 365 | def getFormat(self): 366 | return "ELF" 367 | -------------------------------------------------------------------------------- /ropgadget/loaders/macho.py: -------------------------------------------------------------------------------- 1 | ## -*- coding: utf-8 -*- 2 | ## 3 | ## Jonathan Salwan - 2014-05-12 - ROPgadget tool 4 | ## 5 | ## http://twitter.com/JonathanSalwan 6 | ## http://shell-storm.org/project/ROPgadget/ 7 | ## 8 | 9 | from ctypes import * 10 | 11 | from capstone import * 12 | 13 | 14 | class MACH_HEADER_LE(LittleEndianStructure): 15 | _fields_ = [ 16 | ("magic", c_uint), 17 | ("cputype", c_uint), 18 | ("cpusubtype", c_uint), 19 | ("filetype", c_uint), 20 | ("ncmds", c_uint), 21 | ("sizeofcmds", c_uint), 22 | ("flags", c_uint), 23 | ] 24 | 25 | class MACH_HEADER_BE(BigEndianStructure): 26 | _fields_ = [ 27 | ("magic", c_uint), 28 | ("cputype", c_uint), 29 | ("cpusubtype", c_uint), 30 | ("filetype", c_uint), 31 | ("ncmds", c_uint), 32 | ("sizeofcmds", c_uint), 33 | ("flags", c_uint), 34 | ] 35 | 36 | 37 | class LOAD_COMMAND_LE(LittleEndianStructure): 38 | _fields_ = [ 39 | ("cmd", c_uint), 40 | ("cmdsize", c_uint), 41 | ] 42 | 43 | class LOAD_COMMAND_BE(BigEndianStructure): 44 | _fields_ = [ 45 | ("cmd", c_uint), 46 | ("cmdsize", c_uint), 47 | ] 48 | 49 | 50 | class SEGMENT_COMMAND_LE(LittleEndianStructure): 51 | _fields_ = [ 52 | ("cmd", c_uint), 53 | ("cmdsize", c_uint), 54 | ("segname", c_ubyte * 16), 55 | ("vmaddr", c_uint), 56 | ("vmsize", c_uint), 57 | ("fileoff", c_uint), 58 | ("filesize", c_uint), 59 | ("maxprot", c_uint), 60 | ("initprot", c_uint), 61 | ("nsects", c_uint), 62 | ("flags", c_uint), 63 | ] 64 | 65 | class SEGMENT_COMMAND_BE(BigEndianStructure): 66 | _fields_ = [ 67 | ("cmd", c_uint), 68 | ("cmdsize", c_uint), 69 | ("segname", c_ubyte * 16), 70 | ("vmaddr", c_uint), 71 | ("vmsize", c_uint), 72 | ("fileoff", c_uint), 73 | ("filesize", c_uint), 74 | ("maxprot", c_uint), 75 | ("initprot", c_uint), 76 | ("nsects", c_uint), 77 | ("flags", c_uint), 78 | ] 79 | 80 | 81 | class SEGMENT_COMMAND64_LE(LittleEndianStructure): 82 | _fields_ = [ 83 | ("cmd", c_uint), 84 | ("cmdsize", c_uint), 85 | ("segname", c_ubyte * 16), 86 | ("vmaddr", c_ulonglong), 87 | ("vmsize", c_ulonglong), 88 | ("fileoff", c_ulonglong), 89 | ("filesize", c_ulonglong), 90 | ("maxprot", c_uint), 91 | ("initprot", c_uint), 92 | ("nsects", c_uint), 93 | ("flags", c_uint), 94 | ] 95 | 96 | class SEGMENT_COMMAND64_BE(BigEndianStructure): 97 | _fields_ = [ 98 | ("cmd", c_uint), 99 | ("cmdsize", c_uint), 100 | ("segname", c_ubyte * 16), 101 | ("vmaddr", c_ulonglong), 102 | ("vmsize", c_ulonglong), 103 | ("fileoff", c_ulonglong), 104 | ("filesize", c_ulonglong), 105 | ("maxprot", c_uint), 106 | ("initprot", c_uint), 107 | ("nsects", c_uint), 108 | ("flags", c_uint), 109 | ] 110 | 111 | 112 | class SECTION_LE(LittleEndianStructure): 113 | _fields_ = [ 114 | ("sectname", c_ubyte * 16), 115 | ("segname", c_ubyte * 16), 116 | ("addr", c_uint), 117 | ("size", c_uint), 118 | ("offset", c_uint), 119 | ("align", c_uint), 120 | ("reloff", c_uint), 121 | ("nreloc", c_uint), 122 | ("flags", c_uint), 123 | ("reserved1", c_uint), 124 | ("reserved2", c_uint), 125 | ] 126 | 127 | class SECTION_BE(BigEndianStructure): 128 | _fields_ = [ 129 | ("sectname", c_ubyte * 16), 130 | ("segname", c_ubyte * 16), 131 | ("addr", c_uint), 132 | ("size", c_uint), 133 | ("offset", c_uint), 134 | ("align", c_uint), 135 | ("reloff", c_uint), 136 | ("nreloc", c_uint), 137 | ("flags", c_uint), 138 | ("reserved1", c_uint), 139 | ("reserved2", c_uint), 140 | ] 141 | 142 | 143 | class SECTION64_LE(LittleEndianStructure): 144 | _fields_ = [ 145 | ("sectname", c_ubyte * 16), 146 | ("segname", c_ubyte * 16), 147 | ("addr", c_ulonglong), 148 | ("size", c_ulonglong), 149 | ("offset", c_uint), 150 | ("align", c_uint), 151 | ("reloff", c_uint), 152 | ("nreloc", c_uint), 153 | ("flags", c_uint), 154 | ("reserved1", c_uint), 155 | ("reserved2", c_uint), 156 | ] 157 | 158 | class SECTION64_BE(BigEndianStructure): 159 | _fields_ = [ 160 | ("sectname", c_ubyte * 16), 161 | ("segname", c_ubyte * 16), 162 | ("addr", c_ulonglong), 163 | ("size", c_ulonglong), 164 | ("offset", c_uint), 165 | ("align", c_uint), 166 | ("reloff", c_uint), 167 | ("nreloc", c_uint), 168 | ("flags", c_uint), 169 | ("reserved1", c_uint), 170 | ("reserved2", c_uint), 171 | ] 172 | 173 | 174 | class MACHOFlags(object): 175 | CPU_TYPE_I386 = 0x7 176 | CPU_TYPE_X86_64 = (CPU_TYPE_I386 | 0x1000000) 177 | CPU_TYPE_MIPS = 0x8 178 | CPU_TYPE_ARM = 12 179 | CPU_TYPE_ARM64 = (CPU_TYPE_ARM | 0x1000000) 180 | CPU_TYPE_SPARC = 14 181 | CPU_TYPE_POWERPC = 18 182 | CPU_TYPE_POWERPC64 = (CPU_TYPE_POWERPC | 0x1000000) 183 | LC_SEGMENT = 0x1 184 | LC_SEGMENT_64 = 0x19 185 | S_ATTR_SOME_INSTRUCTIONS = 0x00000400 186 | S_ATTR_PURE_INSTRUCTIONS = 0x80000000 187 | 188 | 189 | class MACHO(object): 190 | """This class parses the Mach-O.""" 191 | 192 | def __init__(self, binary): 193 | self.__binary = bytearray(binary) 194 | 195 | self.__machHeader = None 196 | self.__endianness = None 197 | self.__rawLoadCmd = None 198 | self.__sections_l = [] 199 | 200 | self.__setEndianness() 201 | self.__setHeader() 202 | self.__setLoadCmd() 203 | 204 | def __setEndianness(self): 205 | magic = self.__binary[0] << 24 | \ 206 | self.__binary[1] << 16 | \ 207 | self.__binary[2] << 8 | \ 208 | self.__binary[3] 209 | if magic == 0xfeedface or magic == 0xfeedfacf: 210 | self.__endianness = CS_MODE_BIG_ENDIAN 211 | else: 212 | self.__endianness = 0 213 | 214 | def __setHeader(self): 215 | if self.__endianness == CS_MODE_BIG_ENDIAN: 216 | self.__machHeader = MACH_HEADER_BE.from_buffer_copy(self.__binary) 217 | else: 218 | self.__machHeader = MACH_HEADER_LE.from_buffer_copy(self.__binary) 219 | 220 | if self.getArchMode() == CS_MODE_32: 221 | self.__rawLoadCmd = self.__binary[28:28 + self.__machHeader.sizeofcmds] 222 | 223 | elif self.getArchMode() == CS_MODE_64: 224 | self.__rawLoadCmd = self.__binary[32:32 + self.__machHeader.sizeofcmds] 225 | 226 | def __setLoadCmd(self): 227 | base = self.__rawLoadCmd 228 | for _ in range(self.__machHeader.ncmds): 229 | if self.__endianness == CS_MODE_BIG_ENDIAN: 230 | command = LOAD_COMMAND_BE.from_buffer_copy(base) 231 | else: 232 | command = LOAD_COMMAND_LE.from_buffer_copy(base) 233 | 234 | if command.cmd == MACHOFlags.LC_SEGMENT: 235 | if self.__endianness == CS_MODE_BIG_ENDIAN: 236 | segment = SEGMENT_COMMAND_BE.from_buffer_copy(base) 237 | else: 238 | segment = SEGMENT_COMMAND_LE.from_buffer_copy(base) 239 | 240 | self.__setSections(segment, base[56:], 32) 241 | 242 | elif command.cmd == MACHOFlags.LC_SEGMENT_64: 243 | if self.__endianness == CS_MODE_BIG_ENDIAN: 244 | segment = SEGMENT_COMMAND64_BE.from_buffer_copy(base) 245 | else: 246 | segment = SEGMENT_COMMAND64_LE.from_buffer_copy(base) 247 | self.__setSections(segment, base[72:], 64) 248 | 249 | base = base[command.cmdsize:] 250 | 251 | def __setSections(self, segment, base, sizeHeader): 252 | for _ in range(segment.nsects): 253 | if sizeHeader == 32: 254 | if self.__endianness == CS_MODE_BIG_ENDIAN: 255 | section = SECTION_BE.from_buffer_copy(base) 256 | else: 257 | section = SECTION_LE.from_buffer_copy(base) 258 | section.offset = segment.fileoff + section.addr - segment.vmaddr 259 | base = base[68:] 260 | self.__sections_l += [section] 261 | elif sizeHeader == 64: 262 | if self.__endianness == CS_MODE_BIG_ENDIAN: 263 | section = SECTION64_BE.from_buffer_copy(base) 264 | else: 265 | section = SECTION64_LE.from_buffer_copy(base) 266 | section.offset = segment.fileoff + section.addr - segment.vmaddr 267 | base = base[80:] 268 | self.__sections_l += [section] 269 | 270 | def getEntryPoint(self): 271 | for section in self.__sections_l: 272 | if section.sectname[0:6] == "__text": 273 | return section.addr 274 | 275 | def getExecSections(self): 276 | ret = [] 277 | for section in self.__sections_l: 278 | if section.flags & MACHOFlags.S_ATTR_SOME_INSTRUCTIONS or section.flags & MACHOFlags.S_ATTR_PURE_INSTRUCTIONS: 279 | ret += [{ 280 | "name" : section.sectname, 281 | "offset" : section.offset, 282 | "size" : section.size, 283 | "vaddr" : section.addr, 284 | "opcodes" : bytes(self.__binary[section.offset:section.offset + section.size]), 285 | }] 286 | return ret 287 | 288 | def getDataSections(self): 289 | ret = [] 290 | for section in self.__sections_l: 291 | if not section.flags & MACHOFlags.S_ATTR_SOME_INSTRUCTIONS and not section.flags & MACHOFlags.S_ATTR_PURE_INSTRUCTIONS: 292 | ret += [{ 293 | "name" : section.sectname, 294 | "offset" : section.offset, 295 | "size" : section.size, 296 | "vaddr" : section.addr, 297 | "opcodes" : bytes(self.__binary[section.offset:section.offset + section.size]), 298 | }] 299 | return ret 300 | 301 | def getArch(self): 302 | if self.__machHeader.cputype == MACHOFlags.CPU_TYPE_I386 or self.__machHeader.cputype == MACHOFlags.CPU_TYPE_X86_64: 303 | return CS_ARCH_X86 304 | if self.__machHeader.cputype == MACHOFlags.CPU_TYPE_ARM: 305 | return CS_ARCH_ARM 306 | if self.__machHeader.cputype == MACHOFlags.CPU_TYPE_ARM64: 307 | return CS_ARCH_ARM64 308 | if self.__machHeader.cputype == MACHOFlags.CPU_TYPE_MIPS: 309 | return CS_ARCH_MIPS 310 | if self.__machHeader.cputype == MACHOFlags.CPU_TYPE_POWERPC or self.__machHeader.cputype == MACHOFlags.CPU_TYPE_POWERPC64: 311 | return CS_ARCH_PPC 312 | print("[Error] MACHO.getArch() - Architecture not supported") 313 | return None 314 | 315 | def getArchMode(self): 316 | if self.__machHeader.magic == 0xfeedface: 317 | return CS_MODE_32 318 | elif self.__machHeader.magic == 0xfeedfacf: 319 | return CS_MODE_64 320 | print("[Error] MACHO.getArchMode() - Bad Arch size") 321 | return None 322 | 323 | def getEndian(self): 324 | if self.__endianness is None: 325 | print("[Error] MACHO.getEndian() - Unable to determine endianness") 326 | return self.__endianness 327 | 328 | def getFormat(self): 329 | return "Mach-O" 330 | -------------------------------------------------------------------------------- /ropgadget/loaders/pe.py: -------------------------------------------------------------------------------- 1 | ## -*- coding: utf-8 -*- 2 | ## 3 | ## Jonathan Salwan - 2014-05-12 - ROPgadget tool 4 | ## 5 | ## http://twitter.com/JonathanSalwan 6 | ## http://shell-storm.org/project/ROPgadget/ 7 | ## 8 | 9 | from binascii import unhexlify 10 | from ctypes import * 11 | from struct import unpack 12 | 13 | from capstone import * 14 | 15 | 16 | class PEFlags(object): 17 | IMAGE_MACHINE_INTEL_386 = 0x014c 18 | IMAGE_MACHINE_AMD_8664 = 0x8664 19 | IMAGE_FILE_MACHINE_ARM = 0x1c0 20 | IMAGE_FILE_MACHINE_ARMV7 = 0x1c4 21 | IMAGE_NT_OPTIONAL_HDR32_MAGIC = 0x10b 22 | IMAGE_NT_OPTIONAL_HDR64_MAGIC = 0x20b 23 | IMAGE_SIZEOF_SHORT_NAME = 0x8 24 | 25 | 26 | class IMAGE_FILE_HEADER(LittleEndianStructure): 27 | _fields_ = [ 28 | ("Magic", c_uint), 29 | ("Machine", c_ushort), 30 | ("NumberOfSections", c_ushort), 31 | ("TimeDateStamp", c_uint), 32 | ("PointerToSymbolTable", c_uint), 33 | ("NumberOfSymbols", c_uint), 34 | ("SizeOfOptionalHeader", c_ushort), 35 | ("Characteristics", c_ushort), 36 | ] 37 | 38 | 39 | class IMAGE_OPTIONAL_HEADER(LittleEndianStructure): 40 | _fields_ = [ 41 | ("Magic", c_ushort), 42 | ("MajorLinkerVersion", c_ubyte), 43 | ("MinorLinkerVersion", c_ubyte), 44 | ("SizeOfCode", c_uint), 45 | ("SizeOfInitializedData", c_uint), 46 | ("SizeOfUninitializedData", c_uint), 47 | ("AddressOfEntryPoint", c_uint), 48 | ("BaseOfCode", c_uint), 49 | ("BaseOfData", c_uint), 50 | ("ImageBase", c_uint), 51 | ("SectionAlignment", c_uint), 52 | ("FileAlignment", c_uint), 53 | ("MajorOperatingSystemVersion", c_ushort), 54 | ("MinorOperatingSystemVersion", c_ushort), 55 | ("MajorImageVersion", c_ushort), 56 | ("MinorImageVersion", c_ushort), 57 | ("MajorSubsystemVersion", c_ushort), 58 | ("MinorSubsystemVersion", c_ushort), 59 | ("Win32VersionValue", c_uint), 60 | ("SizeOfImage", c_uint), 61 | ("SizeOfHeaders", c_uint), 62 | ("CheckSum", c_uint), 63 | ("Subsystem", c_ushort), 64 | ("DllCharacteristics", c_ushort), 65 | ("SizeOfStackReserve", c_uint), 66 | ("SizeOfStackCommit", c_uint), 67 | ("SizeOfHeapReserve", c_uint), 68 | ("SizeOfHeapCommit", c_uint), 69 | ("LoaderFlags", c_uint), 70 | ("NumberOfRvaAndSizes", c_uint), 71 | ] 72 | 73 | 74 | class IMAGE_OPTIONAL_HEADER64(LittleEndianStructure): 75 | _fields_ = [ 76 | ("Magic", c_ushort), 77 | ("MajorLinkerVersion", c_ubyte), 78 | ("MinorLinkerVersion", c_ubyte), 79 | ("SizeOfCode", c_uint), 80 | ("SizeOfInitializedData", c_uint), 81 | ("SizeOfUninitializedData", c_uint), 82 | ("AddressOfEntryPoint", c_uint), 83 | ("BaseOfCode", c_uint), 84 | ("ImageBase", c_ulonglong), 85 | ("SectionAlignment", c_uint), 86 | ("FileAlignment", c_uint), 87 | ("MajorOperatingSystemVersion", c_ushort), 88 | ("MinorOperatingSystemVersion", c_ushort), 89 | ("MajorImageVersion", c_ushort), 90 | ("MinorImageVersion", c_ushort), 91 | ("MajorSubsystemVersion", c_ushort), 92 | ("MinorSubsystemVersion", c_ushort), 93 | ("Win32VersionValue", c_uint), 94 | ("SizeOfImage", c_uint), 95 | ("SizeOfHeaders", c_uint), 96 | ("CheckSum", c_uint), 97 | ("Subsystem", c_ushort), 98 | ("DllCharacteristics", c_ushort), 99 | ("SizeOfStackReserve", c_ulonglong), 100 | ("SizeOfStackCommit", c_ulonglong), 101 | ("SizeOfHeapReserve", c_ulonglong), 102 | ("SizeOfHeapCommit", c_ulonglong), 103 | ("LoaderFlags", c_uint), 104 | ("NumberOfRvaAndSizes", c_uint), 105 | ] 106 | 107 | 108 | class IMAGE_NT_HEADERS(LittleEndianStructure): 109 | _fields_ = [ 110 | ("Signature", c_uint), 111 | ("FileHeader", IMAGE_FILE_HEADER), 112 | ("OptionalHeader", IMAGE_OPTIONAL_HEADER), 113 | ] 114 | 115 | 116 | class IMAGE_NT_HEADERS64(LittleEndianStructure): 117 | _fields_ = [ 118 | ("Signature", c_uint), 119 | ("FileHeader", IMAGE_FILE_HEADER), 120 | ("OptionalHeader", IMAGE_OPTIONAL_HEADER64), 121 | ] 122 | 123 | 124 | class IMAGE_SECTION_HEADER(LittleEndianStructure): 125 | _fields_ = [ 126 | ("Name", c_ubyte * PEFlags.IMAGE_SIZEOF_SHORT_NAME), 127 | ("PhysicalAddress", c_uint), 128 | ("VirtualAddress", c_uint), 129 | ("SizeOfRawData", c_uint), 130 | ("PointerToRawData", c_uint), 131 | ("PointerToRelocations", c_uint), 132 | ("PointerToLinenumbers", c_uint), 133 | ("NumberOfRelocations", c_ushort), 134 | ("NumberOfLinenumbers", c_ushort), 135 | ("Characteristics", c_uint), 136 | ] 137 | 138 | 139 | class PE(object): 140 | """This class parses the PE format.""" 141 | 142 | def __init__(self, binary): 143 | self.__binary = bytearray(binary) 144 | 145 | self.__PEOffset = 0x00000000 146 | self.__IMAGE_FILE_HEADER = None 147 | self.__IMAGE_OPTIONAL_HEADER = None 148 | 149 | self.__sections_l = [] 150 | 151 | self.__getPEOffset() 152 | self.__parsePEHeader() 153 | self.__parseOptHeader() 154 | self.__parseSections() 155 | 156 | def __getPEOffset(self): 157 | self.__PEOffset = unpack("([(rax)|(rbx)|(rcx)|(rdx)|(rsi)|(rdi)|(r9)|(r10)|(r11)|(r12)|(r13)|(r14)|(r15)]{3}))\], (?P([(rax)|(rbx)|(rcx)|(rdx)|(rsi)|(rdi)|(r9)|(r10)|(r11)|(r12)|(r13)|(r14)|(r15)]{3}))$", f) 30 | if regex: 31 | lg = gadget["gadget"].split(" ; ")[1:] 32 | try: 33 | for g in lg: 34 | if g.split()[0] != "pop" and g.split()[0] != "ret": 35 | raise 36 | # we need this to filterout 'ret' instructions with an offset like 'ret 0x6', because they ruin the stack pointer 37 | if g != "ret": 38 | if g.split()[0] == "ret" and g.split()[1] != "": 39 | raise 40 | print("\t[+] Gadget found: 0x%x %s" % (gadget["vaddr"], gadget["gadget"])) 41 | return [gadget, regex.group("dst"), regex.group("src")] 42 | except: 43 | continue 44 | return None 45 | 46 | def __lookingForSomeThing(self, something): 47 | for gadget in self.__gadgets: 48 | lg = gadget["gadget"].split(" ; ") 49 | if lg[0] == something: 50 | try: 51 | for g in lg[1:]: 52 | if g.split()[0] != "pop" and g.split()[0] != "ret": 53 | raise 54 | if g != "ret": 55 | # we need this to filterout 'ret' instructions with an offset like 'ret 0x6', because they ruin the stack pointer 56 | if g.split()[0] == "ret" and g.split()[1] != "": 57 | raise 58 | print("\t[+] Gadget found: 0x%x %s" % (gadget["vaddr"], gadget["gadget"])) 59 | return gadget 60 | except: 61 | continue 62 | return None 63 | 64 | def __padding(self, gadget, regAlreadSetted): 65 | lg = gadget["gadget"].split(" ; ") 66 | for g in lg[1:]: 67 | if g.split()[0] == "pop": 68 | reg = g.split()[1] 69 | try: 70 | print("\tp += pack(' mov dword ptr [r32], r32 29 | regex = re.search(r"mov dword ptr \[(?P([(eax)|(ebx)|(ecx)|(edx)|(esi)|(edi)]{3}))\], (?P([(eax)|(ebx)|(ecx)|(edx)|(esi)|(edi)]{3}))$", f) 30 | if regex: 31 | lg = gadget["gadget"].split(" ; ")[1:] 32 | try: 33 | for g in lg: 34 | if g.split()[0] != "pop" and g.split()[0] != "ret": 35 | raise 36 | # we need this to filterout 'ret' instructions with an offset like 'ret 0x6', because they ruin the stack pointer 37 | if g != "ret": 38 | if g.split()[0] == "ret" and g.split()[1] != "": 39 | raise 40 | print("\t[+] Gadget found: 0x%x %s" % (gadget["vaddr"], gadget["gadget"])) 41 | return [gadget, regex.group("dst"), regex.group("src")] 42 | except: 43 | continue 44 | return None 45 | 46 | def __lookingForSomeThing(self, something): 47 | for gadget in self.__gadgets: 48 | lg = gadget["gadget"].split(" ; ") 49 | if lg[0] == something: 50 | try: 51 | for g in lg[1:]: 52 | if g.split()[0] != "pop" and g.split()[0] != "ret": 53 | raise 54 | # we need this to filterout 'ret' instructions with an offset like 'ret 0x6', because they ruin the stack pointer 55 | if g != "ret": 56 | if g.split()[0] == "ret" and g.split()[1] != "": 57 | raise 58 | print("\t[+] Gadget found: 0x%x %s" % (gadget["vaddr"], gadget["gadget"])) 59 | return gadget 60 | except: 61 | continue 62 | return None 63 | 64 | def __padding(self, gadget, regAlreadSetted): 65 | lg = gadget["gadget"].split(" ; ") 66 | for g in lg[1:]: 67 | if g.split()[0] == "pop": 68 | reg = g.split()[1] 69 | try: 70 | print("\tp += pack('[\d])", d).group("value") 31 | minorVersion = re.search(r"MINOR_VERSION.+=.+(?P[\d])", d).group("value") 32 | webVersion = int("%s%s" % (majorVersion, minorVersion)) 33 | curVersion = int("%s%s" % (MAJOR_VERSION, MINOR_VERSION)) 34 | if webVersion > curVersion: 35 | print("The version %s.%s is available. Currently, you use the version %d.%d." % (majorVersion, minorVersion, MAJOR_VERSION, MINOR_VERSION)) 36 | else: 37 | print("Your version is up-to-date.") 38 | -------------------------------------------------------------------------------- /ropgadget/version.py: -------------------------------------------------------------------------------- 1 | ## -*- coding: utf-8 -*- 2 | ## 3 | ## Jonathan Salwan - 2014-05-12 - ROPgadget tool 4 | ## 5 | ## http://twitter.com/JonathanSalwan 6 | ## http://shell-storm.org/project/ROPgadget/ 7 | ## 8 | 9 | MAJOR_VERSION = 7 10 | MINOR_VERSION = 6 11 | PYROPGADGET_VERSION = "ROPgadget v%d.%d" % (MAJOR_VERSION, MINOR_VERSION) 12 | -------------------------------------------------------------------------------- /scripts/ROPgadget: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ## -*- coding: utf-8 -*- 3 | ## 4 | ## Jonathan Salwan - 2014-05-12 - ROPgadget tool 5 | ## 6 | ## http://twitter.com/JonathanSalwan 7 | ## http://shell-storm.org/project/ROPgadget/ 8 | ## 9 | 10 | import ropgadget 11 | 12 | ropgadget.main() 13 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | # All configuration for plugins and other utils is defined here. 2 | # Read more about `setup.cfg`: 3 | # https://docs.python.org/3/distutils/configfile.html 4 | 5 | 6 | # === Linter configuration === 7 | # You can reuse this configuration in your own projects. 8 | # See: https://wemake-python-stylegui.de/en/latest/pages/usage/integrations/nitpick.html 9 | 10 | [flake8] 11 | # Base flake8 configuration: 12 | # https://flake8.pycqa.org/en/latest/user/configuration.html 13 | format = wemake 14 | show-source = True 15 | statistics = False 16 | doctests = True 17 | 18 | # Plugins: 19 | max-complexity = 6 20 | max-line-length = 100 21 | 22 | # Self settings: 23 | max-imports = 17 24 | 25 | # Excluding some directories: 26 | exclude = 27 | .git 28 | __pycache__ 29 | .venv 30 | .eggs 31 | *.egg 32 | dist 33 | 34 | # Exclude some checks globally: 35 | ignore = B001, C901, D100, D101, D102, D103, D104, D107, D205, D400, E221, E241, 36 | E251, E266, E271, E272, E722, F403, F405, I004, N802, N803, N806, P101, 37 | Q000, W503, W504, WPS110, WPS111, WPS112, WPS122, WPS202, WPS204, WPS210, 38 | WPS212, WPS213, WPS214, WPS220, WPS221, WPS222, WPS223, WPS226, WPS229, 39 | WPS231, WPS232, WPS301, WPS323, WPS336, WPS337, WPS338, WPS341, WPS347, 40 | WPS412, WPS420, WPS421, WPS430, WPS432, WPS433, WPS440, WPS504, WPS514, 41 | WPS515, WPS602, WPS605 42 | 43 | per-file-ignores = 44 | ROPgadget.py: WPS102 45 | ropgadget/__init__.py: F401 46 | ropgadget/args.py: E501, WPS317, WPS318 47 | ropgadget/binary.py: E501 48 | ropgadget/core.py: E501, I001, S110, WPS125, WPS503, WPS513, WPS609 49 | ropgadget/gadgets.py: C812, E126, E261, E501, E800, WPS318, WPS319, WPS513 50 | ropgadget/loaders/__init__.py: F401 51 | ropgadget/loaders/elf.py: E126, E203, E222, E501, E701, N801, WPS114, 52 | WPS115, WPS120, WPS318, WPS339 53 | ropgadget/loaders/macho.py: E126, E203, E222, E501, N801, WPS114, WPS115, 54 | WPS120, WPS318, WPS339, WPS349 55 | ropgadget/loaders/pe.py: E126, E203, E222, E501, N801, WPS114, WPS115, 56 | WPS120, WPS318, WPS339, WPS349 57 | ropgadget/loaders/raw.py: E126, E222, E501, WPS318 58 | ropgadget/loaders/universal.py: E126, E501, N801, WPS114, WPS115, WPS120, 59 | WPS318, WPS328, WPS339, WPS519 60 | ropgadget/options.py: E501, S110 61 | ropgadget/ropchain/__init__.py: F401 62 | ropgadget/ropchain/arch/__init__.py: F401 63 | ropgadget/ropchain/arch/ropmakerx64.py: E501, S112, W605, WPS211, WPS327, 64 | WPS503 65 | ropgadget/ropchain/arch/ropmakerx86.py: E501, S112, W605, WPS211, WPS327, 66 | WPS503 67 | ropgadget/ropchain/ropmaker.py: E501, N400 68 | ropgadget/updateAlert.py: E501, I001, I003, S309, W605, WPS102, WPS301 69 | setup.py: E501 70 | 71 | [isort] 72 | # isort configuration: 73 | # https://github.com/timothycrosley/isort/wiki/isort-Settings 74 | include_trailing_comma = true 75 | use_parentheses = true 76 | # See https://github.com/timothycrosley/isort#multi-line-output-modes 77 | multi_line_output = 3 78 | # Is the same as 80 in flake8: 79 | line_length = 100 80 | 81 | 82 | [darglint] 83 | # darglint configuration: 84 | # https://github.com/terrencepreilly/darglint 85 | strictness = long 86 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import os 4 | 5 | from setuptools import setup 6 | 7 | package_name = "ROPGadget" 8 | package_dir = "ropgadget" 9 | package_description = "This tool lets you search your gadgets on your binaries to facilitate your ROP exploitation." 10 | long_description = """ 11 | ROPgadget supports ELF, PE, Mach-O, and Raw formats on x86, x64, ARM, ARM64, PowerPC, SPARC, MIPS, RISC-V 64, and RISC-V Compressed architectures. 12 | https://github.com/JonathanSalwan/ROPgadget 13 | """.strip() 14 | 15 | 16 | def fullsplit(path, result=None): 17 | """ 18 | Split a pathname into components (the opposite of os.path.join) in a 19 | platform-neutral way. 20 | """ 21 | if result is None: 22 | result = [] 23 | head, tail = os.path.split(path) 24 | if head == '': 25 | return [tail] + result 26 | if head == path: 27 | return result 28 | return fullsplit(head, [tail] + result) 29 | 30 | 31 | # Compile the list of packages available, because distutils doesn't have 32 | # an easy way to do this. 33 | packages, data_files = [], [] 34 | root_dir = os.path.dirname(__file__) 35 | if root_dir != '': 36 | os.chdir(root_dir) 37 | 38 | for dirpath, dirnames, filenames in os.walk(package_dir): 39 | # Ignore dirnames that start with '.' 40 | for i, dirname in enumerate(dirnames): 41 | if dirname.startswith('.'): 42 | del dirnames[i] 43 | if '__init__.py' in filenames: 44 | packages.append('.'.join(fullsplit(dirpath))) 45 | elif filenames: 46 | data_files.append([dirpath, [os.path.join(dirpath, f) for f in filenames]]) 47 | 48 | version = "7.6" 49 | 50 | setup( 51 | name = package_name, 52 | version = version, 53 | description = package_description, 54 | long_description = long_description, 55 | packages = packages, 56 | license = "BSD", 57 | author = "Jonathan Salwan", 58 | author_email = "jonathan.salwan@gmail.com", 59 | url = "https://github.com/JonathanSalwan/ROPgadget", 60 | scripts = ['scripts/ROPgadget'], 61 | install_requires = ['capstone>=5.0.1'], 62 | classifiers = [ 63 | 'Topic :: Security', 64 | 'Environment :: Console', 65 | 'Operating System :: OS Independent', 66 | 'License :: OSI Approved :: BSD License', 67 | 'Programming Language :: Python :: 2.7', 68 | 'Programming Language :: Python :: 3', 69 | 'Intended Audience :: Developers', 70 | ], 71 | ) 72 | -------------------------------------------------------------------------------- /test-suite-binaries/.gitignore: -------------------------------------------------------------------------------- 1 | test_output 2 | -------------------------------------------------------------------------------- /test-suite-binaries/Linux_lib32.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JonathanSalwan/ROPgadget/1d72f151a644bfd928bf7134dc9d942f73971394/test-suite-binaries/Linux_lib32.so -------------------------------------------------------------------------------- /test-suite-binaries/Linux_lib64.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JonathanSalwan/ROPgadget/1d72f151a644bfd928bf7134dc9d942f73971394/test-suite-binaries/Linux_lib64.so -------------------------------------------------------------------------------- /test-suite-binaries/UNIVERSAL-x86-x64-libSystem.B.dylib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JonathanSalwan/ROPgadget/1d72f151a644bfd928bf7134dc9d942f73971394/test-suite-binaries/UNIVERSAL-x86-x64-libSystem.B.dylib -------------------------------------------------------------------------------- /test-suite-binaries/core: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JonathanSalwan/ROPgadget/1d72f151a644bfd928bf7134dc9d942f73971394/test-suite-binaries/core -------------------------------------------------------------------------------- /test-suite-binaries/elf-ARM64-bash: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JonathanSalwan/ROPgadget/1d72f151a644bfd928bf7134dc9d942f73971394/test-suite-binaries/elf-ARM64-bash -------------------------------------------------------------------------------- /test-suite-binaries/elf-ARMv7-ls: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JonathanSalwan/ROPgadget/1d72f151a644bfd928bf7134dc9d942f73971394/test-suite-binaries/elf-ARMv7-ls -------------------------------------------------------------------------------- /test-suite-binaries/elf-FreeBSD-x86: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JonathanSalwan/ROPgadget/1d72f151a644bfd928bf7134dc9d942f73971394/test-suite-binaries/elf-FreeBSD-x86 -------------------------------------------------------------------------------- /test-suite-binaries/elf-Linux-RISCV_32: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JonathanSalwan/ROPgadget/1d72f151a644bfd928bf7134dc9d942f73971394/test-suite-binaries/elf-Linux-RISCV_32 -------------------------------------------------------------------------------- /test-suite-binaries/elf-Linux-RISCV_64: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JonathanSalwan/ROPgadget/1d72f151a644bfd928bf7134dc9d942f73971394/test-suite-binaries/elf-Linux-RISCV_64 -------------------------------------------------------------------------------- /test-suite-binaries/elf-Linux-x64: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JonathanSalwan/ROPgadget/1d72f151a644bfd928bf7134dc9d942f73971394/test-suite-binaries/elf-Linux-x64 -------------------------------------------------------------------------------- /test-suite-binaries/elf-Linux-x86: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JonathanSalwan/ROPgadget/1d72f151a644bfd928bf7134dc9d942f73971394/test-suite-binaries/elf-Linux-x86 -------------------------------------------------------------------------------- /test-suite-binaries/elf-Linux-x86-NDH-chall: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JonathanSalwan/ROPgadget/1d72f151a644bfd928bf7134dc9d942f73971394/test-suite-binaries/elf-Linux-x86-NDH-chall -------------------------------------------------------------------------------- /test-suite-binaries/elf-Mips-Defcon-20-pwn100: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JonathanSalwan/ROPgadget/1d72f151a644bfd928bf7134dc9d942f73971394/test-suite-binaries/elf-Mips-Defcon-20-pwn100 -------------------------------------------------------------------------------- /test-suite-binaries/elf-PPC64-bash: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JonathanSalwan/ROPgadget/1d72f151a644bfd928bf7134dc9d942f73971394/test-suite-binaries/elf-PPC64-bash -------------------------------------------------------------------------------- /test-suite-binaries/elf-PowerPC-bash: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JonathanSalwan/ROPgadget/1d72f151a644bfd928bf7134dc9d942f73971394/test-suite-binaries/elf-PowerPC-bash -------------------------------------------------------------------------------- /test-suite-binaries/elf-SparcV8-bash: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JonathanSalwan/ROPgadget/1d72f151a644bfd928bf7134dc9d942f73971394/test-suite-binaries/elf-SparcV8-bash -------------------------------------------------------------------------------- /test-suite-binaries/elf-x64-bash-v4.1.5.1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JonathanSalwan/ROPgadget/1d72f151a644bfd928bf7134dc9d942f73971394/test-suite-binaries/elf-x64-bash-v4.1.5.1 -------------------------------------------------------------------------------- /test-suite-binaries/elf-x86-bash-v4.1.5.1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JonathanSalwan/ROPgadget/1d72f151a644bfd928bf7134dc9d942f73971394/test-suite-binaries/elf-x86-bash-v4.1.5.1 -------------------------------------------------------------------------------- /test-suite-binaries/macho-ppc-openssl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JonathanSalwan/ROPgadget/1d72f151a644bfd928bf7134dc9d942f73971394/test-suite-binaries/macho-ppc-openssl -------------------------------------------------------------------------------- /test-suite-binaries/macho-x64-ls: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JonathanSalwan/ROPgadget/1d72f151a644bfd928bf7134dc9d942f73971394/test-suite-binaries/macho-x64-ls -------------------------------------------------------------------------------- /test-suite-binaries/macho-x86-ls: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JonathanSalwan/ROPgadget/1d72f151a644bfd928bf7134dc9d942f73971394/test-suite-binaries/macho-x86-ls -------------------------------------------------------------------------------- /test-suite-binaries/pe-Windows-ARMv7-Thumb2LE-HelloWorld: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JonathanSalwan/ROPgadget/1d72f151a644bfd928bf7134dc9d942f73971394/test-suite-binaries/pe-Windows-ARMv7-Thumb2LE-HelloWorld -------------------------------------------------------------------------------- /test-suite-binaries/pe-x64-cmd-v6.1.7601: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JonathanSalwan/ROPgadget/1d72f151a644bfd928bf7134dc9d942f73971394/test-suite-binaries/pe-x64-cmd-v6.1.7601 -------------------------------------------------------------------------------- /test-suite-binaries/pe-x86-cmd-v6.1.7600: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JonathanSalwan/ROPgadget/1d72f151a644bfd928bf7134dc9d942f73971394/test-suite-binaries/pe-x86-cmd-v6.1.7600 -------------------------------------------------------------------------------- /test-suite-binaries/raw-x86.raw: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JonathanSalwan/ROPgadget/1d72f151a644bfd928bf7134dc9d942f73971394/test-suite-binaries/raw-x86.raw -------------------------------------------------------------------------------- /test-suite-binaries/ref_output.bz2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JonathanSalwan/ROPgadget/1d72f151a644bfd928bf7134dc9d942f73971394/test-suite-binaries/ref_output.bz2 -------------------------------------------------------------------------------- /test-suite-binaries/test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | export PYTHONPATH=../ 4 | if [ "$#" == "1" ] 5 | then 6 | RUN="python2 ../ROPgadget.py" 7 | else 8 | RUN="python3 ../ROPgadget.py" 9 | fi 10 | 11 | rm -rf test_output 12 | 13 | FILES=`ls | sort -f` 14 | for f in $FILES 15 | do 16 | if [ "$f" != "test.sh" ] && [ "$f" != "ref_output.bz2" ] && [ "$f" != "test_output" ] 17 | then 18 | echo "RUN $f" | tee -a ./test_output 19 | if [ "$f" == "raw-x86.raw" ] 20 | then 21 | $RUN --rawArch=x86 --rawMode=32 --depth 5 --binary $f 1>> ./test_output 22 | else 23 | $RUN --depth 5 --binary $f 1>> ./test_output 24 | fi 25 | fi 26 | done 27 | 28 | echo "RUN elf-Linux-x86 --ropchain" | tee -a ./test_output 29 | $RUN --binary ./elf-Linux-x86 --ropchain 1>> ./test_output 30 | echo "RUN elf-Linux-x86 --depth 3" | tee -a ./test_output 31 | $RUN --binary ./elf-Linux-x86 --depth 3 1>> ./test_output 32 | echo "RUN elf-Linux-x86 --string \"main\"" | tee -a ./test_output 33 | $RUN --binary ./elf-Linux-x86 --string "main" 1>> ./test_output 34 | echo "RUN elf-Linux-x86 --string \"m..n\"" | tee -a ./test_output 35 | $RUN --binary ./elf-Linux-x86 --string "m..n" 1>> ./test_output 36 | echo "RUN elf-Linux-x86 --opcode c9c3" | tee -a ./test_output 37 | $RUN --binary ./elf-Linux-x86 --opcode c9c3 1>> ./test_output 38 | echo "RUN elf-Linux-x86 --only \"mov|ret\"" | tee -a ./test_output 39 | $RUN --binary ./elf-Linux-x86 --only "mov|ret" 1>> ./test_output 40 | echo "RUN elf-Linux-x86 --only \"mov|pop|xor|ret\"" | tee -a ./test_output 41 | $RUN --binary ./elf-Linux-x86 --only "mov|pop|xor|ret" 1>> ./test_output 42 | echo "RUN elf-Linux-x86 --filter \"xchg|add|sub|cmov.*\"" | tee -a ./test_output 43 | $RUN --binary ./elf-Linux-x86 --filter "xchg|add|sub|cmov.*" 1>> ./test_output 44 | echo "RUN elf-Linux-x86 --norop --nosys" | tee -a ./test_output 45 | $RUN --binary ./elf-Linux-x86 --norop --nosys 1>> ./test_output 46 | echo "RUN elf-Linux-x86 --range 0x08041000-0x08042000" | tee -a ./test_output 47 | $RUN --binary ./elf-Linux-x86 --range 0x08041000-0x08042000 1>> ./test_output 48 | echo "RUN elf-Linux-x86 --string main --range 0x080c9aaa-0x080c9aba" | tee -a ./test_output 49 | $RUN --binary ./elf-Linux-x86 --string main --range 0x080c9aaa-0x080c9aba 1>> ./test_output 50 | echo "RUN elf-Linux-x86 --memstr \"/bin/sh\"" | tee -a ./test_output 51 | $RUN --binary ./elf-Linux-x86 --memstr "/bin/sh" 1>> ./test_output 52 | echo "RUN elf-Linux-x86 --badbytes \"00|01-1f|7f|42\"" | tee -a ./test_output 53 | $RUN --binary ./elf-Linux-x86 --badbytes "00|01-1f|7f|42" 1>> ./test_output 54 | echo "RUN elf-Linux-x86 --offset 5555e000 --badbytes \"00-20|80-ff\"" | tee -a ./test_output 55 | $RUN --binary ./elf-Linux-x86 --offset 5555e000 --badbytes "00-20|80-ff" 1>> ./test_output 56 | echo "RUN Linux_lib64.so --offset 0xdeadbeef00000000" | tee -a ./test_output 57 | $RUN --binary ./Linux_lib64.so --offset 0xdeadbeef00000000 1>> ./test_output 58 | echo "RUN elf-ARMv7-ls --depth 5" | tee -a ./test_output 59 | $RUN --binary ./elf-ARMv7-ls --depth 5 1>> ./test_output 60 | echo "RUN elf-ARMv7-ls --thumb --depth 5" | tee -a ./test_output 61 | $RUN --binary ./elf-ARMv7-ls --thumb --depth 5 1>> ./test_output 62 | echo "RUN elf-ARM64-bash --depth 5" | tee -a ./test_output 63 | $RUN --binary ./elf-ARM64-bash --depth 5 1>> ./test_output 64 | echo "RUN elf-PPC64-bash --depth 5" | tee -a ./test_output 65 | $RUN --binary ./elf-PPC64-bash --depth 5 1>> ./test_output 66 | echo "RUN elf-Linux-RISCV_64 --depth 8" | tee -a ./test_output 67 | $RUN --binary ./elf-Linux-RISCV_64 --depth 8 1>> ./test_output 68 | echo "RUN elf-Linux-RISCV_32 --depth 8" | tee -a ./test_output 69 | $RUN --binary ./elf-Linux-RISCV_32 --depth 8 1>> ./test_output 70 | 71 | diff test_output <(bunzip2 --stdout ref_output.bz2) 1>&2 72 | --------------------------------------------------------------------------------