<gh_stars>1-10
# -*- coding:utf-8 -*- 
# Syscall module: building ropchains performing syscalls
from ropgenerator.core.IO import str_special, banner, str_bold, error, set_io_verbose
from ropgenerator.main.Utils import *
from ropgenerator.core.Architecture import *
from ropgenerator.main.Load import loaded_binary
from ropgenerator.core.Gadget import set_gadgets_offset
from ropgenerator.main.Scanner import set_binary_offset, get_readwrite_memory
from ropgenerator.core.ChainingEngine import *
import ropgenerator.exploit.syscall.SyscallLinuxX64 as LinuxX64
import ropgenerator.exploit.syscall.SyscallLinuxX86 as LinuxX86
from ropgenerator.exploit.Syscall import build_syscall
from ropgenerator.core.IO import *
import ropgenerator.exploit.Systems as Systems
from ropgenerator.core.ROPChain import ROPChain, PwnChain
from ropgenerator.exploit.Shellcode import select_shellcode
from ropgenerator.exploit.ChainingUtils import store_string

#############################
# DELIVER SHELLCODE COMMAND #
#############################

OPTION_OUTPUT = '--output-format'
OPTION_OUTPUT_SHORT = '-f'
# Options for output
OUTPUT_CONSOLE = 'console'
OUTPUT_PYTHON = 'python'
OUTPUT_RAW = 'raw'
OUTPUT = None # The one choosen 

OPTION_BAD_BYTES = '--bad-bytes'
OPTION_BAD_BYTES_SHORT = '-b'

OPTION_KEEP_REGS = '--keep-regs'
OPTION_KEEP_REGS_SHORT = '-k'

OPTION_OFFSET="--offset"
OPTION_OFFSET_SHORT = "-off"

OPTION_SHORTEST = '--shortest'
OPTION_SHORTEST_SHORT = '-s'

OPTION_LMAX = '--max-length'
OPTION_LMAX_SHORT = '-m'

OPTION_HELP = "--help"
OPTION_HELP_SHORT = "-h"

OPTION_RW_MEMORY = '--rw-memory'
OPTION_RW_MEMORY_SHORT = '-rw'

OPTION_VERBOSE = "--verbose"
OPTION_VERBOSE_SHORT = "-v"

CMD_DSHELL_HELP =  banner([str_bold("'(A)lloc (C)opy (E)xecute' command"),\
                    str_special("(Deliver a shellcode & Execute it)")])
CMD_DSHELL_HELP += "\n\n\t"+str_bold("Description:")+\
"\n\t\tThis method first creates an executable memory area,"+\
"\n\t\tthen copies a shellcode into this area, and finally"+\
"\n\t\tjumps to execute the shellcode"
CMD_DSHELL_HELP += "\n\n\t"+str_bold("Usage:")+\
"\n\t\tace <sys> [OPTIONS]"
CMD_DSHELL_HELP += "\n\n\t"+str_bold("Options")+":"
CMD_DSHELL_HELP += "\n\n\t\t"+str_special(OPTION_BAD_BYTES_SHORT)+","+str_special(OPTION_BAD_BYTES)+" <bytes>\t Bad bytes for payload.\n\t\t\t\t\t Expected format is a list of bytes \n\t\t\t\t\t separated by comas (e.g '-b 0A,0B,2F')"
CMD_DSHELL_HELP += "\n\n\t\t"+str_special(OPTION_KEEP_REGS_SHORT)+","+str_special(OPTION_KEEP_REGS)+" <regs>\t Registers that shouldn't be modified.\n\t\t\t\t\t Expected format is a list of registers \n\t\t\t\t\t separated by comas (e.g '-k edi,eax')"
CMD_DSHELL_HELP += "\n\n\t\t"+str_special(OPTION_OFFSET_SHORT)+","+\
    str_special(OPTION_OFFSET)+" <int>\t Offset to add to gadget addresses"   
CMD_DSHELL_HELP += "\n\n\t\t"+str_special(OPTION_RW_MEMORY_SHORT)+","+\
    str_special(OPTION_RW_MEMORY)+" <range>\t Usable read-write memory"
CMD_DSHELL_HELP += "\n\n\t\t"+str_special(OPTION_LMAX_SHORT)+","+str_special(OPTION_LMAX)+" <int>\t Max length of the ROPChain in bytes"
CMD_DSHELL_HELP += "\n\n\t\t"+str_special(OPTION_SHORTEST_SHORT)+","+str_special(OPTION_SHORTEST)+"\t\t Find the shortest matching ROP-Chains"
CMD_DSHELL_HELP += "\n\n\t\t"+str_special(OPTION_OUTPUT_SHORT)+","+\
    str_special(OPTION_OUTPUT)+\
    " <fmt> Output format for ropchains.\n\t\t\t\t\t Expected format is one of the\n\t\t\t\t\t following: "+\
    str_special(OUTPUT_CONSOLE)+','+str_special(OUTPUT_PYTHON)
    
CMD_DSHELL_HELP += "\n\n\t\t"+str_special(OPTION_VERBOSE_SHORT)+","+str_special(OPTION_VERBOSE)+"\t\t Print info while building ROP-Chain"
CMD_DSHELL_HELP += "\n\n\t\t"+str_special(OPTION_HELP_SHORT)+","+str_special(OPTION_HELP)+"\t\t Show this help"
CMD_DSHELL_HELP += "\n\n\t"+str_bold("Supported systems")+": "+', '.join([str_special(s) for s in Systems.available_systems_str()])
CMD_DSHELL_HELP += "\n\n\t"+str_bold("Range format")+": "+\
    str_special("<lower_address>")+","+str_special("<higher_address>")

CMD_DSHELL_HELP += "\n\n\t"+str_bold("Examples")+": "+\
    "\n\t\tace LINUX -b 80,E2 -off 0x40178 -m 2000"+\
    "\n\t\tace LINUX -rw 0x30000,0x30100 -f python -s"

def print_help():
    print(CMD_DSHELL_HELP)

def deliver_shellcode(args):
    global OUTPUT, OUTPUT_CONSOLE, OUTPUT_PYTHON

    if( not args):
        print_help()
        return
    OUTPUT = OUTPUT_CONSOLE
    offset = 0
    i = 0
    seenOutput = False
    seenBadBytes = False
    seenKeepRegs = False
    seenShortest = False
    seenLmax = False
    seenOffset = False
    seenRw = False
    bad_bytes = []
    keep_regs = []
    lmax = get_default_lmax()*6 # 6 is an arbitrary value here
    lower_valid_write_addr = 0
    higher_valid_write_addr = 0
    verbose = False
    
    # Parsing arguments
    # First argument must be the target OS
    if( len(args) == 0 ):
        error("Missing arguments")
        return
    system = Systems.str_to_target_system(args[0])
    if( system is None):
        error("Unsupported system '"+args[0]+"'")
        print(str_bold("\tSupported systems")+": "+', '.join([str_special(s) for s in Systems.available_systems_str()]))
        return
    # Then parse the options  
    args = args[1:]
    while i < len(args):
        arg = args[i]
        if( args[i] in [OPTION_BAD_BYTES, OPTION_BAD_BYTES_SHORT]):
            if( seenBadBytes ):
                error( "'" + arg + "' option should be used only once.")
                return 
            if( i+1 >= len(args)):
                error("Missing bad bytes after option '"+arg+"'")
                return 
            seenBadBytes = True
            (success, bad_bytes) = parse_bad_bytes(args[i+1])
            if( not success ):
                error(bad_bytes)
                return
            i = i+1
        elif( args[i] in [OPTION_KEEP_REGS, OPTION_KEEP_REGS_SHORT]):
            if( seenKeepRegs ):
                error( "'" + arg + "' option should be used only once.")
                return 
            if( i+1 >= len(args)):
                error("Missing registers after option '"+arg+"'")
                return 
            seenKeepRegs = True
            (success, keep_regs) = parse_keep_regs(args[i+1])
            if( not success ):
                error(keep_regs)
                return
            i = i+1
        elif( args[i] == OPTION_OFFSET or args[i] == OPTION_OFFSET_SHORT ):
            if( seenOffset ):
                error("'" + arg + "' option should be used only once.")
                return 
            if( i+1 >= len(args)):
                error("Missing output format after option '"+arg+"'")
                return
            (success, offset) = parse_offset(args[i+1])
            if( not success ):
                error(offset)
                return
            i = i+1
            seenOffset = True
        elif( args[i] in [OPTION_RW_MEMORY, OPTION_RW_MEMORY_SHORT]):
            if( seenRw ):
                error( "'" + arg + "' option should be used only once.")
                return 
            if( i+1 >= len(args)):
                error("Missing address range after option '"+arg+"'")
                return 
            seenRw = True
            (success, addr_range) = parse_range(args[i+1])
            if( not success ):
                error(addr_range)
                return
            (lower_valid_write_addr, higher_valid_write_addr) = addr_range
            i = i+1
        elif( args[i] in [OPTION_SHORTEST, OPTION_SHORTEST_SHORT]):
            if( seenShortest ):
                error("'" + arg + "' option should be used only once.")
                return 
            seenShortest = True
        elif( args[i] == OPTION_LMAX or args[i] == OPTION_LMAX_SHORT ):
            if( seenLmax ):
                error("'" + arg + "' option should be used only once.")
                return 
            if( i+1 >= len(args)):
                error("Missing length after option '"+arg+"'")
                return 
            (success, lmax) = parse_lmax(args[i+1])
            if( not success ):
                error(lmax)
                return 
            i = i +1 
            seenLmax = True
        elif( args[i] in [OPTION_OUTPUT, OPTION_OUTPUT_SHORT]):
            if( seenOutput ):
                error("'" + arg + "' option should be used only once.")
                return 
            if( i+1 >= len(args)):
                error("Missing output format after option '"+arg+"'")
                return 
            if( args[i+1] in [OUTPUT_CONSOLE, OUTPUT_PYTHON]):
                OUTPUT = args[i+1]
                seenOutput = True
                i = i +1
            else:
                error("'" + args[i+1] + "' output format is not supported")
                return  
        elif( args[i] in [OPTION_VERBOSE, OPTION_VERBOSE_SHORT]):
            verbose = True
        elif( args[i] in [OPTION_HELP, OPTION_HELP_SHORT]):
            print_help()
            return 
        else:
            error("Error. Unknown option '{}'".format(args[i]))
            return 
        i += 1

    # Check if the user loaded some binaries 
    if( not loaded_binary() ):
        error("You should load a binary before building ROPChains")
        return 
    # Check for valid writable memory to copy strings
    if( lower_valid_write_addr == 0 ):
        (lower_valid_write_addr,higher_valid_write_addr) = get_readwrite_memory() 
    # Select shellcode 
    (shellcode, description) = select_shellcode(curr_arch_type())    
    if( shellcode is None ):
        return 
    # Set offset 
    set_gadgets_offset(offset)
    set_binary_offset(offset)
    # Set verbose
    set_io_verbose(verbose)
    # Build the ropchain
    print('')
    info("Building exploit: Alloc-Copy-Execute strategy \n\n")
    params = SearchParametersBinding(keep_regs, bad_bytes, lmax, seenShortest, lower_valid_write_addr=lower_valid_write_addr, higher_valid_write_addr=higher_valid_write_addr)
    res = deliver_shellcode_build(shellcode, params, system)
    # Print result 
    if( res is None ):
        error("No matching ROPChain found")
    elif( isinstance(res, str) ):
        error(res)
    else:
        print('')
        if( OUTPUT == OUTPUT_CONSOLE ):
            print(res.to_str_console(curr_arch_octets(), bad_bytes ))
        elif( OUTPUT == OUTPUT_PYTHON ):
            print(res.to_str_python(curr_arch_octets(), bad_bytes ))
    # Reset offset 
    set_gadgets_offset(0)
    set_binary_offset(0)
    # Reset verbose
    set_io_verbose(False)

def deliver_shellcode_build(shellcode, params, system):
    if( system == Systems.TargetSystem.Linux ):
        return deliver_shellcode_build_linux(shellcode, params)
    else:
        return "Not yet supported for this system :'("

def deliver_shellcode_build_linux( shellcode, params):
    saved_lmax = params.lmax
    # Deliver shellcode 
    notify("Building chain to copy shellcode in memory")
    verbose("{}/{} bytes available".format(params.lmax*curr_arch_octets(),params.lmax*curr_arch_octets()))
    (shellcode_address, copy_chain) = store_string(bytes_to_str(shellcode), params, Systems.TargetSystem.Linux)
    if( copy_chain is None ):
        verbose("Fatal: couldn't copy shellcode into memory")
        return None
    elif( isinstance(copy_chain, str)):
        verbose("Fatal: " + copy_chain)
        return None
    address = shellcode_address
    shellcode_address_str = hex(address)
    
    # Building mprotect 
    notify("Building mprotect() chain")
    # Getting page to make executable
    # Arg of mprotect MUST be a valid multiple of page size 
    over_page_size = shellcode_address % curr_arch_min_page_size()
    page_address = shellcode_address - over_page_size
    length = len(shellcode)+1+over_page_size
    flag = 7 
    params.lmax -= copy_chain.len()
    verbose("{}/{} bytes available".format(params.lmax*curr_arch_octets(),saved_lmax*curr_arch_octets()))
    if( params.lmax <= 0 ):
        verbose("Fatal: max length was reached")
        return None
    mprotect_args = [page_address, length, flag]
    mprotect_chain = build_syscall("mprotect", mprotect_args, params, Systems.TargetSystem.Linux, chainable=True)
    if( mprotect_chain is None ):
        verbose("Fatal: couldn't build call to mprotect")
        return None
    elif( isinstance(mprotect_chain, str)):
        verbose("Fatal: "+mprotect_chain)
        return None
    
    # Jump to shellcode 
    notify("Building chain to jump to shellcode") 
    params.lmax -= mprotect_chain.len()
    verbose("{}/{} bytes available".format(params.lmax*curr_arch_octets(),saved_lmax*curr_arch_octets()))
    if( params.lmax <= 0 ):
        verbose("Fatal: max length was reached")
        return None
    jmp_chain_res = search(DestArg(DestType.REG, curr_arch_ip()), AssignArg(AssignType.CST, shellcode_address), params)
    if( not jmp_chain_res.found ):
        verbose("Fatal: couldn't jump to shellcode")
        return None
    else:
        jmp_chain = jmp_chain_res.chain
    
    # Build PwnChain res and return
    res = PwnChain()
    res.add_chain(mprotect_chain, "Call mprotect({},{},{})".format(hex(page_address), length, flag))
    res.add_chain(copy_chain, "Copy shellcode to {}".format(shellcode_address_str)) 
    res.add_chain(jmp_chain, "Jump to shellcode (at {})".format(shellcode_address_str))
    return res 
    
def deliver_shellcode_build_windows(params):
    return None

# -*- coding:utf-8 -*- 
# Syscall module: building ropchains performing syscalls
from ropgenerator.core.IO import str_special, banner, str_bold, error, set_io_verbose
from ropgenerator.main.Utils import *
from ropgenerator.core.Architecture import *
from ropgenerator.main.Load import loaded_binary
from ropgenerator.core.Gadget import set_gadgets_offset
from ropgenerator.main.Scanner import set_binary_offset, get_readwrite_memory
from ropgenerator.core.ChainingEngine import *
import ropgenerator.exploit.syscall.SyscallLinuxX64 as LinuxX64
import ropgenerator.exploit.syscall.SyscallLinuxX86 as LinuxX86
from ropgenerator.exploit.Syscall import build_syscall
from ropgenerator.core.IO import *
import ropgenerator.exploit.Systems as Systems
from ropgenerator.core.ROPChain import ROPChain, PwnChain
from ropgenerator.exploit.Shellcode import select_shellcode
from ropgenerator.exploit.ChainingUtils import store_string

#############################
# DELIVER SHELLCODE COMMAND #
#############################

OPTION_OUTPUT = '--output-format'
OPTION_OUTPUT_SHORT = '-f'
# Options for output
OUTPUT_CONSOLE = 'console'
OUTPUT_PYTHON = 'python'
OUTPUT_RAW = 'raw'
OUTPUT = None # The one choosen 

OPTION_BAD_BYTES = '--bad-bytes'
OPTION_BAD_BYTES_SHORT = '-b'

OPTION_KEEP_REGS = '--keep-regs'
OPTION_KEEP_REGS_SHORT = '-k'

OPTION_OFFSET="--offset"
OPTION_OFFSET_SHORT = "-off"

OPTION_SHORTEST = '--shortest'
OPTION_SHORTEST_SHORT = '-s'

OPTION_LMAX = '--max-length'
OPTION_LMAX_SHORT = '-m'

OPTION_HELP = "--help"
OPTION_HELP_SHORT = "-h"

OPTION_RW_MEMORY = '--rw-memory'
OPTION_RW_MEMORY_SHORT = '-rw'

OPTION_VERBOSE = "--verbose"
OPTION_VERBOSE_SHORT = "-v"

CMD_DSHELL_HELP =  banner([str_bold("'(A)lloc (C)opy (E)xecute' command"),\
                    str_special("(Deliver a shellcode & Execute it)")])
CMD_DSHELL_HELP += "\n\n\t"+str_bold("Description:")+\
"\n\t\tThis method first creates an executable memory area,"+\
"\n\t\tthen copies a shellcode into this area, and finally"+\
"\n\t\tjumps to execute the shellcode"
CMD_DSHELL_HELP += "\n\n\t"+str_bold("Usage:")+\
"\n\t\tace <sys> [OPTIONS]"
CMD_DSHELL_HELP += "\n\n\t"+str_bold("Options")+":"
CMD_DSHELL_HELP += "\n\n\t\t"+str_special(OPTION_BAD_BYTES_SHORT)+","+str_special(OPTION_BAD_BYTES)+" <bytes>\t Bad bytes for payload.\n\t\t\t\t\t Expected format is a list of bytes \n\t\t\t\t\t separated by comas (e.g '-b 0A,0B,2F')"
CMD_DSHELL_HELP += "\n\n\t\t"+str_special(OPTION_KEEP_REGS_SHORT)+","+str_special(OPTION_KEEP_REGS)+" <regs>\t Registers that shouldn't be modified.\n\t\t\t\t\t Expected format is a list of registers \n\t\t\t\t\t separated by comas (e.g '-k edi,eax')"
CMD_DSHELL_HELP += "\n\n\t\t"+str_special(OPTION_OFFSET_SHORT)+","+\
    str_special(OPTION_OFFSET)+" <int>\t Offset to add to gadget addresses"   
CMD_DSHELL_HELP += "\n\n\t\t"+str_special(OPTION_RW_MEMORY_SHORT)+","+\
    str_special(OPTION_RW_MEMORY)+" <range>\t Usable read-write memory"
CMD_DSHELL_HELP += "\n\n\t\t"+str_special(OPTION_LMAX_SHORT)+","+str_special(OPTION_LMAX)+" <int>\t Max length of the ROPChain in bytes"
CMD_DSHELL_HELP += "\n\n\t\t"+str_special(OPTION_SHORTEST_SHORT)+","+str_special(OPTION_SHORTEST)+"\t\t Find the shortest matching ROP-Chains"
CMD_DSHELL_HELP += "\n\n\t\t"+str_special(OPTION_OUTPUT_SHORT)+","+\
    str_special(OPTION_OUTPUT)+\
    " <fmt> Output format for ropchains.\n\t\t\t\t\t Expected format is one of the\n\t\t\t\t\t following: "+\
    str_special(OUTPUT_CONSOLE)+','+str_special(OUTPUT_PYTHON)
    
CMD_DSHELL_HELP += "\n\n\t\t"+str_special(OPTION_VERBOSE_SHORT)+","+str_special(OPTION_VERBOSE)+"\t\t Print info while building ROP-Chain"
CMD_DSHELL_HELP += "\n\n\t\t"+str_special(OPTION_HELP_SHORT)+","+str_special(OPTION_HELP)+"\t\t Show this help"
CMD_DSHELL_HELP += "\n\n\t"+str_bold("Supported systems")+": "+', '.join([str_special(s) for s in Systems.available_systems_str()])
CMD_DSHELL_HELP += "\n\n\t"+str_bold("Range format")+": "+\
    str_special("<lower_address>")+","+str_special("<higher_address>")

CMD_DSHELL_HELP += "\n\n\t"+str_bold("Examples")+": "+\
    "\n\t\tace LINUX -b 80,E2 -off 0x40178 -m 2000"+\
    "\n\t\tace LINUX -rw 0x30000,0x30100 -f python -s"

def print_help():
    print(CMD_DSHELL_HELP)

def deliver_shellcode(args):
    global OUTPUT, OUTPUT_CONSOLE, OUTPUT_PYTHON

    if( not args):
        print_help()
        return
    OUTPUT = OUTPUT_CONSOLE
    offset = 0
    i = 0
    seenOutput = False
    seenBadBytes = False
    seenKeepRegs = False
    seenShortest = False
    seenLmax = False
    seenOffset = False
    seenRw = False
    bad_bytes = []
    keep_regs = []
    lmax = get_default_lmax()*6 # 6 is an arbitrary value here
    lower_valid_write_addr = 0
    higher_valid_write_addr = 0
    verbose = False
    
    # Parsing arguments
    # First argument must be the target OS
    if( len(args) == 0 ):
        error("Missing arguments")
        return
    system = Systems.str_to_target_system(args[0])
    if( system is None):
        error("Unsupported system '"+args[0]+"'")
        print(str_bold("\tSupported systems")+": "+', '.join([str_special(s) for s in Systems.available_systems_str()]))
        return
    # Then parse the options  
    args = args[1:]
    while i < len(args):
        arg = args[i]
        if( args[i] in [OPTION_BAD_BYTES, OPTION_BAD_BYTES_SHORT]):
            if( seenBadBytes ):
                error( "'" + arg + "' option should be used only once.")
                return 
            if( i+1 >= len(args)):
                error("Missing bad bytes after option '"+arg+"'")
                return 
            seenBadBytes = True
            (success, bad_bytes) = parse_bad_bytes(args[i+1])
            if( not success ):
                error(bad_bytes)
                return
            i = i+1
        elif( args[i] in [OPTION_KEEP_REGS, OPTION_KEEP_REGS_SHORT]):
            if( seenKeepRegs ):
                error( "'" + arg + "' option should be used only once.")
                return 
            if( i+1 >= len(args)):
                error("Missing registers after option '"+arg+"'")
                return 
            seenKeepRegs = True
            (success, keep_regs) = parse_keep_regs(args[i+1])
            if( not success ):
                error(keep_regs)
                return
            i = i+1
        elif( args[i] == OPTION_OFFSET or args[i] == OPTION_OFFSET_SHORT ):
            if( seenOffset ):
                error("'" + arg + "' option should be used only once.")
                return 
            if( i+1 >= len(args)):
                error("Missing output format after option '"+arg+"'")
                return
            (success, offset) = parse_offset(args[i+1])
            if( not success ):
                error(offset)
                return
            i = i+1
            seenOffset = True
        elif( args[i] in [OPTION_RW_MEMORY, OPTION_RW_MEMORY_SHORT]):
            if( seenRw ):
                error( "'" + arg + "' option should be used only once.")
                return 
            if( i+1 >= len(args)):
                error("Missing address range after option '"+arg+"'")
                return 
            seenRw = True
            (success, addr_range) = parse_range(args[i+1])
            if( not success ):
                error(addr_range)
                return
            (lower_valid_write_addr, higher_valid_write_addr) = addr_range
            i = i+1
        elif( args[i] in [OPTION_SHORTEST, OPTION_SHORTEST_SHORT]):
            if( seenShortest ):
                error("'" + arg + "' option should be used only once.")
                return 
            seenShortest = True
        elif( args[i] == OPTION_LMAX or args[i] == OPTION_LMAX_SHORT ):
            if( seenLmax ):
                error("'" + arg + "' option should be used only once.")
                return 
            if( i+1 >= len(args)):
                error("Missing length after option '"+arg+"'")
                return 
            (success, lmax) = parse_lmax(args[i+1])
            if( not success ):
                error(lmax)
                return 
            i = i +1 
            seenLmax = True
        elif( args[i] in [OPTION_OUTPUT, OPTION_OUTPUT_SHORT]):
            if( seenOutput ):
                error("'" + arg + "' option should be used only once.")
                return 
            if( i+1 >= len(args)):
                error("Missing output format after option '"+arg+"'")
                return 
            if( args[i+1] in [OUTPUT_CONSOLE, OUTPUT_PYTHON]):
                OUTPUT = args[i+1]
                seenOutput = True
                i = i +1
            else:
                error("'" + args[i+1] + "' output format is not supported")
                return  
        elif( args[i] in [OPTION_VERBOSE, OPTION_VERBOSE_SHORT]):
            verbose = True
        elif( args[i] in [OPTION_HELP, OPTION_HELP_SHORT]):
            print_help()
            return 
        else:
            error("Error. Unknown option '{}'".format(args[i]))
            return 
        i += 1

    # Check if the user loaded some binaries 
    if( not loaded_binary() ):
        error("You should load a binary before building ROPChains")
        return 
    # Check for valid writable memory to copy strings
    if( lower_valid_write_addr == 0 ):
        (lower_valid_write_addr,higher_valid_write_addr) = get_readwrite_memory() 
    # Select shellcode 
    (shellcode, description) = select_shellcode(curr_arch_type())    
    if( shellcode is None ):
        return 
    # Set offset 
    set_gadgets_offset(offset)
    set_binary_offset(offset)
    # Set verbose
    set_io_verbose(verbose)
    # Build the ropchain
    print('')
    info("Building exploit: Alloc-Copy-Execute strategy \n\n")
    params = SearchParametersBinding(keep_regs, bad_bytes, lmax, seenShortest, lower_valid_write_addr=lower_valid_write_addr, higher_valid_write_addr=higher_valid_write_addr)
    res = deliver_shellcode_build(shellcode, params, system)
    # Print result 
    if( res is None ):
        error("No matching ROPChain found")
    elif( isinstance(res, str) ):
        error(res)
    else:
        print('')
        if( OUTPUT == OUTPUT_CONSOLE ):
            print(res.to_str_console(curr_arch_octets(), bad_bytes ))
        elif( OUTPUT == OUTPUT_PYTHON ):
            print(res.to_str_python(curr_arch_octets(), bad_bytes ))
    # Reset offset 
    set_gadgets_offset(0)
    set_binary_offset(0)
    # Reset verbose
    set_io_verbose(False)

def deliver_shellcode_build(shellcode, params, system):
    if( system == Systems.TargetSystem.Linux ):
        return deliver_shellcode_build_linux(shellcode, params)
    else:
        return "Not yet supported for this system :'("

def deliver_shellcode_build_linux( shellcode, params):
    saved_lmax = params.lmax
    # Deliver shellcode 
    notify("Building chain to copy shellcode in memory")
    verbose("{}/{} bytes available".format(params.lmax*curr_arch_octets(),params.lmax*curr_arch_octets()))
    (shellcode_address, copy_chain) = store_string(bytes_to_str(shellcode), params, Systems.TargetSystem.Linux)
    if( copy_chain is None ):
        verbose("Fatal: couldn't copy shellcode into memory")
        return None
    elif( isinstance(copy_chain, str)):
        verbose("Fatal: " + copy_chain)
        return None
    address = shellcode_address
    shellcode_address_str = hex(address)
    
    # Building mprotect 
    notify("Building mprotect() chain")
    # Getting page to make executable
    # Arg of mprotect MUST be a valid multiple of page size 
    over_page_size = shellcode_address % curr_arch_min_page_size()
    page_address = shellcode_address - over_page_size
    length = len(shellcode)+1+over_page_size
    flag = 7 
    params.lmax -= copy_chain.len()
    verbose("{}/{} bytes available".format(params.lmax*curr_arch_octets(),saved_lmax*curr_arch_octets()))
    if( params.lmax <= 0 ):
        verbose("Fatal: max length was reached")
        return None
    mprotect_args = [page_address, length, flag]
    mprotect_chain = build_syscall("mprotect", mprotect_args, params, Systems.TargetSystem.Linux, chainable=True)
    if( mprotect_chain is None ):
        verbose("Fatal: couldn't build call to mprotect")
        return None
    elif( isinstance(mprotect_chain, str)):
        verbose("Fatal: "+mprotect_chain)
        return None
    
    # Jump to shellcode 
    notify("Building chain to jump to shellcode") 
    params.lmax -= mprotect_chain.len()
    verbose("{}/{} bytes available".format(params.lmax*curr_arch_octets(),saved_lmax*curr_arch_octets()))
    if( params.lmax <= 0 ):
        verbose("Fatal: max length was reached")
        return None
    jmp_chain_res = search(DestArg(DestType.REG, curr_arch_ip()), AssignArg(AssignType.CST, shellcode_address), params)
    if( not jmp_chain_res.found ):
        verbose("Fatal: couldn't jump to shellcode")
        return None
    else:
        jmp_chain = jmp_chain_res.chain
    
    # Build PwnChain res and return
    res = PwnChain()
    res.add_chain(mprotect_chain, "Call mprotect({},{},{})".format(hex(page_address), length, flag))
    res.add_chain(copy_chain, "Copy shellcode to {}".format(shellcode_address_str)) 
    res.add_chain(jmp_chain, "Jump to shellcode (at {})".format(shellcode_address_str))
    return res 
    
def deliver_shellcode_build_windows(params):
    return None
# -*- coding:utf-8 -*- # Syscall module: building ropchains performing syscalls ############################# # DELIVER SHELLCODE COMMAND # ############################# # Options for output # The one choosen # 6 is an arbitrary value here # Parsing arguments # First argument must be the target OS # Then parse the options # Check if the user loaded some binaries # Check for valid writable memory to copy strings # Select shellcode # Set offset # Set verbose # Build the ropchain # Print result # Reset offset # Reset verbose # Deliver shellcode # Building mprotect # Getting page to make executable # Arg of mprotect MUST be a valid multiple of page size # Jump to shellcode # Build PwnChain res and return