Example #1
0
 def change_symbolic_target(state):
     if state.inspect.address_concretization_action == 'store':
         state.inspect.address_concretization_expr = claripy.BVV(
             0x1000, state.arch.bits)
Example #2
0
Follow HeapHopper Setting
'''

added_options = set()
added_options.add(angr.options.REVERSE_MEMORY_NAME_MAP)             # I don't know wtf
# added_options.add(angr.options.STRICT_PAGE_ACCESS)                  # I don't know wtf
added_options.add(angr.options.CONCRETIZE_SYMBOLIC_FILE_READ_SIZES) # I don't know wtf
added_options.add(angr.options.ZERO_FILL_UNCONSTRAINED_MEMORY)      # make unknown regions hold null
added_options.add(angr.options.ZERO_FILL_UNCONSTRAINED_REGISTERS)   # make unknown regions hold null
state = proj.factory.entry_state(add_options=added_options)


bss = proj.loader.main_object.sections_map['.bss']
heap_base = ((bss.vaddr + bss.memsize) & ~0xfff) + 0x1000
heap_size = 64 * 4096
new_brk = claripy.BVV(heap_base + heap_size, proj.arch.bits)
print(bss)
print(hex(heap_base))
print(new_brk)
heap = angr.SimHeapBrk(heap_base=heap_base, heap_size=heap_size)
set_brk_ret = state.posix.set_brk(new_brk)

state.register_plugin('heap', heap)



is_UAF = False
state.globals['alloc_list'] = []
'''
alloc_status['addr'] = 0xdeadbeef
alloc_status['free'] = False  ### double-free means when this is true, and still free this
Example #3
0
 def _op_generic_CmpNEZ(self, args):
     assert len(args) == 1
     args = [args[0], claripy.BVV(0, args[0].size())]
     return self.generic_compare(
         args, operator.ne)  # TODO: Is this the correct action for scalars?
Example #4
0
    def interpret(self, startpos, args, addr=None, simfd=None):
        """
        implement scanf - extract formatted data from memory or a file according to the stored format
        specifiers and store them into the pointers extracted from `args`.

        :param startpos:    The index of the first argument corresponding to the first format element
        :param args:        A function which, given the index of an argument to the function, returns that argument
        :param addr:        The address in the memory to extract data from, or...
        :param simfd:       A file descriptor to use for reading data from
        :return:            The number of arguments parsed
        """
        if simfd is not None and isinstance(
                simfd.read_storage, SimPackets) and simfd.read_pos == len(
                    simfd.read_storage.content):
            argnum = startpos
            for component in self.components:
                if type(component) is bytes:
                    sdata, _ = simfd.read_data(len(component),
                                               short_reads=False)
                    self.state.solver.add(sdata == component)
                elif isinstance(component, claripy.Bits):
                    sdata, _ = simfd.read_data(len(component) // 8,
                                               short_reads=False)
                    self.state.solver.add(sdata == component)
                elif component.spec_type == b's':
                    if component.length_spec is None:
                        sdata, slen = simfd.read_data(
                            self.state.libc.buf_symbolic_bytes)
                    else:
                        sdata, slen = simfd.read_data(component.length_spec)
                    for byte in sdata.chop(8):
                        self.state.solver.add(
                            claripy.And(*[
                                byte != char for char in self.SCANF_DELIMITERS
                            ]))
                    self.state.memory.store(args(argnum), sdata, size=slen)
                    self.state.memory.store(
                        args(argnum) + slen, claripy.BVV(0, 8))
                    argnum += 1
                elif component.spec_type == b'c':
                    sdata, _ = simfd.read_data(1, short_reads=False)
                    self.state.memory.store(args(argnum), sdata)
                    argnum += 1
                else:
                    bits = component.size * 8
                    if component.spec_type == b'x':
                        base = 16
                    elif component.spec_type == b'o':
                        base = 8
                    else:
                        base = 10

                    # here's the variable representing the result of the parsing
                    target_variable = self.state.solver.BVS(
                        'scanf_' + component.string.decode(),
                        bits,
                        key=('api', 'scanf', argnum - startpos,
                             component.string))
                    negative = claripy.SLT(target_variable, 0)

                    # how many digits does it take to represent this variable fully?
                    max_digits = int(math.ceil(math.log(2**bits, base)))

                    # how many digits does the format specify?
                    spec_digits = component.length_spec

                    # how many bits can we specify as input?
                    available_bits = float(
                        'inf'
                    ) if spec_digits is None else spec_digits * math.log(
                        base, 2)
                    not_enough_bits = available_bits < bits

                    # how many digits will we model this input as?
                    digits = max_digits if spec_digits is None else spec_digits

                    # constrain target variable range explicitly if it can't take on all possible values
                    if not_enough_bits:
                        self.state.solver.add(
                            self.state.solver.And(
                                self.state.solver.SLE(target_variable,
                                                      (base**digits) - 1),
                                self.state.solver.SGE(
                                    target_variable,
                                    -(base**(digits - 1) - 1))))

                    # perform the parsing in reverse - constrain the input digits to be the string version of the input
                    # this only works because we're reading from a packet stream and therefore nobody has the ability
                    # to add other constraints to this data!
                    # this makes z3's job EXTREMELY easy
                    sdata, _ = simfd.read_data(digits, short_reads=False)
                    for i, digit in enumerate(reversed(sdata.chop(8))):
                        digit_value = (target_variable // (base**i)) % base
                        digit_ascii = digit_value + ord('0')
                        if base > 10:
                            digit_ascii = claripy.If(
                                digit_value >= 10,
                                digit_value + (-10 + ord('a')), digit_ascii)

                        # if there aren't enough bits, we can increase the range by accounting for the possibility that
                        # the first digit is a minus sign
                        if not_enough_bits:
                            if i == digits - 1:
                                neg_digit_ascii = ord('-')
                            else:
                                neg_digit_value = (-target_variable //
                                                   (base**i)) % base
                                neg_digit_ascii = neg_digit_value + ord('0')
                                if base > 10:
                                    neg_digit_ascii = claripy.If(
                                        neg_digit_value >= 10,
                                        neg_digit_value + (-10 + ord('a')),
                                        neg_digit_ascii)

                            digit_ascii = claripy.If(negative, neg_digit_ascii,
                                                     digit_ascii)

                        self.state.solver.add(digit == digit_ascii[7:0])

                    self.state.memory.store(
                        args(argnum),
                        target_variable,
                        endness=self.state.arch.memory_endness)
                    argnum += 1

            return argnum - startpos

        # TODO: we only support one format specifier in interpretation for now

        format_specifier_count = sum(1 for x in self.components
                                     if isinstance(x, FormatSpecifier))
        if format_specifier_count > 1:
            l.warning(
                "We don't support more than one format specifiers in format strings."
            )

        if simfd is not None:
            region = simfd.read_storage
            addr = simfd._pos if hasattr(
                simfd, '_pos') else simfd._read_pos  # XXX THIS IS BAD
        else:
            region = self.parser.state.memory

        bits = self.parser.state.arch.bits
        failed = self.parser.state.solver.BVV(0, bits)
        argpos = startpos
        position = addr
        for component in self.components:
            if isinstance(component, bytes):
                # TODO we skip non-format-specifiers in format string interpretation for now
                # if the region doesn't match the concrete component, we need to return immediately
                pass
            else:
                fmt_spec = component
                try:
                    dest = args(argpos)
                except SimProcedureArgumentError:
                    dest = None
                if fmt_spec.spec_type == b's':
                    # set some limits for the find
                    max_str_len = self.parser.state.libc.max_str_len
                    max_sym_bytes = self.parser.state.libc.buf_symbolic_bytes

                    # has the length of the format been limited by the string itself?
                    if fmt_spec.length_spec is not None:
                        max_str_len = fmt_spec.length_spec
                        max_sym_bytes = fmt_spec.length_spec

                    # TODO: look for limits on other characters which scanf is sensitive to, '\x00', '\x20'
                    ohr, ohc, ohi = region.find(
                        position,
                        self.parser.state.solver.BVV(b'\n'),
                        max_str_len,
                        max_symbolic_bytes=max_sym_bytes)

                    # if no newline is found, mm is position + max_strlen
                    # If-branch will really only happen for format specifiers with a length
                    mm = self.parser.state.solver.If(ohr == 0,
                                                     position + max_str_len,
                                                     ohr)
                    # we're just going to concretize the length, load will do this anyways
                    length = self.parser.state.solver.max_int(mm - position)
                    src_str = region.load(position, length)

                    # TODO all of these should be delimiters we search for above
                    # add that the contents of the string cannot be any scanf %s string delimiters
                    for delimiter in set(FormatString.SCANF_DELIMITERS):
                        delim_bvv = self.parser.state.solver.BVV(delimiter)
                        for i in range(length):
                            self.parser.state.add_constraints(
                                region.load(position + i, 1) != delim_bvv)

                    # write it out to the pointer
                    self.parser.state.memory.store(dest, src_str)
                    # store the terminating null byte
                    self.parser.state.memory.store(
                        dest + length, self.parser.state.solver.BVV(0, 8))

                    position += length

                else:

                    # XXX: atoi only supports strings of one byte
                    if fmt_spec.spec_type in [b'd', b'i', b'u', b'x']:
                        base = 16 if fmt_spec.spec_type == b'x' else 10
                        status, i, num_bytes = self.parser._sim_atoi_inner(
                            position,
                            region,
                            base=base,
                            read_length=fmt_spec.length_spec)
                        # increase failed count if we were unable to parse it
                        failed = self.parser.state.solver.If(
                            status, failed, failed + 1)
                        position += num_bytes
                    elif fmt_spec.spec_type == b'c':
                        i = region.load(position, 1)
                        i = i.zero_extend(bits - 8)
                        position += 1
                    else:
                        raise SimProcedureError(
                            "unsupported format spec '%s' in interpret" %
                            fmt_spec.spec_type)

                    i = self.parser.state.solver.Extract(
                        fmt_spec.size * 8 - 1, 0, i)
                    self.parser.state.memory.store(
                        dest,
                        i,
                        size=fmt_spec.size,
                        endness=self.parser.state.arch.memory_endness)

                argpos += 1

        if simfd is not None:
            _, realsize = simfd.read_data(position - addr)
            self.state.solver.add(realsize == position - addr)

        return (argpos - startpos) - failed
Example #5
0
 def _fp_vector_comparison(cmp, a0, a1):
     # for cmpps_eq stuff, i.e. Iop_CmpEQ32Fx4
     return claripy.If(cmp(a0, a1), claripy.BVV(-1, len(a0)),
                       claripy.BVV(0, len(a0)))
Example #6
0
 def _ail_handle_Const(self, expr: Expr.Const) -> PropValue:
     return PropValue.from_value_and_details(
         claripy.BVV(expr.value, expr.bits), expr.size, expr,
         self._codeloc())
Example #7
0
#!/usr/bin/env python3
import angr
import socket
import claripy
import pickle

with open("./code.bin", "rb") as f:
    code = f.read()
code = angr.SimFile('code.bin', content=code)
stdin = claripy.BVV(b"1234567789012345678901234567" + b"\n")

p = angr.Project("./eVMoji")

s = p.factory.main_state(args=["eVMoji", "code.bin"], stdin=stdin)
s.fs.insert("code.bin", code)
s.options.add(angr.options.UNICORN)

# base = tracer.QEMURunner(argv=["eVMoji", "code.bin"], binary="./eVMoji", input=b'A'*32 + b'\n', record_stdout=True, project=p)
# print(base.stdout.decode())

# from IPython import embed
# embed()

sm = p.factory.simulation_manager(s)
sm.explore(find=lambda s: b"tRy" in s.posix.dumps(1))
print(sm)
Example #8
0
 def run(self):
     addr = self.state.libc.heap_location
     self.state.libc.heap_location += 4
     self.state.memory.store(addr, claripy.BVV(0x00000000, 32))
     return addr
Example #9
0
 def run(self, hProv, dwLen, pbBuffer):
     print 'CryptGenRandom(%s, %s, %s)' % (hProv, dwLen, pbBuffer)
     l = self.state.se.any_int(dwLen) * 8
     self.state.memory.store(pbBuffer, claripy.BVV(random.getrandbits(l),
                                                   l))
     return 1
Example #10
0
 def run(self, ptr):
     print 'GetSystemTimeAsFileTime(%s)' % ptr
     self.state.memory.store(ptr, claripy.BVV(0x0000000000000000, 64))
     return 0
Example #11
0
 def run(self, ptr):
     print 'QueryPerformanceCounter(%s)' % ptr
     self.state.memory.store(ptr, claripy.BVV(0x0000000000000000, 64))
     return 1
Example #12
0
 def run(self):
     addr = self.state.libc.heap_location
     self.state.libc.heap_location += 1
     self.state.memory.store(addr, claripy.BVV(0, 8))
     print 'GetCommandLineA() = %s' % hex(addr)
     return addr
Example #13
0
 def run(self, hModule, lpFilename, nSize):
     print 'GetModuleFileName(%s, %s, %s)' % (hModule, lpFilename, nSize)
     self.state.memory.store(lpFilename, claripy.BVV(0, 16))
     return 1
Example #14
0
 def run(self, key, subkey, options, sam, result):
     print 'RegOpenKeyExA(%s, %s, %s, %s, %s)' % (
         key, self.load_str(subkey), options, sam, result)
     self.state.memory.store(result, claripy.BVV(0xdeadbeefdeadbeef, 64))
     return 0
Example #15
0
import angr
import claripy

p = angr.Project("change_my_mind")

flag_chars = [claripy.BVS('flag_%d' % i, 8) for i in range(0x30-1)]
flag = claripy.Concat(*flag_chars + [claripy.BVV(b'\n')])
    
state = p.factory.entry_state(stdin=flag)
simgr = p.factory.simulation_manager(state)

print(simgr.explore(find=(0x400000+0x169d), avoid=(0x400000+0x160A)))
f = simgr.found[0] # this just confirms that the character length is correct (0x2F characters)
simgr.move('found', 'active') 
print(simgr.explore(find=(0x400000+0x1693), avoid=(0x400000+0x160A)))
f = simgr.found[0] # this is the state passing a check of some calculate on input == 0
print(f)
print((b"STDOUT: "+f.posix.dumps(1)).decode("utf-8"))
print((b"FLAG: "+f.solver.eval(flag, cast_to=bytes)).decode("utf-8"))

"""
STDOUT: Hello!
Please provide your credentials!
>>Lets'check...

FLAG: justCTF{1_ch4ng3d_my_m1nd_by_cl34r1n6_7h3_r00m}
"""
Example #16
0
def trace(config_name, binary_name):
    # Get config
    config = parse_config(config_name)
    print(config)

    # Set logging
    logger.info('Searching for vulns')
    logging.basicConfig()
    # TODO: disable in production
    config['log_level'] = "DEBUG"
    angr.manager.l.setLevel(config['log_level'])
    angr.exploration_techniques.spiller.l.setLevel(config['log_level'])
    cle.loader.l.setLevel(config['log_level'])
    logger.setLevel(config['log_level'])

    # Get libc path
    libc_path = os.path.expanduser(config['libc'])
    libc_name = os.path.basename(libc_path)
    # Get allocator path
    allocator_path = os.path.expanduser(config['allocator'])
    if allocator_path == 'default':
        allocator_path = libc_path

    allocator_name = os.path.basename(allocator_path)
    print("allocator_path: ", allocator_path)
    print("libc_path: ", libc_path)

    # Create project and disable sim_procedures for the libc
    proj = angr.Project(
        binary_name,
        exclude_sim_procedures_func=use_sim_procedure,
        load_options={
            'ld_path':
            [os.path.dirname(allocator_path),
             os.path.dirname(libc_path)],
            'auto_load_libs':
            True
        })

    input("@ angr init @")
    # Find write_target
    write_target_var = proj.loader.main_object.get_symbol('write_target')
    print("write_target_var: ", write_target_var)

    # Get libc
    print("libc_name: ", libc_name)
    libc = proj.loader.shared_objects[libc_name]

    # Get allocator
    print("allocator_name: ", allocator_name)
    allocator = proj.loader.shared_objects[allocator_name]

    # Create state and enable reverse memory map
    added_options = set()
    added_options.add(angr.options.REVERSE_MEMORY_NAME_MAP)
    added_options.add(angr.options.STRICT_PAGE_ACCESS)
    added_options.add(angr.options.CONCRETIZE_SYMBOLIC_FILE_READ_SIZES)
    added_options.add(angr.options.ZERO_FILL_UNCONSTRAINED_MEMORY)
    added_options.add(angr.options.ZERO_FILL_UNCONSTRAINED_REGISTERS)

    added_options.add(angr.options.SIMPLIFY_EXPRS)
    added_options.update(angr.options.simplification)
    added_options.update(angr.options.unicorn)

    #print(added_options)
    print("config['use_vsa']: ", config['use_vsa'])
    if config['use_vsa']:
        added_options.add(
            angr.options.APPROXIMATE_SATISFIABILITY)  # vsa for satisfiability
        added_options.add(angr.options.APPROXIMATE_GUARDS)  # vsa for guards
        added_options.add(
            angr.options.APPROXIMATE_MEMORY_SIZES)  # vsa for mem_sizes
        added_options.add(
            angr.options.APPROXIMATE_MEMORY_INDICES)  # vsa for mem_indices
    #print(added_options)

    removed_options = set()
    removed_options.add(angr.options.LAZY_SOLVES)

    # set heap location right after bss
    ### just to know the malloc addr should inside the heap
    ### nothing about heap content
    bss = proj.loader.main_object.sections_map['.bss']
    heap_base = ((bss.vaddr + bss.memsize) & ~0xfff) + 0x1000
    heap_size = 64 * 4096
    new_brk = claripy.BVV(heap_base + heap_size, proj.arch.bits)
    print(bss)
    print(hex(heap_base))
    print(new_brk)

    heap = SimHeapBrk(heap_base=heap_base, heap_size=heap_size)
    state = proj.factory.entry_state(add_options=added_options,
                                     remove_options=removed_options)
    state.register_plugin('heap', heap)
    state.register_plugin(
        'heaphopper',
        HeapConditionTracker(config=config,
                             wtarget=(write_target_var.rebased_addr,
                                      write_target_var.size),
                             libc=libc,
                             allocator=allocator))

    set_brk_ret = state.posix.set_brk(new_brk)
    state.heaphopper.set_level(config['log_level'])

    print("set_brk_ret: ", set_brk_ret)
    print("state.heap: ", state.heap)
    print("state.heaphopper: ", state.heaphopper)
    # IPython.embed()

    #print(config['fix_loader_problem'])
    if config['fix_loader_problem']:
        loader_name = os.path.basename(config['loader'])
        libc_version = re.findall(r'libc-([\d\.]+)', libc_path)[0]
        fix_loader_problem(proj, state, loader_name, libc_version)

    var_dict = setup_state(state, proj, config)
    #print("var_dict:", var_dict)

    # Set memory concretization strategies
    state.memory.read_strategies = [
        angr.state_plugins.symbolic_memory.concretization_strategies.
        SimConcretizationStrategySolutions(16),
        angr.state_plugins.symbolic_memory.concretization_strategies.
        SimConcretizationStrategyControlledData(4096, var_dict['global_vars']),
        angr.state_plugins.symbolic_memory.concretization_strategies.
        SimConcretizationStrategyEval(4096)
    ]
    state.memory.write_strategies = [
        angr.state_plugins.symbolic_memory.concretization_strategies.
        SimConcretizationStrategySolutions(16),
        angr.state_plugins.symbolic_memory.concretization_strategies.
        SimConcretizationStrategyControlledData(4096, var_dict['global_vars']),
        angr.state_plugins.symbolic_memory.concretization_strategies.
        SimConcretizationStrategyEval(4096)
    ]

    # Hook malloc and free
    malloc_addr = allocator.get_symbol('malloc').rebased_addr
    print("malloc_addr: ", hex(malloc_addr))
    free_addr = allocator.get_symbol('free').rebased_addr
    malloc_plt = proj.loader.main_object.plt.get('malloc')
    free_plt = proj.loader.main_object.plt.get('free')
    proj.hook(addr=malloc_plt,
              hook=MallocInspect(malloc_addr=malloc_addr,
                                 vulns=config['vulns'],
                                 ctrl_data=var_dict['allocs']))
    proj.hook(addr=free_plt,
              hook=FreeInspect(free_addr=free_addr,
                               vulns=config['vulns'],
                               sym_data=var_dict['sdata_addrs']))

    found_paths = []

    # Configure simgr
    sm = proj.factory.simgr(thing=state)

    sm.use_technique(
        VulnChecker(config['mem_corruption_fd'],
                    config['input_pre_constraint'], config['input_values'],
                    config['stop_found'], config['filter_fake_frees']))

    if config['use_mem_limiter']:
        sm.use_technique(
            MemLimiter(config['mem_limit'], config['drop_errored']))
    if config['use_dfs']:
        sm.use_technique(angr.exploration_techniques.DFS())
    if config['use_veritesting']:
        sm.use_technique(angr.exploration_techniques.Veritesting())
    if config['use_concretizer']:
        concr_addrs = var_dict['malloc_size_addrs'] + var_dict['allocs']
        sm.use_technique(Concretizer(concr_addrs))
    if config['spiller']:
        if config['dfs']:
            src_stash = 'deferred'
        else:
            src_stash = 'active'
        spill_conf = config['spiller_conf']
        ana_setup()
        spiller = angr.exploration_techniques.Spiller(
            src_stash=src_stash,
            min=spill_conf['min'],
            max=spill_conf['max'],
            staging_min=spill_conf['staging_min'],
            staging_max=spill_conf['staging_max'],
            priority_key=priority_key)
        sm.use_technique(spiller)

    avoids = (libc.get_symbol('abort').rebased_addr, )
    sm.use_technique(
        angr.exploration_techniques.Explorer(find=(var_dict['winning_addr'], ),
                                             avoid=avoids))

    # Create fd for memory corruption input
    name = b'memory_corruption'
    path = b'/tmp/%s' % name
    mem_corr_fd = config['mem_corruption_fd']
    # backing = SimSymbolicMemory(memory_id='file_%s' % name)
    # backing.set_state(state)
    f = SimFile(name, writable=False)
    f.set_state(state)
    state.fs.insert(path, f)
    real_fd = state.posix.open(path,
                               flags=Flags.O_RDONLY,
                               preferred_fd=mem_corr_fd)
    if mem_corr_fd != real_fd:
        raise Exception("Overflow fd already exists.")
    #state.posix.fd[mem_corr_fd] = f
    #state.posix.fs[name] = f

    # constrain input
    if config['input_pre_constraint']:
        if 'overflow' in config['zoo_actions']:
            overflow_bytes = config['zoo_actions']['overflow'] * max(
                config['overflow_sizes'])
        else:
            overflow_bytes = 0

        if 'uaf' in config['zoo_actions']:
            uaf_bytes = config['zoo_actions']['uaf'] * config['header_size']
        else:
            uaf_bytes = 0

        if 'arb_relative_write' in config['zoo_actions']:
            arw_bytes = config['zoo_actions'][
                'arb_relative'] * state.arch.byte_width * 2
        else:
            arw_bytes = 0

        num_bytes = overflow_bytes + uaf_bytes + arw_bytes
        input_bytes = state.posix.fd[mem_corr_fd].read_data(num_bytes)[0].chop(
            8)
        state.posix.fd[mem_corr_fd].seek(0)
        constrain_input(state, input_bytes, config['input_values'])

    # Manual inspection loop
    debug = False
    stop = False
    while len(sm.active) > 0 and not stop:
        if debug:
            debug = False
            IPython.embed()

        sm.step()
        logger.debug(f"sm addr: {sm.active}")
        #input("@")

        if heardEnter():
            debug = True

    print(sm.vuln)
    print("found_paths: ", found_paths)
    sm.move(from_stash='found',
            to_stash='vuln',
            filter_func=lambda p: p.heaphopper.vulnerable)
    found_paths.extend(sm.vuln)
    if config['spiller']:
        ana_teardown()

    print("found_paths: ", found_paths)
    input("@ found vulns @")

    for path in found_paths:
        win_addr, heap_func = get_win_addr(proj,
                                           path.history.bbl_addrs.hardcopy)
        path.heaphopper.win_addr = win_addr
        last_line = get_last_line(win_addr, binary_name)
        path.heaphopper.last_line = last_line
        if path.heaphopper.arb_write_info:
            path.heaphopper.arb_write_info[
                'instr'] = proj.loader.shared_objects[
                    allocator_name].addr_to_offset(
                        path.heaphopper.arb_write_info['instr'])
    logger.info('Found {} vulns'.format(len(found_paths)))

    if len(found_paths) > 0:
        arb_writes = store_results(config['num_results'], binary_name,
                                   found_paths, var_dict,
                                   config['mem_corruption_fd'])
        if config['store_desc']:
            store_vuln_descs(binary_name, found_paths, var_dict, arb_writes)
    IPython.embed()
    return 0
Example #17
0
def test_symbolic_merge(state):

    val = 0x01020304
    state.memory.store(0x0, claripy.BVV(val, 32))

    a = claripy.BVS('a0', 64)
    state.se.add(a <= 1)
    state.memory.store(a, claripy.BVV(0x5, 8))

    res = state.memory.load(0x0, 1)
    check(state, res, [5, 1])

    s1 = state.copy()
    s1.memory.store(0x1, claripy.BVV(0x6, 8))
    a1 = claripy.BVS('a1', 64)
    s1.se.add(a1 >= 1)
    s1.se.add(a1 <= 2)
    s1.memory.store(a1, claripy.BVV(0x7, 8))

    s2 = state.copy()
    s2.memory.store(0x1, claripy.BVV(0x8, 8))
    a2 = claripy.BVS('a2', 64)
    s2.se.add(a2 >= 1)
    s2.se.add(a2 <= 2)
    s2.memory.store(a2, claripy.BVV(0x9, 8))

    s3 = s1.copy()
    guard = claripy.BVS('guard', 32)
    s3.memory.merge([s2.memory], [guard > 1, guard <= 1], s1.memory)

    res = s3.memory.load(0x0, 1)
    check(s3, res, [5], (a == 0, ))
    check(s3, res, [1], (a == 1, ))

    res = s3.memory.load(0x1, 1)
    check(s3, res, [7], (
        guard > 1,
        a1 == 1,
    ))
    check(s3, res, [6], (
        guard > 1,
        a1 == 2,
    ))
    check(s3, res, [9], (
        guard <= 1,
        a2 == 1,
    ))
    check(s3, res, [8], (
        guard <= 1,
        a2 == 2,
    ))

    res = s3.memory.load(0x2, 1)
    check(s3, res, [7], (
        guard > 1,
        a1 == 2,
    ))
    check(s3, res, [3], (
        guard > 1,
        a1 == 1,
    ))
    check(s3, res, [9], (
        guard <= 1,
        a2 == 2,
    ))
    check(s3, res, [3], (
        guard <= 1,
        a2 == 1,
    ))

    res = s3.memory.load(0x3, 1)
    check(s3, res, [4], set())
Example #18
0
File: irop.py Project: webic/angr
 def _op_fgeneric_CmpEQ(self, a0, a1):  # pylint: disable=no-self-use
     # for cmpps_eq stuff, i.e. Iop_CmpEQ32Fx4
     return claripy.If(claripy.fpEQ(a0, a1), claripy.BVV(-1, len(a0)),
                       claripy.BVV(0, len(a0)))
Example #19
0
    def state_blank(self, addr=None, initial_prefix=None, brk=None, stack_end=None, stack_size=1024*1024*8, stdin=None, thread_idx=None, **kwargs):
        """
        Initialize a blank state.

        All parameters are optional.

        :param addr:            The execution start address.
        :param initial_prefix:
        :param stack_end:       The end of the stack (i.e., the byte after the last valid stack address).
        :param stack_size:      The number of bytes to allocate for stack space
        :param brk:             The address of the process' break.
        :return:                The initialized SimState.

        Any additional arguments will be passed to the SimState constructor
        """
        # TODO: move ALL of this into the SimState constructor
        if kwargs.get('mode', None) is None:
            kwargs['mode'] = self.project._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.project.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[(seg.min_addr, seg.max_addr)] = perms
            permissions_backer = (self.project.loader.main_object.execstack, permission_map)
            kwargs['permissions_backer'] = permissions_backer
        if kwargs.get('memory_backer', None) is None:
            kwargs['memory_backer'] = self.project.loader.memory
        if kwargs.get('os_name', None) is None:
            kwargs['os_name'] = self.name

        state = SimState(self.project, **kwargs)

        if stdin is not None and not isinstance(stdin, SimFileBase):
            if type(stdin) is type:
                stdin = stdin(name='stdin', has_end=False)
            else:
                stdin = SimFileStream(name='stdin', content=stdin, has_end=True)

        last_addr = self.project.loader.main_object.max_addr
        actual_brk = (last_addr - last_addr % 0x1000 + 0x1000) if brk is None else brk
        state.register_plugin('posix', SimSystemPosix(stdin=stdin, brk=actual_brk))


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

        if state.arch.sp_offset is not None:
            state.regs.sp = actual_stack_end + (state.arch.stack_change if state.arch.stack_change is not None else 0)

        if initial_prefix is not None:
            for reg in state.arch.default_symbolic_registers:
                state.registers.store(reg, state.solver.BVS(
                    initial_prefix + "_" + reg,
                    state.arch.bits,
                    explicit_name=True,
                    key=('reg', reg),
                    eternal=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)

            # special case for stack pointer override
            if actual_stack_end is not None and state.arch.registers[reg][0] == state.arch.sp_offset:
                continue

            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:
            state.regs.ip = self.project.entry

        thread_name = self.project.loader.main_object.threads[thread_idx] if thread_idx is not None else None
        for reg, val in self.project.loader.main_object.thread_registers(thread_name).items():
            if reg in state.arch.registers or reg in ('flags', 'eflags', 'rflags'):
                setattr(state.regs, reg, val)
            elif reg == 'fctrl':
                state.regs.fpround = (val & 0xC00) >> 10
            elif reg == 'fstat':
                state.regs.fc3210 = (val & 0x4700)
            elif reg == 'ftag':
                empty_bools = [((val >> (x * 2)) & 3) == 3 for x in range(8)]
                tag_chars = [claripy.BVV(0 if x else 1, 8) for x in empty_bools]
                for i, tag in enumerate(tag_chars):
                    setattr(state.regs, 'fpu_t%d' % i, tag)
            elif reg in ('fiseg', 'fioff', 'foseg', 'fooff', 'fop'):
                pass
            elif reg == 'mxcsr':
                state.regs.sseround = (val & 0x600) >> 9
            else:
                _l.error("What is this register %s I have to translate?", reg)


        if addr is not None:
            state.regs.ip = addr

        # set up the "root history" node
        state.scratch.ins_addr = addr
        state.scratch.bbl_addr = addr
        state.scratch.stmt_idx = 0
        state.history.jumpkind = 'Ijk_Boring'

        return state
Example #20
0
def main():
    global retn, pre_dispatcher, main_dispatcher, prologue, b, relevants, opcode
    if len(sys.argv) != 3:
        print('Usage: python deflat.py filename function_address(hex)')
        exit(0)
    opcode = {'a':'\x87', 'ae': '\x83', 'b':'\x82', 'be':'\x86', 'c':'\x82', 'e':'\x84', 'z':'\x84', 'g':'\x8F', 
              'ge':'\x8D', 'l':'\x8C', 'le':'\x8E', 'na':'\x86', 'nae':'\x82', 'nb':'\x83', 'nbe':'\x87', 'nc':'\x83',
              'ne':'\x85', 'ng':'\x8E', 'nge':'\x8C', 'nl':'\x8D', 'nle':'\x8F', 'no':'\x81', 'np':'\x8B', 'ns':'\x89',
              'nz':'\x85', 'o':'\x80', 'p':'\x8A', 'pe':'\x8A', 'po':'\x8B', 's':'\x88', 'nop':'\x90', 'jmp':'\xE9', 'j':'\x0F'}
    
    for k, v in opcode.items():
        opcode[k] = ord(v)

    filename = sys.argv[1]
    start = int(sys.argv[2], 16)
    barf = BARF(filename)
    base_addr = barf.binary.entry_point >> 12 << 12
    b = angr.Project(filename, load_options={'auto_load_libs': False, 'main_opts':{'custom_base_addr': 0}})
    print("entry: ", b.entry)
    cfg = barf.recover_cfg(start=start)
    blocks = cfg.basic_blocks
    prologue = start
    main_dispatcher = cfg.find_basic_block(prologue).direct_branch
    retn, pre_dispatcher = get_retn_predispatcher(cfg)
    relevant_blocks, nop_blocks = get_relevant_nop_blocks(cfg)
    print('*******************relevant blocks************************')
    print('prologue:%#x' % start)
    print('main_dispatcher:%#x' % main_dispatcher)
    print('pre_dispatcher:%#x' % pre_dispatcher)
    print('retn:%#x' % retn)
    print('relevant_blocks:', [hex(addr) for addr in relevant_blocks])

    print('*******************symbolic execution*********************')
    relevants = relevant_blocks
    relevants.append(prologue)
    relevants_without_retn = list(relevants)
    relevants.append(retn)
    flow = {}
    for parent in relevants:
        flow[parent] = []
    modify_value = None
    patch_instrs = {}
    for relevant in relevants_without_retn:
        print('-------------------dse %#x---------------------' % relevant)
        block = cfg.find_basic_block(relevant)
        has_branches = False
        hook_addr = None
        for ins in block.instrs:
            if ins.mnemonic.startswith('cmov'):
                patch_instrs[relevant] = ins
                has_branches = True
            elif ins.mnemonic.startswith('call'):
                hook_addr = ins.address
        if has_branches:
            flow[relevant].append(symbolic_execution(relevant, hook_addr, claripy.BVV(1, 1), True))
            flow[relevant].append(symbolic_execution(relevant, hook_addr, claripy.BVV(0, 1), True))
        else:
            flow[relevant].append(symbolic_execution(relevant, hook_addr))
            
    print('************************flow******************************')
    for (k, v) in flow.items():
        print('%#x:' % k, [hex(child) for child in v])

    print('************************patch*****************************')
    flow.pop(retn)
    origin = open(filename, 'rb')
    origin_data = list(origin.read())
    origin.close()
    recovery = open(filename + '.recovered', 'wb')
    for nop_block in nop_blocks:
        fill_nop(origin_data, nop_block.start_address - base_addr, nop_block.end_address - base_addr + 1)    
    for (parent, childs) in flow.items():
        if len(childs) == 1:
            last_instr = cfg.find_basic_block(parent).instrs[-1]
            file_offset = last_instr.address - base_addr
            origin_data[file_offset] = opcode['jmp']
            file_offset += 1
            fill_nop(origin_data, file_offset, file_offset + last_instr.size - 1)
            fill_jmp_offset(origin_data, file_offset, childs[0] - last_instr.address - 5)
        else:
            instr = patch_instrs[parent]
            file_offset = instr.address - base_addr
            fill_nop(origin_data, file_offset, cfg.find_basic_block(parent).end_address - base_addr + 1)
            origin_data[file_offset] = opcode['j']
            origin_data[file_offset + 1] = opcode[instr.mnemonic[4:]]
            fill_jmp_offset(origin_data, file_offset + 2, childs[0] - instr.address - 6)
            file_offset += 6
            origin_data[file_offset] = opcode['jmp']
            fill_jmp_offset(origin_data, file_offset + 1, childs[1] - (instr.address + 6) - 5)
    recovery.write(bytearray(origin_data))
    recovery.close()
    print('Successful! The recovered file: %s' % (filename + '.recovered'))
Example #21
0
    def state_entry(self, **kwargs):
        if isinstance(self.proj.loader.main_bin, BackedCGC):
            kwargs['permissions_backer'] = (
                True, self.proj.loader.main_bin.permissions_map)
        kwargs['add_options'] = {o.CGC_ZERO_FILL_UNCONSTRAINED_MEMORY
                                 } | kwargs.get('add_options', set())

        state = super(SimCGC, self).state_entry(**kwargs)

        if isinstance(self.proj.loader.main_bin, BackedCGC):
            for reg, val in self.proj.loader.main_bin.initial_register_values(
            ):
                if reg in state.arch.registers:
                    setattr(state.regs, reg, val)
                elif reg == 'eflags':
                    pass
                elif reg == 'fctrl':
                    state.regs.fpround = (val & 0xC00) >> 10
                elif reg == 'fstat':
                    state.regs.fc3210 = (val & 0x4700)
                elif reg == 'ftag':
                    empty_bools = [((val >> (x * 2)) & 3) == 3
                                   for x in xrange(8)]
                    tag_chars = [
                        claripy.BVV(0 if x else 1, 8) for x in empty_bools
                    ]
                    for i, tag in enumerate(tag_chars):
                        setattr(state.regs, 'fpu_t%d' % i, tag)
                elif reg in ('fiseg', 'fioff', 'foseg', 'fooff', 'fop'):
                    pass
                elif reg == 'mxcsr':
                    state.regs.sseround = (val & 0x600) >> 9
                else:
                    l.error("What is this register %s I have to translate?",
                            reg)

            # Update allocation base
            state.cgc.allocation_base = self.proj.loader.main_bin.current_allocation_base

            # Do all the writes
            writes_backer = self.proj.loader.main_bin.writes_backer
            stdout = 1
            for size in writes_backer:
                if size == 0:
                    continue
                str_to_write = state.posix.files[1].content.load(
                    state.posix.files[1].pos, size)
                a = SimActionData(state,
                                  'file_1_0',
                                  'write',
                                  addr=claripy.BVV(state.posix.files[1].pos,
                                                   state.arch.bits),
                                  data=str_to_write,
                                  size=size)
                state.posix.write(stdout, str_to_write, size)
                state.log.add_action(a)

        else:
            # Set CGC-specific variables
            state.regs.eax = 0
            state.regs.ebx = 0
            state.regs.ecx = 0x4347c000
            state.regs.edx = 0
            state.regs.edi = 0
            state.regs.esi = 0
            state.regs.esp = 0xbaaaaffc
            state.regs.ebp = 0
            state.regs.cc_dep1 = 0x202  # default eflags
            state.regs.cc_op = 0  # OP_COPY
            state.regs.cc_dep2 = 0  # doesn't matter
            state.regs.cc_ndep = 0  # doesn't matter

            # fpu values
            state.regs.mm0 = 0
            state.regs.mm1 = 0
            state.regs.mm2 = 0
            state.regs.mm3 = 0
            state.regs.mm4 = 0
            state.regs.mm5 = 0
            state.regs.mm6 = 0
            state.regs.mm7 = 0
            state.regs.fpu_tags = 0
            state.regs.fpround = 0
            state.regs.fc3210 = 0x0300
            state.regs.ftop = 0

            # sse values
            state.regs.sseround = 0
            state.regs.xmm0 = 0
            state.regs.xmm1 = 0
            state.regs.xmm2 = 0
            state.regs.xmm3 = 0
            state.regs.xmm4 = 0
            state.regs.xmm5 = 0
            state.regs.xmm6 = 0
            state.regs.xmm7 = 0

            # segmentation registers
            state.regs.ds = 0
            state.regs.es = 0
            state.regs.fs = 0
            state.regs.gs = 0
            state.regs.ss = 0
            state.regs.cs = 0

        return state
Example #22
0
def test_expression():
    bc = claripy.backends.concrete

    e = claripy.BVV(0x01020304, 32)
    nose.tools.assert_equal(len(e), 32)
    r = e.reversed
    nose.tools.assert_equal(bc.convert(r), 0x04030201)
    nose.tools.assert_equal(len(r), 32)

    nose.tools.assert_equal([ bc.convert(i) for i in r.chop(8) ], [ 4, 3, 2, 1 ] )

    e1 = r[31:24]
    nose.tools.assert_equal(bc.convert(e1), 0x04)
    nose.tools.assert_equal(len(e1), 8)
    nose.tools.assert_equal(bc.convert(e1[2]), 1)
    nose.tools.assert_equal(bc.convert(e1[1]), 0)

    ee1 = e1.zero_extend(8)
    nose.tools.assert_equal(bc.convert(ee1), 0x0004)
    nose.tools.assert_equal(len(ee1), 16)

    ee1 = claripy.BVV(0xfe, 8).sign_extend(8)
    nose.tools.assert_equal(bc.convert(ee1), 0xfffe)
    nose.tools.assert_equal(len(ee1), 16)

    xe1 = [ bc.convert(i) for i in e1.chop(1) ]
    nose.tools.assert_equal(xe1, [ 0, 0, 0, 0, 0, 1, 0, 0 ])

    a = claripy.BVV(1, 1)
    nose.tools.assert_equal(bc.convert(a+a), 2)

    x = claripy.BVV(1, 32)
    nose.tools.assert_equal(x.length, 32)
    y = claripy.LShR(x, 10)
    nose.tools.assert_equal(y.length, 32)

    r = claripy.BVV(0x01020304, 32)
    rr = r.reversed
    rrr = rr.reversed
    #nose.tools.assert_is(bc.convert(r), bc.convert(rrr))
    #nose.tools.assert_is(type(bc.convert(rr)), claripy.A)
    nose.tools.assert_equal(bc.convert(rr), 0x04030201)
    nose.tools.assert_is(r.concat(rr), claripy.Concat(r, rr))

    rsum = r+rr
    nose.tools.assert_equal(bc.convert(rsum), 0x05050505)

    r = claripy.BVS('x', 32)
    rr = r.reversed
    rrr = rr.reversed
    nose.tools.assert_is(r, rrr)

    # test identity
    nose.tools.assert_is(r, rrr)
    nose.tools.assert_is_not(r, rr)
    ii = claripy.BVS('ii', 32)
    ij = claripy.BVS('ij', 32)
    nose.tools.assert_is(ii, ii)
    nose.tools.assert_is_not(ii, ij)

    si = claripy.SI(bits=32, stride=2, lower_bound=20, upper_bound=100)
    sj = claripy.SI(bits=32, stride=2, lower_bound=10, upper_bound=10)
    sk = claripy.SI(bits=32, stride=2, lower_bound=20, upper_bound=100)
    nose.tools.assert_true(claripy.backends.vsa.identical(si, si))
    nose.tools.assert_false(claripy.backends.vsa.identical(si, sj))
    nose.tools.assert_true(claripy.backends.vsa.identical(si, sk))
    nose.tools.assert_is_not(si, sj)
    nose.tools.assert_is_not(sj, sk)
    nose.tools.assert_is_not(sk, si)

    # test hash cache
    nose.tools.assert_is(a+a, a+a)

    # test replacement
    old = claripy.BVS('old', 32, explicit_name=True)
    new = claripy.BVS('new', 32, explicit_name=True)
    ooo = claripy.BVV(0, 32)

    old_formula = claripy.If((old + 1)%256 == 0, old+10, old+20)
    print old_formula.dbg_repr()
    new_formula = old_formula.replace(old, new)
    print new_formula.dbg_repr()
    ooo_formula = new_formula.replace(new, ooo)

    print ooo_formula.dbg_repr()

    nose.tools.assert_not_equal(hash(old_formula), hash(new_formula))
    nose.tools.assert_not_equal(hash(old_formula), hash(ooo_formula))
    nose.tools.assert_not_equal(hash(new_formula), hash(ooo_formula))

    nose.tools.assert_equal(old_formula.variables, { 'old' })
    nose.tools.assert_equal(new_formula.variables, { 'new' })
    nose.tools.assert_equal(ooo_formula.variables, ooo.variables)

    nose.tools.assert_true(old_formula.symbolic)
    nose.tools.assert_true(new_formula.symbolic)
    nose.tools.assert_true(new_formula.symbolic)

    nose.tools.assert_equal(str(old_formula).replace('old', 'new'), str(new_formula))
    nose.tools.assert_equal(bc.convert(ooo_formula), 20)

    # test dict replacement
    old = claripy.BVS('old', 32, explicit_name=True)
    new = claripy.BVS('new', 32, explicit_name=True)
    c = (old + 10) - (old + 20)
    d = (old + 1) - (old + 2)
    cr = c.replace_dict({(old+10).cache_key: (old+1), (old+20).cache_key: (old+2)})
    nose.tools.assert_is(cr, d)

    # test AST collapse
    s = claripy.SI(bits=32, stride=0, lower_bound=10, upper_bound=10)
    b = claripy.BVV(20, 32)

    sb = s+b
    nose.tools.assert_is_instance(sb.args[0], claripy.ast.Base)

    bb = b+b
    # this was broken previously -- it was checking if type(bb.args[0]) == A,
    # and it wasn't, but was instead a subclass. leaving this out for now
    # nose.tools.assert_not_is_instance(bb.args[0], claripy.ast.Base)

    # ss = s+s
    # (see above)
    # nose.tools.assert_not_is_instance(ss.args[0], claripy.ast.Base)

    sob = s|b
    # for now, this is collapsed. Presumably, Fish will make it not collapse at some point
    nose.tools.assert_is_instance(sob.args[0], claripy.ast.Base)

    # make sure the AST collapses for delayed ops like reversing
    rb = b.reversed
    #nose.tools.assert_is_instance(rb.args[0], claripy.ast.Base)
    # TODO: Properly delay reversing: should not be eager

    nose.tools.assert_is_not(rb, bb)
    nose.tools.assert_is(rb, rb)

    # test some alternate bvv creation methods
    nose.tools.assert_is(claripy.BVV('AAAA'), claripy.BVV(0x41414141, 32))
    nose.tools.assert_is(claripy.BVV('AAAA', 32), claripy.BVV(0x41414141, 32))
    nose.tools.assert_is(claripy.BVV('AB'), claripy.BVV(0x4142, 16))
    nose.tools.assert_is(claripy.BVV('AB', 16), claripy.BVV(0x4142, 16))
    nose.tools.assert_raises(claripy.errors.ClaripyValueError, claripy.BVV, 'AB', 8)
Example #23
0
def test_complex_guy():
    guy_wide = claripy.widen(
        claripy.union(
            claripy.union(
                claripy.union(claripy.BVV(0L, 32), claripy.BVV(1, 32)),
                claripy.union(claripy.BVV(0L, 32), claripy.BVV(1, 32)) +
                claripy.BVV(1, 32)),
            claripy.union(
                claripy.union(claripy.BVV(0L, 32), claripy.BVV(1, 32)),
                claripy.union(claripy.BVV(0L, 32), claripy.BVV(1, 32)) +
                claripy.BVV(1, 32)) + claripy.BVV(1, 32)),
        claripy.union(
            claripy.union(
                claripy.union(
                    claripy.union(claripy.BVV(0L, 32), claripy.BVV(1, 32)),
                    claripy.union(claripy.BVV(0L, 32), claripy.BVV(1, 32)) +
                    claripy.BVV(1, 32)),
                claripy.union(
                    claripy.union(claripy.BVV(0L, 32), claripy.BVV(1, 32)),
                    claripy.union(claripy.BVV(0L, 32), claripy.BVV(1, 32)) +
                    claripy.BVV(1, 32)) + claripy.BVV(1, 32)),
            claripy.union(
                claripy.union(
                    claripy.union(claripy.BVV(0L, 32), claripy.BVV(1, 32)),
                    claripy.union(claripy.BVV(0L, 32), claripy.BVV(1, 32)) +
                    claripy.BVV(1, 32)),
                claripy.union(
                    claripy.union(claripy.BVV(0L, 32), claripy.BVV(1, 32)),
                    claripy.union(claripy.BVV(0L, 32), claripy.BVV(1, 32)) +
                    claripy.BVV(1, 32)) + claripy.BVV(1, 32)) +
            claripy.BVV(1, 32)))
    guy_inc = guy_wide + claripy.BVV(1, 32)
    guy_zx = claripy.ZeroExt(32, guy_inc)

    s, r = claripy.balancer.Balancer(claripy.backends.vsa,
                                     guy_inc <= claripy.BVV(39, 32)).compat_ret
    assert s
    assert r[0][0] is guy_wide
    assert claripy.backends.vsa.min(r[0][1]) == 0
    assert set(claripy.backends.vsa.eval(r[0][1], 1000)) == set([4294967295] +
                                                                range(39))

    s, r = claripy.balancer.Balancer(claripy.backends.vsa,
                                     guy_zx <= claripy.BVV(39, 64)).compat_ret
    assert r[0][0] is guy_wide
    assert claripy.backends.vsa.min(r[0][1]) == 0
    assert set(claripy.backends.vsa.eval(r[0][1], 1000)) == set([4294967295] +
                                                                range(39))
Example #24
0
    def _initialize_page(self, n, new_page):
        if n in self._initialized:
            return False
        self._initialized.add(n)

        new_page_addr = n * self._page_size
        initialized = False

        if self.state is not None:
            self.state.scratch.push_priv(True)

        if self._memory_backer is None:
            pass
        elif isinstance(self._memory_backer, cle.Clemory):
            # first, find the right clemory backer
            for addr, backer in self._memory_backer.cbackers:
                start_backer = new_page_addr - addr
                if isinstance(start_backer, BV):
                    continue
                if start_backer < 0 and abs(start_backer) >= self._page_size:
                    continue
                if start_backer >= len(backer):
                    continue

                # find permission backer associated with the address, there should be a
                # memory backer that matches the start_backer. if not fall back to read-write
                flags = Page.PROT_READ | Page.PROT_WRITE
                for start, end in self._permission_map:
                    if start == addr:
                        flags = self._permission_map[(start, end)]
                        break

                snip_start = max(0, start_backer)
                write_start = max(new_page_addr, addr + snip_start)
                write_size = self._page_size - write_start % self._page_size

                snip = _ffi.buffer(backer)[snip_start:snip_start + write_size]
                mo = SimMemoryObject(claripy.BVV(snip), write_start)
                self._apply_object_to_page(n * self._page_size,
                                           mo,
                                           page=new_page)

                new_page.permissions = claripy.BVV(flags, 3)
                initialized = True

        elif len(self._memory_backer) <= self._page_size:
            for i in self._memory_backer:
                if new_page_addr <= i and i <= new_page_addr + self._page_size:
                    if isinstance(self._memory_backer[i], claripy.ast.Base):
                        backer = self._memory_backer[i]
                    else:
                        backer = claripy.BVV(self._memory_backer[i])
                    mo = SimMemoryObject(backer, i)
                    self._apply_object_to_page(n * self._page_size,
                                               mo,
                                               page=new_page)
                    initialized = True
        elif len(self._memory_backer) > self._page_size:
            for i in range(self._page_size):
                try:
                    if isinstance(self._memory_backer[i], claripy.ast.Base):
                        backer = self._memory_backer[i]
                    else:
                        backer = claripy.BVV(self._memory_backer[i])
                    mo = SimMemoryObject(backer, new_page_addr + i)
                    self._apply_object_to_page(n * self._page_size,
                                               mo,
                                               page=new_page)
                    initialized = True
                except KeyError:
                    pass

        if self.state is not None:
            self.state.scratch.pop_priv()
        return initialized
Example #25
0
    def call(cls, project, target, args=(), start=None, prototype=None, **kwargs): #pylint:disable=unused-argument
        """
        Calls a function in the binary, returning a PathGroup with the call set up.

        :param project:     A Project instance.
        :type  project:     angr.project.Project
        :param target:      Address of function to call.
        :param args:        Arguments to call the function with.
        :param start:       Optional, path (or paths) to start the call with.
        :param prototype:   Optional, A SimTypeFunction to typecheck arguments against.
        :param kwargs:      Any other keyword args will be passed to the PathGroup constructor.
        :returns:           A PathGroup calling the function.
        :rtype:             PathGroup
        """

        fake_return_addr = project._extern_obj.get_pseudo_addr('FAKE_RETURN_ADDR')
        if not project.is_hooked(fake_return_addr):
            project.hook(fake_return_addr, CallReturn)
        cc = simuvex.DefaultCC[project.arch.name](project.arch)

        active_paths = []
        if start is None:
            active_paths.append(project.factory.path(addr=target))
        elif hasattr(start, '__iter__'):
            active_paths.extend(start)
        else:
            active_paths.append(start)

        ret_addr = claripy.BVV(fake_return_addr, project.arch.bits)

        def fix_arg(st, arg):
            if isinstance(arg, str):
                # store the string, nul-terminated, at the current heap location
                # then return a pointer to that location
                ptr = st.libc.heap_location
                st.memory.store(ptr, st.se.BVV(arg, st.arch.bits))
                st.memory.store(ptr + len(arg), st.se.BVV(0, 8))
                st.libc.heap_location += len(arg) + 1
                return ptr
            elif isinstance(arg, (tuple, list)):
                # fix the entries of the list, then store them in a
                # NULL-terminated array at the current heap location and return
                # a pointer to there
                # N.B.: uses host endianness to store entries!!! mostly useful for string arrays
                fixed_entries = [fix_arg(st, entry) for entry in arg]
                cur_ptr = start_ptr = st.libc.heap_location
                for entry in fixed_entries:
                    st.memory.store(cur_ptr, entry, endness=st.arch.memory_endness)
                    cur_ptr += entry.length

                entry_length = fixed_entries[0].length if len(fixed_entries) > 0 else st.arch.bits
                st.memory.store(cur_ptr, st.se.BVV(0, entry_length))

                st.libc.heap_location = cur_ptr + entry_length
                return start_ptr
            elif isinstance(arg, (int, long)):
                return st.se.BVV(arg, st.arch.bits)
            elif isinstance(arg, StringSpec):
                ptr = st.libc.heap_location
                arg.dump(st, ptr)
                st.libc.heap_location += len(arg)
                return ptr
            else:
                return arg

        for p in active_paths:
            p.state.ip = target
            fixed_args = [fix_arg(p.state, arg) for arg in args]
            cc.setup_callsite(p.state, ret_addr, fixed_args)

        return cls(project, active_paths=active_paths, **kwargs)
Example #26
0
    def state_entry(self, args=None, env=None, argc=None, **kwargs):
        state = super(SimLinux, self).state_entry(**kwargs)

        # Handle default values
        filename = self.project.filename or 'dummy_filename'
        if args is None:
            args = [filename]

        if env is None:
            env = {}

        # Prepare argc
        if argc is None:
            argc = claripy.BVV(len(args), state.arch.bits)
        elif type(argc) is int:  # pylint: disable=unidiomatic-typecheck
            argc = claripy.BVV(argc, state.arch.bits)

        # Make string table for args/env/auxv
        table = StringTableSpec()

        # Add args to string table
        table.append_args(args)

        # Add environment to string table
        table.append_env(env)

        # Prepare the auxiliary vector and add it to the end of the string table
        # TODO: Actually construct a real auxiliary vector
        # current vector is an AT_RANDOM entry where the "random" value is 0xaec0aec0aec0...
        aux = [(25, b"\xAE\xC0" * 8)]
        for a, b in aux:
            table.add_pointer(a)
            if isinstance(b, bytes):
                table.add_string(b)
            else:
                table.add_pointer(b)

        table.add_null()
        table.add_null()

        # Dump the table onto the stack, calculate pointers to args, env, and auxv
        state.memory.store(state.regs.sp - 16, claripy.BVV(0, 8 * 16))
        argv = table.dump(state, state.regs.sp - 16)
        envp = argv + ((len(args) + 1) * state.arch.bytes)
        auxv = argv + ((len(args) + len(env) + 2) * state.arch.bytes)

        # Put argc on stack and fix the stack pointer
        newsp = argv - state.arch.bytes
        state.memory.store(newsp, argc, endness=state.arch.memory_endness)
        state.regs.sp = newsp

        if state.arch.name in ('PPC32', ):
            state.stack_push(claripy.BVV(0, 32))
            state.stack_push(claripy.BVV(0, 32))
            state.stack_push(claripy.BVV(0, 32))
            state.stack_push(claripy.BVV(0, 32))

        # store argc argv envp auxv in the posix plugin
        state.posix.argv = argv
        state.posix.argc = argc
        state.posix.environ = envp
        state.posix.auxv = auxv
        self.set_entry_register_values(state)

        # set __progname
        progname_full = 0
        progname = 0
        if args:
            progname_full = state.mem[argv].long.concrete
            progname_cur = progname_full
            progname = progname_full
            while True:
                byte = state.mem[progname_cur].byte.resolved
                if byte.symbolic:
                    break
                else:
                    if state.solver.eval(byte) == ord('/'):
                        progname = progname_cur + 1
                    elif state.solver.eval(byte) == 0:
                        break

                progname_cur += 1

        # there will be multiple copies of these symbol but the canonical ones (in the main binary,
        # or elsewhere if the main binary didn't have one) should get picked up here
        for name, val in [('__progname_full', progname_full),
                          ('__progname', progname), ('__environ', envp),
                          ('environ', envp),
                          ('__libc_stack_end', state.regs.sp)]:
            sym = self.project.loader.find_symbol(name)
            if sym is not None:
                if sym.size != self.arch.bytes:
                    _l.warning("Something is wrong with %s - bad size", name)
                else:
                    state.mem[sym.rebased_addr].long = val

        return state
Example #27
0
    def state_entry(self, args=None, env=None, argc=None, **kwargs):
        state = super(SimLinux, self).state_entry(**kwargs)

        # Handle default values
        if args is None:
            args = []

        if env is None:
            env = {}

        # Prepare argc
        if argc is None:
            argc = claripy.BVV(len(args), state.arch.bits)
        elif type(argc) in (int, long):  # pylint: disable=unidiomatic-typecheck
            argc = claripy.BVV(argc, state.arch.bits)

        # Make string table for args/env/auxv
        table = StringTableSpec()

        # Add args to string table
        table.append_args(args)

        # Add environment to string table
        table.append_env(env)

        # Prepare the auxiliary vector and add it to the end of the string table
        # TODO: Actually construct a real auxiliary vector
        # current vector is an AT_RANDOM entry where the "random" value is 0xaec0aec0aec0...
        aux = [(25, ("AEC0" * 8).decode('hex'))]
        for a, b in aux:
            table.add_pointer(a)
            if isinstance(b, str):
                table.add_string(b)
            else:
                table.add_pointer(b)

        table.add_null()
        table.add_null()

        # Dump the table onto the stack, calculate pointers to args, env, and auxv
        state.memory.store(state.regs.sp - 16, claripy.BVV(0, 8 * 16))
        argv = table.dump(state, state.regs.sp - 16)
        envp = argv + ((len(args) + 1) * state.arch.bytes)
        auxv = argv + ((len(args) + len(env) + 2) * state.arch.bytes)

        # Put argc on stack and fix the stack pointer
        newsp = argv - state.arch.bytes
        state.memory.store(newsp, argc, endness=state.arch.memory_endness)
        state.regs.sp = newsp

        if state.arch.name in ('PPC32', ):
            state.stack_push(claripy.BVV(0, 32))
            state.stack_push(claripy.BVV(0, 32))
            state.stack_push(claripy.BVV(0, 32))
            state.stack_push(claripy.BVV(0, 32))

        # store argc argv envp auxv in the posix plugin
        state.posix.argv = argv
        state.posix.argc = argc
        state.posix.environ = envp
        state.posix.auxv = auxv
        self.set_entry_register_values(state)

        return state
Example #28
0
    def state_entry(self, add_options=None, **kwargs):
        if isinstance(self.project.loader.main_object, BackedCGC):
            kwargs['permissions_backer'] = (
                True, self.project.loader.main_object.permissions_map)
        if add_options is None:
            add_options = set()
        add_options.add(o.ZERO_FILL_UNCONSTRAINED_MEMORY)

        state = super(SimCGC, self).state_entry(add_options=add_options,
                                                **kwargs)

        if isinstance(self.project.loader.main_object, BackedCGC):
            # Update allocation base
            state.cgc.allocation_base = self.project.loader.main_object.current_allocation_base

            # Do all the writes
            writes_backer = self.project.loader.main_object.writes_backer
            stdout = state.posix.get_fd(1)
            pos = 0
            for size in writes_backer:
                if size == 0:
                    continue
                str_to_write = state.solver.BVS('file_write', size * 8)
                a = SimActionData(state,
                                  'file_1_0',
                                  'write',
                                  addr=claripy.BVV(pos, state.arch.bits),
                                  data=str_to_write,
                                  size=size)
                stdout.write_data(str_to_write)
                state.history.add_action(a)
                pos += size

        else:
            # Set CGC-specific variables
            state.regs.eax = 0
            state.regs.ebx = 0
            state.regs.ecx = 0x4347c000
            state.regs.edx = 0
            state.regs.edi = 0
            state.regs.esi = 0
            state.regs.esp = 0xbaaaaffc
            state.regs.ebp = 0
            state.regs.cc_dep1 = 0x202  # default eflags
            state.regs.cc_op = 0  # OP_COPY
            state.regs.cc_dep2 = 0  # doesn't matter
            state.regs.cc_ndep = 0  # doesn't matter

            # fpu values
            state.regs.mm0 = 0
            state.regs.mm1 = 0
            state.regs.mm2 = 0
            state.regs.mm3 = 0
            state.regs.mm4 = 0
            state.regs.mm5 = 0
            state.regs.mm6 = 0
            state.regs.mm7 = 0
            state.regs.fpu_tags = 0
            state.regs.fpround = 0
            state.regs.fc3210 = 0x0300
            state.regs.ftop = 0

            # sse values
            state.regs.sseround = 0
            state.regs.xmm0 = 0
            state.regs.xmm1 = 0
            state.regs.xmm2 = 0
            state.regs.xmm3 = 0
            state.regs.xmm4 = 0
            state.regs.xmm5 = 0
            state.regs.xmm6 = 0
            state.regs.xmm7 = 0

            # segmentation registers
            state.regs.ds = 0
            state.regs.es = 0
            state.regs.fs = 0
            state.regs.gs = 0
            state.regs.ss = 0
            state.regs.cs = 0

        return state
Example #29
0
def setup_state(state, proj, config):
    # set heap location right after bss
    bss = proj.loader.main_object.sections_map['.bss']
    heap_start = ((bss.vaddr + bss.memsize) & ~0xfff) + 0x1000
    heap_size = 64 * 4096
    new_brk = claripy.BVV(heap_start + heap_size, state.arch.bits)
    state.posix.set_brk(new_brk)

    state.libc.heap_location = heap_start
    state.libc.mmap_base = heap_start + heap_size * 2

    # Inject symbolic controlled data into memory
    var_dict = dict()
    var_dict['global_vars'] = []
    var_dict['allocs'] = []
    for i in range(20):
        cdata = proj.loader.main_object.get_symbol('ctrl_data_{}'.format(i))
        # check if ctrl_data exists
        if not cdata:
            break

        var_dict['global_vars'].append(cdata.rebased_addr)
        var_dict['allocs'].append(cdata.rebased_addr)

    # Set mem2chunk offset
    mem2chunk_var = proj.loader.main_object.get_symbol('mem2chunk_offset')
    var_dict['mem2chunk_addr'] = mem2chunk_var.rebased_addr
    mem2chunk = state.solver.BVV(value=config['mem2chunk_offset'], size=8 * 8)
    state.memory.store(var_dict['mem2chunk_addr'],
                       mem2chunk,
                       8,
                       endness='Iend_LE')

    # Inject symbolic data into memory that can't be resolved
    var_dict['sdata_addrs'] = []
    sdata_var = proj.loader.main_object.get_symbol('sym_data')
    # check if sym_data exists
    if sdata_var:
        for i in range(0, config['sym_data_size'], 8):
            smem_elem = state.solver.BVS('smem', 8 * 8)
            state.memory.store(sdata_var.rebased_addr + i,
                               smem_elem,
                               8,
                               endness='Iend_LE')
            var_dict['sdata_addrs'].append(sdata_var.rebased_addr + i)

        # create entry in sym_data state storage
        var_dict['sym_data_ptr'] = sdata_var.rebased_addr + config[
            'mem2chunk_offset']
        state.heaphopper.sym_data_states[var_dict['sym_data_ptr']] = None
        # add sym_data_size to heap state
        state.heaphopper.sym_data_size = config['sym_data_size']
        # add global_ptr to global_vars:
        var_dict['global_vars'].append(sdata_var.rebased_addr)

    # Setup write_target
    var_dict['wtarget_addrs'] = []
    write_target_var = proj.loader.main_object.get_symbol('write_target')
    for i in range(0, write_target_var.size, 8):
        write_mem_elem = state.solver.BVS('write_mem', 8 * 8)
        state.memory.store(write_target_var.rebased_addr + i,
                           write_mem_elem,
                           8,
                           endness='Iend_LE')
        var_dict['wtarget_addrs'].append(write_target_var.rebased_addr + i)
        var_dict['global_vars'].append(write_target_var.rebased_addr + i)

    # Set header size
    header_size_var = proj.loader.main_object.get_symbol('header_size')
    var_dict['header_size_addr'] = header_size_var.rebased_addr
    header_size = state.solver.BVV(value=config['header_size'], size=8 * 8)
    state.memory.store(var_dict['header_size_addr'],
                       header_size,
                       8,
                       endness='Iend_LE')

    # Set malloc sizes
    malloc_size_var = proj.loader.main_object.get_symbol('malloc_sizes')
    var_dict['malloc_size_addrs'] = [
        malloc_size_var.rebased_addr + i
        for i in range(0, malloc_size_var.size, 8)
    ]
    var_dict['malloc_size_bvs'] = []

    if max(config['malloc_sizes']) != 0:
        bvs_size = int(math.ceil(math.log(max(config['malloc_sizes']), 2))) + 1
    else:
        bvs_size = 8
    num_bytes = int(math.ceil(bvs_size / float(state.arch.byte_width)))
    bit_diff = num_bytes * state.arch.byte_width - bvs_size

    for msize in var_dict['malloc_size_addrs']:
        if len(config['malloc_sizes']) > 1:
            malloc_var = state.solver.BVS('malloc_size',
                                          bvs_size).zero_extend(bit_diff)
            constraint = claripy.Or(malloc_var == config['malloc_sizes'][0])
            for bin_size in config['malloc_sizes'][1:]:
                constraint = claripy.Or(malloc_var == bin_size, constraint)
            state.add_constraints(constraint)
        else:
            malloc_var = state.solver.BVV(config['malloc_sizes'][0],
                                          state.arch.bits)
        var_dict['malloc_size_bvs'].append(malloc_var)
        state.memory.store(msize, claripy.BVV(0, 8 * 8),
                           endness='Iend_LE')  # zero-fill first just in case
        state.memory.store(msize, malloc_var, endness='Iend_LE')

    # Set fill sizes
    fill_size_var = proj.loader.main_object.get_symbol('fill_sizes')
    var_dict['fill_size_addrs'] = [
        fill_size_var.rebased_addr + i for i in range(0, fill_size_var.size, 8)
    ]
    var_dict['fill_size_vars'] = []
    if config['chunk_fill_size'] == 'zero':
        var_dict['fill_size_vars'] = [state.solver.BVV(0, 8 * 8)] * len(
            var_dict['fill_size_addrs'])
    if config['chunk_fill_size'] == 'header_size':
        var_dict['fill_size_vars'] = [header_size] * len(
            var_dict['fill_size_addrs'])
    if config['chunk_fill_size'] == 'chunk_size':
        var_dict['fill_size_vars'] = var_dict['malloc_size_bvs']
    if type(config['chunk_fill_size']) in (int, int):
        var_dict['fill_size_vars'] = [
            claripy.BVV(config['chunk_fill_size'], 8 * 8)
        ] * len(var_dict['fill_size_addrs'])

    for fsize, fill_var in zip(var_dict['fill_size_addrs'],
                               var_dict['fill_size_vars']):
        state.memory.store(fsize, claripy.BVV(0, 8 * 8),
                           endness='Iend_LE')  # zero-fill first just in case
        state.memory.store(fsize, fill_var, endness='Iend_LE')

    # Set overflow sizes
    overflow_size_var = proj.loader.main_object.get_symbol('overflow_sizes')
    overflow_size_offset = overflow_size_var.rebased_addr
    var_dict['overflow_sizes_addrs'] = [
        overflow_size_offset + i for i in range(0, overflow_size_var.size, 8)
    ]

    if max(config['overflow_sizes']) != 0:
        bvs_size = int(math.ceil(math.log(max(config['overflow_sizes']),
                                          2))) + 1
    else:
        bvs_size = 8
    num_bytes = int(math.ceil(bvs_size / float(state.arch.byte_width)))
    bit_diff = num_bytes * state.arch.byte_width - bvs_size

    var_dict['overflow_sizes'] = []
    for overflow_size_addr in var_dict['overflow_sizes_addrs']:
        if len(config['overflow_sizes']) > 1:
            overflow_var = state.solver.BVS('overflow_size',
                                            bvs_size).zero_extend(bit_diff)
            constraint = claripy.Or(
                overflow_var == config['overflow_sizes'][0])
            for bin_size in config['overflow_sizes'][1:]:
                constraint = claripy.Or(overflow_var == bin_size, constraint)
            state.add_constraints(constraint)
        else:
            overflow_var = state.solver.BVV(config['overflow_sizes'][0],
                                            state.arch.bits)
        var_dict['overflow_sizes'].append(overflow_var)

        state.memory.store(overflow_size_addr, overflow_var, endness='Iend_LE')

    # Get arb_write_offsets
    var_dict['arb_offset_vars'] = []
    arb_write_var = proj.loader.main_object.get_symbol('arw_offsets')
    for i in range(0, arb_write_var.size, 8):
        var_dict['arb_offset_vars'].append(arb_write_var.rebased_addr + i)

    # Get bf_offsets
    var_dict['bf_offset_vars'] = []
    bf_var = proj.loader.main_object.get_symbol('bf_offsets')
    for i in range(0, bf_var.size, 8):
        var_dict['bf_offset_vars'].append(bf_var.rebased_addr + i)

    # get winning addr
    var_dict['winning_addr'] = proj.loader.main_object.get_symbol(
        'winning').rebased_addr

    return var_dict
Example #30
0
 def _ail_handle_Const(self, expr):
     return RichR(claripy.BVV(expr.value,
                              expr.size * self.state.arch.byte_width),
                  typevar=typeconsts.int_type(expr.size *
                                              self.state.arch.byte_width))