#!/usr/bin/python3

import angr
import claripy

proj = angr.Project(
	'crackme', 
	main_opts = {'base_addr': 0x0}, 
	load_options = {'auto_load_libs': False}
)

# Flag is 10 characters
flag = claripy.BVS("flag", 8 * 10)

state = proj.factory.entry_state(stdin = flag) 

# Silence the warnings
state.options.add(angr.options.ZERO_FILL_UNCONSTRAINED_MEMORY)

# Flags consists only on numbers ('0' -> '9')
for i in range(10):
    state.solver.add(flag.get_byte(i) >= 48)
    state.solver.add(flag.get_byte(i) <= 57)

sm = proj.factory.simulation_manager(state)

FIND_ADDR = 0x1219   # 'Congratualtions ...' message
AVOID_ADDR = 0x1227  # 'Try again ...' message

sm.explore(find = FIND_ADDR, avoid = AVOID_ADDR)
示例#2
0
    def __init__(self, binary, input=None, pov_file=None, simprocedures=None,
                 hooks=None, seed=None, preconstrain_input=True,
                 preconstrain_flag=True, resiliency=True, chroot=None,
                 add_options=None, remove_options=None, trim_history=True,
                 project=None, dump_syscall=False, dump_cache=True,
                 max_size = None, exclude_sim_procedures_list=None,
                 argv = None):
        """
        :param binary: path to the binary to be traced
        :param input: concrete input string to feed to binary
        :param povfile: CGC PoV describing the input to trace
        :param hooks: A dictionary of hooks to add
        :param simprocedures: dictionary of replacement simprocedures
        :param seed: optional seed used for randomness, will be passed to QEMU
        :param preconstrain_input: should the path be preconstrained to the
            provided input
        :param preconstrain_flag: should the path have the cgc flag page
            preconstrained
        :param resiliency: should we continue to step forward even if qemu and
            angr disagree?
        :param chroot: trace the program as though it were executing in a
            chroot
        :param add_options: add options to the state which used to do tracing
        :param remove_options: remove options from the state which is used to
            do tracing
        :param trim_history: Trim the history of a path.
        :param project: The original project.
        :param dump_syscall: True if we want to dump the syscall information
        :param max_size: Optionally set max size of input. Defaults to size
            of preconstrained input.
        :param exclude_sim_procedures_list: What SimProcedures to hook or not
            at load time. Defaults to ["malloc","free","calloc","realloc"]
        :param argv: Optionally specify argv params (i,e,: ['./calc', 'parm1'])
            defaults to binary name with no params.
        """

        self.binary = binary
        self.input = input
        self.pov_file = pov_file
        self.preconstrain_input = preconstrain_input
        self.preconstrain_flag = preconstrain_flag
        self.simprocedures = {} if simprocedures is None else simprocedures
        self._hooks = {} if hooks is None else hooks
        self.input_max_size = max_size or len(input)
        self.exclude_sim_procedures_list = exclude_sim_procedures_list or ["malloc","free","calloc","realloc"]
        self.argv = argv or [binary]

        for h in self._hooks:
            l.debug("Hooking %#x -> %s", h, self._hooks[h].__name__)

        if isinstance(seed, (int, long)):
            seed = str(seed)
        self.seed = seed
        self.resiliency = resiliency
        self.chroot = chroot
        self.add_options = set() if add_options is None else add_options
        self.trim_history = trim_history
        self.constrained_addrs = []
        # the final state after execution with input/pov_file
        self.final_state = None
        # the path after execution with input/pov_file
        self.path = None

        cm = LocalCacheManager(dump_cache=dump_cache) if GlobalCacheManager is None else GlobalCacheManager
        # cache managers need the tracer to be set for them
        self._cache_manager = cm
        self._cache_manager.set_tracer(self)

        # set by a cache manager
        self._loaded_from_cache = False

        if remove_options is None:
            self.remove_options = set()
        else:
            self.remove_options = remove_options

        if self.pov_file is None and self.input is None:
            raise ValueError("must specify input or pov_file")

        if self.pov_file is not None and self.input is not None:
            raise ValueError("cannot specify both a pov_file and an input")

        # validate seed
        if self.seed is not None:
            try:
                iseed = int(self.seed)
                if iseed > 4294967295 or iseed < 0:
                    raise ValueError
            except ValueError:
                raise ValueError(
                    "the passed seed is either not an integer or is not between 0 and UINT_MAX"
                    )

        # set up cache hook
        receive.cache_hook = self._cache_manager.cacher

        # a PoV was provided
        if self.pov_file is not None:
            self.pov_file = TracerPoV(self.pov_file)
            self.pov = True
        else:
            self.pov = False

        # internal project object, useful for obtaining certain kinds of info
        if project is None:
            self._p = angr.Project(self.binary)
        else:
            self._p = project
        self.base = None
        self.tracer_qemu = None
        self.tracer_qemu_path = None
        self._setup()

        l.debug("accumulating basic block trace...")
        l.debug("self.tracer_qemu_path: %s", self.tracer_qemu_path)

        # does the input cause a crash?
        self.crash_mode = False
        # if the input causes a crash, what address does it crash at?
        self.crash_addr = None

        self.crash_state = None

        self.crash_type = None

        # CGC flag data
        self.cgc_flag_bytes = [claripy.BVS("cgc-flag-byte-%d" % i, 8) for i in xrange(0x1000)]

        # content of the magic flag page as reported by QEMU
        # we need this to keep symbolic traces following the same path
        # as their dynamic counterpart
        self._magic_content = None

        # will set crash_mode correctly and also discover the QEMU base addr
        self.trace = self.dynamic_trace()

        l.info("trace consists of %d basic blocks", len(self.trace))

        # Check if we need to rebase to QEMU's addr
        if self.qemu_base_addr != self._p.loader.main_bin.get_min_addr():
            l.warn("Our base address doesn't match QEMU's. Changing ours to 0x%x",self.qemu_base_addr)

        self.preconstraints = []

        # map of variable string names to preconstraints, for re-applying
        # constraints
        self.variable_map = {}

        # initialize the basic block counter to 0
        self.bb_cnt = 0

        # keep track of the last basic block we hit
        self.previous = None
        self.previous_addr = None

        # whether we should follow the qemu trace
        self.no_follow = False

        # this will be set by _prepare_paths
        self.unicorn_enabled = False

        # initilize the syscall statistics if the flag is on
        self._dump_syscall = dump_syscall
        if self._dump_syscall:
            self._syscall = []

        self.path_group = self._prepare_paths()

        # this is used to track constrained addresses
        self._address_concretization = []
示例#3
0
def scan_target(file_path, target_addr):
    """
    Scans the target binary for memory vulnurabilites
    """
    logging.getLogger('angr.anager').setLevel(logging.CRITICAL)

    if not os.path.isfile(file_path):
        subprocess.call("make clean",
                        cwd=os.path.dirname(file_path),
                        shell=True)
    subprocess.call("make", cwd=os.path.dirname(file_path), shell=True)
    project = angr.Project(file_path,\
            load_options={'auto_load_libs':False})
    print("Architecture: " + project.arch.name + " Starting at address:  " +
          hex(project.entry))
    print("Endianness: " + project.arch.memory_endness)

    assert project.loader.aslr == False, "ASLR is enabled, analysis is not possible"
    assert project.loader.main_object.execstack == True, "Stack is not executable"
    assert project.loader.main_object.pic == False, "Position Independant Code\
    enabled"

    entry_block = project.factory.block(project.entry)
    entry_block.pp()
    cfg = project.analyses.CFG()

    def get_func_addr(func_name, plt=None):
        """
        Returns function address of a non stripped binary
        """
        found = [
            addr for addr, func in cfg.kb.functions.items()
            if func_name == func.name and (plt is None or func.is_plt == plt)
        ]
        if len(found) > 0:
            print("Found " + func_name + "'s address at " + hex(found[0]) +
                  "!")
            return found[0]
        else:
            raise Exception("No address found for function : " + func_name)

    argv = [project.filename]

    sym_arg_size = 550

    sym_arg = claripy.BVS('sym_arg', 8 * sym_arg_size)
    argv.append(sym_arg)
    argv.append("Found-the-canary")

    state = project.factory.entry_state(args=argv)

    target_addr[0] = get_func_addr("exit")
    exit_addr = get_func_addr("exit")
    strcpy_addr = get_func_addr("strcpy")
    strcat_addr = get_func_addr("strcat")

    sm = project.factory.simulation_manager(state)

    def find_vuln_func(state):
        """
        'Lambda' to simulation manager that returns true if the address of strcpy is found
        """
        if (state.ip.args[0] == strcpy_addr):
            print("Strcpy found during simulation!")
            bv_strcpy_mem = state.memory.load(state.regs.rdi, len(argv[1]))
            strcpy_src = state.solver.eval(bv_strcpy_mem, cast_to=bytes)
            return True if argv[2].encode() in strcpy_src else False
        elif (state.ip.args[0] == strcat_addr):
            print("Strcat found during simulation!")
            bv_strcat_mem = state.memory.load(state.regs.rdi, len(argv[1]))
            strcat_src = state.solver.eval(bv_strcat_mem, cast_to=bytes)
            return True if argv[2].encode() in strcat_src else False
        else:
            return False

    sm = sm.explore(find=find_vuln_func, avoid=(exit_addr, ))
    found = sm.found
    result = ""
    if len(found) > 0:
        print(f"Number of possible exploits: {len(sm.found)}")
        found = sm.found[0]
        print(found.solver.eval(sm.found[0].regs.rbp, cast_to=bytes))
        result = found.solver.eval(argv[1], cast_to=bytes)
    else:
        result = "ERROR: Could not find any paths!"
    buffer_size = found.solver.eval(found.regs.rbp - found.regs.rdi,
                                    cast_to=int)
    return (result, buffer_size)
示例#4
0
def main(argv):
    path_to_binary = argv[1]
    project = angr.Project(path_to_binary)

    # Make a symbolic input that has a decent size to trigger overflow
    # (!)
    symbolic_input = claripy.BVS("input", 100 * 8)

    # Create initial state and set stdin to the symbolic input
    initial_state = project.factory.entry_state(
        stdin=symbolic_input,
        add_options={
            angr.options.SYMBOL_FILL_UNCONSTRAINED_MEMORY,
            angr.options.SYMBOL_FILL_UNCONSTRAINED_REGISTERS
        })

    # The save_unconstrained=True parameter specifies to Angr to not throw out
    # unconstrained states. Instead, it will move them to the list called
    # 'simulation.unconstrained'.  Additionally, we will be using a few stashes
    # that are not included by default, such as 'found' and 'not_needed'. You will
    # see how these are used later.
    # (!)
    simulation = project.factory.simgr(initial_state,
                                       save_unconstrained=True,
                                       stashes={
                                           'active': [initial_state],
                                           'unconstrained': [],
                                           'found': [],
                                           'not_needed': []
                                       })

    # Explore will not work for us, since the method specified with the 'find'
    # parameter will not be called on an unconstrained state. Instead, we want to
    # explore the binary ourselves. To get started, construct an exit condition
    # to know when the simulation has found a solution. We will later move
    # states from the unconstrained list to the simulation.found list.
    # Create a boolean value that indicates a state has been found.
    def has_found_solution():
        return simulation.found

    # An unconstrained state occurs when there are too many possible branches
    # from a single instruction. This occurs, among other ways, when the
    # instruction pointer (on x86, eip) is completely symbolic, meaning
    # that user input can control the address of code the computer executes.
    # For example, imagine the following pseudo assembly:
    #
    # mov user_input, eax
    # jmp eax
    #
    # The value of what the user entered dictates the next instruction. This
    # is an unconstrained state. It wouldn't usually make sense for the execution
    # engine to continue. (Where should the program jump to if eax could be
    # anything?) Normally, when Angr encounters an unconstrained state, it throws
    # it out. In our case, we want to exploit the unconstrained state to jump to
    # a location of our choosing.  Check if there are still unconstrained states
    # by examining the simulation.unconstrained list.
    # (!)
    def has_unconstrained_to_check():
        return simulation.unconstrained

    # The list simulation.active is a list of all states that can be explored
    # further.
    # (!)
    def has_active():
        return simulation.active

    while (has_active()
           or has_unconstrained_to_check()) and (not has_found_solution()):
        for unconstrained_state in simulation.unconstrained:
            # Look for unconstrained states and move them to the 'found' stash.
            # A 'stash' should be a string that corresponds to a list that stores
            # all the states that the state group keeps. Values include:
            #  'active' = states that can be stepped
            #  'deadended' = states that have exited the program
            #  'errored' = states that encountered an error with Angr
            #  'unconstrained' = states that are unconstrained
            #  'found' = solutions
            #  anything else = whatever you want, perhaps you want a 'not_needed',
            #                  you can call it whatever you want
            # (!)
            simulation.move('unconstrained', 'found')

        # Advance the simulation.
        simulation.step()

    if simulation.found:
        solution_state = simulation.found[0]

        # Constrain the instruction pointer to target the print_good function and
        # (!)
        solution_state.add_constraints(solution_state.regs.eip == 0x4d435250)

        # Constrain the symbolic input to fall within printable range (capital
        # letters) for the web UI.  Ensure UTF-8 encoding.
        # (!)
        for byte in symbolic_input.chop(bits=8):
            solution_state.add_constraints(byte >= 'A'.encode(),
                                           byte <= 'Z'.encode())

        # Solve for the symbolic_input
        solution = solution_state.solver.eval(symbolic_input,
                                              cast_to=bytes).decode()
        print(solution)
    else:
        raise Exception('Could not find the solution')
示例#5
0
文件: simos.py 项目: xalexchen/angr
    def state_blank(self,
                    addr=None,
                    initial_prefix=None,
                    stack_size=1024 * 1024 * 8,
                    **kwargs):
        """
        Initialize a blank state.

        All parameters are optional.

        :param addr:            The execution start address.
        :param initial_prefix:
        :return:                The initialized SimState.
        :rtype:                 simuvex.SimState
        """
        if kwargs.get('mode', None) is None:
            kwargs['mode'] = self.proj._default_analysis_mode
        if kwargs.get('permissions_backer', None) is None:
            # just a dict of address ranges to permission bits
            permission_map = {}
            for obj in self.proj.loader.all_objects:
                for seg in obj.segments:
                    perms = 0
                    # bit values based off of protection bit values from sys/mman.h
                    if seg.is_readable:
                        perms |= 1  # PROT_READ
                    if seg.is_writable:
                        perms |= 2  # PROT_WRITE
                    if seg.is_executable:
                        perms |= 4  # PROT_EXEC
                    permission_map[(obj.rebase_addr + seg.min_addr,
                                    obj.rebase_addr + seg.max_addr)] = perms
            permissions_backer = (self.proj.loader.main_bin.execstack,
                                  permission_map)
            kwargs['permissions_backer'] = permissions_backer
        if kwargs.get('memory_backer', None) is None:
            kwargs['memory_backer'] = self.proj.loader.memory
        if kwargs.get('arch', None) is None:
            kwargs['arch'] = self.proj.arch
        if kwargs.get('os_name', None) is None:
            kwargs['os_name'] = self.name

        state = SimState(**kwargs)

        stack_end = state.arch.initial_sp
        if o.ABSTRACT_MEMORY not in state.options:
            state.memory.mem._preapproved_stack = IRange(
                stack_end - stack_size, stack_end)

        if o.INITIALIZE_ZERO_REGISTERS in state.options:
            highest_reg_offset, reg_size = max(state.arch.registers.values())
            for i in range(0, highest_reg_offset + reg_size, state.arch.bytes):
                state.registers.store(i, state.se.BVV(0, state.arch.bits))

        state.regs.sp = stack_end

        if initial_prefix is not None:
            for reg in state.arch.default_symbolic_registers:
                state.registers.store(
                    reg,
                    claripy.BVS(initial_prefix + "_" + reg,
                                state.arch.bits,
                                explicit_name=True))

        for reg, val, is_addr, mem_region in state.arch.default_register_values:

            region_base = None  # so pycharm does not complain

            if is_addr:
                if isinstance(mem_region, tuple):
                    # unpack it
                    mem_region, region_base = mem_region
                elif mem_region == 'global':
                    # Backward compatibility
                    region_base = 0
                else:
                    raise AngrSimOSError(
                        'You must specify the base address for memory region "%s". '
                        % mem_region)

            if o.ABSTRACT_MEMORY in state.options and is_addr:
                address = claripy.ValueSet(state.arch.bits, mem_region,
                                           region_base, val)
                state.registers.store(reg, address)
            else:
                state.registers.store(reg, val)

        if addr is None: addr = self.proj.entry
        state.regs.ip = addr

        state.scratch.ins_addr = addr
        state.scratch.bbl_addr = addr
        state.scratch.stmt_idx = 0
        state.scratch.jumpkind = 'Ijk_Boring'

        state.procedure_data.hook_addr = self.continue_addr
        return state
示例#6
0
import sys
sys.path.append(
    '/home/soyccan/.local/share/virtualenvs/vwvwvw-SJfVni3y/lib/python3.6/site-packages/'
)

import angr
import claripy

angr.l.setLevel('DEBUG')
p = angr.Project('./verify', load_options={"auto_load_libs": False})

args = claripy.BVS('args', 8 * 24)
initial_state = p.factory.entry_state(
    args=[p.filename, args], add_options={'BYPASS_UNSUPPORTED_SYSCALL'})

prefix = 'FLAG{'
for i, b in enumerate(args.chop(8)):
    initial_state.add_constraints(b >= 0x21, b <= 0x7e)
#    if i < len(prefix):
#        initial_state.add_constraints(b == prefix[i])
#    if i == 23:
#        initial_state.add_constraints(b == '}')

pg = p.factory.simulation_manager(initial_state)
pg.explore(find=[0x4022cb], avoid=[])
print(pg)

#print(pg.found[0].posix.dumps(0).strip('\0\n'))
#args_str = pg.found[0].state.se.any_str(args)
#stdin = f.state.posix.dumps(0)
#ans = pg.found[0].state.se._solver.result.model
示例#7
0
import angr
import claripy

proj = angr.Project("./main")

input_size = 12

argv1 = claripy.BVS("argv1", input_size * 8)
initial_state = proj.factory.entry_state(args=["./main"], stdin=argv1, add_options=angr.options.unicorn)

for i in range(input_size - 1):
	initial_state.add_constraints(argv1.get_byte(i) >= ord(' '))
	initial_state.add_constraints(argv1.get_byte(i) <= ord('}'))

initial_state.add_constraints(argv1.get_byte(input_size - 1) == 0x10)

find_address = 0x400D32
avoid_address = (0x400D58, 0x400D08)
	
sm = proj.factory.simulation_manager(initial_state)
sm.explore(find=find_address, avoid=avoid_address)

if sm.found:
	found = sm.found[0] 
	solution = found.solver.eval(argv1, cast_to=bytes)
	print(f"Flag is: {str(solution)}")

else:
	print("Failed! No flag for u")
示例#8
0
    exit(0)


alogger = logging.getLogger()
alogger.setLevel(logging.INFO)

logger = logging.getLogger('solve.py')
logging.basicConfig()
logger.setLevel(logging.INFO)

p = angr.Project('baby-re', auto_load_libs=False)

CheckSolution_addr = p.loader.find_symbol("CheckSolution").rebased_addr
CheckSolution = p.factory.callable(CheckSolution_addr)

argv = claripy.BVS("all_args", 32 * 13)
args = [argv.get_bytes(i, 4) for i in range(0, 13 * 4, 4)]

logger.info("Starting Symbolic Execution")
r = CheckSolution(args)
s = CheckSolution.result_state
logger.info("Symbolic Execution Complete")

logger.info("Attempting to reverse the function")
try:
    resolved_argv = s.solver.eval(argv, extra_constraints=[r != 0])
    logger.info("Got: %s", resolved_argv)
    raw = hex(resolved_argv)[2:].strip('L').decode('hex')
    resolved_args = struct.unpack('<' + 'I' * 13, raw)
    logger.info("FOUND FLAG: %s", resolved_args)
    logger.info(''.join(map(chr, resolved_args)))
示例#9
0
#!/usr/bin/env python3
import angr
import claripy

p = angr.Project('./angrme')

base = 0x400000

flag_chars = [claripy.BVS('flag_%d' % i, 8) for i in range(0x24)]
flag = claripy.Concat(*flag_chars + [claripy.BVV(b'\n')])

state = p.factory.entry_state(stdin=flag)
sm = p.factory.simulation_manager(state)

good = base + 0x2370
bad = base + 0x2390
sm.explore(find=good, avoid=bad)

print(sm.found[0].posix.dumps(0))
示例#10
0
def test_inspect_concretization():
    # some values for the test
    x = claripy.BVS('x', 64)
    y = claripy.BVS('y', 64)

    #
    # This tests concretization-time address redirection.
    #

    def change_symbolic_target(state):
        if state.inspect.address_concretization_action == 'store':
            state.inspect.address_concretization_expr = claripy.BVV(
                0x1000, state.arch.bits)

    s = SimState(arch='AMD64')
    s.inspect.b('address_concretization',
                BP_BEFORE,
                action=change_symbolic_target)
    s.memory.store(x, 'A')
    assert list(s.solver.eval_upto(x, 10)) == [0x1000]
    assert list(s.solver.eval_upto(s.memory.load(0x1000, 1), 10)) == [0x41]

    #
    # This tests disabling constraint adding through siminspect -- the write still happens
    #

    def dont_add_constraints(state):
        state.inspect.address_concretization_add_constraints = False

    s = SimState(arch='AMD64')
    s.inspect.b('address_concretization',
                BP_BEFORE,
                action=dont_add_constraints)
    s.memory.store(x, 'A')
    assert len(s.solver.eval_upto(x, 10)) == 10

    #
    # This tests raising an exception if symbolic concretization fails (i.e., if the address
    # is too unconstrained). The write aborts.
    #

    class UnconstrainedAbort(Exception):
        def __init__(self, message, state):
            Exception.__init__(self, message)
            self.state = state

    def abort_unconstrained(state):
        print(state.inspect.address_concretization_strategy,
              state.inspect.address_concretization_result)
        if (isinstance(
                state.inspect.address_concretization_strategy,
                concretization_strategies.SimConcretizationStrategyRange)
                and state.inspect.address_concretization_result is None):
            raise UnconstrainedAbort("uh oh", state)

    s = SimState(arch='AMD64')
    s.memory.write_strategies.insert(
        0, concretization_strategies.SimConcretizationStrategyRange(128))
    s.memory._write_address_range = 1
    s.memory._write_address_range_approx = 1
    s.add_constraints(y == 10)
    s.inspect.b('address_concretization', BP_AFTER, action=abort_unconstrained)
    s.memory.store(y, 'A')
    assert list(s.solver.eval_upto(s.memory.load(y, 1), 10)) == [0x41]

    try:
        s.memory.store(x, 'A')
        print("THIS SHOULD NOT BE REACHED")
        assert False
    except UnconstrainedAbort as e:
        assert e.state.memory is s.memory
示例#11
0
def main(argv):
    path_to_binary = argv[1]
    project = angr.Project(path_to_binary)

    # Sometimes, you want to specify where the program should start. The variable
    # start_address will specify where the symbolic execution engine should begin.
    # Note that we are using blank_state, not entry_state.
    # (!)
    start_address = 0x80488a0  # :integer (probably hexadecimal)
    initial_state = project.factory.blank_state(addr=start_address)

    # Create a symbolic bitvector (the datatype Angr uses to inject symbolic
    # values into the binary.) The first parameter is just a name Angr uses
    # to reference it.
    # You will have to construct multiple bitvectors. Copy the two lines below
    # and change the variable names. To figure out how many (and of what size)
    # you need, dissassemble the binary and determine the format parameter passed
    # to scanf.
    # (!)
    password0_size_in_bits = 32  # :integer
    password1_size_in_bits = 32  # :integer
    password2_size_in_bits = 32  # :integer
    password0 = claripy.BVS('password0', password0_size_in_bits)
    password1 = claripy.BVS('password1', password1_size_in_bits)
    password2 = claripy.BVS('password2', password2_size_in_bits)

    # Set a register to a symbolic value. This is one way to inject symbols into
    # the program.
    # initial_state.regs stores a number of convenient attributes that reference
    # registers by name. For example, to set eax to password0, use:
    #
    # initial_state.regs.eax = password0
    #
    # You will have to set multiple registers to distinct bitvectors. Copy and
    # paste the line below and change the register. To determine which registers
    # to inject which symbol, dissassemble the binary and look at the instructions
    # immediately following the call to scanf.
    # (!)
    initial_state.regs.eax = password0
    initial_state.regs.ebx = password1
    initial_state.regs.edx = password2

    simulation = project.factory.simgr(initial_state)

    def is_successful(state):
        stdout_output = state.posix.dumps(sys.stdout.fileno())
        if re.findall(r'Good Job.', stdout_output):
            return True
        # Return whether 'Good Job.' has been printed yet.
        # (!)
        return False  # :boolean

    def should_abort(state):
        stdout_output = state.posix.dumps(sys.stdout.fileno())
        if re.findall(r'Try again.', stdout_output):
            return True
        # Return whether 'Good Job.' has been printed yet.
        # (!)
        return False  # :boolean

    simulation.explore(find=is_successful, avoid=should_abort)

    if simulation.found:
        solution_state = simulation.found[0]

        # Solve for the symbolic values. If there are multiple solutions, we only
        # care about one, so we can use eval, which returns any (but only one)
        # solution. Pass eval the bitvector you want to solve for.
        # (!)
        solution0 = solution_state.se.eval(password0)
        solution1 = solution_state.se.eval(password1)
        solution2 = solution_state.se.eval(password2)

        # Aggregate and format the solutions you computed above, and then print
        # the full string. Pay attention to the order of the integers, and the
        # expected base (decimal, octal, hexadecimal, etc).
        solution = str(hex(solution0)).strip('L') + ' ' + str(
            hex(solution1)).strip('L') + ' ' + str(hex(solution2)).strip(
                'L')  # :string
        print solution
    else:
        raise Exception('Could not find the solution')
示例#12
0
def checkFormat(binary_name, inputType="STDIN"):

    p = angr.Project(binary_name, load_options={"auto_load_libs": False})

    # Stdio based ones
    p.hook_symbol("printf", printf_model.printFormat(0))
    p.hook_symbol("fprintf", printf_model.printFormat(1))
    p.hook_symbol("dprintf", printf_model.printFormat(1))
    p.hook_symbol("sprintf", printf_model.printFormat(1))
    p.hook_symbol("snprintf", printf_model.printFormat(2))

    # Stdarg base ones
    p.hook_symbol("vprintf", printf_model.printFormat(0))
    p.hook_symbol("vfprintf", printf_model.printFormat(1))
    p.hook_symbol("vdprintf", printf_model.printFormat(1))
    p.hook_symbol("vsprintf", printf_model.printFormat(1))
    p.hook_symbol("vsnprintf", printf_model.printFormat(2))

    extras = {
        so.REVERSE_MEMORY_NAME_MAP, so.TRACK_ACTION_HISTORY,
        so.TRACK_CONSTRAINTS
    }
    # Setup state based on input type
    argv = [binary_name]
    input_arg = claripy.BVS("input", 300 * 8)
    if inputType == "STDIN":
        state = p.factory.full_init_state(
            args=argv,
            stdin=input_arg,
            add_options=extras,
        )
        state.globals["user_input"] = input_arg
    elif inputType == "LIBPWNABLE":
        handle_connection = p.loader.main_object.get_symbol(
            "handle_connection")
        state = p.factory.entry_state(
            addr=handle_connection.rebased_addr,
            add_options=extras,
        )
        state.globals["user_input"] = input_arg
    else:
        argv.append(input_arg)
        state = p.factory.full_init_state(
            args=argv,
            add_options=extras,
        )
        state.globals["user_input"] = input_arg

    state.libc.buf_symbolic_bytes = 0x100
    state.globals["inputType"] = inputType
    simgr = p.factory.simgr(state, save_unconstrained=True)

    run_environ = {}
    run_environ["type"] = None
    end_state = None
    # Lame way to do a timeout
    try:

        @timeout_decorator.timeout(1200)
        def exploreBinary(simgr):
            simgr.explore(find=lambda s: "type" in s.globals)

        exploreBinary(simgr)
        if "found" in simgr.stashes and len(simgr.found):
            end_state = simgr.found[0]
            run_environ["type"] = end_state.globals["type"]
            run_environ["position"] = end_state.globals["position"]
            run_environ["length"] = end_state.globals["length"]

    except (KeyboardInterrupt, timeout_decorator.TimeoutError) as e:
        print("[~] Format check timed out")

    if "input" in end_state.globals.keys():
        run_environ["input"] = end_state.globals["input"]
        print("[+] Triggerable with input : {}".format(
            end_state.globals["input"]))

    return run_environ
示例#13
0
import angr
import claripy
"""
Not working, find and fix the bugs ;-)
"""
"""
Load the exercise binary into angr
"""
proj = angr.Project('exercise1')
"""
Create our symbolic input to pass via argv
"""
input = claripy.BVS('input', 2 * 8)
"""
Start angr analysis at the entry point of the binary
"""
state = proj.factory.entry_state(args=[proj.filename, input])
pg = proj.factory.path_group(state)
"""
Try to find a path to our destination basic block
"""
pg = pg.explore(find=0x400b15)
"""
Extract our found path's state for analysis
"""
state = pg.found[0].state
"""
Look at the constraints found to execute the given path
"""
print(state.simplify())
"""
示例#14
0
#!/usr/bin/env python
import angr
import claripy

p = angr.Project('./test')
flag = claripy.BVS('flag', 5 * 8)
s = p.factory.blank_state(addr=0x400550, stdin=flag)

for c in flag.chop(8):
    s.solver.add(s.solver.And(c<='~', c>=' '))

sm = p.factory.simulation_manager(s)
sm.use_technique(angr.exploration_techniques.Explorer(find=0x4006C1, avoid=0x4006CD))
sm.run()

print(sm.one_found.posix.dumps(0))

示例#15
0
    # next, create constraints representing an unsafe condition. In this case,
    # let's check if the return address can point *outside* of the program.
    unsafe_constraints = [
        state.se.Or(saved_eip < project.loader.min_addr,
                    saved_eip > project.loader.max_addr)
    ]

    # check if the state is satisfiable with these conditions, and return True if it is
    return state.se.satisfiable(extra_constraints=unsafe_constraints)


# This time, the initialization is a bit different. The application takes a commandline argument, so we must:
# first, create a symbolic bitvector representing the argument.
# We're interested in the last few bytes (the part that will actually overflow the return address), so make it a
# concatination of 60 concrete bytes and 60 symbolic bytes.
arg = claripy.BVV("A" * 60).concat(claripy.BVS("arg", 240))
# next, create a state with this argument
state = project.factory.entry_state(args=['overflow3', arg])
# now, create the simulation manager with that state as the initial state
simgr = project.factory.simgr(state)

# initiate a "vuln" stash
simgr.stashes['vuln'] = []

# Since we have the address of main in the knowledgebase, let's make a less janky initialization procedure.
print "Initializing initial state..."
while simgr.active[0].addr != project.kb.functions['main'].addr:
    simgr.step()

# Now that we are all set up, let's loop until a vulnerable state has been found
print "Searching for the vulnerability!"
示例#16
0
#!/usr/bin/env python
import angr
import claripy
p = angr.Project("arg_string")
arg1 = claripy.BVS("arg1", 8*2)
st = p.factory.entry_state(args=["a.out", arg1])
sm = p.factory.simulation_manager(st)
sm.explore(find=(0x4006b9,))
found = sm.found[0]
print found.state.se.eval(arg1, cast_to=str)

示例#17
0
    def BVS(self,
            name,
            size,
            min=None,
            max=None,
            stride=None,
            uninitialized=False,
            explicit_name=None,
            key=None,
            eternal=False,
            inspect=True,
            events=True,
            **kwargs):  #pylint:disable=redefined-builtin
        """
        Creates a bit-vector symbol (i.e., a variable). Other keyword parameters are passed directly on to the
        constructor of claripy.ast.BV.

        :param name:            The name of the symbol.
        :param size:            The size (in bits) of the bit-vector.
        :param min:             The minimum value of the symbol. Note that this **only** work when using VSA.
        :param max:             The maximum value of the symbol. Note that this **only** work when using VSA.
        :param stride:          The stride of the symbol. Note that this **only** work when using VSA.
        :param uninitialized:   Whether this value should be counted as an "uninitialized" value in the course of an
                                analysis.
        :param explicit_name:   Set to True to prevent an identifier from appended to the name to ensure uniqueness.
        :param key:             Set this to a tuple of increasingly specific identifiers (for example,
                                ``('mem', 0xffbeff00)`` or ``('file', 4, 0x20)`` to cause it to be tracked, i.e.
                                accessable through ``solver.get_variables``.
        :param eternal:         Set to True in conjunction with setting a key to cause all states with the same
                                ancestry to retrieve the same symbol when trying to create the value. If False, a
                                counter will be appended to the key.
        :param inspect:         Set to False to avoid firing SimInspect breakpoints
        :param events:          Set to False to avoid generating a SimEvent for the occasion

        :return:                A BV object representing this symbol.
        """

        # should this be locked for multithreading?
        if key is not None and eternal and key in self.eternal_tracked_variables:
            r = self.eternal_tracked_variables[key]
            # pylint: disable=too-many-boolean-expressions
            if size != r.length or min != r.args[1] or max != r.args[
                    2] or stride != r.args[3] or uninitialized != r.args[
                        4] or bool(explicit_name) ^ (r.args[0] == name):
                l.warning(
                    "Variable %s being retrieved with differnt settings than it was tracked with",
                    name)
        else:
            r = claripy.BVS(name,
                            size,
                            min=min,
                            max=max,
                            stride=stride,
                            uninitialized=uninitialized,
                            explicit_name=explicit_name,
                            **kwargs)
            if key is not None:
                self.register_variable(r, key, eternal)

        if inspect:
            self.state._inspect('symbolic_variable',
                                BP_AFTER,
                                symbolic_name=next(iter(r.variables)),
                                symbolic_size=size,
                                symbolic_expr=r)
        if events:
            self.state.history.add_event('unconstrained',
                                         name=next(iter(r.variables)),
                                         bits=size,
                                         **kwargs)
        if o.TRACK_SOLVER_VARIABLES in self.state.options:
            self.all_variables = list(self.all_variables)
            self.all_variables.append(r)
        return r
示例#18
0
import angr
import time
import re
import claripy
p = angr.Project("./baby-re")
flag_buf = [claripy.BVS("flag_%d" % x, 32) for x in range(13)]
s = p.factory.blank_state(addr=0x4028E0)
for x in range(13):
    s.memory.store(s.regs.rdi + x * 4, flag_buf[x])
sim = p.factory.simulation_manager(s)
sim.active[0].options.add(angr.options.LAZY_SOLVES)
start_time = time.time()
sim.explore(find=0x4028E9, avoid=0x402941)
print sim.found[0].solver.eval(flag_buf[0])
print str(time.time() - start_time)
示例#19
0
文件: solveit.py 项目: xcode2010/ctf
    print('EXP: ' + str(exp))
    with open('all0', 'wb') as fp:
        fp.write(dump_objs(state, 0x26308, 0x26344, 0x26348, 0x26384))
    sol = bk(exp)
    print('SOL: ' + str(sol))
    rep = 0
    for i in range(rep):
        sol = bk(sol)
        print('SOL: ' + str(sol))
    check = fw(sol)
    print('CHK: ' + str(check))
    for i in range(rep):
        check = fw(check)
        print('CHK: ' + str(check))
    assert check == exp
    with open('all1', 'wb') as fp:
        fp.write(dump_objs(state, 0x26290, 0x262c8, 0x262cc, 0x26304) + sol)

if False:
    input_string = claripy.BVS('input_string', 8 * 0x100)
    output_string = bytes(0x100)
    length = claripy.BVS('length', 32, 1, 0x100)
    pack_addr = 0x10ad4
    pack_ret_addr = 0x10ba8
    state = p.factory.call_state(pack_addr, input_string, output_string,
                                 length)
    state.regs.t9 = pack_addr  # report to angr? https://www.cr0.org/paper/mips.elf.external.resolution.txt
    simgr = p.factory.simgr(state)
    simgr.explore(find=pack_ret_addr)
    print('OK')
示例#20
0
    def claripy_ast_from_ail_condition(self, condition) -> claripy.ast.Base:

        # Unpack a condition all the way to the leaves
        if isinstance(condition, claripy.ast.Base):  # pylint:disable=isinstance-second-argument-not-valid-type
            return condition

        def _op_with_unified_size(op, conv, operand0, operand1):
            # ensure operand1 is of the same size as operand0
            if isinstance(operand1, ailment.Expr.Const):
                # amazing - we do the eazy thing here
                return op(conv(operand0), operand1.value)
            if operand1.bits == operand0.bits:
                return op(conv(operand0), conv(operand1))
            # extension is required
            assert operand1.bits < operand0.bits
            operand1 = ailment.Expr.Convert(None, operand1.bits, operand0.bits, False, operand1)
            return op(conv(operand0), conv(operand1))

        def _dummy_bvs(condition):
            var = claripy.BVS('ailexpr_%s' % repr(condition), condition.bits, explicit_name=True)
            self._condition_mapping[var.args[0]] = condition
            return var

        _mapping = {
            'LogicalAnd': lambda expr, conv: claripy.And(conv(expr.operands[0]), conv(expr.operands[1])),
            'LogicalOr': lambda expr, conv: claripy.Or(conv(expr.operands[0]), conv(expr.operands[1])),
            'CmpEQ': lambda expr, conv: conv(expr.operands[0]) == conv(expr.operands[1]),
            'CmpNE': lambda expr, conv: conv(expr.operands[0]) != conv(expr.operands[1]),
            'CmpLE': lambda expr, conv: conv(expr.operands[0]) <= conv(expr.operands[1]),
            'CmpLEs': lambda expr, conv: claripy.SLE(conv(expr.operands[0]), conv(expr.operands[1])),
            'CmpLT': lambda expr, conv: conv(expr.operands[0]) < conv(expr.operands[1]),
            'CmpLTs': lambda expr, conv: claripy.SLT(conv(expr.operands[0]), conv(expr.operands[1])),
            'CmpGE': lambda expr, conv: conv(expr.operands[0]) >= conv(expr.operands[1]),
            'CmpGEs': lambda expr, conv: claripy.SGE(conv(expr.operands[0]), conv(expr.operands[1])),
            'CmpGT': lambda expr, conv: conv(expr.operands[0]) > conv(expr.operands[1]),
            'CmpGTs': lambda expr, conv: claripy.SGT(conv(expr.operands[0]), conv(expr.operands[1])),
            'Add': lambda expr, conv: conv(expr.operands[0]) + conv(expr.operands[1]),
            'Sub': lambda expr, conv: conv(expr.operands[0]) - conv(expr.operands[1]),
            'Mul': lambda expr, conv: conv(expr.operands[0]) * conv(expr.operands[1]),
            'Div': lambda expr, conv: conv(expr.operands[0]) / conv(expr.operands[1]),
            'Not': lambda expr, conv: claripy.Not(conv(expr.operand)),
            'Xor': lambda expr, conv: conv(expr.operands[0]) ^ conv(expr.operands[1]),
            'And': lambda expr, conv: conv(expr.operands[0]) & conv(expr.operands[1]),
            'Or': lambda expr, conv: conv(expr.operands[0]) | conv(expr.operands[1]),
            'Shr': lambda expr, conv: _op_with_unified_size(claripy.LShR, conv, expr.operands[0], expr.operands[1]),
            'Shl': lambda expr, conv: _op_with_unified_size(operator.lshift, conv, expr.operands[0], expr.operands[1]),
            'Sar': lambda expr, conv: _op_with_unified_size(operator.rshift, conv, expr.operands[0], expr.operands[1]),

            # There are no corresponding claripy operations for the following operations
            'DivMod': lambda expr, _: _dummy_bvs(expr),
            'CmpF': lambda expr, _: _dummy_bvs(expr),
            'Mull': lambda expr, _: _dummy_bvs(expr),
            'Mulls': lambda expr, _: _dummy_bvs(expr),
        }

        if isinstance(condition, (ailment.Expr.Load, ailment.Expr.DirtyExpression, ailment.Expr.BasePointerOffset,
                                  ailment.Expr.ITE, ailment.Stmt.Call)):
            return _dummy_bvs(condition)
        elif isinstance(condition, ailment.Expr.Register):
            var = claripy.BVS('ailexpr_%s-%d' % (repr(condition), condition.idx), condition.bits, explicit_name=True)
            self._condition_mapping[var.args[0]] = condition
            return var
        elif isinstance(condition, ailment.Expr.Convert):
            # convert is special. if it generates a 1-bit variable, it should be treated as a BVS
            if condition.to_bits == 1:
                var_ = self.claripy_ast_from_ail_condition(condition.operands[0])
                name = 'ailcond_Conv(%d->%d, %s)' % (condition.from_bits, condition.to_bits, repr(var_))
                var = claripy.BoolS(name, explicit_name=True)
            else:
                var_ = self.claripy_ast_from_ail_condition(condition.operands[0])
                name = 'ailexpr_Conv(%d->%d, %s)' % (condition.from_bits, condition.to_bits, repr(var_))
                var = claripy.BVS(name, condition.to_bits, explicit_name=True)
            self._condition_mapping[var.args[0]] = condition
            return var
        elif isinstance(condition, ailment.Expr.Const):
            var = claripy.BVV(condition.value, condition.bits)
            return var
        elif isinstance(condition, ailment.Expr.Tmp):
            l.warning("Left-over ailment.Tmp variable %s.", condition)
            if condition.bits == 1:
                var = claripy.BoolV('ailtmp_%d' % condition.tmp_idx)
            else:
                var = claripy.BVS('ailtmp_%d' % condition.tmp_idx, condition.bits, explicit_name=True)
            self._condition_mapping[var.args[0]] = condition
            return var

        lambda_expr = _mapping.get(condition.verbose_op, None)
        if lambda_expr is None:
            raise NotImplementedError("Unsupported AIL expression operation %s. Consider implementing."
                                      % condition.verbose_op)
        r = lambda_expr(condition, self.claripy_ast_from_ail_condition)
        if r is NotImplemented:
            r = claripy.BVS("ailexpr_%r" % condition, condition.bits, explicit_name=True)
            self._condition_mapping[r.args[0]] = condition
        else:
            # don't lose tags
            r = r.annotate(TagsAnnotation(**condition.tags))
        return r
示例#21
0
文件: summarizer.py 项目: jarsp/angr
    def _has_side_effect(self, f):
        # TODO: Assumes any write to outside the base of the stack frame is a
        #       side effect, and everything else is not
        #       Not sure if address concretization messes with this

        for b in f.blocks:
            # Technically I don't need this?
            for stmt in b.vex.statements:
                if isinstance(stmt, pyvex.stmt.Dirty):
                    return True
            if b.vex.jumpkind == 'Ijk_Call' and isinstance(b.vex.next, pyvex.expr.Const) \
               and b.vex.next.con.value in self._is_summarized:
                continue
            if b.vex.jumpkind not in ['Ijk_Boring', 'Ijk_Ret']:
                return True

        cc = f.calling_convention if f.calling_convention is not None \
                                  else simuvex.DefaultCC[self._p.arch.name](self._p.arch)
        deadend_addr = self._p._simos.return_deadend
        num_args = f.num_arguments - 1
        args = [claripy.BVS(self._fresh_name(), 64) for _ in range(num_args)]
        state = self._p.factory.call_state(
            f.addr,
            *args,
            cc=cc,
            base_state=None,
            ret_addr=deadend_addr,
            add_options={simuvex.o.REPLACEMENT_SOLVER},
            toc=None)
        self._abstract_globals(state)

        base_sp = state.regs.sp
        stack_grows_to_zero = self._p.arch.stack_change < 0
        stack_lim = self._p.arch.initial_sp - self._p.arch.stack_size \
                    if stack_grows_to_zero \
                    else self._p.arch.initial_sp + self._p.arch.stack_size

        class BPCallback:
            def __init__(self):
                self.has_effect = False

            def check_side_effect(self, s):
                if self.has_effect: return

                write_addr = s.inspect.mem_write_address
                if stack_grows_to_zero:
                    cond = (claripy.Or(write_addr > base_sp,
                                       write_addr <= stack_lim), )
                else:
                    cond = (claripy.Or(write_addr < base_sp,
                                       write_addr >= stack_lim), )
                #l.debug(cond)
                self.has_effect = s.se.satisfiable(extra_constraints=cond)

        callback = BPCallback()
        state.inspect.b('mem_write',
                        when=simuvex.BP_BEFORE,
                        action=callback.check_side_effect)

        caller = self._p.factory.path_group(state)
        caller.step(
            until=lambda pg: callback.has_effect or len(pg.active) == 0)

        return callback.has_effect
示例#22
0
 def _dummy_bvs(condition):
     var = claripy.BVS('ailexpr_%s' % repr(condition), condition.bits, explicit_name=True)
     self._condition_mapping[var.args[0]] = condition
     return var
示例#23
0
 def heap_address(self, offset: int) -> claripy.ast.Base:
     base = claripy.BVS("heap_base", self.arch.bits, explicit_name=True)
     if offset:
         return base + offset
     return base
示例#24
0
import angr
import claripy

base_addr = 0x100000

project = angr.Project("Riga", main_opts={'base_addr': base_addr})
args = claripy.BVS('flag', 30 * 8)

# target  = 0x1194 # IDA
target = 0x00101194  # Ghidra

state = project.factory.entry_state(args=["./Riga", args])
simum = project.factory.simulation_manager(state)

print(simum.explore(find=target))

print("SIMUM : " + str(simum.found))
result = simum.found[0]

print(result.solver.eval(args, cast_to=bytes))
示例#25
0
文件: exp.py 项目: n132/Watermalon
import angr
import time
import claripy
p = angr.Project('./angrybird')
s = p.factory.blank_state(addr=0x4007DA)


@p.hook(0x400590, length=6)
def n132_puts(ptr):
    print "A"
    s.rax = 1


flag = [claripy.BVS("flag_%d" % i, 8) for i in range(21)]
for x in range(21):
    s.memory.store(s.regs.rbp - 0x50 + x, flag[x])
s.regs.rbp = s.regs.rsp + 0x80
#s.globals['idx']=0
s.mem[s.regs.rbp - 0x74].dword = 21
s.mem[s.regs.rbp - 0x70].qword = 0x605018
s.mem[s.regs.rbp - 0x68].qword = 0x605020
s.mem[s.regs.rbp - 0x60].qword = 0x605028
s.mem[s.regs.rbp - 0x58].qword = 0x605038
sim = p.factory.simgr(s)

sim.active[0].options.add(angr.options.LAZY_SOLVES)

#sim.explore(find=0x000000000404FB7)
av = [
    2 + 0x00000000004007ED, 43 + 0x00000000004007ED, 75 + 0x00000000004007ED,
    116 + 0x00000000004007ED, 163 + 0x00000000004007ED, 204 +
def main(file):
    with open(file, encoding='utf-8') as json_file:
        global EXPLORE_OPT
        EXPLORE_OPT = json.load(json_file)

    # Options parser
    # JSON can't handle with hex values, so we need to do it manually
    if "blank_state" in EXPLORE_OPT:
        blank_state = int(EXPLORE_OPT["blank_state"], 16)

    find = int(EXPLORE_OPT["find"], 16)

    if "avoid" in EXPLORE_OPT:
        avoid = [int(x, 16) for x in EXPLORE_OPT["avoid"].split(',')]

    # User can input hex or decimal value (argv length / symbolic memory length)
    argv = [EXPLORE_OPT["binary_file"]]
    if "Arguments" in EXPLORE_OPT:
        index = 1
        for arg, length in EXPLORE_OPT["Arguments"].items():
            argv.append(
                claripy.BVS("argv" + str(index),
                            int(str(length), 0) * 8))
            index += 1

    if EXPLORE_OPT["auto_load_libs"] is True:
        p = angr.Project(EXPLORE_OPT["binary_file"],
                         load_options={"auto_load_libs": True})
    else:
        p = angr.Project(EXPLORE_OPT["binary_file"],
                         load_options={"auto_load_libs": False})

    global REGISTERS
    REGISTERS = p.arch.default_symbolic_registers

    if len(argv) > 1:
        state = p.factory.entry_state(args=argv)
    elif "blank_state" in locals():
        state = p.factory.blank_state(addr=blank_state)
    else:
        state = p.factory.entry_state()

    # Store symbolic vectors in memory
    if "Memory" in EXPLORE_OPT:
        Memory = {}
        for addr, length in EXPLORE_OPT["Memory"].items():
            symbmem_addr = int(addr, 16)
            symbmem_len = int(length, 0)
            Memory.update({symbmem_addr: symbmem_len})
            symb_vector = claripy.BVS('input', symbmem_len * 8)
            state.memory.store(symbmem_addr, symb_vector)

    # Write to memory
    if "Store" in EXPLORE_OPT:
        for addr, value in EXPLORE_OPT["Store"].items():
            store_addr = int(addr, 16)
            store_value = int(value, 16)
            store_length = len(value) - 2
            state.memory.store(store_addr,
                               state.solver.BVV(store_value, 4 * store_length))

    # Handle Symbolic Registers
    if "Registers" in EXPLORE_OPT:
        for register, data in EXPLORE_OPT["Registers"].items():
            if "sv" in data:
                symbvector_length = int(data[2:], 0)
                symbvector = claripy.BVS('symvector', symbvector_length * 8)
                SYMVECTORS.append(symbvector)
                data = symbvector
            else:
                data = int(str(data), 0)
            for REG in REGISTERS:
                if REG == register:
                    setattr(state.regs, register, data)
                    break

    # Handle Hooks
    if "Hooks" in EXPLORE_OPT:
        for object in EXPLORE_OPT["Hooks"]:
            for frame in object.items():
                hook_address = frame[0]
                for option, data in frame[1].items():
                    data = int(str(data), 0)
                    if option == "Length":
                        hook_length = data
                        break
                p.hook(int(hook_address, 16),
                       hook_function,
                       length=hook_length)

    simgr = p.factory.simulation_manager(state)
    if "avoid" in locals():
        simgr.use_technique(
            angr.exploration_techniques.Explorer(find=find, avoid=avoid))
    else:
        simgr.use_technique(angr.exploration_techniques.Explorer(find=find))

    simgr.run()

    if simgr.found:
        found_path = simgr.found[0]

        win_sequence = ""
        for win_block in found_path.history.bbl_addrs.hardcopy:
            win_block = p.factory.block(win_block)
            addresses = win_block.instruction_addrs
            for address in addresses:
                win_sequence += hex(address) + ","
        win_sequence = win_sequence[:-1]
        print("Trace:" + win_sequence)

        if len(argv) > 1:
            for i in range(1, len(argv)):
                print("argv[{id}] = {solution}".format(
                    id=i,
                    solution=found_path.solver.eval(argv[i], cast_to=bytes)))

        if "Memory" in locals() and len(Memory) != 0:
            for address, length in Memory.items():
                print("{addr} = {value}".format(addr=hex(address),
                                                value=found_path.solver.eval(
                                                    found_path.memory.load(
                                                        address, length),
                                                    cast_to=bytes)))

        if len(SYMVECTORS) > 0:
            for SV in SYMVECTORS:
                print(found_path.solver.eval(SV, cast_to=bytes))

        found_stdins = found_path.posix.stdin.content
        if len(found_stdins) > 0:
            std_id = 1
            for stdin in found_stdins:
                print("stdin[{id}] = {solution}".format(
                    id=std_id,
                    solution=found_path.solver.eval(stdin[0], cast_to=bytes)))
                std_id += 1
    else:
        print("")
    return
示例#27
0
    next_simgr = simgr.explore(find=ECHOCOMMAND)

    print("Reached the command dispatcher echocommand")
    next_state = next_simgr.found[0]

    # Ok, right now we have the input to reach the dispatcher, but due to previous
    # approximation ( strstr ) we have a very simple input ( ! \r\n ).
    # Instead of waiting for the correct input to show up we can do 2 things:
    #    1- Either synchronize the concrete process up to this point and reset the symbuffer.
    #    2- Just reset the symbolic buffer where the command dispatcher expects the command to be.
    #
    # We are going for the second one here.

    print("Restoring symbolic buffer")
    command_buffer_address2 = next_state.regs.rax
    command_buffer_symbolic2 = claripy.BVS('CommandBuffer2',
                                           8 * symbolic_buffer_size)
    # This is another buffer that the malware uses to decide what to do, let's make it symbolic.
    command_tokens_symbolic_size = claripy.BVS('CommandTokens', 8 * 8)

    print("Setting symbolic buffer at {} on state {}".format(
        str(command_buffer_address2), str(next_state)))
    print("Setting symbolic register edi on state {}".format(str(next_state)))
    next_state.memory.store(command_buffer_address2, command_buffer_symbolic2)
    next_state.regs.edi = command_tokens_symbolic_size

    # Now we want to reach a specific functionality in the program, for example the ovhflood.
    # To do that we want to see which BB we have to execute to reach that call, let's compute this
    # information statically using the CFG!
    print("Creating malware CFG")
    whole_cfg = ANGR_PROJECT.analyses.CFGFast(regions=[
        (ECHOCOMMAND, CUSTOM_END_CFG_REGION)
示例#28
0
 def top(bits) -> claripy.ast.BV:
     if bits in VariableRecoveryStateBase._tops:
         return VariableRecoveryStateBase._tops[bits]
     r = claripy.BVS("top", bits, explicit_name=True)
     VariableRecoveryStateBase._tops[bits] = r
     return r
示例#29
0
def main():
    '''
     Just a helper function to grab function names from resolved symbols.
     This will not be so easy if the binary is stripped.  You will have to
     open the binary in a disassembler and find the addresses of the
     functions you are trying to find/avoid in your paths rather than using
     this helper function.
    '''
    def getFuncAddress(funcName):
        found = [
            addr for addr, func in cfg.function_manager.functions.iteritems()
            if funcName == func.name
        ]
        if len(found) > 0:
            print "Found " + funcName + "'s address at " + hex(found[0]) + "!"
            return found[0]
        else:
            raise Exception("No address found for function : " + funcName)

    def get_byte(s, i):
        pos = s.size() / 8 - 1 - i
        return s[pos * 8 + 7:pos * 8]

    '''
     load the binary, don't load extra libs to save time/memory from state explosion
    '''
    project = angr.Project("strcpy_test",
                           load_options={'auto_load_libs': False})
    '''
     Set up CFG so we can grab function addresses from symbols.
     I set the fail_fast option to True to minimize how long
     this process takes.
    '''
    cfg = project.analyses.CFG(fail_fast=True)
    '''
     Get addresses of our functions to find or avoid
    '''
    addrStrcpy = getFuncAddress('strcpy')
    addrBadFunc = getFuncAddress('func3')
    '''
     Create the list of command-line arguments and add the program name
    '''
    argv = [project.filename]  #argv[0]
    ''' 
     Add symbolic variable for the password buffer which we are solving for:
    '''
    sym_arg_size = 40  #max number of bytes we'll try to solve for
    '''
     We use 8 * sym_arg_size because the size argument is in BITS, not bytes
    '''
    sym_arg = claripy.BVS('sym_arg', 8 * sym_arg_size)
    argv.append(sym_arg)  #argv[1]
    '''
     Add the buffer we will copy in if the password is correct
     When we find a path to strcpy, we will check to make sure
     that this is the value that is being copied!
    '''
    argv.append("HAHAHAHA")  # argv[2]
    '''
     Initializes an entry state starting at the address of the program entry point
     We simply pass it the same kind of argument vector that would be passed to the
     program, in execv() for example.
    '''
    state = project.factory.entry_state(args=argv)
    '''
     Create a new path group from the entry state
    '''
    path_group = project.factory.path_group(state)
    '''
     Since we want to find a path to strcpy ONLY where we have control of the
     source buffer, we have to have a custom check function which takes a Path
     as an argument.

     You might be wondering what we should do to instruct angr to find our
     target address since we're replacing the 'find=' argument with this
     'check' function.  Just check p.state.ip.args[0] (the current instruction
     pointer) to make sure we're at our intended path destination before checking
     to make sure the other conditions are satisfied.
    '''

    def check(p):
        if (p.state.ip.args[0] == addrStrcpy):  # Ensure that we're at strcpy
            '''
             By looking at the disassembly, I've found that the pointer to the
             source buffer given to strcpy() is kept in RSI.  Here, we dereference
             the pointer in RSI and grab 8 bytes (len("HAHAHAHA")) from that buffer.
            '''
            BV_strCpySrc = p.state.memory.load(p.state.regs.rsi, len(argv[2]))
            '''
             Now that we have the contents of the source buffer in the form of a bit
             vector, we grab its string representation using the current state's
             solver engine's function "any_str".
            '''
            strCpySrc = p.state.se.any_str(BV_strCpySrc)
            '''
             Now we simply return True (found path) if we've found a path to strcpy
             where we control the source buffer, or False (keep looking for paths) if we
             don't control the source buffer
            '''
            return True if argv[2] in strCpySrc else False
        else:
            '''
             If we aren't in the strcpy function, we need to tell angr to keep looking
             for new paths.
            '''
            return False

    '''
     Call the function at the entry_state and find a path that satisfies
     the check function.  If you specify a tuple/list/set for find or avoid,
     it translates to an address to find/avoid.  If you just give a function
     it will pass a Path to the function and check to see if the function returns
     True or False and proceed accordingly.

     Here, we tell the explore function to find a path that satisfies our check
     method and avoids any paths that end up in addrBadFunc ('func3')
    '''
    path_group = path_group.explore(find=check, avoid=(addrBadFunc, ))

    found = path_group.found
    ''' 
     Retrieve a concrete value for the password value from the found path.
     If you put this password in the program's first argument, you should be
     able to strcpy() any string you want into the destination buffer and
     cause a segmentation fault if it is too large :)
    '''
    if (len(found) >
            0):  #   Make sure we found a path before giving the solution
        found = path_group.found[0]
        result = found.state.se.any_str(argv[1])
    else:  # Aww somehow we didn't find a path.  Time to work on that check() function!
        result = "Couldn't find any paths which satisfied our conditions."
    return result
示例#30
0
import angr
import claripy
import glob

def number(state, n):
    return state.se.And(n <= '9', n >= '0')

FIND = 0x40203c
AVOID = 0x40205a
# bins = glob.glob("binaries/*.exe")
bins = ["./binaries/00000.exe"]
for binary in bins:
    p = angr.Project(binary)
    state = p.factory.blank_state()

    _input = claripy.BVS("input", 32, explicit_name=True)

    state.add_constraints(_input < 2147483648)
    state.add_constraints(_input >= 0)

    path = p.factory.path(state)
    pg = p.factory.path_group(state)
    pg.explore(find=FIND, avoid=AVOID)

    for pp in pg.deadended:
        print pp.state.posix.dumps(0)
    # print pg.deadended[0]
    # pg.explore(find=FIND, avoid=AVOID)
    found = pg.found[0].state

    flag = found.se.BVS("input", 32, explicit_name="True")