parent
d0e48acb8d
commit
4cbcd36c74
@ -0,0 +1,21 @@
|
||||
#include <stdio.h>
|
||||
|
||||
void secretFunction()
|
||||
{
|
||||
printf("Congratulations!\n");
|
||||
printf("You have entered in the secret function!\n");
|
||||
}
|
||||
|
||||
void echo()
|
||||
{
|
||||
char buffer[20];
|
||||
printf("Enter some text:\n");
|
||||
scanf("%s", buffer);
|
||||
printf("You entered: %s\n", buffer);
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
echo();
|
||||
return 0;
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
FROM ubuntu:latest
|
||||
|
||||
RUN apt-get update && \
|
||||
apt install -y python3 gcc musl-dev python3-pip && \
|
||||
python3 -m pip install ROPgadget && \
|
||||
python3 -m pip install capstone
|
||||
|
||||
COPY Bufferoverflow /root/Bufferoverflow
|
||||
COPY ROPgadget /root/ROPgadget
|
||||
|
||||
WORKDIR /root/Bufferoverflow
|
||||
|
||||
RUN gcc main.c -o binaire -fno-stack-protector
|
||||
|
||||
WORKDIR /root
|
||||
|
||||
ENTRYPOINT ["/bin/bash"]
|
||||
|
||||
#python3 ROPgadget/ROPgadget.py --binary Bufferoverflow/binaire
|
@ -0,0 +1,4 @@
|
||||
*.pyc
|
||||
build
|
||||
dist
|
||||
ROPGadget.egg-info
|
@ -0,0 +1,46 @@
|
||||
|
||||
ROPgadget project (>= v5.0)
|
||||
===================================================
|
||||
|
||||
Authors:
|
||||
|
||||
* Jonathan Salwan
|
||||
* Alexey Vishnyakov
|
||||
|
||||
|
||||
Contributors:
|
||||
|
||||
* hugsy - Has added the --offset option
|
||||
* Francisco Falcon - Has fixed the --badbytes option and added the count/loaddb/save2db console features
|
||||
* Kevin Hamacher - Added some functionality for using ROPgadget as library. Also added support for x86(_64) jmp {r,e}sp/call {r,e}sp instructions
|
||||
* Florian Meier - Added the 64b ROP chain generation
|
||||
* Álvaro Felipe Melchor (increase performance)
|
||||
* Sascha Schirra (features, python3, bugs fix)
|
||||
* Stephen Edwards (increase performance)
|
||||
* Mikhail Davidov (features)
|
||||
* penguin-wwy (features)
|
||||
* Alexey Nurmukhametov (increase performance)
|
||||
* Mario Haustein (PowerPC for MachO binaries)
|
||||
* pkubaj (PowerPC 64-bit)
|
||||
* 0xMirasio (RISC-V 64 and Compressed)
|
||||
|
||||
|
||||
|
||||
ROPgadget initial project (<= v4.0.3)
|
||||
===================================================
|
||||
|
||||
Authors:
|
||||
|
||||
* Jonathan Salwan
|
||||
* Allan Wirth
|
||||
|
||||
|
||||
Contributors:
|
||||
|
||||
* Hellman (Bug Fix)
|
||||
* Axel "0vercl0k" Souchet (Bug Fix)
|
||||
* k3rensk1 (Bug repport)
|
||||
* brianairb (Bug Fix)
|
||||
* cao (Bug Fix)
|
||||
* dark-rose (Made searching for gadgets faster)
|
||||
* Dennis Semakin (Bug Fix)
|
@ -0,0 +1,27 @@
|
||||
This is the software license for the ROPgadget project.
|
||||
|
||||
Copyright (c) 2016-2023. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
* Neither the name of the developers nor the names of its
|
||||
contributors may be used to endorse or promote products derived from this
|
||||
software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
@ -0,0 +1,160 @@
|
||||
ROPgadget Tool
|
||||
==============
|
||||
|
||||
This tool lets you search your gadgets on your binaries to facilitate your ROP
|
||||
exploitation. ROPgadget supports ELF/PE/Mach-O/Raw formats on x86, x64, ARM,
|
||||
ARM64, PowerPC, SPARC, MIPS, RISC-V 64, and RISC-V Compressed architectures.
|
||||
|
||||
Install
|
||||
-------
|
||||
|
||||
The easiest way is installing ROPgadget from PyPi:
|
||||
|
||||
$ sudo apt install python3-pip
|
||||
$ sudo -H python3 -m pip install ROPgadget
|
||||
$ ROPgadget --help
|
||||
|
||||
Alternatively you can install ROPgadget from source.
|
||||
You have to install [Capstone](http://www.capstone-engine.org/) first.
|
||||
|
||||
For the Capstone's installation on nix machine:
|
||||
|
||||
$ sudo apt install python3-pip
|
||||
$ sudo -H python3 -m pip install capstone
|
||||
|
||||
Capstone supports multi-platforms (windows, ios, android, cygwin...). For the cross-compilation,
|
||||
please refer to the https://github.com/capstone-engine/capstone/blob/master/COMPILE.TXT file.
|
||||
|
||||
After Capstone is installed, ROPgadget can be used as a standalone tool:
|
||||
|
||||
$ python3 ROPgadget.py --help
|
||||
|
||||
Or installed into the Python site-packages library, and executed from $PATH.
|
||||
|
||||
$ sudo -H python3 setup.py install
|
||||
$ ROPgadget --help
|
||||
|
||||
Usage
|
||||
-----
|
||||
|
||||
usage: ROPgadget.py [-h] [-v] [-c] [--binary <binary>] [--opcode <opcodes>]
|
||||
[--string <string>] [--memstr <string>] [--depth <nbyte>]
|
||||
[--only <key>] [--filter <key>] [--range <start-end>]
|
||||
[--badbytes <byte>] [--rawArch <arch>] [--rawMode <mode>]
|
||||
[--rawEndian <endian>] [--re <re>] [--offset <hexaddr>]
|
||||
[--ropchain] [--thumb] [--console] [--norop] [--nojop]
|
||||
[--callPreceded] [--nosys] [--multibr] [--all] [--noinstr]
|
||||
[--dump] [--silent] [--align ALIGN] [--mipsrop <rtype>]
|
||||
|
||||
description:
|
||||
ROPgadget lets you search your gadgets on a binary. It supports several
|
||||
file formats and architectures and uses the Capstone disassembler for
|
||||
the search engine.
|
||||
|
||||
formats supported:
|
||||
- ELF
|
||||
- PE
|
||||
- Mach-O
|
||||
- Raw
|
||||
|
||||
architectures supported:
|
||||
- x86
|
||||
- x86-64
|
||||
- ARM
|
||||
- ARM64
|
||||
- MIPS
|
||||
- PowerPC
|
||||
- Sparc
|
||||
- RISC-V 64
|
||||
- RISC-V Compressed
|
||||
|
||||
optional arguments:
|
||||
-h, --help show this help message and exit
|
||||
-v, --version Display the ROPgadget's version
|
||||
-c, --checkUpdate Checks if a new version is available
|
||||
--binary <binary> Specify a binary filename to analyze
|
||||
--opcode <opcodes> Search opcode in executable segment
|
||||
--string <string> Search string in readable segment
|
||||
--memstr <string> Search each byte in all readable segment
|
||||
--depth <nbyte> Depth for search engine (default 10)
|
||||
--only <key> Only show specific instructions
|
||||
--filter <key> Suppress specific mnemonics
|
||||
--range <start-end> Search between two addresses (0x...-0x...)
|
||||
--badbytes <byte> Rejects specific bytes in the gadget's address
|
||||
--rawArch <arch> Specify an arch for a raw file
|
||||
x86|arm|arm64|sparc|mips|ppc|riscv
|
||||
--rawMode <mode> Specify a mode for a raw file 32|64|arm|thumb
|
||||
--rawEndian <endian> Specify an endianness for a raw file little|big
|
||||
--re <re> Regular expression
|
||||
--offset <hexaddr> Specify an offset for gadget addresses
|
||||
--ropchain Enable the ROP chain generation
|
||||
--thumb Use the thumb mode for the search engine (ARM only)
|
||||
--console Use an interactive console for search engine
|
||||
--norop Disable ROP search engine
|
||||
--nojop Disable JOP search engine
|
||||
--callPreceded Only show gadgets which are call-preceded
|
||||
--nosys Disable SYS search engine
|
||||
--multibr Enable multiple branch gadgets
|
||||
--all Disables the removal of duplicate gadgets
|
||||
--noinstr Disable the gadget instructions console printing
|
||||
--dump Outputs the gadget bytes
|
||||
--silent Disables printing of gadgets during analysis
|
||||
--align ALIGN Align gadgets addresses (in bytes)
|
||||
--mipsrop <rtype> MIPS useful gadgets finder
|
||||
stackfinder|system|tails|lia0|registers
|
||||
|
||||
examples:
|
||||
ROPgadget.py --binary ./test-suite-binaries/elf-Linux-x86
|
||||
ROPgadget.py --binary ./test-suite-binaries/elf-Linux-x86 --ropchain
|
||||
ROPgadget.py --binary ./test-suite-binaries/elf-Linux-x86 --depth 3
|
||||
ROPgadget.py --binary ./test-suite-binaries/elf-Linux-x86 --string "main"
|
||||
ROPgadget.py --binary ./test-suite-binaries/elf-Linux-x86 --string "m..n"
|
||||
ROPgadget.py --binary ./test-suite-binaries/elf-Linux-x86 --opcode c9c3
|
||||
ROPgadget.py --binary ./test-suite-binaries/elf-Linux-x86 --only "mov|ret"
|
||||
ROPgadget.py --binary ./test-suite-binaries/elf-Linux-x86 --only "mov|pop|xor|ret"
|
||||
ROPgadget.py --binary ./test-suite-binaries/elf-Linux-x86 --filter "xchg|add|sub|cmov.*"
|
||||
ROPgadget.py --binary ./test-suite-binaries/elf-Linux-x86 --norop --nosys
|
||||
ROPgadget.py --binary ./test-suite-binaries/elf-Linux-x86 --range 0x08041000-0x08042000
|
||||
ROPgadget.py --binary ./test-suite-binaries/elf-Linux-x86 --string main --range 0x080c9aaa-0x080c9aba
|
||||
ROPgadget.py --binary ./test-suite-binaries/elf-Linux-x86 --memstr "/bin/sh"
|
||||
ROPgadget.py --binary ./test-suite-binaries/elf-Linux-x86 --console
|
||||
ROPgadget.py --binary ./test-suite-binaries/elf-Linux-x86 --badbytes "00|01-1f|7f|42"
|
||||
ROPgadget.py --binary ./test-suite-binaries/Linux_lib64.so --offset 0xdeadbeef00000000
|
||||
ROPgadget.py --binary ./test-suite-binaries/elf-ARMv7-ls --depth 5
|
||||
ROPgadget.py --binary ./test-suite-binaries/elf-ARM64-bash --depth 5
|
||||
ROPgadget.py --binary ./test-suite-binaries/raw-x86.raw --rawArch=x86 --rawMode=32
|
||||
ROPgadget.py --binary ./test-suite-binaries/elf-Linux-RISCV_64 --depth 8
|
||||
|
||||
How can I contribute ?
|
||||
----------------------
|
||||
|
||||
- Add system gadgets for PPC, Sparc, ARM64 (Gadgets.addSYSGadgets()).
|
||||
- Support RISC-V 32-bit.
|
||||
- Handle bad bytes in data during ROP chain generation.
|
||||
- Manage big endian in Mach-O format like the ELF class.
|
||||
- Everything you think is cool :)
|
||||
|
||||
Bugs/Patches/Contact
|
||||
--------------------
|
||||
|
||||
Please, report bugs, submit pull requests, etc. on GitHub at https://github.com/JonathanSalwan/ROPgadget
|
||||
|
||||
License
|
||||
-------
|
||||
|
||||
See LICENSE_BSD.txt and the license header on all source files.
|
||||
|
||||
Screenshots
|
||||
-----------
|
||||
|
||||
<img src="http://shell-storm.org/project/ROPgadget/x64.png" alt="x64"></img>
|
||||
|
||||
<img src="http://shell-storm.org/project/ROPgadget/arm.png" alt="ARM"></img>
|
||||
|
||||
<img src="http://shell-storm.org/project/ROPgadget/sparc.png" alt="Sparc"></img>
|
||||
|
||||
<img src="http://shell-storm.org/project/ROPgadget/mips.png" alt="MIPS"></img>
|
||||
|
||||
<img src="http://shell-storm.org/project/ROPgadget/ppc.png" alt="PowerPC"></img>
|
||||
|
||||
<img src="http://shell-storm.org/project/ROPgadget/ropchain.png" alt="ROP chain"></img>
|
@ -0,0 +1,12 @@
|
||||
#!/usr/bin/env python
|
||||
## -*- coding: utf-8 -*-
|
||||
##
|
||||
## Jonathan Salwan - 2014-05-12 - ROPgadget tool
|
||||
##
|
||||
## http://twitter.com/JonathanSalwan
|
||||
## http://shell-storm.org/project/ROPgadget/
|
||||
##
|
||||
|
||||
import ropgadget
|
||||
|
||||
ropgadget.main()
|
@ -0,0 +1,30 @@
|
||||
## -*- coding: utf-8 -*-
|
||||
##
|
||||
## Jonathan Salwan - 2014-05-12 - ROPgadget tool
|
||||
##
|
||||
## http://twitter.com/JonathanSalwan
|
||||
## http://shell-storm.org/project/ROPgadget/
|
||||
##
|
||||
|
||||
import ropgadget.args
|
||||
import ropgadget.binary
|
||||
import ropgadget.core
|
||||
import ropgadget.gadgets
|
||||
import ropgadget.loaders
|
||||
import ropgadget.options
|
||||
import ropgadget.rgutils
|
||||
import ropgadget.ropchain
|
||||
import ropgadget.updateAlert
|
||||
import ropgadget.version
|
||||
|
||||
|
||||
def main():
|
||||
import sys
|
||||
from ropgadget.args import Args
|
||||
from ropgadget.core import Core
|
||||
try:
|
||||
args = Args()
|
||||
except ValueError as e:
|
||||
print(e)
|
||||
sys.exit(-1)
|
||||
sys.exit(0 if Core(args.getArgs()).analyze() else 1)
|
@ -0,0 +1,161 @@
|
||||
## -*- coding: utf-8 -*-
|
||||
##
|
||||
## Jonathan Salwan - 2014-05-12 - ROPgadget tool
|
||||
##
|
||||
## http://twitter.com/JonathanSalwan
|
||||
## http://shell-storm.org/project/ROPgadget/
|
||||
##
|
||||
|
||||
import argparse
|
||||
import sys
|
||||
|
||||
from ropgadget.updateAlert import UpdateAlert
|
||||
from ropgadget.version import *
|
||||
|
||||
|
||||
class Args(object):
|
||||
def __init__(self, arguments=None):
|
||||
self.__args = None
|
||||
custom_arguments_provided = True
|
||||
|
||||
# If no custom arguments are provided, use the program arguments
|
||||
if not arguments:
|
||||
arguments = sys.argv[1:]
|
||||
custom_arguments_provided = False
|
||||
|
||||
self.__parse(arguments, custom_arguments_provided)
|
||||
|
||||
def __parse(self, arguments, custom_arguments_provided=False):
|
||||
parser = argparse.ArgumentParser(formatter_class=argparse.RawDescriptionHelpFormatter,
|
||||
description="""description:
|
||||
ROPgadget lets you search your gadgets on a binary. It supports several
|
||||
file formats and architectures and uses the Capstone disassembler for
|
||||
the search engine.
|
||||
|
||||
formats supported:
|
||||
- ELF
|
||||
- PE
|
||||
- Mach-O
|
||||
- Raw
|
||||
|
||||
architectures supported:
|
||||
- x86
|
||||
- x86-64
|
||||
- ARM
|
||||
- ARM64
|
||||
- MIPS
|
||||
- PowerPC
|
||||
- Sparc
|
||||
- RISC-V 64
|
||||
- RISC-V Compressed
|
||||
""",
|
||||
epilog="""examples:
|
||||
ROPgadget.py --binary ./test-suite-binaries/elf-Linux-x86
|
||||
ROPgadget.py --binary ./test-suite-binaries/elf-Linux-x86 --ropchain
|
||||
ROPgadget.py --binary ./test-suite-binaries/elf-Linux-x86 --depth 3
|
||||
ROPgadget.py --binary ./test-suite-binaries/elf-Linux-x86 --string "main"
|
||||
ROPgadget.py --binary ./test-suite-binaries/elf-Linux-x86 --string "m..n"
|
||||
ROPgadget.py --binary ./test-suite-binaries/elf-Linux-x86 --opcode c9c3
|
||||
ROPgadget.py --binary ./test-suite-binaries/elf-Linux-x86 --only "mov|ret"
|
||||
ROPgadget.py --binary ./test-suite-binaries/elf-Linux-x86 --only "mov|pop|xor|ret"
|
||||
ROPgadget.py --binary ./test-suite-binaries/elf-Linux-x86 --filter "xchg|add|sub|cmov.*"
|
||||
ROPgadget.py --binary ./test-suite-binaries/elf-Linux-x86 --norop --nosys
|
||||
ROPgadget.py --binary ./test-suite-binaries/elf-Linux-x86 --range 0x08041000-0x08042000
|
||||
ROPgadget.py --binary ./test-suite-binaries/elf-Linux-x86 --string main --range 0x080c9aaa-0x080c9aba
|
||||
ROPgadget.py --binary ./test-suite-binaries/elf-Linux-x86 --memstr "/bin/sh"
|
||||
ROPgadget.py --binary ./test-suite-binaries/elf-Linux-x86 --console
|
||||
ROPgadget.py --binary ./test-suite-binaries/elf-Linux-x86 --badbytes "00|01-1f|7f|42"
|
||||
ROPgadget.py --binary ./test-suite-binaries/Linux_lib64.so --offset 0xdeadbeef00000000
|
||||
ROPgadget.py --binary ./test-suite-binaries/elf-ARMv7-ls --depth 5
|
||||
ROPgadget.py --binary ./test-suite-binaries/elf-ARM64-bash --depth 5
|
||||
ROPgadget.py --binary ./test-suite-binaries/raw-x86.raw --rawArch=x86 --rawMode=32
|
||||
ROPgadget.py --binary ./test-suite-binaries/elf-Linux-RISCV_64 --depth 8
|
||||
""")
|
||||
|
||||
parser.add_argument("-v", "--version", action="store_true", help="Display the ROPgadget's version")
|
||||
parser.add_argument("-c", "--checkUpdate", action="store_true", help="Checks if a new version is available")
|
||||
parser.add_argument("--binary", type=str, metavar="<binary>", help="Specify a binary filename to analyze")
|
||||
parser.add_argument("--opcode", type=str, metavar="<opcodes>", help="Search opcode in executable segment")
|
||||
parser.add_argument("--string", type=str, metavar="<string>", help="Search string in readable segment")
|
||||
parser.add_argument("--memstr", type=str, metavar="<string>", help="Search each byte in all readable segment")
|
||||
parser.add_argument("--depth", type=int, metavar="<nbyte>", default=10, help="Depth for search engine (default 10)")
|
||||
parser.add_argument("--only", type=str, metavar="<key>", help="Only show specific instructions")
|
||||
parser.add_argument("--filter", type=str, metavar="<key>", help="Suppress specific mnemonics")
|
||||
parser.add_argument("--range", type=str, metavar="<start-end>", default="0x0-0x0", help="Search between two addresses (0x...-0x...)")
|
||||
parser.add_argument("--badbytes", type=str, metavar="<byte>", help="Rejects specific bytes in the gadget's address")
|
||||
parser.add_argument("--rawArch", type=str, metavar="<arch>", help="Specify an arch for a raw file x86|arm|arm64|sparc|mips|ppc|riscv")
|
||||
parser.add_argument("--rawMode", type=str, metavar="<mode>", help="Specify a mode for a raw file 32|64|arm|thumb")
|
||||
parser.add_argument("--rawEndian", type=str, metavar="<endian>", help="Specify an endianness for a raw file little|big")
|
||||
parser.add_argument("--re", type=str, metavar="<re>", help="Regular expression")
|
||||
parser.add_argument("--offset", type=str, metavar="<hexaddr>", help="Specify an offset for gadget addresses")
|
||||
parser.add_argument("--ropchain", action="store_true", help="Enable the ROP chain generation")
|
||||
parser.add_argument("--thumb", action="store_true", help="Use the thumb mode for the search engine (ARM only)")
|
||||
parser.add_argument("--console", action="store_true", help="Use an interactive console for search engine")
|
||||
parser.add_argument("--norop", action="store_true", help="Disable ROP search engine")
|
||||
parser.add_argument("--nojop", action="store_true", help="Disable JOP search engine")
|
||||
parser.add_argument("--callPreceded", action="store_true", help="Only show gadgets which are call-preceded")
|
||||
parser.add_argument("--nosys", action="store_true", help="Disable SYS search engine")
|
||||
parser.add_argument("--multibr", action="store_true", help="Enable multiple branch gadgets")
|
||||
parser.add_argument("--all", action="store_true", help="Disables the removal of duplicate gadgets")
|
||||
parser.add_argument("--noinstr", action="store_true", help="Disable the gadget instructions console printing")
|
||||
parser.add_argument("--dump", action="store_true", help="Outputs the gadget bytes")
|
||||
parser.add_argument("--silent", action="store_true", help="Disables printing of gadgets during analysis")
|
||||
parser.add_argument("--align", type=int, help="Align gadgets addresses (in bytes)")
|
||||
parser.add_argument("--mipsrop", type=str, metavar="<rtype>", help="MIPS useful gadgets finder stackfinder|system|tails|lia0|registers")
|
||||
|
||||
self.__args = parser.parse_args(arguments)
|
||||
|
||||
if self.__args.noinstr and self.__args.only:
|
||||
raise ValueError("[Error] --noinstr and --only=<key> can't be used together")
|
||||
|
||||
if self.__args.noinstr and self.__args.re:
|
||||
raise ValueError("[Error] --noinstr and --re=<re> can't be used together")
|
||||
|
||||
if self.__args.thumb and self.__args.rawMode and self.__args.rawMode != "thumb":
|
||||
raise ValueError("[Error] --rawMode is conflicting with --thumb")
|
||||
|
||||
if not self.__args.rawArch and self.__args.rawMode:
|
||||
raise ValueError("[Error] Specify --rawArch")
|
||||
|
||||
if not self.__args.rawArch and self.__args.rawEndian:
|
||||
raise ValueError("[Error] Specify --rawArch")
|
||||
|
||||
rawMode = "thumb" if self.__args.thumb else self.__args.rawMode
|
||||
|
||||
if self.__args.rawArch and not rawMode:
|
||||
raise ValueError("[Error] Specify --rawMode")
|
||||
|
||||
if self.__args.rawArch and not self.__args.rawEndian and self.__args.rawArch != "x86":
|
||||
raise ValueError("[Error] Specify --rawEndian")
|
||||
|
||||
if self.__args.version:
|
||||
self.__printVersion()
|
||||
sys.exit(0)
|
||||
|
||||
elif self.__args.checkUpdate:
|
||||
UpdateAlert().checkUpdate()
|
||||
sys.exit(0)
|
||||
|
||||
elif self.__args.depth < 2:
|
||||
raise ValueError("[Error] The depth must be >= 2")
|
||||
|
||||
elif not custom_arguments_provided and not self.__args.binary and not self.__args.console:
|
||||
raise ValueError("[Error] Need a binary filename (--binary/--console or --help)")
|
||||
|
||||
elif self.__args.range:
|
||||
try:
|
||||
rangeS = int(self.__args.range.split('-')[0], 16)
|
||||
rangeE = int(self.__args.range.split('-')[1], 16)
|
||||
except:
|
||||
raise ValueError("[Error] A range must be set in hexadecimal. Ex: 0x08041000-0x08042000")
|
||||
if rangeS > rangeE:
|
||||
raise ValueError("[Error] The start value must be greater than end value")
|
||||
|
||||
def __printVersion(self):
|
||||
print("Version: %s" % (PYROPGADGET_VERSION))
|
||||
print("Author: Jonathan Salwan")
|
||||
print("Author page: https://twitter.com/JonathanSalwan")
|
||||
print("Project page: http://shell-storm.org/project/ROPgadget/")
|
||||
|
||||
def getArgs(self):
|
||||
return self.__args
|
@ -0,0 +1,80 @@
|
||||
## -*- coding: utf-8 -*-
|
||||
##
|
||||
## Jonathan Salwan - 2014-05-12 - ROPgadget tool
|
||||
##
|
||||
## http://twitter.com/JonathanSalwan
|
||||
## http://shell-storm.org/project/ROPgadget/
|
||||
##
|
||||
|
||||
from binascii import unhexlify
|
||||
|
||||
from ropgadget.loaders.elf import *
|
||||
from ropgadget.loaders.macho import *
|
||||
from ropgadget.loaders.pe import *
|
||||
from ropgadget.loaders.raw import *
|
||||
from ropgadget.loaders.universal import *
|
||||
|
||||
|
||||
class Binary(object):
|
||||
def __init__(self, options):
|
||||
self.__fileName = options.binary
|
||||
self.__rawBinary = None
|
||||
self.__binary = None
|
||||
|
||||
try:
|
||||
fd = open(self.__fileName, "rb")
|
||||
self.__rawBinary = fd.read()
|
||||
fd.close()
|
||||
except:
|
||||
print("[Error] Can't open the binary or binary not found")
|
||||
return None
|
||||
|
||||
if options.rawArch:
|
||||
self.__binary = Raw(
|
||||
self.__rawBinary,
|
||||
options.rawArch,
|
||||
"thumb" if options.thumb else options.rawMode,
|
||||
options.rawEndian,
|
||||
)
|
||||
elif self.__rawBinary[:4] == unhexlify(b"7f454c46"):
|
||||
self.__binary = ELF(self.__rawBinary)
|
||||
elif self.__rawBinary[:2] == unhexlify(b"4d5a"):
|
||||
self.__binary = PE(self.__rawBinary)
|
||||
elif self.__rawBinary[:4] == unhexlify(b"cafebabe"):
|
||||
self.__binary = UNIVERSAL(self.__rawBinary)
|
||||
elif self.__rawBinary[:4] == unhexlify(b"cefaedfe") or self.__rawBinary[:4] == unhexlify(b"cffaedfe") or \
|
||||
self.__rawBinary[:4] == unhexlify(b"feedface") or self.__rawBinary[:4] == unhexlify(b"feedfacf"):
|
||||
self.__binary = MACHO(self.__rawBinary)
|
||||
else:
|
||||
print("[Error] Binary format not supported")
|
||||
return None
|
||||
|
||||
def getFileName(self):
|
||||
return self.__fileName
|
||||
|
||||
def getRawBinary(self):
|
||||
return self.__rawBinary
|
||||
|
||||
def getBinary(self):
|
||||
return self.__binary
|
||||
|
||||
def getEntryPoint(self):
|
||||
return self.__binary.getEntryPoint()
|
||||
|
||||
def getDataSections(self):
|
||||
return self.__binary.getDataSections()
|
||||
|
||||
def getExecSections(self):
|
||||
return self.__binary.getExecSections()
|
||||
|
||||
def getArch(self):
|
||||
return self.__binary.getArch()
|
||||
|
||||
def getArchMode(self):
|
||||
return self.__binary.getArchMode()
|
||||
|
||||
def getEndian(self):
|
||||
return self.__binary.getEndian()
|
||||
|
||||
def getFormat(self):
|
||||
return self.__binary.getFormat()
|
@ -0,0 +1,653 @@
|
||||
## -*- coding: utf-8 -*-
|
||||
##
|
||||
## Jonathan Salwan - 2014-05-17 - ROPgadget tool
|
||||
##
|
||||
## http://twitter.com/JonathanSalwan
|
||||
## http://shell-storm.org/project/ROPgadget/
|
||||
##
|
||||
|
||||
import binascii
|
||||
import cmd
|
||||
import re
|
||||
import string
|
||||
|
||||
from capstone import CS_MODE_32
|
||||
|
||||
import ropgadget.rgutils as rgutils
|
||||
from ropgadget.binary import Binary
|
||||
from ropgadget.gadgets import Gadgets
|
||||
from ropgadget.options import Options
|
||||
from ropgadget.ropchain.ropmaker import ROPMaker
|
||||
|
||||
|
||||
class Core(cmd.Cmd):
|
||||
def __init__(self, options):
|
||||
cmd.Cmd.__init__(self)
|
||||
self.__options = options
|
||||
self.__binary = None
|
||||
self.__gadgets = []
|
||||
self.__offset = 0
|
||||
self.prompt = '(ROPgadget)> '
|
||||
|
||||
def __checksBeforeManipulations(self):
|
||||
if self.__binary is None or self.__binary.getBinary() is None or self.__binary.getArch() is None or self.__binary.getArchMode() is None or self.__binary.getEndian() is None:
|
||||
return False
|
||||
return True
|
||||
|
||||
def _sectionInRange(self, section):
|
||||
"""Given a section and a range, edit the section so that all opcodes are within the range"""
|
||||
if self.__options.range == "0x0-0x0":
|
||||
return section
|
||||
|
||||
rangeStart, rangeEnd = map(lambda x: int(x, 16), self.__options.range.split('-'))
|
||||
|
||||
sectionStart = section['vaddr']
|
||||
sectionEnd = sectionStart + section['size']
|
||||
|
||||
opcodes = section['opcodes']
|
||||
if rangeEnd < sectionStart or rangeStart > sectionEnd:
|
||||
return None
|
||||
if rangeStart > sectionStart:
|
||||
diff = rangeStart - sectionStart
|
||||
opcodes = opcodes[diff:]
|
||||
section['vaddr'] += diff
|
||||
section['offset'] += diff
|
||||
section['size'] -= diff
|
||||
if rangeEnd < sectionEnd:
|
||||
diff = sectionEnd - rangeEnd
|
||||
opcodes = opcodes[:-diff]
|
||||
section['size'] -= diff
|
||||
|
||||
if not section['size']:
|
||||
return None
|
||||
section['opcodes'] = opcodes
|
||||
return section
|
||||
|
||||
def __getGadgets(self):
|
||||
if not self.__checksBeforeManipulations():
|
||||
return False
|
||||
|
||||
G = Gadgets(self.__binary, self.__options, self.__offset)
|
||||
execSections = self.__binary.getExecSections()
|
||||
|
||||
# Find ROP/JOP/SYS gadgets
|
||||
self.__gadgets = []
|
||||
for section in execSections:
|
||||
section = self._sectionInRange(section)
|
||||
if not section:
|
||||
continue
|
||||
if not self.__options.norop:
|
||||
self.__gadgets += G.addROPGadgets(section)
|
||||
if not self.__options.nojop:
|
||||
self.__gadgets += G.addJOPGadgets(section)
|
||||
if not self.__options.nosys:
|
||||
self.__gadgets += G.addSYSGadgets(section)
|
||||
|
||||
# Delete duplicate gadgets
|
||||
if not self.__options.all and not self.__options.noinstr:
|
||||
self.__gadgets = rgutils.deleteDuplicateGadgets(self.__gadgets)
|
||||
|
||||
# Applicate some Options
|
||||
self.__gadgets = Options(self.__options, self.__binary, self.__gadgets).getGadgets()
|
||||
|
||||
# Sorted alphabetically
|
||||
if not self.__options.noinstr:
|
||||
self.__gadgets = rgutils.alphaSortgadgets(self.__gadgets)
|
||||
|
||||
return True
|
||||
|
||||
def __lookingForGadgets(self):
|
||||
if not self.__checksBeforeManipulations():
|
||||
return False
|
||||
|
||||
if self.__options.silent:
|
||||
return True
|
||||
|
||||
arch = self.__binary.getArchMode()
|
||||
print("Gadgets information\n============================================================")
|
||||
for gadget in self.__gadgets:
|
||||
vaddr = gadget["vaddr"]
|
||||
insts = gadget.get("gadget", "")
|
||||
insts = " : {}".format(insts) if insts else ""
|
||||
bytesStr = " // " + binascii.hexlify(gadget["bytes"]).decode('utf8') if self.__options.dump else ""
|
||||
print("0x{{0:0{}x}}{{1}}{{2}}".format(8 if arch == CS_MODE_32 else 16).format(vaddr, insts, bytesStr))
|
||||
|
||||
print("\nUnique gadgets found: %d" % (len(self.__gadgets)))
|
||||
return True
|
||||
|
||||
def __lookingForMIPSgadgets(self, mips_option):
|
||||
if not self.__checksBeforeManipulations():
|
||||
return False
|
||||
|
||||
if self.__options.silent:
|
||||
return True
|
||||
|
||||
arch = self.__binary.getArchMode()
|
||||
if mips_option == 'stackfinder':
|
||||
mipsFindRegex = [r'addiu .*, \$sp']
|
||||
elif mips_option == 'system':
|
||||
mipsFindRegex = [r'addiu \$a0, \$sp']
|
||||
elif mips_option == 'tails':
|
||||
mipsFindRegex = [r'lw \$t[0-9], 0x[0-9a-z]{0,4}\(\$s[0-9]', r'move \$t9, \$(s|a|v)']
|
||||
elif mips_option == 'lia0':
|
||||
mipsFindRegex = [r'li \$a0']
|
||||
elif mips_option == 'registers':
|
||||
mipsFindRegex = [r'lw \$ra, 0x[0-9a-z]{0,4}\(\$sp']
|
||||
else:
|
||||
print("Unrecognized option " + mips_option)
|
||||
print("Accepted options stackfinder|system|tails|lia0|registers")
|
||||
return False
|
||||
|
||||
print("MIPS ROP (" + mips_option + ")\n============================================================")
|
||||
self.__getGadgets()
|
||||
|
||||
gadget_counter = 0
|
||||
for gadget in self.__gadgets:
|
||||
vaddr = gadget["vaddr"]
|
||||
insts = gadget.get("gadget", "")
|
||||
insts = " : {}".format(insts) if insts else ""
|
||||
bytesStr = " // " + binascii.hexlify(gadget["bytes"]).decode('utf8') if self.__options.dump else ""
|
||||
for thisRegex in mipsFindRegex:
|
||||
toFind = re.findall(thisRegex, insts)
|
||||
if toFind:
|
||||
print("0x{{0:0{}x}}{{1}}{{2}}".format(8 if arch == CS_MODE_32 else 16).format(vaddr, insts, bytesStr))
|
||||
gadget_counter += 1
|
||||
|
||||
print("\nUnique gadgets found: %d" % gadget_counter)
|
||||
return True
|
||||
|
||||
def __lookingForAString(self, s):
|
||||
if not self.__checksBeforeManipulations():
|
||||
return False
|
||||
|
||||
if self.__options.silent:
|
||||
return True
|
||||
|
||||
dataSections = self.__binary.getDataSections()
|
||||
arch = self.__binary.getArchMode()
|
||||
print("Strings information\n============================================================")
|
||||
for section in dataSections:
|
||||
section = self._sectionInRange(section)
|
||||
if not section:
|
||||
continue
|
||||
allRef = [m.start() for m in re.finditer(s.encode(), section["opcodes"])]
|
||||
for ref in allRef:
|
||||
vaddr = self.__offset + section["vaddr"] + ref
|
||||
match = section["opcodes"][ref:ref + len(s)]
|
||||
printable = string.printable.encode()
|
||||
match = "".join((chr(m) if isinstance(m, int) else m) if m in printable else "." for m in match)
|
||||
print("0x{{0:0{}x}} : {{1}}".format(8 if arch == CS_MODE_32 else 16).format(vaddr, match))
|
||||
return True
|
||||
|
||||
def __lookingForOpcodes(self, opcodes):
|
||||
if not self.__checksBeforeManipulations():
|
||||
return False
|
||||
|
||||
if self.__options.silent:
|
||||
return True
|
||||
|
||||
execSections = self.__binary.getExecSections()
|
||||
arch = self.__binary.getArchMode()
|
||||
print("Opcodes information\n============================================================")
|
||||
for section in execSections:
|
||||
section = self._sectionInRange(section)
|
||||
if not section:
|
||||
continue
|
||||
allRef = [m.start() for m in re.finditer(re.escape(binascii.unhexlify(opcodes)), section["opcodes"])]
|
||||
for ref in allRef:
|
||||
vaddr = self.__offset + section["vaddr"] + ref
|
||||
print("0x{{0:0{}x}} : {{1}}".format(8 if arch == CS_MODE_32 else 16).format(vaddr, opcodes))
|
||||
return True
|
||||
|
||||
def __lookingForMemStr(self, memstr):
|
||||
if not self.__checksBeforeManipulations():
|
||||
return False
|
||||
|
||||
if self.__options.silent:
|
||||
return True
|
||||
|
||||
sections = self.__binary.getExecSections()
|
||||
sections += self.__binary.getDataSections()
|
||||
arch = self.__binary.getArchMode()
|
||||
print("Memory bytes information\n=======================================================")
|
||||
chars = list(memstr)
|
||||
for char in chars:
|
||||
try:
|
||||
for section in sections:
|
||||
section = self._sectionInRange(section)
|
||||
if not section:
|
||||
continue
|
||||
allRef = [m.start() for m in re.finditer(char.encode('utf-8'), section["opcodes"])]
|
||||
for ref in allRef:
|
||||
vaddr = self.__offset + section["vaddr"] + ref
|
||||
print("0x{{0:0{}x}} : '{{1}}'".format(8 if arch == CS_MODE_32 else 16).format(vaddr, char))
|
||||
raise
|
||||
except:
|
||||
pass
|
||||
return True
|
||||
|
||||
def analyze(self):
|
||||
try:
|
||||
self.__offset = int(self.__options.offset, 16) if self.__options.offset else 0
|
||||
except ValueError:
|
||||
print("[Error] The offset must be in hexadecimal")
|
||||
return False
|
||||
|
||||
if self.__options.console:
|
||||
if self.__options.binary:
|
||||
self.__binary = Binary(self.__options)
|
||||
if not self.__checksBeforeManipulations():
|
||||
return False
|
||||
self.cmdloop()
|
||||
return True
|
||||
|
||||
self.__binary = Binary(self.__options)
|
||||
if not self.__checksBeforeManipulations():
|
||||
return False
|
||||
|
||||
if self.__options.string:
|
||||
return self.__lookingForAString(self.__options.string)
|
||||
elif self.__options.opcode:
|
||||
return self.__lookingForOpcodes(self.__options.opcode)
|
||||
elif self.__options.memstr:
|
||||
return self.__lookingForMemStr(self.__options.memstr)
|
||||
elif self.__options.mipsrop:
|
||||
return self.__lookingForMIPSgadgets(self.__options.mipsrop)
|
||||
else:
|
||||
self.__getGadgets()
|
||||
self.__lookingForGadgets()
|
||||
if self.__options.ropchain:
|
||||
ROPMaker(self.__binary, self.__gadgets, self.__offset)
|
||||
return True
|
||||
|
||||
def gadgets(self):
|
||||
return self.__gadgets
|
||||
|
||||
# Console methods ============================================
|
||||
def do_binary(self, s, silent=False):
|
||||
# Do not split the filename with spaces since it might contain
|
||||
# whitespaces
|
||||
if not s:
|
||||
if not silent:
|
||||
return self.help_binary()
|
||||
return False
|
||||
|
||||
binary = s
|
||||
|
||||
self.__options.binary = binary
|
||||
self.__binary = Binary(self.__options)
|
||||
if not self.__checksBeforeManipulations():
|
||||
return False
|
||||
|
||||
if not silent:
|
||||
print("[+] Binary loaded")
|
||||
|
||||
def help_binary(self):
|
||||
print("Syntax: binary <file> -- Load a binary")
|
||||
return False
|
||||
|
||||
def do_EOF(self, s, silent=False):
|
||||
return self.do_quit(s, silent)
|
||||
|
||||
def do_quit(self, s, silent=False):
|
||||
return True
|
||||
|
||||
def help_quit(self):
|
||||
print("Syntax: quit -- Terminates the application")
|
||||
return False
|
||||
|
||||
def do_load(self, s, silent=False):
|
||||
if self.__binary is None:
|
||||
if not silent:
|
||||
print("[-] No binary loaded.")
|
||||
return False
|
||||
|
||||
if not silent:
|
||||
print("[+] Loading gadgets, please wait...")
|
||||
self.__getGadgets()
|
||||
|
||||
if not silent:
|
||||
print("[+] Gadgets loaded !")
|
||||
|
||||
def help_load(self):
|
||||
print("Syntax: load -- Load all gadgets")
|
||||
return False
|
||||
|
||||
def do_display(self, s, silent=False):
|
||||
self.__lookingForGadgets()
|
||||
|
||||
def help_display(self):
|
||||
print("Syntax: display -- Display all gadgets loaded")
|
||||
return False
|
||||
|
||||
def do_depth(self, s, silent=False):
|
||||
try:
|
||||
depth = int(s.split()[0])
|
||||
except:
|
||||
if not silent:
|
||||
return self.help_depth()
|
||||
return False
|
||||
if depth <= 0:
|
||||
if not silent:
|
||||
print("[-] The depth value must be > 0")
|
||||
return False
|
||||
self.__options.depth = int(depth)
|
||||
|
||||
if not silent:
|
||||
print("[+] Depth updated. You have to reload gadgets")
|
||||
|
||||
def help_depth(self):
|
||||
print("Syntax: depth <value> -- Set the depth search engine")
|
||||
return False
|
||||
|
||||
def do_badbytes(self, s, silent=False):
|
||||
try:
|
||||
bb = s.split()[0]
|
||||
except:
|
||||
if not silent:
|
||||
return self.help_badbytes()
|
||||
else:
|
||||
return False
|
||||
self.__options.badbytes = bb
|
||||
|
||||
if not silent:
|
||||
print("[+] Bad bytes updated. You have to reload gadgets")
|
||||
|
||||
def help_badbytes(self):
|
||||
print("Syntax: badbytes <badbyte1|badbyte2...> -- ")
|
||||
return False
|
||||
|
||||
def __withK(self, listK, gadget):
|
||||
if not listK:
|
||||
return True
|
||||
for a in listK:
|
||||
if a not in gadget:
|
||||
return False
|
||||
return True
|
||||
|
||||
def __withoutK(self, listK, gadget):
|
||||
for a in listK:
|
||||
if a in gadget:
|
||||
return False
|
||||
return True
|
||||
|
||||
def do_search(self, s, silent=False):
|
||||
args = s.split()
|
||||
if not len(args):
|
||||
return self.help_search()
|
||||
withK, withoutK = [], []
|
||||
for a in args:
|
||||
if a[0] == "!":
|
||||
withoutK += [a[1:]]
|
||||
else:
|
||||
withK += [a]
|
||||
if not self.__checksBeforeManipulations():
|
||||
if not silent:
|
||||
print("[-] You have to load a binary")
|
||||
return False
|
||||
arch = self.__binary.getArchMode()
|
||||
for gadget in self.__gadgets:
|
||||
vaddr = gadget["vaddr"]
|
||||
insts = gadget["gadget"]
|
||||
if self.__withK(withK, insts) and self.__withoutK(withoutK, insts):
|
||||
# What to do if silent = True?
|
||||
print("0x{{0:0{}x}} : {{1}}".format(8 if arch == CS_MODE_32 else 16).format(vaddr, insts))
|
||||
|
||||
def help_search(self):
|
||||
print("Syntax: search <keyword1 keyword2 keyword3...> -- Filter with or without keywords")
|
||||
print("keyword = with")
|
||||
print("!keyword = without")
|
||||
return False
|
||||
|
||||
def count(self):
|
||||
return len(self.__gadgets)
|
||||
|
||||
def do_count(self, s, silent=False):
|
||||
if not silent:
|
||||
print("[+] %d loaded gadgets." % self.count())
|
||||
|
||||
def help_count(self):
|
||||
print("Shows the number of loaded gadgets.")
|
||||
return False
|
||||
|
||||
def do_filter(self, s, silent=False):
|
||||
try:
|
||||
self.__options.filter = s.split()[0]
|
||||
except:
|
||||
if not silent:
|
||||
return self.help_filter()
|
||||
return False
|
||||
|
||||
if not silent:
|
||||
print("[+] Filter setted. You have to reload gadgets")
|
||||
|
||||
def help_filter(self):
|
||||
print("Syntax: filter <filter1|filter2|...> - Suppress specific mnemonics")
|
||||
return False
|
||||
|
||||
def do_only(self, s, silent=False):
|
||||
try:
|
||||
if s.lower() == "none":
|
||||
self.__options.only = None
|
||||
else:
|
||||
self.__options.only = s.split()[0]
|
||||
except:
|
||||
if not silent:
|
||||
return self.help_only()
|
||||
return False
|
||||
|
||||
if not silent:
|
||||
print("[+] Only setted. You have to reload gadgets")
|
||||
|
||||
def help_only(self):
|
||||
print("Syntax: only <only1|only2|...> - Only show specific instructions")
|
||||
return False
|
||||
|
||||
def do_range(self, s, silent=False):
|
||||
try:
|
||||
rangeS = int(s.split('-')[0], 16)
|
||||
rangeE = int(s.split('-')[1], 16)
|
||||
self.__options.range = s.split()[0]
|
||||
except:
|
||||
if not silent:
|
||||
return self.help_range()
|
||||
return False
|
||||
|
||||
if rangeS > rangeE:
|
||||
if not silent:
|
||||
print("[-] The start value must be greater than the end value")
|
||||
return False
|
||||
|
||||
if not silent:
|
||||
print("[+] Range setted. You have to reload gadgets")
|
||||
|
||||
def help_range(self):
|
||||
print("Syntax: range <start-and> - Search between two addresses (0x...-0x...)")
|
||||
return False
|
||||
|
||||
def do_settings(self, s, silent=False):
|
||||
print("All: %s" % self.__options.all)
|
||||
print("Badbytes: %s" % self.__options.badbytes)
|
||||
print("Binary: %s" % self.__options.binary)
|
||||
print("Depth: %s" % self.__options.depth)
|
||||
print("Filter: %s" % self.__options.filter)
|
||||
print("Memstr: %s" % self.__options.memstr)
|
||||
print("MultiBr: %s" % self.__options.multibr)
|
||||
print("NoJOP: %s" % self.__options.nojop)
|
||||
print("NoROP: %s" % self.__options.norop)
|
||||
print("NoSYS: %s" % self.__options.nosys)
|
||||
print("Offset: %s" % self.__options.offset)
|
||||
print("Only: %s" % self.__options.only)
|
||||
print("Opcode: %s" % self.__options.opcode)
|
||||
print("ROPchain: %s" % self.__options.ropchain)
|
||||
print("Range: %s" % self.__options.range)
|
||||
print("RawArch: %s" % self.__options.rawArch)
|
||||
print("RawMode: %s" % self.__options.rawMode)
|
||||
print("RawEndian: %s" % self.__options.rawEndian)
|
||||
print("Re: %s" % self.__options.re)
|
||||
print("String: %s" % self.__options.string)
|
||||
print("Thumb: %s" % self.__options.thumb)
|
||||
print("Mipsrop: %s" % self.__options.mipsrop)
|
||||
|
||||
def help_settings(self):
|
||||
print("Display setting's environment")
|
||||
return False
|
||||
|
||||
def do_nojop(self, s, silent=False):
|
||||
try:
|
||||
arg = s.split()[0]
|
||||
except:
|
||||
return self.help_nojop()
|
||||
|
||||
if arg == "enable":
|
||||
self.__options.nojop = True
|
||||
if not silent:
|
||||
print("[+] NoJOP enable. You have to reload gadgets")
|
||||
|
||||
elif arg == "disable":
|
||||
self.__options.nojop = False
|
||||
if not silent:
|
||||
print("[+] NoJOP disable. You have to reload gadgets")
|
||||
|
||||
else:
|
||||
if not silent:
|
||||
return self.help_nojop()
|
||||
return False
|
||||
|
||||
def help_nojop(self):
|
||||
print("Syntax: nojop <enable|disable> - Disable JOP search engin")
|
||||
return False
|
||||
|
||||
def do_norop(self, s, silent=False):
|
||||
try:
|
||||
arg = s.split()[0]
|
||||
except:
|
||||
return self.help_norop()
|
||||
|
||||
if arg == "enable":
|
||||
self.__options.norop = True
|
||||
if not silent:
|
||||
print("[+] NoROP enable. You have to reload gadgets")
|
||||
|
||||
elif arg == "disable":
|
||||
self.__options.norop = False
|
||||
if not silent:
|
||||
print("[+] NoROP disable. You have to reload gadgets")
|
||||
|
||||
else:
|
||||
if not silent:
|
||||
return self.help_norop()
|
||||
return False
|
||||
|
||||
def help_norop(self):
|
||||
print("Syntax: norop <enable|disable> - Disable ROP search engin")
|
||||
return False
|
||||
|
||||
def do_nosys(self, s, silent=False):
|
||||
try:
|
||||
arg = s.split()[0]
|
||||
except:
|
||||
return self.help_nosys()
|
||||
|
||||
if arg == "enable":
|
||||
self.__options.nosys = True
|
||||
if not silent:
|
||||
print("[+] NoSYS enable. You have to reload gadgets")
|
||||
|
||||
elif arg == "disable":
|
||||
self.__options.nosys = False
|
||||
if not silent:
|
||||
print("[+] NoSYS disable. You have to reload gadgets")
|
||||
|
||||
else:
|
||||
if not silent:
|
||||
return self.help_nosys()
|
||||
|
||||
return False
|
||||
|
||||
def help_nosys(self):
|
||||
print("Syntax: nosys <enable|disable> - Disable SYS search engin")
|
||||
return False
|
||||
|
||||
def do_thumb(self, s, silent=False):
|
||||
try:
|
||||
arg = s.split()[0]
|
||||
except:
|
||||
return self.help_thumb()
|
||||
|
||||
if arg == "enable":
|
||||
self.__options.thumb = True
|
||||
if not silent:
|
||||
print("[+] Thumb enable. You have to reload gadgets")
|
||||
|
||||
elif arg == "disable":
|
||||
self.__options.thumb = False
|
||||
if not silent:
|
||||
print("[+] Thumb disable. You have to reload gadgets")
|
||||
|
||||
else:
|
||||
if not silent:
|
||||
return self.help_thumb()
|
||||
return False
|
||||
|
||||
def help_thumb(self):
|
||||
print("Syntax: thumb <enable|disable> - Use the thumb mode for the search engine (ARM only)")
|
||||
return False
|
||||
|
||||
def do_all(self, s, silent=False):
|
||||
if s == "enable":
|
||||
self.__options.all = True
|
||||
if not silent:
|
||||
print("[+] Showing all gadgets enabled. You have to reload gadgets")
|
||||
|
||||
elif s == "disable":
|
||||
self.__options.all = False
|
||||
if not silent:
|
||||
print("[+] Showing all gadgets disabled. You have to reload gadgets")
|
||||
|
||||
else:
|
||||
if not silent:
|
||||
return self.help_all()
|
||||
|
||||
return False
|
||||
|
||||
def help_multibr(self):
|
||||
print("Syntax: multibr <enable|disable> - Enable/Disable multiple branch gadgets")
|
||||
return False
|
||||
|
||||
def do_multibr(self, s, silent=False):
|
||||
if s == "enable":
|
||||
self.__options.multibr = True
|
||||
if not silent:
|
||||
print("[+] Multiple branch gadgets enabled. You have to reload gadgets")
|
||||
|
||||
elif s == "disable":
|
||||
self.__options.multibr = False
|
||||
if not silent:
|
||||
print("[+] Multiple branch gadgets disabled. You have to reload gadgets")
|
||||
|
||||
else:
|
||||
if not silent:
|
||||
return self.help_all()
|
||||
|
||||
return False
|
||||
|
||||
def help_all(self):
|
||||
print("Syntax: all <enable|disable - Show all gadgets (disable removing duplicate gadgets)")
|
||||
return False
|
||||
|
||||
def help_re(self):
|
||||
print("Syntax: re <pattern1 | pattern2 |...> - Regular expression")
|
||||
return False
|
||||
|
||||
def do_re(self, s, silent=False):
|
||||
if s.lower() == 'none':
|
||||
self.__options.re = None
|
||||
elif s == "":
|
||||
self.help_re()
|
||||
silent = True
|
||||
else:
|
||||
self.__options.re = s
|
||||
|
||||
if not silent:
|
||||
print("[+] Re setted. You have to reload gadgets")
|
@ -0,0 +1,412 @@
|
||||
## -*- coding: utf-8 -*-
|
||||
##
|
||||
## Jonathan Salwan - 2014-05-12 - ROPgadget tool
|
||||
##
|
||||
## http://twitter.com/JonathanSalwan
|
||||
## http://shell-storm.org/project/ROPgadget/
|
||||
##
|
||||
|
||||
import re
|
||||
|
||||
from capstone import *
|
||||
|
||||
|
||||
class Gadgets(object):
|
||||
def __init__(self, binary, options, offset):
|
||||
self.__binary = binary
|
||||
self.__options = options
|
||||
self.__offset = offset
|
||||
self.__arch = self.__binary.getArch()
|
||||
|
||||
re_str = ""
|
||||
if self.__arch == CS_ARCH_X86:
|
||||
re_str = "db|int3"
|
||||
elif self.__arch == CS_ARCH_ARM64:
|
||||
re_str = "brk|smc|hvc"
|
||||
if self.__options.filter:
|
||||
if re_str:
|
||||
re_str += "|"
|
||||
re_str += self.__options.filter
|
||||
|
||||
self.__filterRE = re.compile("({})$".format(re_str)) if re_str else None
|
||||
|
||||
def __passCleanX86(self, decodes):
|
||||
br = ["ret", "repz ret", "retf", "int", "sysenter", "jmp", "notrack jmp", "call", "notrack call", "syscall"]
|
||||
|
||||
if decodes[-1][2] not in br:
|
||||
return True
|
||||
if not self.__options.multibr and any(mnemonic in br for _, _, mnemonic, _ in decodes[:-1]):
|
||||
return True
|
||||
if any("ret" in mnemonic for _, _, mnemonic, _ in decodes[:-1]):
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def __gadgetsFinding(self, section, gadgets, arch, mode):
|
||||
|
||||
PREV_BYTES = 9 # Number of bytes prior to the gadget to store.
|
||||
|
||||
opcodes = section["opcodes"]
|
||||
sec_vaddr = section["vaddr"]
|
||||
|
||||
ret = []
|
||||
md = Cs(arch, mode)
|
||||
for gad_op, gad_size, gad_align in gadgets:
|
||||
if self.__options.align:
|
||||
gad_align = self.__options.align
|
||||
allRefRet = [m.start() for m in re.finditer(gad_op, opcodes)]
|
||||
for ref in allRefRet:
|
||||
end = ref + gad_size
|
||||
for i in range(self.__options.depth):
|
||||
start = ref - (i * gad_align)
|
||||
if (sec_vaddr + start) % gad_align == 0:
|
||||
code = opcodes[start:end]
|
||||
decodes = md.disasm_lite(code, sec_vaddr + start)
|
||||
decodes = list(decodes)
|
||||
if sum(size for _, size, _, _ in decodes) != i * gad_align + gad_size:
|
||||
# We've read less instructions than planned so something went wrong
|
||||
continue
|
||||
if self.passClean(decodes):
|
||||
continue
|
||||
off = self.__offset
|
||||
vaddr = off + sec_vaddr + start
|
||||
g = {"vaddr": vaddr}
|
||||
if not self.__options.noinstr:
|
||||
g["gadget"] = " ; ".join("{}{}{}".format(mnemonic, " " if op_str else "", op_str)
|
||||
for _, _, mnemonic, op_str in decodes).replace(" ", " ")
|
||||
if self.__options.callPreceded:
|
||||
prevBytesAddr = max(sec_vaddr, vaddr - PREV_BYTES)
|
||||
g["prev"] = opcodes[prevBytesAddr - sec_vaddr:vaddr - sec_vaddr]
|
||||
if self.__options.dump:
|
||||
g["bytes"] = code
|
||||
ret.append(g)
|
||||
return ret
|
||||
|
||||
def addROPGadgets(self, section):
|
||||
|
||||
arch = self.__binary.getArch()
|
||||
arch_mode = self.__binary.getArchMode()
|
||||
arch_endian = self.__binary.getEndian()
|
||||
|
||||
if arch == CS_ARCH_X86:
|
||||
gadgets = [
|
||||
[b"\xc3", 1, 1], # ret
|
||||
[b"\xc2[\x00-\xff]{2}", 3, 1], # ret <imm>
|
||||
[b"\xcb", 1, 1], # retf
|
||||
[b"\xca[\x00-\xff]{2}", 3, 1], # retf <imm>
|
||||
# MPX
|
||||
[b"\xf2\xc3", 2, 1], # ret
|
||||
[b"\xf2\xc2[\x00-\xff]{2}", 4, 1], # ret <imm>
|
||||
]
|
||||
|
||||
elif arch == CS_ARCH_MIPS:
|
||||
gadgets = [] # MIPS doesn't have RET instructions. Only JOP gadgets
|
||||
elif arch == CS_ARCH_PPC:
|
||||
if arch_endian == CS_MODE_BIG_ENDIAN:
|
||||
gadgets = [
|
||||
[b"\x4e\x80\x00\x20", 4, 4] # blr
|
||||
]
|
||||
else:
|
||||
gadgets = [
|
||||
[b"\x20\x00\x80\x4e", 4, 4] # blr
|
||||
]
|
||||
|
||||
elif arch == CS_ARCH_SPARC:
|
||||
if arch_endian == CS_MODE_BIG_ENDIAN:
|
||||
gadgets = [
|
||||
[b"\x81\xc3\xe0\x08", 4, 4], # retl
|
||||
[b"\x81\xc7\xe0\x08", 4, 4], # ret
|
||||
[b"\x81\xe8\x00\x00", 4, 4] # restore
|
||||
]
|
||||
else:
|
||||
gadgets = [
|
||||
[b"\x08\xe0\xc3\x81", 4, 4], # retl
|
||||
[b"\x08\xe0\xc7\x81", 4, 4], # ret
|
||||
[b"\x00\x00\xe8\x81", 4, 4] # restore
|
||||
]
|
||||
arch_mode = 0
|
||||
|
||||
elif arch == CS_ARCH_ARM:
|
||||
gadgets = [] # ARM doesn't have RET instructions. Only JOP gadgets
|
||||
elif arch == CS_ARCH_ARM64:
|
||||
if arch_endian == CS_MODE_BIG_ENDIAN:
|
||||
gadgets = [
|
||||
[b"\xd6\x5f\x03\xc0", 4, 4] # ret
|
||||
]
|
||||
else:
|
||||
gadgets = [
|
||||
[b"\xc0\x03\x5f\xd6", 4, 4] # ret
|
||||
]
|
||||
arch_mode = CS_MODE_ARM
|
||||
|
||||
elif arch == CS_ARCH_RISCV:
|
||||
if arch_endian == CS_MODE_BIG_ENDIAN:
|
||||
gadgets = [
|
||||
[b"\x80\x82", 2, 1], # c.ret
|
||||
]
|
||||
else:
|
||||
gadgets = [
|
||||
[b"\x82\x80", 2, 1], # c.ret
|
||||
]
|
||||
arch_mode = CS_MODE_RISCV64 | CS_MODE_RISCVC
|
||||
|
||||
else:
|
||||
print("Gadgets().addROPGadgets() - Architecture not supported")
|
||||
return None
|
||||
|
||||
if gadgets:
|
||||
return self.__gadgetsFinding(section, gadgets, arch, arch_mode + arch_endian)
|
||||
return gadgets
|
||||
|
||||
def addJOPGadgets(self, section):
|
||||
arch = self.__binary.getArch()
|
||||
arch_mode = self.__binary.getArchMode()
|
||||
arch_endian = self.__binary.getEndian()
|
||||
|
||||
if arch == CS_ARCH_X86:
|
||||
# we start with x86 and x64 common sequences operating on registers
|
||||
gadgets = [
|
||||
# call/jmp reg
|
||||
# d0-d7=call,e0-e7=jmp
|
||||
# x86: 0=eax,1=ecx,2=edx,3=ebx,4=esp,5=ebp,6=esi,7=edi
|
||||
# x64: 0=rax,1=rcx,2=rdx,3=rbx,4=rsp,5=rbp,6=rsi,7=rdi
|
||||
[b"\xff[\xd0-\xd7\xe0-\xe7]", 2, 1],
|
||||
|
||||
# call/jmp [reg]
|
||||
# 10-17=call,20-27=jmp
|
||||
# x86: 0=eax,1=ecx,2=edx,3=ebx, 6=esi,7=edi
|
||||
# x64: 0=rax,1=rcx,2=rdx,3=rbx, 6=rsi,7=rdi
|
||||
[b"\xff[\x10-\x13\x16-\x17\x20-\x23\x26-\x27]", 2, 1],
|
||||
# call/jmp [reg]
|
||||
# 14=call,24=jmp
|
||||
# x86: esp
|
||||
# x64: rsp
|
||||
[b"\xff[\x14\x24]\x24", 3, 1],
|
||||
|
||||
# call/jmp [reg + offset], -0x80 <= offset <= 0x7f
|
||||
# 50-57=call,60-67=jmp
|
||||
# x86: 0=eax,1=ecx,2=edx,3=ebx, 5=ebp,6=esi,7=edi
|
||||
# x64: 0=rax,1=rcx,2=rdx,3=rbx, 5=rbp,6=rsi,7=rdi
|
||||
[b"\xff[\x50-\x53\x55-\x57\x60-\x63\x65-\x67][\x00-\xff]", 3, 1],
|
||||
# call/jmp [reg + offset], -0x80 <= offset <= 0x7f
|
||||
# 54=call,64=jmp
|
||||
# x86: esp
|
||||
# x64: rsp
|
||||
[b"\xff[\x54\x64]\x24[\x00-\xff]", 4, 1],
|
||||
|
||||
# call/jmp [reg + offset], -0x80000000 <= offset <= 0x7fffffff
|
||||
# 90-97=call,a0-a7=jmp
|
||||
# x86: 0=eax,1=ecx,2=edx,3=ebx, 5=ebp,6=esi,7=edi
|
||||
# x64: 0=rax,1=rcx,2=rdx,3=rbx, 5=rbp,6=rsi,7=rdi
|
||||
[b"\xff[\x90-\x93\x95-\x97\xa0-\xa3\xa5-\xa7][\x00-\xff]{4}", 6, 1],
|
||||
# call/jmp [reg + offset], -0x80000000 <= offset <= 0x7fffffff
|
||||
# 94=call,a4=jmp
|
||||
# x86: esp
|
||||
# x64: rsp
|
||||
[b"\xff[\x94\xa4]\x24[\x00-\xff]{4}", 7, 1]
|
||||
]
|
||||
# in x64, by adding 41 before a sequence with
|
||||
# 0=rax,1=rcx,2=rdx,3=rbx,4=rsp,5=rbp,6=rsi,7=rdi
|
||||
# we convert it to the same sequence with
|
||||
# 0= r8,1= r9,2=r10,3=r11,4=r12,5=r13,6=r14,7=r15
|
||||
if arch_mode == CS_MODE_64:
|
||||
gadgets += [(b"\x41" + op, size + 1, align) for (op, size, align) in gadgets]
|
||||
# finally, add extra sequences common to x86 and x64
|
||||
gadgets += [
|
||||
[b"\xeb[\x00-\xff]", 2, 1], # jmp offset
|
||||
[b"\xe9[\x00-\xff]{4}", 5, 1], # jmp offset
|
||||
# MPX
|
||||
[b"\xf2\xff[\x20\x21\x22\x23\x26\x27]{1}", 3, 1], # jmp [reg]
|
||||
[b"\xf2\xff[\xe0\xe1\xe2\xe3\xe4\xe6\xe7]{1}", 3, 1], # jmp [reg]
|
||||
[b"\xf2\xff[\x10\x11\x12\x13\x16\x17]{1}", 3, 1], # jmp [reg]
|
||||
[b"\xf2\xff[\xd0\xd1\xd2\xd3\xd4\xd6\xd7]{1}", 3, 1] # call [reg]
|
||||
]
|
||||
elif arch == CS_ARCH_MIPS:
|
||||
if arch_endian == CS_MODE_BIG_ENDIAN:
|
||||
gadgets = [
|
||||
[b"\x00[\x40\x60\x80\xa0\xc0\xe0]\xf8\x09[\x00-\xff]{4}", 8, 4], # jalr $v[0-1]|$a[0-3]
|
||||
[b"[\x01\x02][\x00\x20\x40\x60\x80\xa0\xc0\xe0]\xf8\x09[\x00-\xff]{4}", 8, 4], # jalr $t[0-7]|$s[0-7]
|
||||
[b"\x03[\x00\x20\xc0\xe0]\xf8\x09[\x00-\xff]{4}", 8, 4], # jalr $t[8-9]|$s8|$ra
|
||||
[b"\x00[\x40\x60\x80\xa0\xc0\xe0]\x00\x08[\x00-\xff]{4}", 8, 4], # jr $v[0-1]|$a[0-3]
|
||||
[b"[\x01\x02][\x00\x20\x40\x60\x80\xa0\xc0\xe0]\x00\x08[\x00-\xff]{4}", 8, 4], # jr $t[0-7]|$s[0-7]
|
||||
[b"\x03[\x00\x20\xc0\xe0]\x00\x08[\x00-\xff]{4}", 8, 4], # jr $t[8-9]|$s8|$ra
|
||||
[b"[\x0c-\x0f][\x00-\xff]{7}", 8, 4], # jal addr
|
||||
[b"[\x08-\x0b][\x00-\xff]{7}", 8, 4] # j addr
|
||||
]
|
||||
else:
|
||||
gadgets = [
|
||||
[b"\x09\xf8[\x40\x60\x80\xa0\xc0\xe0]\x00[\x00-\xff]{4}", 8, 4], # jalr $v[0-1]|$a[0-3]
|
||||
[b"\x09\xf8[\x00\x20\x40\x60\x80\xa0\xc0\xe0][\x01\x02][\x00-\xff]{4}", 8, 4], # jalr $t[0-7]|$s[0-7]
|
||||
[b"\x09\xf8[\x00\x20\xc0\xe0]\x03[\x00-\xff]{4}", 8, 4], # jalr $t[8-9]|$s8|$ra
|
||||
[b"\x08\x00[\x40\x60\x80\xa0\xc0\xe0]\x00[\x00-\xff]{4}", 8, 4], # jr $v[0-1]|$a[0-3]
|
||||
[b"\x08\x00[\x00\x20\x40\x60\x80\xa0\xc0\xe0][\x01\x02][\x00-\xff]{4}", 8, 4], # jr $t[0-7]|$s[0-7]
|
||||
[b"\x08\x00[\x00\x20\xc0\xe0]\x03[\x00-\xff]{4}", 8, 4], # jr $t[8-9]|$s8|$ra
|
||||
[b"[\x00-\xff]{3}[\x0c-\x0f][\x00-\xff]{4}", 8, 4], # jal addr
|
||||
[b"[\x00-\xff]{3}[\x08-\x0b][\x00-\xff]{4}", 8, 4] # j addr
|
||||
]
|
||||
elif arch == CS_ARCH_PPC:
|
||||
gadgets = [] # PPC doesn't have reg branch instructions
|
||||
elif arch == CS_ARCH_SPARC:
|
||||
if arch_endian == CS_MODE_BIG_ENDIAN:
|
||||
gadgets = [
|
||||
[b"\x81\xc0[\x00\x40\x80\xc0]{1}\x00", 4, 4] # jmp %g[0-3]
|
||||
]
|
||||
else:
|
||||
gadgets = [
|
||||
[b"\x00[\x00\x40\x80\xc0]{1}\xc0\x81", 4, 4] # jmp %g[0-3]
|
||||
]
|
||||
arch_mode = 0
|
||||
elif arch == CS_ARCH_ARM64:
|
||||
if arch_endian == CS_MODE_BIG_ENDIAN:
|
||||
gadgets = [
|
||||
[b"\xd6[\x1f\x5f]{1}[\x00-\x03]{1}[\x00\x20\x40\x60\x80\xa0\xc0\xe0]{1}", 4, 4], # br reg
|
||||
[b"\xd6\?[\x00-\x03]{1}[\x00\x20\x40\x60\x80\xa0\xc0\xe0]{1}", 4, 4] # blr reg # noqa: W605 # FIXME: \?
|
||||
]
|
||||
else:
|
||||
gadgets = [
|
||||
[b"[\x00\x20\x40\x60\x80\xa0\xc0\xe0]{1}[\x00-\x03]{1}[\x1f\x5f]{1}\xd6", 4, 4], # br reg
|
||||
[b"[\x00\x20\x40\x60\x80\xa0\xc0\xe0]{1}[\x00-\x03]{1}\?\xd6", 4, 4] # blr reg # noqa: W605 # FIXME: \?
|
||||
]
|
||||
arch_mode = CS_MODE_ARM
|
||||
elif arch == CS_ARCH_ARM:
|
||||
if self.__options.thumb or self.__options.rawMode == "thumb":
|
||||
if arch_endian == CS_MODE_BIG_ENDIAN:
|
||||
gadgets = [
|
||||
[b"\x47[\x00\x08\x10\x18\x20\x28\x30\x38\x40\x48\x70]{1}", 2, 2], # bx reg
|
||||
[b"\x47[\x80\x88\x90\x98\xa0\xa8\xb0\xb8\xc0\xc8\xf0]{1}", 2, 2], # blx reg
|
||||
[b"\xbd[\x00-\xff]{1}", 2, 2] # pop {,pc}
|
||||
]
|
||||
else:
|
||||
gadgets = [
|
||||
[b"[\x00\x08\x10\x18\x20\x28\x30\x38\x40\x48\x70]{1}\x47", 2, 2], # bx reg
|
||||
[b"[\x80\x88\x90\x98\xa0\xa8\xb0\xb8\xc0\xc8\xf0]{1}\x47", 2, 2], # blx reg
|
||||
[b"[\x00-\xff]{1}\xbd", 2, 2] # pop {,pc}
|
||||
]
|
||||
arch_mode = CS_MODE_THUMB
|
||||
else:
|
||||
if arch_endian == CS_MODE_BIG_ENDIAN:
|
||||
gadgets = [
|
||||
[b"\xe1\x2f\xff[\x10-\x19\x1e]{1}", 4, 4], # bx reg
|
||||
[b"\xe1\x2f\xff[\x30-\x39\x3e]{1}", 4, 4], # blx reg
|
||||
[b"[\xe8\xe9][\x10-\x1e\x30-\x3e\x50-\x5e\x70-\x7e\x90-\x9e\xb0-\xbe\xd0-\xde\xf0-\xfe][\x80-\xff][\x00-\xff]", 4, 4] # ldm {,pc}
|
||||
]
|
||||
else:
|
||||
gadgets = [
|
||||
[b"[\x10-\x19\x1e]{1}\xff\x2f\xe1", 4, 4], # bx reg
|
||||
[b"[\x30-\x39\x3e]{1}\xff\x2f\xe1", 4, 4], # blx reg
|
||||
[b"[\x00-\xff][\x80-\xff][\x10-\x1e\x30-\x3e\x50-\x5e\x70-\x7e\x90-\x9e\xb0-\xbe\xd0-\xde\xf0-\xfe][\xe8\xe9]", 4, 4] # ldm {,pc}
|
||||
]
|
||||
arch_mode = CS_MODE_ARM
|
||||
elif arch == CS_ARCH_RISCV:
|
||||
if arch_endian == CS_MODE_BIG_ENDIAN:
|
||||
gadgets = [
|
||||
#32 bits encoded register
|
||||
[b"[\x00-\xff]{2}[\x00-\xff][\x67\x6f\xe7\xef]",4 , 1],
|
||||
[b"[\x00-\xff]{2}[\x00-\xff][\x63\xe3]", 4 , 1],
|
||||
|
||||
#16bits encoded register
|
||||
[b"[\xa0-\xff]{1}[\xfd\xf9\xf5\xf1\xed\xe9\xe5\xe1\xdd\xd9\xd5\xd1\xcd\xc9\xc5\xc1\xbd\xb9\xb5\xb1\xad\xa9\xa5\xa1]", 2, 1], # c.j | c.beqz | c.bnez
|
||||
[b"[\xa0-\xff]{1}[\x0d\x09\x05\x01\x1d\x19\x15\x11\x2d\x29\x25\x21\x3d\x39\x35\x31\x4d\x49\x45\x41\x5d\x59\x55\x51]", 2, 1], # c.j | c.beqz | c.bnez
|
||||
[b"[\xa0-\xff]{1}[\x6d\x69\x65\x61\x7d\x79\x75\x71\x8d\x89\x85\x81\x9d\x99\x95\x91]", 2, 1], # c.j | c.beqz| c.bnez
|
||||
[b"[\x81-\x8f]{1}[\x02\x82]", 2, 1], #c.jr register
|
||||
[b"[\x91-\x9f]{1}[\x02\x82]", 2, 1], #c.jalr register
|
||||
|
||||
]
|
||||
else:
|
||||
gadgets = [
|
||||
#32 bits encoded register
|
||||
[b"[\x67\x6f\xe7\xef][\x00-\xff][\x00-\xff]{2}" , 4, 1], #jalr/j/jal register, offset
|
||||
[b"[\x63\xe3][\x00-\xff][\x00-\xff]{2}" , 4, 1], #branch register, offset
|
||||
|
||||
#16 bits encoded register
|
||||
[b"[\xfd\xf9\xf5\xf1\xed\xe9\xe5\xe1\xdd\xd9\xd5\xd1\xcd\xc9\xc5\xc1\xbd\xb9\xb5\xb1\xad\xa9\xa5\xa1][\xa0-\xff]{1}", 2, 1], # c.j | c.beqz | c.bnez
|
||||
[b"[\x0d\x09\x05\x01\x1d\x19\x15\x11\x2d\x29\x25\x21\x3d\x39\x35\x31\x4d\x49\x45\x41\x5d\x59\x55\x51][\xa0-\xff]{1}", 2, 1], # c.j | c.beqz | c.bnez
|
||||
[b"[\x6d\x69\x65\x61\x7d\x79\x75\x71\x8d\x89\x85\x81\x9d\x99\x95\x91][\xa0-\xff]{1}", 2, 1], # c.j | c.beqz| c.bnez
|
||||
[b"[\x02\x82][\x81-\x8f]{1}", 2, 1], #c.jr register
|
||||
[b"[\x02\x82][\x91-\x9f]{1}", 2, 1], #c.jalr register
|
||||
|
||||
]
|
||||
arch_mode = CS_MODE_RISCV64 | CS_MODE_RISCVC
|
||||
else:
|
||||
print("Gadgets().addJOPGadgets() - Architecture not supported")
|
||||
return None
|
||||
|
||||
if gadgets:
|
||||
return self.__gadgetsFinding(section, gadgets, arch, arch_mode + arch_endian)
|
||||
return gadgets
|
||||
|
||||
def addSYSGadgets(self, section):
|
||||
|
||||
arch = self.__binary.getArch()
|
||||
arch_mode = self.__binary.getArchMode()
|
||||
arch_endian = self.__binary.getEndian()
|
||||
|
||||
if arch == CS_ARCH_X86:
|
||||
gadgets = [
|
||||
[b"\xcd\x80", 2, 1], # int 0x80
|
||||
[b"\x0f\x34", 2, 1], # sysenter
|
||||
[b"\x0f\x05", 2, 1], # syscall
|
||||
[b"\x65\xff\x15\x10\x00\x00\x00", 7, 1], # call DWORD PTR gs:0x10
|
||||
[b"\xcd\x80\xc3", 3, 1], # int 0x80 ; ret
|
||||
[b"\x0f\x34\xc3", 3, 1], # sysenter ; ret
|
||||
[b"\x0f\x05\xc3", 3, 1], # syscall ; ret
|
||||
[b"\x65\xff\x15\x10\x00\x00\x00\xc3", 8, 1], # call DWORD PTR gs:0x10 ; ret
|
||||
]
|
||||
|
||||
elif arch == CS_ARCH_MIPS:
|
||||
if arch_endian == CS_MODE_BIG_ENDIAN:
|
||||
gadgets = [
|
||||
[b"\x00\x00\x00\x0c", 4, 4] # syscall
|
||||
]
|
||||
else:
|
||||
gadgets = [
|
||||
[b"\x0c\x00\x00\x00", 4, 4] # syscall
|
||||
]
|
||||
elif arch == CS_ARCH_PPC:
|
||||
gadgets = [] # TODO (sc inst)
|
||||
elif arch == CS_ARCH_SPARC:
|
||||
gadgets = [] # TODO (ta inst)
|
||||
elif arch == CS_ARCH_ARM64:
|
||||
gadgets = [] # TODO
|
||||
elif arch == CS_ARCH_ARM:
|
||||
if self.__options.thumb or self.__options.rawMode == "thumb":
|
||||
gadgets = [
|
||||
[b"\x00-\xff]{1}\xef", 2, 2] # FIXME: svc
|
||||
]
|
||||
arch_mode = CS_MODE_THUMB
|
||||
else:
|
||||
gadgets = [
|
||||
[b"\x00-\xff]{3}\xef", 4, 4] # FIXME: svc
|
||||
]
|
||||
arch_mode = CS_MODE_ARM
|
||||
elif arch == CS_ARCH_RISCV:
|
||||
|
||||
if arch_endian == CS_MODE_BIG_ENDIAN:
|
||||
gadgets = [
|
||||
[b"\x00\x00\x00\x73", 4, 2] # syscall
|
||||
]
|
||||
else:
|
||||
gadgets = [
|
||||
[b"\x73\x00\x00\x00", 4, 2] # syscall
|
||||
]
|
||||
|
||||
arch_mode = CS_MODE_RISCV64 | CS_MODE_RISCVC
|
||||
else:
|
||||
print("Gadgets().addSYSGadgets() - Architecture not supported")
|
||||
return None
|
||||
|
||||
if gadgets:
|
||||
return self.__gadgetsFinding(section, gadgets, arch, arch_mode + arch_endian)
|
||||
return []
|
||||
|
||||
def passClean(self, decodes):
|
||||
if not decodes:
|
||||
return True
|
||||
|
||||
if self.__arch == CS_ARCH_X86 and self.__passCleanX86(decodes):
|
||||
return True
|
||||
|
||||
if self.__filterRE and any(self.__filterRE.match(mnemonic) for _, _, mnemonic, _ in decodes):
|
||||
return True
|
||||
|
||||
return False
|
@ -0,0 +1,12 @@
|
||||
## -*- coding: utf-8 -*-
|
||||
##
|
||||
## Jonathan Salwan - 2014-05-12 - ROPgadget tool
|
||||
##
|
||||
## http://twitter.com/JonathanSalwan
|
||||
## http://shell-storm.org/project/ROPgadget/
|
||||
##
|
||||
|
||||
import ropgadget.loaders.elf
|
||||
import ropgadget.loaders.macho
|
||||
import ropgadget.loaders.pe
|
||||
import ropgadget.loaders.raw
|
@ -0,0 +1,366 @@
|
||||
## -*- coding: utf-8 -*-
|
||||
##
|
||||
## Jonathan Salwan - 2014-05-12 - ROPgadget tool
|
||||
##
|
||||
## http://twitter.com/JonathanSalwan
|
||||
## http://shell-storm.org/project/ROPgadget/
|
||||
##
|
||||
|
||||
from ctypes import *
|
||||
|
||||
from capstone import *
|
||||
|
||||
|
||||
class ELFFlags(object):
|
||||
ELFCLASS32 = 0x01
|
||||
ELFCLASS64 = 0x02
|
||||
EI_CLASS = 0x04
|
||||
EI_DATA = 0x05
|
||||
ELFDATA2LSB = 0x01
|
||||
ELFDATA2MSB = 0x02
|
||||
EM_386 = 0x03
|
||||
EM_X86_64 = 0x3e
|
||||
EM_ARM = 0x28
|
||||
EM_MIPS = 0x08
|
||||
EM_SPARCv8p = 0x12
|
||||
EM_PowerPC = 0x14
|
||||
EM_PPC64 = 0x15
|
||||
EM_ARM64 = 0xb7
|
||||
EM_RISCV = 0xf3
|
||||
|
||||
|
||||
class Elf32_Ehdr_LSB(LittleEndianStructure):
|
||||
_fields_ = [
|
||||
("e_ident", c_ubyte * 16),
|
||||
("e_type", c_ushort),
|
||||
("e_machine", c_ushort),
|
||||
("e_version", c_uint),
|
||||
("e_entry", c_uint),
|
||||
("e_phoff", c_uint),
|
||||
("e_shoff", c_uint),
|
||||
("e_flags", c_uint),
|
||||
("e_ehsize", c_ushort),
|
||||
("e_phentsize", c_ushort),
|
||||
("e_phnum", c_ushort),
|
||||
("e_shentsize", c_ushort),
|
||||
("e_shnum", c_ushort),
|
||||
("e_shstrndx", c_ushort),
|
||||
]
|
||||
|
||||
|
||||
class Elf64_Ehdr_LSB(LittleEndianStructure):
|
||||
_fields_ = [
|
||||
("e_ident", c_ubyte * 16),
|
||||
("e_type", c_ushort),
|
||||
("e_machine", c_ushort),
|
||||
("e_version", c_uint),
|
||||
("e_entry", c_ulonglong),
|
||||
("e_phoff", c_ulonglong),
|
||||
("e_shoff", c_ulonglong),
|
||||
("e_flags", c_uint),
|
||||
("e_ehsize", c_ushort),
|
||||
("e_phentsize", c_ushort),
|
||||
("e_phnum", c_ushort),
|
||||
("e_shentsize", c_ushort),
|
||||
("e_shnum", c_ushort),
|
||||
("e_shstrndx", c_ushort),
|
||||
]
|
||||
|
||||
|
||||
class Elf32_Phdr_LSB(LittleEndianStructure):
|
||||
_fields_ = [
|
||||
("p_type", c_uint),
|
||||
("p_offset", c_uint),
|
||||
("p_vaddr", c_uint),
|
||||
("p_paddr", c_uint),
|
||||
("p_filesz", c_uint),
|
||||
("p_memsz", c_uint),
|
||||
("p_flags", c_uint),
|
||||
("p_align", c_uint),
|
||||
]
|
||||
|
||||
|
||||
class Elf64_Phdr_LSB(LittleEndianStructure):
|
||||
_fields_ = [
|
||||
("p_type", c_uint),
|
||||
("p_flags", c_uint),
|
||||
("p_offset", c_ulonglong),
|
||||
("p_vaddr", c_ulonglong),
|
||||
("p_paddr", c_ulonglong),
|
||||
("p_filesz", c_ulonglong),
|
||||
("p_memsz", c_ulonglong),
|
||||
("p_align", c_ulonglong),
|
||||
]
|
||||
|
||||
|
||||
class Elf32_Shdr_LSB(LittleEndianStructure):
|
||||
_fields_ = [
|
||||
("sh_name", c_uint),
|
||||
("sh_type", c_uint),
|
||||
("sh_flags", c_uint),
|
||||
("sh_addr", c_uint),
|
||||
("sh_offset", c_uint),
|
||||
("sh_size", c_uint),
|
||||
("sh_link", c_uint),
|
||||
("sh_info", c_uint),
|
||||
("sh_addralign", c_uint),
|
||||
("sh_entsize", c_uint),
|
||||
]
|
||||
|
||||
|
||||
class Elf64_Shdr_LSB(LittleEndianStructure):
|
||||
_fields_ = [
|
||||
("sh_name", c_uint),
|
||||
("sh_type", c_uint),
|
||||
("sh_flags", c_ulonglong),
|
||||
("sh_addr", c_ulonglong),
|
||||
("sh_offset", c_ulonglong),
|
||||
("sh_size", c_ulonglong),
|
||||
("sh_link", c_uint),
|
||||
("sh_info", c_uint),
|
||||
("sh_addralign", c_ulonglong),
|
||||
("sh_entsize", c_ulonglong),
|
||||
]
|
||||
|
||||
|
||||
class Elf32_Ehdr_MSB(BigEndianStructure):
|
||||
_fields_ = [
|
||||
("e_ident", c_ubyte * 16),
|
||||
("e_type", c_ushort),
|
||||
("e_machine", c_ushort),
|
||||
("e_version", c_uint),
|
||||
("e_entry", c_uint),
|
||||
("e_phoff", c_uint),
|
||||
("e_shoff", c_uint),
|
||||
("e_flags", c_uint),
|
||||
("e_ehsize", c_ushort),
|
||||
("e_phentsize", c_ushort),
|
||||
("e_phnum", c_ushort),
|
||||
("e_shentsize", c_ushort),
|
||||
("e_shnum", c_ushort),
|
||||
("e_shstrndx", c_ushort),
|
||||
]
|
||||
|
||||
|
||||
class Elf64_Ehdr_MSB(BigEndianStructure):
|
||||
_fields_ = [
|
||||
("e_ident", c_ubyte * 16),
|
||||
("e_type", c_ushort),
|
||||
("e_machine", c_ushort),
|
||||
("e_version", c_uint),
|
||||
("e_entry", c_ulonglong),
|
||||
("e_phoff", c_ulonglong),
|
||||
("e_shoff", c_ulonglong),
|
||||
("e_flags", c_uint),
|
||||
("e_ehsize", c_ushort),
|
||||
("e_phentsize", c_ushort),
|
||||
("e_phnum", c_ushort),
|
||||
("e_shentsize", c_ushort),
|
||||
("e_shnum", c_ushort),
|
||||
("e_shstrndx", c_ushort),
|
||||
]
|
||||
|
||||
|
||||
class Elf32_Phdr_MSB(BigEndianStructure):
|
||||
_fields_ = [
|
||||
("p_type", c_uint),
|
||||
("p_offset", c_uint),
|
||||
("p_vaddr", c_uint),
|
||||
("p_paddr", c_uint),
|
||||
("p_filesz", c_uint),
|
||||
("p_memsz", c_uint),
|
||||
("p_flags", c_uint),
|
||||
("p_align", c_uint),
|
||||
]
|
||||
|
||||
|
||||
class Elf64_Phdr_MSB(BigEndianStructure):
|
||||
_fields_ = [
|
||||
("p_type", c_uint),
|
||||
("p_flags", c_uint),
|
||||
("p_offset", c_ulonglong),
|
||||
("p_vaddr", c_ulonglong),
|
||||
("p_paddr", c_ulonglong),
|
||||
("p_filesz", c_ulonglong),
|
||||
("p_memsz", c_ulonglong),
|
||||
("p_align", c_ulonglong),
|
||||
]
|
||||
|
||||
|
||||
class Elf32_Shdr_MSB(BigEndianStructure):
|
||||
_fields_ = [
|
||||
("sh_name", c_uint),
|
||||
("sh_type", c_uint),
|
||||
("sh_flags", c_uint),
|
||||
("sh_addr", c_uint),
|
||||
("sh_offset", c_uint),
|
||||
("sh_size", c_uint),
|
||||
("sh_link", c_uint),
|
||||
("sh_info", c_uint),
|
||||
("sh_addralign", c_uint),
|
||||
("sh_entsize", c_uint),
|
||||
]
|
||||
|
||||
|
||||
class Elf64_Shdr_MSB(BigEndianStructure):
|
||||
_fields_ = [
|
||||
("sh_name", c_uint),
|
||||
("sh_type", c_uint),
|
||||
("sh_flags", c_ulonglong),
|
||||
("sh_addr", c_ulonglong),
|
||||
("sh_offset", c_ulonglong),
|
||||
("sh_size", c_ulonglong),
|
||||
("sh_link", c_uint),
|
||||
("sh_info", c_uint),
|
||||
("sh_addralign", c_ulonglong),
|
||||
("sh_entsize", c_ulonglong),
|
||||
]
|
||||
|
||||
|
||||
class ELF(object):
|
||||
"""This class parses the ELF."""
|
||||
|
||||
def __init__(self, binary):
|
||||
self.__binary = bytearray(binary)
|
||||
self.__ElfHeader = None
|
||||
self.__shdr_l = []
|
||||
self.__phdr_l = []
|
||||
|
||||
self.__setHeaderElf()
|
||||
self.__setShdr()
|
||||
self.__setPhdr()
|
||||
|
||||
def __setHeaderElf(self):
|
||||
"""Parse ELF header."""
|
||||
e_ident = self.__binary[:15]
|
||||
|
||||
ei_class = e_ident[ELFFlags.EI_CLASS]
|
||||
ei_data = e_ident[ELFFlags.EI_DATA]
|
||||
|
||||
if ei_class != ELFFlags.ELFCLASS32 and ei_class != ELFFlags.ELFCLASS64:
|
||||
print("[Error] ELF.__setHeaderElf() - Bad Arch size")
|
||||
return None
|
||||
|
||||
if ei_data != ELFFlags.ELFDATA2LSB and ei_data != ELFFlags.ELFDATA2MSB:
|
||||
print("[Error] ELF.__setHeaderElf() - Bad architecture endian")
|
||||
return None
|
||||
|
||||
if ei_class == ELFFlags.ELFCLASS32:
|
||||
if ei_data == ELFFlags.ELFDATA2LSB: self.__ElfHeader = Elf32_Ehdr_LSB.from_buffer_copy(self.__binary)
|
||||
elif ei_data == ELFFlags.ELFDATA2MSB: self.__ElfHeader = Elf32_Ehdr_MSB.from_buffer_copy(self.__binary)
|
||||
elif ei_class == ELFFlags.ELFCLASS64:
|
||||
if ei_data == ELFFlags.ELFDATA2LSB: self.__ElfHeader = Elf64_Ehdr_LSB.from_buffer_copy(self.__binary)
|
||||
elif ei_data == ELFFlags.ELFDATA2MSB: self.__ElfHeader = Elf64_Ehdr_MSB.from_buffer_copy(self.__binary)
|
||||
|
||||
self.getArch() # Check if architecture is supported
|
||||
|
||||
def __setShdr(self):
|
||||
"""Parse Section header."""
|
||||
shdr_num = self.__ElfHeader.e_shnum
|
||||
base = self.__binary[self.__ElfHeader.e_shoff:]
|
||||
self.__shdr_l = []
|
||||
|
||||
e_ident = self.__binary[:15]
|
||||
ei_data = e_ident[ELFFlags.EI_DATA]
|
||||
|
||||
for _ in range(shdr_num):
|
||||
if self.getArchMode() == CS_MODE_32:
|
||||
if ei_data == ELFFlags.ELFDATA2LSB: shdr = Elf32_Shdr_LSB.from_buffer_copy(base)
|
||||
elif ei_data == ELFFlags.ELFDATA2MSB: shdr = Elf32_Shdr_MSB.from_buffer_copy(base)
|
||||
elif self.getArchMode() == CS_MODE_64:
|
||||
if ei_data == ELFFlags.ELFDATA2LSB: shdr = Elf64_Shdr_LSB.from_buffer_copy(base)
|
||||
elif ei_data == ELFFlags.ELFDATA2MSB: shdr = Elf64_Shdr_MSB.from_buffer_copy(base)
|
||||
|
||||
self.__shdr_l.append(shdr)
|
||||
base = base[self.__ElfHeader.e_shentsize:]
|
||||
|
||||
# setup name from the strings table
|
||||
if self.__ElfHeader.e_shstrndx != 0:
|
||||
string_table = bytes(self.__binary[(self.__shdr_l[self.__ElfHeader.e_shstrndx].sh_offset):])
|
||||
for i in range(shdr_num):
|
||||
self.__shdr_l[i].str_name = string_table[self.__shdr_l[i].sh_name:].split(b'\x00')[0].decode('utf8')
|
||||
|
||||
def __setPhdr(self):
|
||||
"""Parse Program header."""
|
||||
pdhr_num = self.__ElfHeader.e_phnum
|
||||
base = self.__binary[self.__ElfHeader.e_phoff:]
|
||||
self.__phdr_l = []
|
||||
|
||||
e_ident = self.__binary[:15]
|
||||
ei_data = e_ident[ELFFlags.EI_DATA]
|
||||
|
||||
for _ in range(pdhr_num):
|
||||
if self.getArchMode() == CS_MODE_32:
|
||||
if ei_data == ELFFlags.ELFDATA2LSB: phdr = Elf32_Phdr_LSB.from_buffer_copy(base)
|
||||
elif ei_data == ELFFlags.ELFDATA2MSB: phdr = Elf32_Phdr_MSB.from_buffer_copy(base)
|
||||
elif self.getArchMode() == CS_MODE_64:
|
||||
if ei_data == ELFFlags.ELFDATA2LSB: phdr = Elf64_Phdr_LSB.from_buffer_copy(base)
|
||||
elif ei_data == ELFFlags.ELFDATA2MSB: phdr = Elf64_Phdr_MSB.from_buffer_copy(base)
|
||||
|
||||
self.__phdr_l.append(phdr)
|
||||
base = base[self.__ElfHeader.e_phentsize:]
|
||||
|
||||
def getEntryPoint(self):
|
||||
return self.__e_entry
|
||||
|
||||
def getExecSections(self):
|
||||
ret = []
|
||||
for segment in self.__phdr_l:
|
||||
if segment.p_flags & 0x1:
|
||||
ret += [{
|
||||
"offset" : segment.p_offset,
|
||||
"size" : segment.p_memsz,
|
||||
"vaddr" : segment.p_vaddr,
|
||||
"opcodes" : bytes(self.__binary[segment.p_offset:segment.p_offset + segment.p_memsz]),
|
||||
}]
|
||||
return ret
|
||||
|
||||
def getDataSections(self):
|
||||
ret = []
|
||||
for section in self.__shdr_l:
|
||||
if not (section.sh_flags & 0x4) and (section.sh_flags & 0x2):
|
||||
ret += [{
|
||||
"name" : section.str_name,
|
||||
"offset" : section.sh_offset,
|
||||
"size" : section.sh_size,
|
||||
"vaddr" : section.sh_addr,
|
||||
"opcodes" : bytes(self.__binary[section.sh_offset:section.sh_offset + section.sh_size]),
|
||||
}]
|
||||
return ret
|
||||
|
||||
def getArch(self):
|
||||
if self.__ElfHeader.e_machine == ELFFlags.EM_386 or self.__ElfHeader.e_machine == ELFFlags.EM_X86_64:
|
||||
return CS_ARCH_X86
|
||||
elif self.__ElfHeader.e_machine == ELFFlags.EM_ARM:
|
||||
return CS_ARCH_ARM
|
||||
elif self.__ElfHeader.e_machine == ELFFlags.EM_ARM64:
|
||||
return CS_ARCH_ARM64
|
||||
elif self.__ElfHeader.e_machine == ELFFlags.EM_MIPS:
|
||||
return CS_ARCH_MIPS
|
||||
elif self.__ElfHeader.e_machine == ELFFlags.EM_PowerPC or self.__ElfHeader.e_machine == ELFFlags.EM_PPC64:
|
||||
return CS_ARCH_PPC
|
||||
elif self.__ElfHeader.e_machine == ELFFlags.EM_SPARCv8p:
|
||||
return CS_ARCH_SPARC
|
||||
elif self.__ElfHeader.e_machine == ELFFlags.EM_RISCV:
|
||||
return CS_ARCH_RISCV
|
||||
print("[Error] ELF.getArch() - Architecture not supported")
|
||||
return None
|
||||
|
||||
def getArchMode(self):
|
||||
if self.__ElfHeader.e_ident[ELFFlags.EI_CLASS] == ELFFlags.ELFCLASS32:
|
||||
return CS_MODE_32
|
||||
elif self.__ElfHeader.e_ident[ELFFlags.EI_CLASS] == ELFFlags.ELFCLASS64:
|
||||
return CS_MODE_64
|
||||
print("[Error] ELF.getArchMode() - Bad Arch size")
|
||||
return None
|
||||
|
||||
def getEndian(self):
|
||||
if self.__ElfHeader.e_ident[ELFFlags.EI_DATA] == ELFFlags.ELFDATA2LSB:
|
||||
return 0
|
||||
if self.__ElfHeader.e_ident[ELFFlags.EI_DATA] == ELFFlags.ELFDATA2MSB:
|
||||
return CS_MODE_BIG_ENDIAN
|
||||
print("[Error] ELF.getEndian() - Bad Endianness")
|
||||
return None
|
||||
|
||||
def getFormat(self):
|
||||
return "ELF"
|
@ -0,0 +1,329 @@
|
||||
## -*- coding: utf-8 -*-
|
||||
##
|
||||
## Jonathan Salwan - 2014-05-12 - ROPgadget tool
|
||||
##
|
||||
## http://twitter.com/JonathanSalwan
|
||||
## http://shell-storm.org/project/ROPgadget/
|
||||
##
|
||||
|
||||
from ctypes import *
|
||||
|
||||
from capstone import *
|
||||
|
||||
|
||||
class MACH_HEADER_LE(LittleEndianStructure):
|
||||
_fields_ = [
|
||||
("magic", c_uint),
|
||||
("cputype", c_uint),
|
||||
("cpusubtype", c_uint),
|
||||
("filetype", c_uint),
|
||||
("ncmds", c_uint),
|
||||
("sizeofcmds", c_uint),
|
||||
("flags", c_uint),
|
||||
]
|
||||
|
||||
class MACH_HEADER_BE(BigEndianStructure):
|
||||
_fields_ = [
|
||||
("magic", c_uint),
|
||||
("cputype", c_uint),
|
||||
("cpusubtype", c_uint),
|
||||
("filetype", c_uint),
|
||||
("ncmds", c_uint),
|
||||
("sizeofcmds", c_uint),
|
||||
("flags", c_uint),
|
||||
]
|
||||
|
||||
|
||||
class LOAD_COMMAND_LE(LittleEndianStructure):
|
||||
_fields_ = [
|
||||
("cmd", c_uint),
|
||||
("cmdsize", c_uint),
|
||||
]
|
||||
|
||||
class LOAD_COMMAND_BE(BigEndianStructure):
|
||||
_fields_ = [
|
||||
("cmd", c_uint),
|
||||
("cmdsize", c_uint),
|
||||
]
|
||||
|
||||
|
||||
class SEGMENT_COMMAND_LE(LittleEndianStructure):
|
||||
_fields_ = [
|
||||
("cmd", c_uint),
|
||||
("cmdsize", c_uint),
|
||||
("segname", c_ubyte * 16),
|
||||
("vmaddr", c_uint),
|
||||
("vmsize", c_uint),
|
||||
("fileoff", c_uint),
|
||||
("filesize", c_uint),
|
||||
("maxprot", c_uint),
|
||||
("initprot", c_uint),
|
||||
("nsects", c_uint),
|
||||
("flags", c_uint),
|
||||
]
|
||||
|
||||
class SEGMENT_COMMAND_BE(BigEndianStructure):
|
||||
_fields_ = [
|
||||
("cmd", c_uint),
|
||||
("cmdsize", c_uint),
|
||||
("segname", c_ubyte * 16),
|
||||
("vmaddr", c_uint),
|
||||
("vmsize", c_uint),
|
||||
("fileoff", c_uint),
|
||||
("filesize", c_uint),
|
||||
("maxprot", c_uint),
|
||||
("initprot", c_uint),
|
||||
("nsects", c_uint),
|
||||
("flags", c_uint),
|
||||
]
|
||||
|
||||
|
||||
class SEGMENT_COMMAND64_LE(LittleEndianStructure):
|
||||
_fields_ = [
|
||||
("cmd", c_uint),
|
||||
("cmdsize", c_uint),
|
||||
("segname", c_ubyte * 16),
|
||||
("vmaddr", c_ulonglong),
|
||||
("vmsize", c_ulonglong),
|
||||
("fileoff", c_ulonglong),
|
||||
("filesize", c_ulonglong),
|
||||
("maxprot", c_uint),
|
||||
("initprot", c_uint),
|
||||
("nsects", c_uint),
|
||||
("flags", c_uint),
|
||||
]
|
||||
|
||||
class SEGMENT_COMMAND64_BE(BigEndianStructure):
|
||||
_fields_ = [
|
||||
("cmd", c_uint),
|
||||
("cmdsize", c_uint),
|
||||
("segname", c_ubyte * 16),
|
||||
("vmaddr", c_ulonglong),
|
||||
("vmsize", c_ulonglong),
|
||||
("fileoff", c_ulonglong),
|
||||
("filesize", c_ulonglong),
|
||||
("maxprot", c_uint),
|
||||
("initprot", c_uint),
|
||||
("nsects", c_uint),
|
||||
("flags", c_uint),
|
||||
]
|
||||
|
||||
|
||||
class SECTION_LE(LittleEndianStructure):
|
||||
_fields_ = [
|
||||
("sectname", c_ubyte * 16),
|
||||
("segname", c_ubyte * 16),
|
||||
("addr", c_uint),
|
||||
("size", c_uint),
|
||||
("offset", c_uint),
|
||||
("align", c_uint),
|
||||
("reloff", c_uint),
|
||||
("nreloc", c_uint),
|
||||
("flags", c_uint),
|
||||
("reserved1", c_uint),
|
||||
("reserved2", c_uint),
|
||||
]
|
||||
|
||||
class SECTION_BE(BigEndianStructure):
|
||||
_fields_ = [
|
||||
("sectname", c_ubyte * 16),
|
||||
("segname", c_ubyte * 16),
|
||||
("addr", c_uint),
|
||||
("size", c_uint),
|
||||
("offset", c_uint),
|
||||
("align", c_uint),
|
||||
("reloff", c_uint),
|
||||
("nreloc", c_uint),
|
||||
("flags", c_uint),
|
||||
("reserved1", c_uint),
|
||||
("reserved2", c_uint),
|
||||
]
|
||||
|
||||
|
||||
class SECTION64_LE(LittleEndianStructure):
|
||||
_fields_ = [
|
||||
("sectname", c_ubyte * 16),
|
||||
("segname", c_ubyte * 16),
|
||||
("addr", c_ulonglong),
|
||||
("size", c_ulonglong),
|
||||
("offset", c_uint),
|
||||
("align", c_uint),
|
||||
("reloff", c_uint),
|
||||
("nreloc", c_uint),
|
||||
("flags", c_uint),
|
||||
("reserved1", c_uint),
|
||||
("reserved2", c_uint),
|
||||
]
|
||||
|
||||
class SECTION64_BE(BigEndianStructure):
|
||||
_fields_ = [
|
||||
("sectname", c_ubyte * 16),
|
||||
("segname", c_ubyte * 16),
|
||||
("addr", c_ulonglong),
|
||||
("size", c_ulonglong),
|
||||
("offset", c_uint),
|
||||
("align", c_uint),
|
||||
("reloff", c_uint),
|
||||
("nreloc", c_uint),
|
||||
("flags", c_uint),
|
||||
("reserved1", c_uint),
|
||||
("reserved2", c_uint),
|
||||
]
|
||||
|
||||
|
||||
class MACHOFlags(object):
|
||||
CPU_TYPE_I386 = 0x7
|
||||
CPU_TYPE_X86_64 = (CPU_TYPE_I386 | 0x1000000)
|
||||
CPU_TYPE_MIPS = 0x8
|
||||
CPU_TYPE_ARM = 12
|
||||
CPU_TYPE_ARM64 = (CPU_TYPE_ARM | 0x1000000)
|
||||
CPU_TYPE_SPARC = 14
|
||||
CPU_TYPE_POWERPC = 18
|
||||
CPU_TYPE_POWERPC64 = (CPU_TYPE_POWERPC | 0x1000000)
|
||||
LC_SEGMENT = 0x1
|
||||
LC_SEGMENT_64 = 0x19
|
||||
S_ATTR_SOME_INSTRUCTIONS = 0x00000400
|
||||
S_ATTR_PURE_INSTRUCTIONS = 0x80000000
|
||||
|
||||
|
||||
class MACHO(object):
|
||||
"""This class parses the Mach-O."""
|
||||
|
||||
def __init__(self, binary):
|
||||
self.__binary = bytearray(binary)
|
||||
|
||||
self.__machHeader = None
|
||||
self.__endianness = None
|
||||
self.__rawLoadCmd = None
|
||||
self.__sections_l = []
|
||||
|
||||
self.__setEndianness()
|
||||
self.__setHeader()
|
||||
self.__setLoadCmd()
|
||||
|
||||
def __setEndianness(self):
|
||||
magic = self.__binary[0] << 24 | \
|
||||
self.__binary[1] << 16 | \
|
||||
self.__binary[2] << 8 | \
|
||||
self.__binary[3]
|
||||
if magic == 0xfeedface or magic == 0xfeedfacf:
|
||||
self.__endianness = CS_MODE_BIG_ENDIAN
|
||||
else:
|
||||
self.__endianness = 0
|
||||
|
||||
def __setHeader(self):
|
||||
if self.__endianness == CS_MODE_BIG_ENDIAN:
|
||||
self.__machHeader = MACH_HEADER_BE.from_buffer_copy(self.__binary)
|
||||
else:
|
||||
self.__machHeader = MACH_HEADER_LE.from_buffer_copy(self.__binary)
|
||||
|
||||
if self.getArchMode() == CS_MODE_32:
|
||||
self.__rawLoadCmd = self.__binary[28:28 + self.__machHeader.sizeofcmds]
|
||||
|
||||
elif self.getArchMode() == CS_MODE_64:
|
||||
self.__rawLoadCmd = self.__binary[32:32 + self.__machHeader.sizeofcmds]
|
||||
|
||||
def __setLoadCmd(self):
|
||||
base = self.__rawLoadCmd
|
||||
for _ in range(self.__machHeader.ncmds):
|
||||
if self.__endianness == CS_MODE_BIG_ENDIAN:
|
||||
command = LOAD_COMMAND_BE.from_buffer_copy(base)
|
||||
else:
|
||||
command = LOAD_COMMAND_LE.from_buffer_copy(base)
|
||||
|
||||
if command.cmd == MACHOFlags.LC_SEGMENT:
|
||||
if self.__endianness == CS_MODE_BIG_ENDIAN:
|
||||
segment = SEGMENT_COMMAND_BE.from_buffer_copy(base)
|
||||
else:
|
||||
segment = SEGMENT_COMMAND_LE.from_buffer_copy(base)
|
||||
|
||||
self.__setSections(segment, base[56:], 32)
|
||||
|
||||
elif command.cmd == MACHOFlags.LC_SEGMENT_64:
|
||||
if self.__endianness == CS_MODE_BIG_ENDIAN:
|
||||
segment = SEGMENT_COMMAND64_BE.from_buffer_copy(base)
|
||||
else:
|
||||
segment = SEGMENT_COMMAND64_LE.from_buffer_copy(base)
|
||||
self.__setSections(segment, base[72:], 64)
|
||||
|
||||
base = base[command.cmdsize:]
|
||||
|
||||
def __setSections(self, segment, base, sizeHeader):
|
||||
for _ in range(segment.nsects):
|
||||
if sizeHeader == 32:
|
||||
if self.__endianness == CS_MODE_BIG_ENDIAN:
|
||||
section = SECTION_BE.from_buffer_copy(base)
|
||||
else:
|
||||
section = SECTION_LE.from_buffer_copy(base)
|
||||
section.offset = segment.fileoff + section.addr - segment.vmaddr
|
||||
base = base[68:]
|
||||
self.__sections_l += [section]
|
||||
elif sizeHeader == 64:
|
||||
if self.__endianness == CS_MODE_BIG_ENDIAN:
|
||||
section = SECTION64_BE.from_buffer_copy(base)
|
||||
else:
|
||||
section = SECTION64_LE.from_buffer_copy(base)
|
||||
section.offset = segment.fileoff + section.addr - segment.vmaddr
|
||||
base = base[80:]
|
||||
self.__sections_l += [section]
|
||||
|
||||
def getEntryPoint(self):
|
||||
for section in self.__sections_l:
|
||||
if section.sectname[0:6] == "__text":
|
||||
return section.addr
|
||||
|
||||
def getExecSections(self):
|
||||
ret = []
|
||||
for section in self.__sections_l:
|
||||
if section.flags & MACHOFlags.S_ATTR_SOME_INSTRUCTIONS or section.flags & MACHOFlags.S_ATTR_PURE_INSTRUCTIONS:
|
||||
ret += [{
|
||||
"name" : section.sectname,
|
||||
"offset" : section.offset,
|
||||
"size" : section.size,
|
||||
"vaddr" : section.addr,
|
||||
"opcodes" : bytes(self.__binary[section.offset:section.offset + section.size]),
|
||||
}]
|
||||
return ret
|
||||
|
||||
def getDataSections(self):
|
||||
ret = []
|
||||
for section in self.__sections_l:
|
||||
if not section.flags & MACHOFlags.S_ATTR_SOME_INSTRUCTIONS and not section.flags & MACHOFlags.S_ATTR_PURE_INSTRUCTIONS:
|
||||
ret += [{
|
||||
"name" : section.sectname,
|
||||
"offset" : section.offset,
|
||||
"size" : section.size,
|
||||
"vaddr" : section.addr,
|
||||
"opcodes" : bytes(self.__binary[section.offset:section.offset + section.size]),
|
||||
}]
|
||||
return ret
|
||||
|
||||
def getArch(self):
|
||||
if self.__machHeader.cputype == MACHOFlags.CPU_TYPE_I386 or self.__machHeader.cputype == MACHOFlags.CPU_TYPE_X86_64:
|
||||
return CS_ARCH_X86
|
||||
if self.__machHeader.cputype == MACHOFlags.CPU_TYPE_ARM:
|
||||
return CS_ARCH_ARM
|
||||
if self.__machHeader.cputype == MACHOFlags.CPU_TYPE_ARM64:
|
||||
return CS_ARCH_ARM64
|
||||
if self.__machHeader.cputype == MACHOFlags.CPU_TYPE_MIPS:
|
||||
return CS_ARCH_MIPS
|
||||
if self.__machHeader.cputype == MACHOFlags.CPU_TYPE_POWERPC or self.__machHeader.cputype == MACHOFlags.CPU_TYPE_POWERPC64:
|
||||
return CS_ARCH_PPC
|
||||
print("[Error] MACHO.getArch() - Architecture not supported")
|
||||
return None
|
||||
|
||||
def getArchMode(self):
|
||||
if self.__machHeader.magic == 0xfeedface:
|
||||
return CS_MODE_32
|
||||
elif self.__machHeader.magic == 0xfeedfacf:
|
||||
return CS_MODE_64
|
||||
print("[Error] MACHO.getArchMode() - Bad Arch size")
|
||||
return None
|
||||
|
||||
def getEndian(self):
|
||||
if self.__endianness is None:
|
||||
print("[Error] MACHO.getEndian() - Unable to determine endianness")
|
||||
return self.__endianness
|
||||
|
||||
def getFormat(self):
|
||||
return "Mach-O"
|
@ -0,0 +1,241 @@
|
||||
## -*- coding: utf-8 -*-
|
||||
##
|
||||
## Jonathan Salwan - 2014-05-12 - ROPgadget tool
|
||||
##
|
||||
## http://twitter.com/JonathanSalwan
|
||||
## http://shell-storm.org/project/ROPgadget/
|
||||
##
|
||||
|
||||
from binascii import unhexlify
|
||||
from ctypes import *
|
||||
from struct import unpack
|
||||
|
||||
from capstone import *
|
||||
|
||||
|
||||
class PEFlags(object):
|
||||
IMAGE_MACHINE_INTEL_386 = 0x014c
|
||||
IMAGE_MACHINE_AMD_8664 = 0x8664
|
||||
IMAGE_FILE_MACHINE_ARM = 0x1c0
|
||||
IMAGE_FILE_MACHINE_ARMV7 = 0x1c4
|
||||
IMAGE_NT_OPTIONAL_HDR32_MAGIC = 0x10b
|
||||
IMAGE_NT_OPTIONAL_HDR64_MAGIC = 0x20b
|
||||
IMAGE_SIZEOF_SHORT_NAME = 0x8
|
||||
|
||||
|
||||
class IMAGE_FILE_HEADER(LittleEndianStructure):
|
||||
_fields_ = [
|
||||
("Magic", c_uint),
|
||||
("Machine", c_ushort),
|
||||
("NumberOfSections", c_ushort),
|
||||
("TimeDateStamp", c_uint),
|
||||
("PointerToSymbolTable", c_uint),
|
||||
("NumberOfSymbols", c_uint),
|
||||
("SizeOfOptionalHeader", c_ushort),
|
||||
("Characteristics", c_ushort),
|
||||
]
|
||||
|
||||
|
||||
class IMAGE_OPTIONAL_HEADER(LittleEndianStructure):
|
||||
_fields_ = [
|
||||
("Magic", c_ushort),
|
||||
("MajorLinkerVersion", c_ubyte),
|
||||
("MinorLinkerVersion", c_ubyte),
|
||||
("SizeOfCode", c_uint),
|
||||
("SizeOfInitializedData", c_uint),
|
||||
("SizeOfUninitializedData", c_uint),
|
||||
("AddressOfEntryPoint", c_uint),
|
||||
("BaseOfCode", c_uint),
|
||||
("BaseOfData", c_uint),
|
||||
("ImageBase", c_uint),
|
||||
("SectionAlignment", c_uint),
|
||||
("FileAlignment", c_uint),
|
||||
("MajorOperatingSystemVersion", c_ushort),
|
||||
("MinorOperatingSystemVersion", c_ushort),
|
||||
("MajorImageVersion", c_ushort),
|
||||
("MinorImageVersion", c_ushort),
|
||||
("MajorSubsystemVersion", c_ushort),
|
||||
("MinorSubsystemVersion", c_ushort),
|
||||
("Win32VersionValue", c_uint),
|
||||
("SizeOfImage", c_uint),
|
||||
("SizeOfHeaders", c_uint),
|
||||
("CheckSum", c_uint),
|
||||
("Subsystem", c_ushort),
|
||||
("DllCharacteristics", c_ushort),
|
||||
("SizeOfStackReserve", c_uint),
|
||||
("SizeOfStackCommit", c_uint),
|
||||
("SizeOfHeapReserve", c_uint),
|
||||
("SizeOfHeapCommit", c_uint),
|
||||
("LoaderFlags", c_uint),
|
||||
("NumberOfRvaAndSizes", c_uint),
|
||||
]
|
||||
|
||||
|
||||
class IMAGE_OPTIONAL_HEADER64(LittleEndianStructure):
|
||||
_fields_ = [
|
||||
("Magic", c_ushort),
|
||||
("MajorLinkerVersion", c_ubyte),
|
||||
("MinorLinkerVersion", c_ubyte),
|
||||
("SizeOfCode", c_uint),
|
||||
("SizeOfInitializedData", c_uint),
|
||||
("SizeOfUninitializedData", c_uint),
|
||||
("AddressOfEntryPoint", c_uint),
|
||||
("BaseOfCode", c_uint),
|
||||
("ImageBase", c_ulonglong),
|
||||
("SectionAlignment", c_uint),
|
||||
("FileAlignment", c_uint),
|
||||
("MajorOperatingSystemVersion", c_ushort),
|
||||
("MinorOperatingSystemVersion", c_ushort),
|
||||
("MajorImageVersion", c_ushort),
|
||||
("MinorImageVersion", c_ushort),
|
||||
("MajorSubsystemVersion", c_ushort),
|
||||
("MinorSubsystemVersion", c_ushort),
|
||||
("Win32VersionValue", c_uint),
|
||||
("SizeOfImage", c_uint),
|
||||
("SizeOfHeaders", c_uint),
|
||||
("CheckSum", c_uint),
|
||||
("Subsystem", c_ushort),
|
||||
("DllCharacteristics", c_ushort),
|
||||
("SizeOfStackReserve", c_ulonglong),
|
||||
("SizeOfStackCommit", c_ulonglong),
|
||||
("SizeOfHeapReserve", c_ulonglong),
|
||||
("SizeOfHeapCommit", c_ulonglong),
|
||||
("LoaderFlags", c_uint),
|
||||
("NumberOfRvaAndSizes", c_uint),
|
||||
]
|
||||
|
||||
|
||||
class IMAGE_NT_HEADERS(LittleEndianStructure):
|
||||
_fields_ = [
|
||||
("Signature", c_uint),
|
||||
("FileHeader", IMAGE_FILE_HEADER),
|
||||
("OptionalHeader", IMAGE_OPTIONAL_HEADER),
|
||||
]
|
||||
|
||||
|
||||
class IMAGE_NT_HEADERS64(LittleEndianStructure):
|
||||
_fields_ = [
|
||||
("Signature", c_uint),
|
||||
("FileHeader", IMAGE_FILE_HEADER),
|
||||
("OptionalHeader", IMAGE_OPTIONAL_HEADER64),
|
||||
]
|
||||
|
||||
|
||||
class IMAGE_SECTION_HEADER(LittleEndianStructure):
|
||||
_fields_ = [
|
||||
("Name", c_ubyte * PEFlags.IMAGE_SIZEOF_SHORT_NAME),
|
||||
("PhysicalAddress", c_uint),
|
||||
("VirtualAddress", c_uint),
|
||||
("SizeOfRawData", c_uint),
|
||||
("PointerToRawData", c_uint),
|
||||
("PointerToRelocations", c_uint),
|
||||
("PointerToLinenumbers", c_uint),
|
||||
("NumberOfRelocations", c_ushort),
|
||||
("NumberOfLinenumbers", c_ushort),
|
||||
("Characteristics", c_uint),
|
||||
]
|
||||
|
||||
|
||||
class PE(object):
|
||||
"""This class parses the PE format."""
|
||||
|
||||
def __init__(self, binary):
|
||||
self.__binary = bytearray(binary)
|
||||
|
||||
self.__PEOffset = 0x00000000
|
||||
self.__IMAGE_FILE_HEADER = None
|
||||
self.__IMAGE_OPTIONAL_HEADER = None
|
||||
|
||||
self.__sections_l = []
|
||||
|
||||
self.__getPEOffset()
|
||||
self.__parsePEHeader()
|
||||
self.__parseOptHeader()
|
||||
self.__parseSections()
|
||||
|
||||
def __getPEOffset(self):
|
||||
self.__PEOffset = unpack("<I", bytes(self.__binary[60:64]))[0]
|
||||
if self.__binary[self.__PEOffset:self.__PEOffset + 4] != unhexlify(b"50450000"):
|
||||
print("[Error] PE.__getPEOffset() - Bad PE signature")
|
||||
return None
|
||||
|
||||
def __parsePEHeader(self):
|
||||
PEheader = self.__binary[self.__PEOffset:]
|
||||
self.__IMAGE_FILE_HEADER = IMAGE_FILE_HEADER.from_buffer_copy(PEheader)
|
||||
|
||||
def __parseOptHeader(self):
|
||||
PEoptHeader = self.__binary[self.__PEOffset + 24:self.__PEOffset + 24 + self.__IMAGE_FILE_HEADER.SizeOfOptionalHeader]
|
||||
|
||||
if unpack("<H", bytes(PEoptHeader[0:2]))[0] == PEFlags.IMAGE_NT_OPTIONAL_HDR32_MAGIC:
|
||||
self.__IMAGE_OPTIONAL_HEADER = IMAGE_OPTIONAL_HEADER.from_buffer_copy(PEoptHeader)
|
||||
|
||||
elif unpack("<H", bytes(PEoptHeader[0:2]))[0] == PEFlags.IMAGE_NT_OPTIONAL_HDR64_MAGIC:
|
||||
self.__IMAGE_OPTIONAL_HEADER = IMAGE_OPTIONAL_HEADER64.from_buffer_copy(PEoptHeader)
|
||||
|
||||
else:
|
||||
print("[Error] PE.__parseOptHeader - Bad size header")
|
||||
return None
|
||||
|
||||
def __parseSections(self):
|
||||
baseSections = self.__PEOffset + 24 + self.__IMAGE_FILE_HEADER.SizeOfOptionalHeader
|
||||
sizeSections = self.__IMAGE_FILE_HEADER.NumberOfSections * sizeof(IMAGE_SECTION_HEADER)
|
||||
base = self.__binary[baseSections:baseSections + sizeSections]
|
||||
|
||||
for _ in range(self.__IMAGE_FILE_HEADER.NumberOfSections):
|
||||
sec = IMAGE_SECTION_HEADER.from_buffer_copy(base)
|
||||
base = base[sizeof(IMAGE_SECTION_HEADER):]
|
||||
self.__sections_l += [sec]
|
||||
|
||||
return 0
|
||||
|
||||
def getEntryPoint(self):
|
||||
return self.__IMAGE_OPTIONAL_HEADER.ImageBase + self.__IMAGE_OPTIONAL_HEADER.AddressOfEntryPoint
|
||||
|
||||
def getDataSections(self):
|
||||
ret = []
|
||||
for section in self.__sections_l:
|
||||
if section.Characteristics & 0x80000000:
|
||||
ret += [{
|
||||
"name" : section.Name,
|
||||
"offset" : section.PointerToRawData,
|
||||
"size" : section.SizeOfRawData,
|
||||
"vaddr" : section.VirtualAddress + self.__IMAGE_OPTIONAL_HEADER.ImageBase,
|
||||
"opcodes" : bytes(self.__binary[section.PointerToRawData:section.PointerToRawData + section.SizeOfRawData]),
|
||||
}]
|
||||
return ret
|
||||
|
||||
def getExecSections(self):
|
||||
ret = []
|
||||
for section in self.__sections_l:
|
||||
if section.Characteristics & 0x20000000:
|
||||
ret += [{
|
||||
"name" : section.Name,
|
||||
"offset" : section.PointerToRawData,
|
||||
"size" : section.SizeOfRawData,
|
||||
"vaddr" : section.VirtualAddress + self.__IMAGE_OPTIONAL_HEADER.ImageBase,
|
||||
"opcodes" : bytes(self.__binary[section.PointerToRawData:section.PointerToRawData + section.SizeOfRawData]),
|
||||
}]
|
||||
return ret
|
||||
|
||||
def getArch(self):
|
||||
if self.__IMAGE_FILE_HEADER.Machine == PEFlags.IMAGE_MACHINE_INTEL_386 or self.__IMAGE_FILE_HEADER.Machine == PEFlags.IMAGE_MACHINE_AMD_8664:
|
||||
return CS_ARCH_X86
|
||||
if self.__IMAGE_FILE_HEADER.Machine == PEFlags.IMAGE_FILE_MACHINE_ARM or self.__IMAGE_FILE_HEADER.Machine == PEFlags.IMAGE_FILE_MACHINE_ARMV7:
|
||||
return CS_ARCH_ARM
|
||||
print("[Error] PE.getArch() - Bad Arch")
|
||||
return None
|
||||
|
||||
def getArchMode(self):
|
||||
if self.__IMAGE_OPTIONAL_HEADER.Magic == PEFlags.IMAGE_NT_OPTIONAL_HDR32_MAGIC:
|
||||
return CS_MODE_32
|
||||
elif self.__IMAGE_OPTIONAL_HEADER.Magic == PEFlags.IMAGE_NT_OPTIONAL_HDR64_MAGIC:
|
||||
return CS_MODE_64
|
||||
print("[Error] PE.getArch() - Bad arch size")
|
||||
return None
|
||||
|
||||
def getEndian(self):
|
||||
# PE is little-endian only
|
||||
return 0
|
||||
|
||||
def getFormat(self):
|
||||
return "PE"
|
@ -0,0 +1,75 @@
|
||||
## -*- coding: utf-8 -*-
|
||||
##
|
||||
## Jonathan Salwan - 2014-05-12
|
||||
##
|
||||
## http://shell-storm.org
|
||||
## http://twitter.com/JonathanSalwan
|
||||
##
|
||||
|
||||
from capstone import *
|
||||
|
||||
|
||||
class Raw(object):
|
||||
def __init__(self, binary, arch, mode, endian):
|
||||
self.__binary = bytearray(binary)
|
||||
self.__arch = arch
|
||||
self.__mode = mode
|
||||
self.__endian = endian
|
||||
|
||||
def getEntryPoint(self):
|
||||
return 0x0
|
||||
|
||||
def getExecSections(self):
|
||||
return [{"name": "raw", "offset": 0x0, "size": len(self.__binary), "vaddr": 0x0, "opcodes": bytes(self.__binary)}]
|
||||
|
||||
def getDataSections(self):
|
||||
return []
|
||||
|
||||
def getArch(self):
|
||||
arch = {
|
||||
"x86": CS_ARCH_X86,
|
||||
"arm": CS_ARCH_ARM,
|
||||
"arm64": CS_ARCH_ARM64,
|
||||
"sparc": CS_ARCH_SPARC,
|
||||
"mips": CS_ARCH_MIPS,
|
||||
"ppc": CS_ARCH_PPC,
|
||||
"riscv" : CS_ARCH_RISCV,
|
||||
}
|
||||
try:
|
||||
ret = arch[self.__arch]
|
||||
except:
|
||||
print("[Error] Raw.getArch() - Architecture not supported. Only supported: x86 arm arm64 sparc mips ppc")
|
||||
return None
|
||||
return ret
|
||||
|
||||
def getArchMode(self):
|
||||
mode = {
|
||||
"32": CS_MODE_32,
|
||||
"64": CS_MODE_64,
|
||||
"arm": CS_MODE_ARM,
|
||||
"thumb": CS_MODE_THUMB,
|
||||
"riscv": CS_MODE_RISCV64 | CS_MODE_RISCVC,
|
||||
}
|
||||
try:
|
||||
ret = mode[self.__mode]
|
||||
except:
|
||||
print("[Error] Raw.getArchMode() - Mode not supported. Only supported: 32 64 arm thumb")
|
||||
return None
|
||||
return ret
|
||||
|
||||
def getEndian(self):
|
||||
if self.getArch() == CS_ARCH_X86:
|
||||
return 0
|
||||
endian = {
|
||||
"little": 0,
|
||||
"big": CS_MODE_BIG_ENDIAN,
|
||||
}
|
||||
try:
|
||||
ret = endian[self.__endian]
|
||||
except:
|
||||
print("[Error] Raw.getArchEndian() - Endianness not supported. Only supported: little big")
|
||||
return None
|
||||
return ret
|
||||
|
||||
def getFormat(self):
|
||||
return "Raw"
|
@ -0,0 +1,112 @@
|
||||
## -*- coding: utf-8 -*-
|
||||
##
|
||||
## Christoffer Brodd-Reijer - 2014-07-20 - ROPgadget tool
|
||||
##
|
||||
## http://twitter.com/ephracis
|
||||
## http://shell-storm.org/project/ROPgadget/
|
||||
##
|
||||
|
||||
import sys
|
||||
from binascii import *
|
||||
from ctypes import *
|
||||
|
||||
from capstone import *
|
||||
|
||||
from ropgadget.loaders.macho import *
|
||||
|
||||
|
||||
class FAT_HEADER(BigEndianStructure):
|
||||
_fields_ = [
|
||||
("magic", c_uint),
|
||||
("nfat_arch", c_uint),
|
||||
]
|
||||
|
||||
|
||||
class FAT_ARC(BigEndianStructure):
|
||||
_fields_ = [
|
||||
("cputype", c_uint),
|
||||
("cpusubtype", c_uint),
|
||||
("offset", c_uint),
|
||||
("size", c_uint),
|
||||
("align", c_uint),
|
||||
]
|
||||
|
||||
|
||||
class MACHOFlags(object):
|
||||
CPU_TYPE_I386 = 0x7
|
||||
CPU_TYPE_X86_64 = (CPU_TYPE_I386 | 0x1000000)
|
||||
CPU_TYPE_MIPS = 0x8
|
||||
CPU_TYPE_ARM = 12
|
||||
CPU_TYPE_SPARC = 14
|
||||
CPU_TYPE_POWERPC = 18
|
||||
CPU_TYPE_POWERPC64 = (CPU_TYPE_POWERPC | 0x1000000)
|
||||
LC_SEGMENT = 0x1
|
||||
LC_SEGMENT_64 = 0x19
|
||||
S_ATTR_SOME_INSTRUCTIONS = 0x00000400
|
||||
S_ATTR_PURE_INSTRUCTIONS = 0x80000000
|
||||
|
||||
|
||||
class UNIVERSAL(object):
|
||||
"""This class parses the Universal binary."""
|
||||
|
||||
def __init__(self, binary):
|
||||
self.__binary = bytearray(binary)
|
||||
self.__machoBinaries = []
|
||||
|
||||
self.__fatHeader = None
|
||||
self.__rawLoadCmd = None
|
||||
self.__sections_l = []
|
||||
|
||||
self.__setHeader()
|
||||
self.__setBinaries()
|
||||
|
||||
def __setHeader(self):
|
||||
self.__fatHeader = FAT_HEADER.from_buffer_copy(self.__binary)
|
||||
|
||||
def __setBinaries(self):
|
||||
offset = 8
|
||||
for i in xrange(self.__fatHeader.nfat_arch):
|
||||
header = FAT_ARC.from_buffer_copy(self.__binary[offset:])
|
||||
rawBinary = self.__binary[header.offset:header.offset + header.size]
|
||||
if rawBinary[:4] == unhexlify(b"cefaedfe") or rawBinary[:4] == unhexlify(b"cffaedfe"):
|
||||
self.__machoBinaries.append(MACHO(rawBinary))
|
||||
else:
|
||||
print("[Error] Binary #" + str(i + 1) + " in Universal binary has an unsupported format")
|
||||
offset += sizeof(header)
|
||||
|
||||
def getExecSections(self):
|
||||
ret = []
|
||||
for binary in self.__machoBinaries:
|
||||
ret += binary.getExecSections()
|
||||
return ret
|
||||
|
||||
def getDataSections(self):
|
||||
ret = []
|
||||
for binary in self.__machoBinaries:
|
||||
ret += binary.getDataSections()
|
||||
return ret
|
||||
|
||||
def getFormat(self):
|
||||
return "Universal"
|
||||
|
||||
# TODO: These three will just return whatever is in the first binary.
|
||||
# Perhaps the rest of ROPgadget should support loading multiple binaries?
|
||||
def getEntryPoint(self):
|
||||
for binary in self.__machoBinaries:
|
||||
return binary.getEntryPoint()
|
||||
|
||||
def getArch(self):
|
||||
for binary in self.__machoBinaries:
|
||||
return binary.getArch()
|
||||
|
||||
def getArchMode(self):
|
||||
for binary in self.__machoBinaries:
|
||||
return binary.getArchMode()
|
||||
|
||||
def getEndian(self):
|
||||
for binary in self.__machoBinaries:
|
||||
return binary.getEndian()
|
||||
|
||||
|
||||
if sys.version_info.major == 3:
|
||||
xrange = range
|
@ -0,0 +1,148 @@
|
||||
## -*- coding: utf-8 -*-
|
||||
##
|
||||
## Jonathan Salwan - 2014-05-17 - ROPgadget tool
|
||||
##
|
||||
## http://twitter.com/JonathanSalwan
|
||||
## http://shell-storm.org/project/ROPgadget/
|
||||
##
|
||||
|
||||
import codecs
|
||||
import re
|
||||
from struct import pack
|
||||
|
||||
from capstone import *
|
||||
|
||||
|
||||
class Options(object):
|
||||
def __init__(self, options, binary, gadgets):
|
||||
self.__options = options
|
||||
self.__gadgets = gadgets
|
||||
self.__binary = binary
|
||||
|
||||
if options.only:
|
||||
self.__onlyOption()
|
||||
if options.range:
|
||||
self.__rangeOption()
|
||||
if options.re:
|
||||
self.__reOption()
|
||||
if options.badbytes:
|
||||
self.__deleteBadBytes()
|
||||
if options.callPreceded:
|
||||
self.__removeNonCallPreceded()
|
||||
|
||||
def __onlyOption(self):
|
||||
new = []
|
||||
if not self.__options.only:
|
||||
return
|
||||
only = self.__options.only.split("|")
|
||||
if not len(only):
|
||||
return
|
||||
for gadget in self.__gadgets:
|
||||
flag = 0
|
||||
insts = gadget["gadget"].split(" ; ")
|
||||
for ins in insts:
|
||||
if ins.split(" ")[0] not in only:
|
||||
flag = 1
|
||||
break
|
||||
if not flag:
|
||||
new += [gadget]
|
||||
self.__gadgets = new
|
||||
|
||||
def __rangeOption(self):
|
||||
new = []
|
||||
rangeS = int(self.__options.range.split('-')[0], 16)
|
||||
rangeE = int(self.__options.range.split('-')[1], 16)
|
||||
if rangeS == 0 and rangeE == 0:
|
||||
return
|
||||
for gadget in self.__gadgets:
|
||||
vaddr = gadget["vaddr"]
|
||||
if rangeS <= vaddr <= rangeE:
|
||||
new += [gadget]
|
||||
self.__gadgets = new
|
||||
|
||||
def __reOption(self):
|
||||
new = []
|
||||
re_strs = []
|
||||
|
||||
if not self.__options.re:
|
||||
return
|
||||
|
||||
if '|' in self.__options.re:
|
||||
re_strs = self.__options.re.split(' | ')
|
||||
if len(re_strs) == 1:
|
||||
re_strs = self.__options.re.split('|')
|
||||
else:
|
||||
re_strs.append(self.__options.re)
|
||||
|
||||
patterns = []
|
||||
for __re_str in re_strs:
|
||||
pattern = re.compile(__re_str)
|
||||
patterns.append(pattern)
|
||||
|
||||
for gadget in self.__gadgets:
|
||||
flag = 1
|
||||
insts = gadget["gadget"].split(" ; ")
|
||||
for pattern in patterns:
|
||||
for ins in insts:
|
||||
res = pattern.search(ins)
|
||||
if res:
|
||||
flag = 1
|
||||
break
|
||||
else:
|
||||
flag = 0
|
||||
if not flag:
|
||||
break
|
||||
if flag:
|
||||
new += [gadget]
|
||||
self.__gadgets = new
|
||||
|
||||
def __removeNonCallPreceded(self):
|
||||
def __isGadgetCallPreceded(gadget):
|
||||
# Given a gadget, determine if the bytes immediately preceding are a call instruction
|
||||
prevBytes = gadget["prev"]
|
||||
# TODO: Improve / Semantically document each of these cases.
|
||||
callPrecededExpressions = [
|
||||
"\xe8[\x00-\xff][\x00-\xff][\x00-\xff][\x00-\xff]$",
|
||||
"\xe8[\x00-\xff][\x00-\xff][\x00-\xff][\x00-\xff][\x00-\xff][\x00-\xff][\x00-\xff][\x00-\xff]$",
|
||||
"\xff[\x00-\xff]$",
|
||||
"\xff[\x00-\xff][\x00-\xff]$",
|
||||
"\xff[\x00-\xff][\x00-\xff][\x00-\xff][\x00-\xff]$",
|
||||
"\xff[\x00-\xff][\x00-\xff][\x00-\xff][\x00-\xff][\x00-\xff][\x00-\xff][\x00-\xff][\x00-\xff]$",
|
||||
]
|
||||
return bool(reduce(lambda x, y: x or y, map(lambda x: re.search(x, prevBytes), callPrecededExpressions)))
|
||||
arch = self.__binary.getArch()
|
||||
if arch == CS_ARCH_X86:
|
||||
initial_length = len(self.__gadgets)
|
||||
self.__gadgets = filter(__isGadgetCallPreceded, self.__gadgets)
|
||||
print("Options().removeNonCallPreceded(): Filtered out {} gadgets.".format(initial_length - len(self.__gadgets)))
|
||||
else:
|
||||
print("Options().removeNonCallPreceded(): Unsupported architecture.")
|
||||
|
||||
def __deleteBadBytes(self):
|
||||
if not self.__options.badbytes:
|
||||
return
|
||||
new = []
|
||||
# Filter out empty badbytes (i.e if badbytes was set to 00|ff| there's an empty badbyte after the last '|')
|
||||
# and convert each one to the corresponding byte
|
||||
bbytes = []
|
||||
for bb in self.__options.badbytes.split("|"):
|
||||
if '-' in bb:
|
||||
rng = bb.split('-')
|
||||
low = ord(codecs.decode(rng[0], "hex"))
|
||||
high = ord(codecs.decode(rng[1], "hex"))
|
||||
bbytes += bytes(bytearray(i for i in range(low, high + 1)))
|
||||
else:
|
||||
bbytes.append(codecs.decode(bb.encode("ascii"), "hex"))
|
||||
|
||||
archMode = self.__binary.getArchMode()
|
||||
for gadget in self.__gadgets:
|
||||
gadAddr = pack("<L", gadget["vaddr"]) if archMode == CS_MODE_32 else pack("<Q", gadget["vaddr"])
|
||||
for x in bbytes:
|
||||
if x in gadAddr:
|
||||
break
|
||||
else:
|
||||
new += [gadget]
|
||||
self.__gadgets = new
|
||||
|
||||
def getGadgets(self):
|
||||
return self.__gadgets
|
@ -0,0 +1,22 @@
|
||||
## -*- coding: utf-8 -*-
|
||||
##
|
||||
## Jonathan Salwan - 2014-05-17 - ROPgadget tool
|
||||
##
|
||||
## http://twitter.com/JonathanSalwan
|
||||
## http://shell-storm.org/project/ROPgadget/
|
||||
##
|
||||
|
||||
def deleteDuplicateGadgets(currentGadgets):
|
||||
gadgets_content_set = set()
|
||||
unique_gadgets = []
|
||||
for gadget in currentGadgets:
|
||||
gad = gadget["gadget"]
|
||||
if gad in gadgets_content_set:
|
||||
continue
|
||||
gadgets_content_set.add(gad)
|
||||
unique_gadgets += [gadget]
|
||||
return unique_gadgets
|
||||
|
||||
|
||||
def alphaSortgadgets(currentGadgets):
|
||||
return sorted(currentGadgets, key=lambda key: key["gadget"])
|
@ -0,0 +1,10 @@
|
||||
## -*- coding: utf-8 -*-
|
||||
##
|
||||
## Jonathan Salwan - 2014-05-13
|
||||
##
|
||||
## http://shell-storm.org
|
||||
## http://twitter.com/JonathanSalwan
|
||||
##
|
||||
|
||||
import ropgadget.ropchain.arch
|
||||
import ropgadget.ropchain.ropmaker
|
@ -0,0 +1,10 @@
|
||||
## -*- coding: utf-8 -*-
|
||||
##
|
||||
## Jonathan Salwan - 2014-05-13
|
||||
##
|
||||
## http://shell-storm.org
|
||||
## http://twitter.com/JonathanSalwan
|
||||
##
|
||||
|
||||
import ropgadget.ropchain.arch.ropmakerx64
|
||||
import ropgadget.ropchain.arch.ropmakerx86
|
@ -0,0 +1,221 @@
|
||||
#!/usr/bin/env python3
|
||||
## -*- coding: utf-8 -*-
|
||||
##
|
||||
## Jonathan Salwan - 2014-05-13
|
||||
## Florian Meier - 2014-08-31 - The 64b ROP chain generation
|
||||
##
|
||||
## http://shell-storm.org
|
||||
## http://twitter.com/JonathanSalwan
|
||||
##
|
||||
|
||||
import re
|
||||
|
||||
|
||||
class ROPMakerX64(object):
|
||||
def __init__(self, binary, gadgets, liboffset=0x0):
|
||||
self.__binary = binary
|
||||
self.__gadgets = gadgets
|
||||
|
||||
# If it's a library, we have the option to add an offset to the addresses
|
||||
self.__liboffset = liboffset
|
||||
|
||||
self.__generate()
|
||||
|
||||
def __lookingForWrite4Where(self, gadgetsAlreadyTested):
|
||||
for gadget in self.__gadgets:
|
||||
if gadget in gadgetsAlreadyTested:
|
||||
continue
|
||||
f = gadget["gadget"].split(" ; ")[0]
|
||||
regex = re.search("mov .* ptr \[(?P<dst>([(rax)|(rbx)|(rcx)|(rdx)|(rsi)|(rdi)|(r9)|(r10)|(r11)|(r12)|(r13)|(r14)|(r15)]{3}))\], (?P<src>([(rax)|(rbx)|(rcx)|(rdx)|(rsi)|(rdi)|(r9)|(r10)|(r11)|(r12)|(r13)|(r14)|(r15)]{3}))$", f)
|
||||
if regex:
|
||||
lg = gadget["gadget"].split(" ; ")[1:]
|
||||
try:
|
||||
for g in lg:
|
||||
if g.split()[0] != "pop" and g.split()[0] != "ret":
|
||||
raise
|
||||
# we need this to filterout 'ret' instructions with an offset like 'ret 0x6', because they ruin the stack pointer
|
||||
if g != "ret":
|
||||
if g.split()[0] == "ret" and g.split()[1] != "":
|
||||
raise
|
||||
print("\t[+] Gadget found: 0x%x %s" % (gadget["vaddr"], gadget["gadget"]))
|
||||
return [gadget, regex.group("dst"), regex.group("src")]
|
||||
except:
|
||||
continue
|
||||
return None
|
||||
|
||||
def __lookingForSomeThing(self, something):
|
||||
for gadget in self.__gadgets:
|
||||
lg = gadget["gadget"].split(" ; ")
|
||||
if lg[0] == something:
|
||||
try:
|
||||
for g in lg[1:]:
|
||||
if g.split()[0] != "pop" and g.split()[0] != "ret":
|
||||
raise
|
||||
if g != "ret":
|
||||
# we need this to filterout 'ret' instructions with an offset like 'ret 0x6', because they ruin the stack pointer
|
||||
if g.split()[0] == "ret" and g.split()[1] != "":
|
||||
raise
|
||||
print("\t[+] Gadget found: 0x%x %s" % (gadget["vaddr"], gadget["gadget"]))
|
||||
return gadget
|
||||
except:
|
||||
continue
|
||||
return None
|
||||
|
||||
def __padding(self, gadget, regAlreadSetted):
|
||||
lg = gadget["gadget"].split(" ; ")
|
||||
for g in lg[1:]:
|
||||
if g.split()[0] == "pop":
|
||||
reg = g.split()[1]
|
||||
try:
|
||||
print("\tp += pack('<Q', 0x%016x) # padding without overwrite %s" % (regAlreadSetted[reg], reg))
|
||||
except KeyError:
|
||||
print("\tp += pack('<Q', 0x4141414141414141) # padding")
|
||||
|
||||
def __buildRopChain(self, write4where, popDst, popSrc, xorSrc, xorRax, incRax, popRdi, popRsi, popRdx, syscall):
|
||||
|
||||
sects = self.__binary.getDataSections()
|
||||
dataAddr = None
|
||||
for s in sects:
|
||||
if s["name"] == ".data":
|
||||
dataAddr = s["vaddr"] + self.__liboffset
|
||||
if dataAddr is None:
|
||||
print("\n[-] Error - Can't find a writable section")
|
||||
return
|
||||
|
||||
print("#!/usr/bin/env python3")
|
||||
print("# execve generated by ROPgadget\n")
|
||||
print("from struct import pack\n")
|
||||
|
||||
print("# Padding goes here")
|
||||
print("p = b''\n")
|
||||
|
||||
print("p += pack('<Q', 0x%016x) # %s" % (popDst["vaddr"], popDst["gadget"]))
|
||||
print("p += pack('<Q', 0x%016x) # @ .data" % dataAddr)
|
||||
self.__padding(popDst, {})
|
||||
|
||||
print("p += pack('<Q', 0x%016x) # %s" % (popSrc["vaddr"], popSrc["gadget"]))
|
||||
print("p += b'/bin//sh'")
|
||||
self.__padding(popSrc, {popDst["gadget"].split()[1]: dataAddr}) # Don't overwrite reg dst
|
||||
|
||||
print("p += pack('<Q', 0x%016x) # %s" % (write4where["vaddr"], write4where["gadget"]))
|
||||
self.__padding(write4where, {})
|
||||
|
||||
print("p += pack('<Q', 0x%016x) # %s" % (popDst["vaddr"], popDst["gadget"]))
|
||||
print("p += pack('<Q', 0x%016x) # @ .data + 8" % (dataAddr + 8))
|
||||
self.__padding(popDst, {})
|
||||
|
||||
print("p += pack('<Q', 0x%016x) # %s" % (xorSrc["vaddr"], xorSrc["gadget"]))
|
||||
self.__padding(xorSrc, {})
|
||||
|
||||
print("p += pack('<Q', 0x%016x) # %s" % (write4where["vaddr"], write4where["gadget"]))
|
||||
self.__padding(write4where, {})
|
||||
|
||||
print("p += pack('<Q', 0x%016x) # %s" % (popRdi["vaddr"], popRdi["gadget"]))
|
||||
print("p += pack('<Q', 0x%016x) # @ .data" % dataAddr)
|
||||
self.__padding(popRdi, {})
|
||||
|
||||
print("p += pack('<Q', 0x%016x) # %s" % (popRsi["vaddr"], popRsi["gadget"]))
|
||||
print("p += pack('<Q', 0x%016x) # @ .data + 8" % (dataAddr + 8))
|
||||
self.__padding(popRsi, {"rdi": dataAddr}) # Don't overwrite rdi
|
||||
|
||||
print("p += pack('<Q', 0x%016x) # %s" % (popRdx["vaddr"], popRdx["gadget"]))
|
||||
print("p += pack('<Q', 0x%016x) # @ .data + 8" % (dataAddr + 8))
|
||||
self.__padding(popRdx, {"rdi": dataAddr, "rsi": dataAddr + 8}) # Don't overwrite rdi and rsi
|
||||
|
||||
print("p += pack('<Q', 0x%016x) # %s" % (xorRax["vaddr"], xorRax["gadget"]))
|
||||
self.__padding(xorRax, {"rdi": dataAddr, "rsi": dataAddr + 8}) # Don't overwrite rdi and rsi
|
||||
|
||||
for _ in range(59):
|
||||
print("p += pack('<Q', 0x%016x) # %s" % (incRax["vaddr"], incRax["gadget"]))
|
||||
self.__padding(incRax, {"rdi": dataAddr, "rsi": dataAddr + 8}) # Don't overwrite rdi and rsi
|
||||
|
||||
print("p += pack('<Q', 0x%016x) # %s" % (syscall["vaddr"], syscall["gadget"]))
|
||||
|
||||
def __generate(self):
|
||||
|
||||
# To find the smaller gadget
|
||||
self.__gadgets.reverse()
|
||||
|
||||
print("\nROP chain generation\n===========================================================")
|
||||
|
||||
print("\n- Step 1 -- Write-what-where gadgets\n")
|
||||
|
||||
gadgetsAlreadyTested = []
|
||||
while True:
|
||||
write4where = self.__lookingForWrite4Where(gadgetsAlreadyTested)
|
||||
if not write4where:
|
||||
print("\t[-] Can't find the 'mov qword ptr [r64], r64' gadget")
|
||||
return
|
||||
|
||||
popDst = self.__lookingForSomeThing("pop %s" % write4where[1])
|
||||
if not popDst:
|
||||
print("\t[-] Can't find the 'pop %s' gadget. Try with another 'mov [reg], reg'\n" % write4where[1])
|
||||
gadgetsAlreadyTested += [write4where[0]]
|
||||
continue
|
||||
|
||||
popSrc = self.__lookingForSomeThing("pop %s" % write4where[2])
|
||||
if not popSrc:
|
||||
print("\t[-] Can't find the 'pop %s' gadget. Try with another 'mov [reg], reg'\n" % write4where[2])
|
||||
gadgetsAlreadyTested += [write4where[0]]
|
||||
continue
|
||||
|
||||
xorSrc = self.__lookingForSomeThing("xor %s, %s" % (write4where[2], write4where[2]))
|
||||
if not xorSrc:
|
||||
print("\t[-] Can't find the 'xor %s, %s' gadget. Try with another 'mov [reg], reg'\n" % (write4where[2], write4where[2]))
|
||||
gadgetsAlreadyTested += [write4where[0]]
|
||||
continue
|
||||
else:
|
||||
break
|
||||
|
||||
print("\n- Step 2 -- Init syscall number gadgets\n")
|
||||
|
||||
xorRax = self.__lookingForSomeThing("xor rax, rax")
|
||||
if not xorRax:
|
||||
print("\t[-] Can't find the 'xor rax, rax' instruction")
|
||||
return
|
||||
|
||||
incRax = self.__lookingForSomeThing("inc rax")
|
||||
incEax = self.__lookingForSomeThing("inc eax")
|
||||
incAx = self.__lookingForSomeThing("inc al")
|
||||
addRax = self.__lookingForSomeThing("add rax, 1")
|
||||
addEax = self.__lookingForSomeThing("add eax, 1")
|
||||
addAx = self.__lookingForSomeThing("add al, 1")
|
||||
|
||||
instr = [incRax, incEax, incAx, addRax, addEax, addAx]
|
||||
|
||||
if all(v is None for v in instr):
|
||||
print("\t[-] Can't find the 'inc rax' or 'add rax, 1' instruction")
|
||||
return
|
||||
|
||||
for i in instr:
|
||||
if i is not None:
|
||||
incRax = i
|
||||
break
|
||||
|
||||
print("\n- Step 3 -- Init syscall arguments gadgets\n")
|
||||
|
||||
popRdi = self.__lookingForSomeThing("pop rdi")
|
||||
if not popRdi:
|
||||
print("\t[-] Can't find the 'pop rdi' instruction")
|
||||
return
|
||||
|
||||
popRsi = self.__lookingForSomeThing("pop rsi")
|
||||
if not popRsi:
|
||||
print("\t[-] Can't find the 'pop rsi' instruction")
|
||||
return
|
||||
|
||||
popRdx = self.__lookingForSomeThing("pop rdx")
|
||||
if not popRdx:
|
||||
print("\t[-] Can't find the 'pop rdx' instruction")
|
||||
return
|
||||
|
||||
print("\n- Step 4 -- Syscall gadget\n")
|
||||
|
||||
syscall = self.__lookingForSomeThing("syscall")
|
||||
if not syscall:
|
||||
print("\t[-] Can't find the 'syscall' instruction")
|
||||
return
|
||||
|
||||
print("\n- Step 5 -- Build the ROP chain\n")
|
||||
|
||||
self.__buildRopChain(write4where[0], popDst, popSrc, xorSrc, xorRax, incRax, popRdi, popRsi, popRdx, syscall)
|
@ -0,0 +1,219 @@
|
||||
#!/usr/bin/env python3
|
||||
## -*- coding: utf-8 -*-
|
||||
##
|
||||
## Jonathan Salwan - 2014-05-13
|
||||
##
|
||||
## http://shell-storm.org
|
||||
## http://twitter.com/JonathanSalwan
|
||||
##
|
||||
|
||||
import re
|
||||
|
||||
|
||||
class ROPMakerX86(object):
|
||||
def __init__(self, binary, gadgets, liboffset=0x0):
|
||||
self.__binary = binary
|
||||
self.__gadgets = gadgets
|
||||
|
||||
# If it's a library, we have the option to add an offset to the addresses
|
||||
self.__liboffset = liboffset
|
||||
|
||||
self.__generate()
|
||||
|
||||
def __lookingForWrite4Where(self, gadgetsAlreadyTested):
|
||||
for gadget in self.__gadgets:
|
||||
if gadget in gadgetsAlreadyTested:
|
||||
continue
|
||||
f = gadget["gadget"].split(" ; ")[0]
|
||||
# regex -> mov dword ptr [r32], r32
|
||||
regex = re.search("mov dword ptr \[(?P<dst>([(eax)|(ebx)|(ecx)|(edx)|(esi)|(edi)]{3}))\], (?P<src>([(eax)|(ebx)|(ecx)|(edx)|(esi)|(edi)]{3}))$", f)
|
||||
if regex:
|
||||
lg = gadget["gadget"].split(" ; ")[1:]
|
||||
try:
|
||||
for g in lg:
|
||||
if g.split()[0] != "pop" and g.split()[0] != "ret":
|
||||
raise
|
||||
# we need this to filterout 'ret' instructions with an offset like 'ret 0x6', because they ruin the stack pointer
|
||||
if g != "ret":
|
||||
if g.split()[0] == "ret" and g.split()[1] != "":
|
||||
raise
|
||||
print("\t[+] Gadget found: 0x%x %s" % (gadget["vaddr"], gadget["gadget"]))
|
||||
return [gadget, regex.group("dst"), regex.group("src")]
|
||||
except:
|
||||
continue
|
||||
return None
|
||||
|
||||
def __lookingForSomeThing(self, something):
|
||||
for gadget in self.__gadgets:
|
||||
lg = gadget["gadget"].split(" ; ")
|
||||
if lg[0] == something:
|
||||
try:
|
||||
for g in lg[1:]:
|
||||
if g.split()[0] != "pop" and g.split()[0] != "ret":
|
||||
raise
|
||||
# we need this to filterout 'ret' instructions with an offset like 'ret 0x6', because they ruin the stack pointer
|
||||
if g != "ret":
|
||||
if g.split()[0] == "ret" and g.split()[1] != "":
|
||||
raise
|
||||
print("\t[+] Gadget found: 0x%x %s" % (gadget["vaddr"], gadget["gadget"]))
|
||||
return gadget
|
||||
except:
|
||||
continue
|
||||
return None
|
||||
|
||||
def __padding(self, gadget, regAlreadSetted):
|
||||
lg = gadget["gadget"].split(" ; ")
|
||||
for g in lg[1:]:
|
||||
if g.split()[0] == "pop":
|
||||
reg = g.split()[1]
|
||||
try:
|
||||
print("\tp += pack('<I', 0x%08x) # padding without overwrite %s" % (regAlreadSetted[reg], reg))
|
||||
except KeyError:
|
||||
print("\tp += pack('<I', 0x41414141) # padding")
|
||||
|
||||
def __buildRopChain(self, write4where, popDst, popSrc, xorSrc, xorEax, incEax, popEbx, popEcx, popEdx, syscall):
|
||||
|
||||
sects = self.__binary.getDataSections()
|
||||
dataAddr = None
|
||||
for s in sects:
|
||||
if s["name"] == ".data":
|
||||
dataAddr = s["vaddr"] + self.__liboffset
|
||||
if dataAddr is None:
|
||||
print("\n[-] Error - Can't find a writable section")
|
||||
return
|
||||
|
||||
print("#!/usr/bin/env python3")
|
||||
print("# execve generated by ROPgadget\n")
|
||||
print("from struct import pack\n")
|
||||
|
||||
print("# Padding goes here")
|
||||
print("p = b''\n")
|
||||
|
||||
print("p += pack('<I', 0x%08x) # %s" % (popDst["vaddr"], popDst["gadget"]))
|
||||
print("p += pack('<I', 0x%08x) # @ .data" % dataAddr)
|
||||
self.__padding(popDst, {})
|
||||
|
||||
print("p += pack('<I', 0x%08x) # %s" % (popSrc["vaddr"], popSrc["gadget"]))
|
||||
print("p += b'/bin'")
|
||||
self.__padding(popSrc, {popDst["gadget"].split()[1]: dataAddr}) # Don't overwrite reg dst
|
||||
|
||||
print("p += pack('<I', 0x%08x) # %s" % (write4where["vaddr"], write4where["gadget"]))
|
||||
self.__padding(write4where, {})
|
||||
|
||||
print("p += pack('<I', 0x%08x) # %s" % (popDst["vaddr"], popDst["gadget"]))
|
||||
print("p += pack('<I', 0x%08x) # @ .data + 4" % (dataAddr + 4))
|
||||
self.__padding(popDst, {})
|
||||
|
||||
print("p += pack('<I', 0x%08x) # %s" % (popSrc["vaddr"], popSrc["gadget"]))
|
||||
print("p += b'//sh'")
|
||||
self.__padding(popSrc, {popDst["gadget"].split()[1]: dataAddr + 4}) # Don't overwrite reg dst
|
||||
|
||||
print("p += pack('<I', 0x%08x) # %s" % (write4where["vaddr"], write4where["gadget"]))
|
||||
self.__padding(write4where, {})
|
||||
|
||||
print("p += pack('<I', 0x%08x) # %s" % (popDst["vaddr"], popDst["gadget"]))
|
||||
print("p += pack('<I', 0x%08x) # @ .data + 8" % (dataAddr + 8))
|
||||
self.__padding(popDst, {})
|
||||
|
||||
print("p += pack('<I', 0x%08x) # %s" % (xorSrc["vaddr"], xorSrc["gadget"]))
|
||||
self.__padding(xorSrc, {})
|
||||
|
||||
print("p += pack('<I', 0x%08x) # %s" % (write4where["vaddr"], write4where["gadget"]))
|
||||
self.__padding(write4where, {})
|
||||
|
||||
print("p += pack('<I', 0x%08x) # %s" % (popEbx["vaddr"], popEbx["gadget"]))
|
||||
print("p += pack('<I', 0x%08x) # @ .data" % dataAddr)
|
||||
self.__padding(popEbx, {})
|
||||
|
||||
print("p += pack('<I', 0x%08x) # %s" % (popEcx["vaddr"], popEcx["gadget"]))
|
||||
print("p += pack('<I', 0x%08x) # @ .data + 8" % (dataAddr + 8))
|
||||
self.__padding(popEcx, {"ebx": dataAddr}) # Don't overwrite ebx
|
||||
|
||||
print("p += pack('<I', 0x%08x) # %s" % (popEdx["vaddr"], popEdx["gadget"]))
|
||||
print("p += pack('<I', 0x%08x) # @ .data + 8" % (dataAddr + 8))
|
||||
self.__padding(popEdx, {"ebx": dataAddr, "ecx": dataAddr + 8}) # Don't overwrite ebx and ecx
|
||||
|
||||
print("p += pack('<I', 0x%08x) # %s" % (xorEax["vaddr"], xorEax["gadget"]))
|
||||
self.__padding(xorEax, {"ebx": dataAddr, "ecx": dataAddr + 8}) # Don't overwrite ebx and ecx
|
||||
|
||||
for _ in range(11):
|
||||
print("p += pack('<I', 0x%08x) # %s" % (incEax["vaddr"], incEax["gadget"]))
|
||||
self.__padding(incEax, {"ebx": dataAddr, "ecx": dataAddr + 8}) # Don't overwrite ebx and ecx
|
||||
|
||||
print("p += pack('<I', 0x%08x) # %s" % (syscall["vaddr"], syscall["gadget"]))
|
||||
|
||||
def __generate(self):
|
||||
|
||||
# To find the smaller gadget
|
||||
self.__gadgets.reverse()
|
||||
|
||||
print("\nROP chain generation\n===========================================================")
|
||||
|
||||
print("\n- Step 1 -- Write-what-where gadgets\n")
|
||||
|
||||
gadgetsAlreadyTested = []
|
||||
while True:
|
||||
write4where = self.__lookingForWrite4Where(gadgetsAlreadyTested)
|
||||
if not write4where:
|
||||
print("\t[-] Can't find the 'mov dword ptr [r32], r32' gadget")
|
||||
return
|
||||
|
||||
popDst = self.__lookingForSomeThing("pop %s" % write4where[1])
|
||||
if not popDst:
|
||||
print("\t[-] Can't find the 'pop %s' gadget. Try with another 'mov [reg], reg'\n" % write4where[1])
|
||||
gadgetsAlreadyTested += [write4where[0]]
|
||||
continue
|
||||
|
||||
popSrc = self.__lookingForSomeThing("pop %s" % write4where[2])
|
||||
if not popSrc:
|
||||
print("\t[-] Can't find the 'pop %s' gadget. Try with another 'mov [reg], reg'\n" % write4where[2])
|
||||
gadgetsAlreadyTested += [write4where[0]]
|
||||
continue
|
||||
|
||||
xorSrc = self.__lookingForSomeThing("xor %s, %s" % (write4where[2], write4where[2]))
|
||||
if not xorSrc:
|
||||
print("\t[-] Can't find the 'xor %s, %s' gadget. Try with another 'mov [r], r'\n" % (write4where[2], write4where[2]))
|
||||
gadgetsAlreadyTested += [write4where[0]]
|
||||
continue
|
||||
else:
|
||||
break
|
||||
|
||||
print("\n- Step 2 -- Init syscall number gadgets\n")
|
||||
|
||||
xorEax = self.__lookingForSomeThing("xor eax, eax")
|
||||
if not xorEax:
|
||||
print("\t[-] Can't find the 'xor eax, eax' instruction")
|
||||
return
|
||||
|
||||
incEax = self.__lookingForSomeThing("inc eax")
|
||||
if not incEax:
|
||||
print("\t[-] Can't find the 'inc eax' instruction")
|
||||
return
|
||||
|
||||
print("\n- Step 3 -- Init syscall arguments gadgets\n")
|
||||
|
||||
popEbx = self.__lookingForSomeThing("pop ebx")
|
||||
if not popEbx:
|
||||
print("\t[-] Can't find the 'pop ebx' instruction")
|
||||
return
|
||||
|
||||
popEcx = self.__lookingForSomeThing("pop ecx")
|
||||
if not popEcx:
|
||||
print("\t[-] Can't find the 'pop ecx' instruction")
|
||||
return
|
||||
|
||||
popEdx = self.__lookingForSomeThing("pop edx")
|
||||
if not popEdx:
|
||||
print("\t[-] Can't find the 'pop edx' instruction")
|
||||
return
|
||||
|
||||
print("\n- Step 4 -- Syscall gadget\n")
|
||||
|
||||
syscall = self.__lookingForSomeThing("int 0x80")
|
||||
if not syscall:
|
||||
print("\t[-] Can't find the 'syscall' instruction")
|
||||
return
|
||||
|
||||
print("\n- Step 5 -- Build the ROP chain\n")
|
||||
|
||||
self.__buildRopChain(write4where[0], popDst, popSrc, xorSrc, xorEax, incEax, popEbx, popEcx, popEdx, syscall)
|
@ -0,0 +1,40 @@
|
||||
## -*- coding: utf-8 -*-
|
||||
##
|
||||
## Jonathan Salwan - 2014-05-13
|
||||
##
|
||||
## http://shell-storm.org
|
||||
## http://twitter.com/JonathanSalwan
|
||||
##
|
||||
|
||||
from capstone import *
|
||||
|
||||
from ropgadget.ropchain.arch.ropmakerx64 import *
|
||||
from ropgadget.ropchain.arch.ropmakerx86 import *
|
||||
|
||||
|
||||
class ROPMaker(object):
|
||||
def __init__(self, binary, gadgets, offset):
|
||||
self.__binary = binary
|
||||
self.__gadgets = gadgets
|
||||
self.__offset = offset
|
||||
|
||||
self.__handlerArch()
|
||||
|
||||
def __handlerArch(self):
|
||||
|
||||
if (
|
||||
self.__binary.getArch() == CS_ARCH_X86
|
||||
and self.__binary.getArchMode() == CS_MODE_32
|
||||
and self.__binary.getFormat() == "ELF"
|
||||
):
|
||||
ROPMakerX86(self.__binary, self.__gadgets, self.__offset)
|
||||
|
||||
elif (
|
||||
self.__binary.getArch() == CS_ARCH_X86
|
||||
and self.__binary.getArchMode() == CS_MODE_64
|
||||
and self.__binary.getFormat() == "ELF"
|
||||
):
|
||||
ROPMakerX64(self.__binary, self.__gadgets, self.__offset)
|
||||
|
||||
else:
|
||||
print("\n[Error] ROPMaker.__handlerArch - Arch not supported yet for the rop chain generation")
|
@ -0,0 +1,37 @@
|
||||
## -*- coding: utf-8 -*-
|
||||
##
|
||||
## Jonathan Salwan - 2014-05-12 - ROPgadget tool
|
||||
##
|
||||
## http://twitter.com/JonathanSalwan
|
||||
## http://shell-storm.org/project/ROPgadget/
|
||||
##
|
||||
|
||||
import re
|
||||
try:
|
||||
import httplib
|
||||
except ImportError:
|
||||
import http.client as httplib
|
||||
|
||||
|
||||
from ropgadget.version import *
|
||||
|
||||
|
||||
class UpdateAlert(object):
|
||||
|
||||
@staticmethod
|
||||
def checkUpdate():
|
||||
try:
|
||||
conn = httplib.HTTPSConnection("raw.githubusercontent.com", 443)
|
||||
conn.request("GET", "/JonathanSalwan/ROPgadget/master/ropgadget/version.py")
|
||||
except:
|
||||
print("Can't connect to raw.githubusercontent.com")
|
||||
return
|
||||
d = conn.getresponse().read().decode()
|
||||
majorVersion = re.search("MAJOR_VERSION.+=.+(?P<value>[\d])", d).group("value")
|
||||
minorVersion = re.search("MINOR_VERSION.+=.+(?P<value>[\d])", d).group("value")
|
||||
webVersion = int("%s%s" % (majorVersion, minorVersion))
|
||||
curVersion = int("%s%s" % (MAJOR_VERSION, MINOR_VERSION))
|
||||
if webVersion > curVersion:
|
||||
print("The version %s.%s is available. Currently, you use the version %d.%d." % (majorVersion, minorVersion, MAJOR_VERSION, MINOR_VERSION))
|
||||
else:
|
||||
print("Your version is up-to-date.")
|
@ -0,0 +1,11 @@
|
||||
## -*- coding: utf-8 -*-
|
||||
##
|
||||
## Jonathan Salwan - 2014-05-12 - ROPgadget tool
|
||||
##
|
||||
## http://twitter.com/JonathanSalwan
|
||||
## http://shell-storm.org/project/ROPgadget/
|
||||
##
|
||||
|
||||
MAJOR_VERSION = 7
|
||||
MINOR_VERSION = 4
|
||||
PYROPGADGET_VERSION = "ROPgadget v%d.%d" % (MAJOR_VERSION, MINOR_VERSION)
|
@ -0,0 +1,12 @@
|
||||
#!/usr/bin/env python
|
||||
## -*- coding: utf-8 -*-
|
||||
##
|
||||
## Jonathan Salwan - 2014-05-12 - ROPgadget tool
|
||||
##
|
||||
## http://twitter.com/JonathanSalwan
|
||||
## http://shell-storm.org/project/ROPgadget/
|
||||
##
|
||||
|
||||
import ropgadget
|
||||
|
||||
ropgadget.main()
|
@ -0,0 +1,85 @@
|
||||
# All configuration for plugins and other utils is defined here.
|
||||
# Read more about `setup.cfg`:
|
||||
# https://docs.python.org/3/distutils/configfile.html
|
||||
|
||||
|
||||
# === Linter configuration ===
|
||||
# You can reuse this configuration in your own projects.
|
||||
# See: https://wemake-python-stylegui.de/en/latest/pages/usage/integrations/nitpick.html
|
||||
|
||||
[flake8]
|
||||
# Base flake8 configuration:
|
||||
# https://flake8.pycqa.org/en/latest/user/configuration.html
|
||||
format = wemake
|
||||
show-source = True
|
||||
statistics = False
|
||||
doctests = True
|
||||
|
||||
# Plugins:
|
||||
max-complexity = 6
|
||||
max-line-length = 100
|
||||
|
||||
# Self settings:
|
||||
max-imports = 17
|
||||
|
||||
# Excluding some directories:
|
||||
exclude =
|
||||
.git
|
||||
__pycache__
|
||||
.venv
|
||||
.eggs
|
||||
*.egg
|
||||
dist
|
||||
|
||||
# Exclude some checks globally:
|
||||
ignore = B001, C901, D100, D101, D102, D103, D104, D107, D205, D400, E221, E241,
|
||||
E251, E266, E271, E272, E722, F403, F405, I004, N802, N803, N806, P101,
|
||||
Q000, W503, W504, WPS110, WPS111, WPS112, WPS122, WPS202, WPS204, WPS210,
|
||||
WPS212, WPS213, WPS214, WPS220, WPS221, WPS222, WPS223, WPS226, WPS229,
|
||||
WPS231, WPS232, WPS301, WPS323, WPS336, WPS337, WPS338, WPS341, WPS347,
|
||||
WPS412, WPS420, WPS421, WPS430, WPS432, WPS433, WPS440, WPS504, WPS514,
|
||||
WPS515, WPS602, WPS605
|
||||
|
||||
per-file-ignores =
|
||||
ROPgadget.py: WPS102
|
||||
ropgadget/__init__.py: F401
|
||||
ropgadget/args.py: E501, WPS317, WPS318
|
||||
ropgadget/binary.py: E501
|
||||
ropgadget/core.py: E501, I001, S110, WPS125, WPS503, WPS513, WPS609
|
||||
ropgadget/gadgets.py: C812, E126, E261, E501, E800, WPS318, WPS319, WPS513
|
||||
ropgadget/loaders/__init__.py: F401
|
||||
ropgadget/loaders/elf.py: E126, E203, E222, E501, E701, N801, WPS114,
|
||||
WPS115, WPS120, WPS318, WPS339
|
||||
ropgadget/loaders/macho.py: E126, E203, E222, E501, N801, WPS114, WPS115,
|
||||
WPS120, WPS318, WPS339, WPS349
|
||||
ropgadget/loaders/pe.py: E126, E203, E222, E501, N801, WPS114, WPS115,
|
||||
WPS120, WPS318, WPS339, WPS349
|
||||
ropgadget/loaders/raw.py: E126, E222, E501, WPS318
|
||||
ropgadget/loaders/universal.py: E126, E501, N801, WPS114, WPS115, WPS120,
|
||||
WPS318, WPS328, WPS339, WPS519
|
||||
ropgadget/options.py: E501, S110
|
||||
ropgadget/ropchain/__init__.py: F401
|
||||
ropgadget/ropchain/arch/__init__.py: F401
|
||||
ropgadget/ropchain/arch/ropmakerx64.py: E501, S112, W605, WPS211, WPS327,
|
||||
WPS503
|
||||
ropgadget/ropchain/arch/ropmakerx86.py: E501, S112, W605, WPS211, WPS327,
|
||||
WPS503
|
||||
ropgadget/ropchain/ropmaker.py: E501, N400
|
||||
ropgadget/updateAlert.py: E501, I001, I003, S309, W605, WPS102, WPS301
|
||||
setup.py: E501
|
||||
|
||||
[isort]
|
||||
# isort configuration:
|
||||
# https://github.com/timothycrosley/isort/wiki/isort-Settings
|
||||
include_trailing_comma = true
|
||||
use_parentheses = true
|
||||
# See https://github.com/timothycrosley/isort#multi-line-output-modes
|
||||
multi_line_output = 3
|
||||
# Is the same as 80 in flake8:
|
||||
line_length = 100
|
||||
|
||||
|
||||
[darglint]
|
||||
# darglint configuration:
|
||||
# https://github.com/terrencepreilly/darglint
|
||||
strictness = long
|
@ -0,0 +1,71 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import os
|
||||
|
||||
from setuptools import setup
|
||||
|
||||
package_name = "ROPGadget"
|
||||
package_dir = "ropgadget"
|
||||
package_description = "This tool lets you search your gadgets on your binaries to facilitate your ROP exploitation."
|
||||
long_description = """
|
||||
ROPgadget supports ELF, PE, Mach-O, and Raw formats on x86, x64, ARM, ARM64, PowerPC, SPARC, MIPS, RISC-V 64, and RISC-V Compressed architectures.
|
||||
https://github.com/JonathanSalwan/ROPgadget
|
||||
""".strip()
|
||||
|
||||
|
||||
def fullsplit(path, result=None):
|
||||
"""
|
||||
Split a pathname into components (the opposite of os.path.join) in a
|
||||
platform-neutral way.
|
||||
"""
|
||||
if result is None:
|
||||
result = []
|
||||
head, tail = os.path.split(path)
|
||||
if head == '':
|
||||
return [tail] + result
|
||||
if head == path:
|
||||
return result
|
||||
return fullsplit(head, [tail] + result)
|
||||
|
||||
|
||||
# Compile the list of packages available, because distutils doesn't have
|
||||
# an easy way to do this.
|
||||
packages, data_files = [], []
|
||||
root_dir = os.path.dirname(__file__)
|
||||
if root_dir != '':
|
||||
os.chdir(root_dir)
|
||||
|
||||
for dirpath, dirnames, filenames in os.walk(package_dir):
|
||||
# Ignore dirnames that start with '.'
|
||||
for i, dirname in enumerate(dirnames):
|
||||
if dirname.startswith('.'):
|
||||
del dirnames[i]
|
||||
if '__init__.py' in filenames:
|
||||
packages.append('.'.join(fullsplit(dirpath)))
|
||||
elif filenames:
|
||||
data_files.append([dirpath, [os.path.join(dirpath, f) for f in filenames]])
|
||||
|
||||
version = "7.4"
|
||||
|
||||
setup(
|
||||
name = package_name,
|
||||
version = version,
|
||||
description = package_description,
|
||||
long_description = long_description,
|
||||
packages = packages,
|
||||
license = "BSD",
|
||||
author = "Jonathan Salwan",
|
||||
author_email = "jonathan.salwan@gmail.com",
|
||||
url = "https://github.com/JonathanSalwan/ROPgadget",
|
||||
scripts = ['scripts/ROPgadget'],
|
||||
install_requires = ['capstone>=5.0.1'],
|
||||
classifiers = [
|
||||
'Topic :: Security',
|
||||
'Environment :: Console',
|
||||
'Operating System :: OS Independent',
|
||||
'License :: OSI Approved :: BSD License',
|
||||
'Programming Language :: Python :: 2.7',
|
||||
'Programming Language :: Python :: 3',
|
||||
'Intended Audience :: Developers',
|
||||
],
|
||||
)
|
@ -0,0 +1 @@
|
||||
test_output
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -0,0 +1,69 @@
|
||||
#!/bin/bash
|
||||
|
||||
export PYTHONPATH=../
|
||||
if [ "$#" == "1" ]
|
||||
then
|
||||
RUN="python2 ../ROPgadget.py"
|
||||
else
|
||||
RUN="python3 ../ROPgadget.py"
|
||||
fi
|
||||
|
||||
rm -rf test_output
|
||||
|
||||
FILES=`ls | sort -f`
|
||||
for f in $FILES
|
||||
do
|
||||
if [ "$f" != "test.sh" ] && [ "$f" != "ref_output.bz2" ] && [ "$f" != "test_output" ]
|
||||
then
|
||||
echo "RUN $f" | tee -a ./test_output
|
||||
if [ "$f" == "raw-x86.raw" ]
|
||||
then
|
||||
$RUN --rawArch=x86 --rawMode=32 --depth 5 --binary $f 1>> ./test_output
|
||||
else
|
||||
$RUN --depth 5 --binary $f 1>> ./test_output
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
echo "RUN elf-Linux-x86 --ropchain" | tee -a ./test_output
|
||||
$RUN --binary ./elf-Linux-x86 --ropchain 1>> ./test_output
|
||||
echo "RUN elf-Linux-x86 --depth 3" | tee -a ./test_output
|
||||
$RUN --binary ./elf-Linux-x86 --depth 3 1>> ./test_output
|
||||
echo "RUN elf-Linux-x86 --string \"main\"" | tee -a ./test_output
|
||||
$RUN --binary ./elf-Linux-x86 --string "main" 1>> ./test_output
|
||||
echo "RUN elf-Linux-x86 --string \"m..n\"" | tee -a ./test_output
|
||||
$RUN --binary ./elf-Linux-x86 --string "m..n" 1>> ./test_output
|
||||
echo "RUN elf-Linux-x86 --opcode c9c3" | tee -a ./test_output
|
||||
$RUN --binary ./elf-Linux-x86 --opcode c9c3 1>> ./test_output
|
||||
echo "RUN elf-Linux-x86 --only \"mov|ret\"" | tee -a ./test_output
|
||||
$RUN --binary ./elf-Linux-x86 --only "mov|ret" 1>> ./test_output
|
||||
echo "RUN elf-Linux-x86 --only \"mov|pop|xor|ret\"" | tee -a ./test_output
|
||||
$RUN --binary ./elf-Linux-x86 --only "mov|pop|xor|ret" 1>> ./test_output
|
||||
echo "RUN elf-Linux-x86 --filter \"xchg|add|sub|cmov.*\"" | tee -a ./test_output
|
||||
$RUN --binary ./elf-Linux-x86 --filter "xchg|add|sub|cmov.*" 1>> ./test_output
|
||||
echo "RUN elf-Linux-x86 --norop --nosys" | tee -a ./test_output
|
||||
$RUN --binary ./elf-Linux-x86 --norop --nosys 1>> ./test_output
|
||||
echo "RUN elf-Linux-x86 --range 0x08041000-0x08042000" | tee -a ./test_output
|
||||
$RUN --binary ./elf-Linux-x86 --range 0x08041000-0x08042000 1>> ./test_output
|
||||
echo "RUN elf-Linux-x86 --string main --range 0x080c9aaa-0x080c9aba" | tee -a ./test_output
|
||||
$RUN --binary ./elf-Linux-x86 --string main --range 0x080c9aaa-0x080c9aba 1>> ./test_output
|
||||
echo "RUN elf-Linux-x86 --memstr \"/bin/sh\"" | tee -a ./test_output
|
||||
$RUN --binary ./elf-Linux-x86 --memstr "/bin/sh" 1>> ./test_output
|
||||
echo "RUN elf-Linux-x86 --badbytes \"00|01-1f|7f|42\"" | tee -a ./test_output
|
||||
$RUN --binary ./elf-Linux-x86 --badbytes "00|01-1f|7f|42" 1>> ./test_output
|
||||
echo "RUN elf-Linux-x86 --offset 5555e000 --badbytes \"00-20|80-ff\"" | tee -a ./test_output
|
||||
$RUN --binary ./elf-Linux-x86 --offset 5555e000 --badbytes "00-20|80-ff" 1>> ./test_output
|
||||
echo "RUN Linux_lib64.so --offset 0xdeadbeef00000000" | tee -a ./test_output
|
||||
$RUN --binary ./Linux_lib64.so --offset 0xdeadbeef00000000 1>> ./test_output
|
||||
echo "RUN elf-ARMv7-ls --depth 5" | tee -a ./test_output
|
||||
$RUN --binary ./elf-ARMv7-ls --depth 5 1>> ./test_output
|
||||
echo "RUN elf-ARM64-bash --depth 5" | tee -a ./test_output
|
||||
$RUN --binary ./elf-ARM64-bash --depth 5 1>> ./test_output
|
||||
echo "RUN elf-PPC64-bash --depth 5" | tee -a ./test_output
|
||||
$RUN --binary ./elf-PPC64-bash --depth 5 1>> ./test_output
|
||||
echo "RUN elf-Linux-RISCV_64 --depth 8" | tee -a ./test_output
|
||||
$RUN --binary ./elf-Linux-RISCV_64 --depth 8 1>> ./test_output
|
||||
echo "RUN elf-Linux-RISCV_32 --depth 8" | tee -a ./test_output
|
||||
$RUN --binary ./elf-Linux-RISCV_32 --depth 8 1>> ./test_output
|
||||
|
||||
diff test_output <(bunzip2 --stdout ref_output.bz2) 1>&2
|
Loading…
Reference in new issue