Example #1
0
    def __iter__(self):
        terminated = False
        index = 0
        constraint = bl.Constant(True)
        while not terminated:
            read_address = self.address + bv.Constant(self.address.size, index)
            byte = self.state.read(read_address, 8)

            if self.state.solver.check(byte.can_be_nonzero()):
                if byte.symbolic:
                    if not constraint.symbolic:
                        constraint = (byte != 0)
                    else:
                        # not sure that I've implemented &= in smt
                        constraint = constraint & (byte != 0)

                    # this might look silly, but it actually makes the
                    # output smt formulae substantially smaller...

                    returned_constraint = bl.Symbol(
                        unique_name('string_length'))
                    self.state.solver.add(returned_constraint == constraint)
                    yield (byte, returned_constraint)
                else:
                    yield (byte, constraint)
            else:
                terminated = True
                yield (bv.Constant(8, 0), constraint)
            index += 1
Example #2
0
    def _load_registers(self, state):
        context = self._t.getRegisterContext(self._t.getCurrentThread())

        state.ip = context.getProgramCounter()

        for reg in [
                'rax', 'rbx', 'rcx', 'rdx', 'rsi', 'rdi', 'rbp', 'rsp', 'r8',
                'r9', 'r10', 'r11', 'r12', 'r13', 'r14', 'r15'
        ]:
            state.registers[reg] = bv.Constant(64,
                                               context.getRegisterByName(reg))

        for reg in ['cf', 'pf', 'af', 'zf', 'sf', 'df', 'of']:
            state.registers[reg] = bv.Constant(
                8, context.getRegisterByName(reg.upper()))

        # vdb doesn't appear to read xmm registers

        for reg in [
                'xmm0', 'xmm1', 'xmm2', 'xmm3', 'xmm4', 'xmm5', 'xmm6', 'xmm7',
                'xmm8', 'xmm9', 'xmm10', 'xmm11', 'xmm12', 'xmm13', 'xmm14',
                'xmm15'
        ]:
            state.registers[reg] = \
                bv.Constant(128,
                            context.getRegisterByName('x' + reg[1:]) & 0xffffffffffffffffffffffffffffffff)

        state.registers['fsbase'] = bv.Constant(64, self._get_fsbase())
        state.registers['gsbase'] = bv.Constant(64, self._get_gsbase())
Example #3
0
    def append(self, c):
        if isinstance(c, str):
            c = bv.Constant(8, ord(c))

        write_address = self.address + bv.Constant(self.address.size,
                                                   self.index)
        self.index += 1
        self.state.write(write_address, c)
Example #4
0
def op_bisz(i, s):
    a = operand_value(s, i.input0)
    dst = i.output

    result = bv.if_then_else(
        a == bv.Constant(a.size, 0),
        bv.Constant(dst.size, 1),
        bv.Constant(dst.size, 0))

    s.registers[dst.name] = result
    return [s]
Example #5
0
    def ret(self, value=None):
        return_address = bv.Constant(64, self.state.ip)

        # set return value (if set)
        if value is not None:
            if isinstance(value, int):
                self.state.registers['rax'] = bv.Constant(64, value)
            elif isinstance(value, str):
                self.state.registers['rax'] = bv.Symbol(64, unique_name(value))
            else:
                self.state.registers['rax'] = value

        print 'returning to {}'.format(return_address)

        return self.state.branch(return_address)
Example #6
0
    def ret(self, value=None):
        # load return address, adjust stack pointer
        esp = self.state.registers['esp']
        self.state.registers['esp'] = esp + bv.Constant(32, 4)
        return_address = self.state.read(esp, 32)

        # set return value (if set)
        if value is not None:
            if isinstance(value, int):
                self.state.registers['eax'] = bv.Constant(32, value)
            elif isinstance(value, str):
                self.state.registers['eax'] = bv.Symbol(32, unique_name(value))
            else:
                self.state.registers['eax'] = value

        return self.state.branch(return_address)
Example #7
0
def fetch_instruction(s, x86_64=False):
    ip = s.ip
    s.trace.append(ip)

    if ip not in _translation_cache:
        bs = []

        for i in range(0, 128):
            try:
                bs.append(s.memory.read_byte(s, ip + i))
            except IndexError():
                break

        bs = ''.join(map(lambda x: chr(x.value), bs))
        for i in x86.translate(bs, ip, x86_64):
            _translation_cache[i.address] = i

    if ip not in _translation_cache:
        raise InvalidExecution(s, ip)

    i = _translation_cache[ip]
    s.ip += i.size

    if x86_64:
        s.registers['rip'] = bv.Constant(64, s.ip)

    return i
Example #8
0
def minimum(state, value):
    if not value.symbolic:
        return value

    absolute_max = -1 & mask(value.size)
    lower = 0
    upper = absolute_max

    while (upper - lower) > 1:
        mid = (upper + lower) // 2
        if state.solver.check(value < bv.Constant(value.size, mid)):
            upper = mid
        else:
            lower = mid

    return bv.Constant(value.size, lower)
Example #9
0
    def ret(self, value=None):
        # load return address, adjust stack pointer
        rsp = self.state.registers['rsp']
        self.state.registers['rsp'] = rsp + bv.Constant(64, 8)
        return_address = self.state.read(rsp, 64)

        # set return value (if set)
        if value is not None:
            if isinstance(value, int) or isinstance(value, long):
                self.state.registers['rax'] = bv.Constant(64, value)
            elif isinstance(value, str):
                self.state.registers['rax'] = bv.Symbol(64, unique_name(value))
            else:
                self.state.registers['rax'] = value

        return self.state.branch(return_address)
Example #10
0
def sys_read(s, cc):
    f = cc(s)

    fd = f.params[0]
    buf = f.params[1]
    size = f.params[2]

    s.log.syscall(f, 'sys_read(fd={}, ptr={}, size={})', fd, buf, size)

    output = OutputBuffer(s, buf)

    if fd.symbolic:
        raise ValueError('wtf')

    if fd.value > len(s.files):
        return f.ret(value=0)
    else:
        file = s.files[fd.value]
        offset = file['offset']
        output = OutputBuffer(s, buf)

        real_fd = None
        if file['path'] not in ['stdin', 'stdout', 'stderr']:
            real_fd = open(file['path'], 'rb')

        if size.symbolic:
            raise NotImplementedError()
        elif real_fd is None:
            for i in xrange(0, size.value):
                b = bv.Symbol(8, 'file_{}_{:x}'.format(fd.value, offset))
                output.append(b)
                file['bytes'][offset] = b
                offset += 1
        else:
            real_fd.seek(offset, 0)
            for i in range(0, size.value):
                byte = real_fd.read(1)
                if len(byte) == 1:
                    if byte == '#':
                        b = bv.Symbol(8,
                                      'file_{}_{:x}'.format(fd.value, offset))
                    else:
                        b = bv.Constant(8, ord(byte))
                    output.append(b)
                    file['bytes'][offset] = b
                    offset += 1
                else:
                    break

        file['offset'] = offset

        if real_fd is not None:
            real_fd.close()

    return f.ret(value=size)
Example #11
0
def operand_value(s, o):
    output = o
    if isinstance(o, reil.ImmediateOperand):
        output = bv.Constant(o.size, o.value)
    elif isinstance(o, reil.RegisterOperand):
        output = s.registers[o.name]
        if output.size > o.size:
            output = output.extract(o.size)
        elif output.size < o.size:
            output = output.zero_extend_to(o.size)
    return output
Example #12
0
def sys_write(s, cc):
    f = cc(s)

    fd = f.params[0]
    buf = f.params[1]
    size = f.params[2]

    s.log.syscall(f, 'sys_write(fd={}, buf={}, size={})', fd, buf, size)

    o = DummyOutputBuffer()

    if size.symbolic:
        raise NotImplementedError()
    else:
        for i in range(0, size.value):
            o.append(s.read(buf + bv.Constant(buf.size, i), 8))

    output_string = o.string.strip('\r').strip('\n')
    s.log.output(output_string)

    return f.ret(value=bv.Constant(size.size, o.index))
Example #13
0
def gets(s, cc):
    f = cc(s)

    buf = f.params[0]


    s.log.function_call(f, 'gets(buf={})', buf)

    output = OutputBuffer(s, buf)

    # TODO: this needs to use the file for stdin instead of this nonsense

    for i in xrange(0, 0x100000):
        byte = bv.Symbol(8, unique_name('stdin_{0}'.format(i)))
        s.files[0]['bytes'].append(byte)
        output.append(byte)

    s.files[0]['bytes'].append(bv.Constant(8, 0x0a))
    output.append(bv.Constant(8, 0))

    return f.ret(value=buf)
Example #14
0
    def _load_registers(self, state):
        context = self._t.getRegisterContext(self._t.getCurrentThread())

        state.ip = context.getProgramCounter()

        for reg in ['eax', 'ebx', 'ecx', 'edx', 'esi', 'edi', 'ebp', 'esp']:
            state.registers[reg] = bv.Constant(32,
                                               context.getRegisterByName(reg))

        for reg in ['cf', 'pf', 'af', 'zf', 'sf', 'df', 'of']:
            state.registers[reg] = bv.Constant(
                8, context.getRegisterByName(reg.upper()))

        # vdb doesn't appear to read xmm registers...

        for reg in [
                'xmm0', 'xmm1', 'xmm2', 'xmm3', 'xmm4', 'xmm5', 'xmm6', 'xmm7'
        ]:
            state.registers[reg] = bv.Constant(128,
                                               context.getRegisterByName(reg))

        state.registers['gsbase'] = bv.Constant(32, self._get_gsbase())
Example #15
0
    def read_byte(self, state, address):

        try:
            return self._cache[address]

        except KeyError:
            for b, l, d in self._pages:
                if b <= address < l:
                    value = bv.Constant(8, ord(d[address - b]))
                    self._cache[address] = value
                    return value

        state.throw(InvalidRead(state, address))
Example #16
0
def fread(s, cc):
    f = cc(s)

    buf = f.params[0]
    size = f.params[1]
    count = f.params[2]
    stream = f.params[3]

    s.log.function_call(f, 'fread(ptr={}, size={}, count={}, stream={})', buf, size, count, stream)

    if stream.symbolic:
        raise ValueError('wtf')

    if stream.value > len(s.files):
        return f.ret(value=0)
    else:
        file = s.files[stream.value]
        offset = file['offset']
        output = OutputBuffer(s, buf)

        fd = None
        if file['path'] not in ['stdin', 'stdout', 'stderr']:
            fd = open(file['path'], 'rb')

        if size.symbolic or count.symbolic:
            raise NotImplementedError()
        elif fd is None:
            for i in xrange(0, size.value * count.value):
                output.append(bv.Symbol(8, 'file_{}_{:x}'.format(stream.value, offset)))
                offset += 1
        else:
            fd.seek(offset, 0)
            for i in range(0, size.value * count.value):
                byte = fd.read(1)
                if len(byte) == 1:
                    if byte == '#':
                        output.append(bv.Symbol(8, 'file_{}_{:x}'.format(stream.value, offset)))
                    else:
                        output.append(bv.Constant(8, ord(byte)))
                    offset += 1
                else:
                    break

        file['offset'] = offset

        if fd is not None:
            fd.close()

    return f.ret(value=output.index)
Example #17
0
    def _parse_model(self, results, expr=None):
        output = dict()

        expressions = list(self.roots())
        if expr is not None:
            self._cache(expr)
            expressions.append(expr)

        symbols = set()
        for e in expressions:

            symbols.update(e.symbols())

        for bl_match in self.bl_re.findall(results):
            name = bl_match[0]
            if bl_match[1] == 'true':
                value = True
            else:
                value = False
            output[name] = bl.Constant(value)

        for bv_match in self.bv_re.findall(results):
            name = bv_match[0]
            size = int(bv_match[1])
            value = int('0x' + bv_match[2], 16)
            output[name] = bv.Constant(size, value)

        for symbol in symbols:
            if symbol.name not in output:
                if isinstance(symbol, bv.Expression):
                    output[symbol.name] = bv.Constant(symbol.size,
                                                      0x2323232323232323)
                else:
                    output[symbol.name] = bl.Constant(True)

        return output
Example #18
0
    def run(states):
        while not exit_event.is_set():
            active_threads.acquire()

            while available_states.acquire(blocking=False):
                try:
                    s = states.pop()
                    ns = emulator.single_step(s, x86_64)
                    for n in ns:
                        if culling_function is not None:
                            if culling_function(n):
                                continue

                        if scoring_function is not None:
                            n.score = scoring_function(n)
                            states.append(n)
                            states.sort(key=lambda x: x.score)
                        else:
                            states.append(n)

                        available_states.release()
                except StateException, v:
                    v.state.log.vulnerability(v)
                    v.state.log.debug('saving vuln state {}'.format(
                        v.state.id))
                    serialisation.save('vuln_state_{}'.format(v.state.id), v)
                    data = ''

                    if isinstance(v, ArbitraryRead):
                        v.state.solver.add(v.address == bv.Constant(
                            v.address.size, 0xc01db33f))

                    s = v.state
                    m = v.state.solver.model()
                    for i in range(0, 0x4000):
                        name = 'ttf_{:x}'.format(i)
                        if name in m:
                            data += chr(m[name].value)
                        else:
                            data += '#'

                    print colored(data, 'white', 'on_red', attrs=['bold'])
                    print data.encode('hex')
                    with open('font_{}.ttf'.format(v.state.id), 'wb') as tmp:
                        tmp.write(data)

            active_threads.release()
            time.sleep(1.0)
Example #19
0
def calloc(s, cc):
    f = cc(s)

    size = f.params[0]
    count = f.params[1]

    if size.symbolic or count.symbolic:
        raise NotImplementedError()
    else:
        ptr = s.memory.allocate(s, size.value * count.value)
        zero = bv.Constant(8, 0)
        for i in xrange(0, size.value * count.value):
            s.memory.write_byte(s, ptr + i, zero)

    s.log.function_call(f, 'calloc(size={}, count={}) [{:x}]', size, count, ptr)

    return f.ret(value=ptr)
Example #20
0
def malloc(s, cc):
    f = cc(s)

    size = f.params[0]

    ss = []
    sizes = []
    if size.symbolic:
        min_size = minimum(s, size)
        max_size = maximum(s, size)

        sizes.append(min_size.value)

        if min_size.value != max_size.value:
            sizes.append(max_size.value)
    else:
        sizes.append(size.value)

    # TODO: decide if this is worthwhile
    # insert malloc failure
    sizes.append(None)

    ss = []
    total_sizes = len(sizes)
    while len(sizes) > 0:
        size_ = sizes.pop()

        if total_sizes > 1:
            s_ = s.fork()
        else:
            s_ = s

        if size_ is None:
            ptr = 0

            s_.log.function_call(f, 'malloc(<FAIL>) [NULL]')
        else:
            s_.solver.add(size == bv.Constant(size.size, size_))
            ptr = s_.memory.allocate(s_, size_)

            s_.log.function_call(f, 'malloc(size={:x}) [{:x}]', size_, ptr)

        f_ = cc(s_)
        ss += f_.ret(value=ptr)

    return ss
Example #21
0
def memset(s, cc):
    f = cc(s)

    dst = f.params[0]
    val = f.params[1].resize(8)
    count = f.params[2]

    if dst.symbolic:
        if arbitrary(s, dst):
            raise ArbitraryWrite(s, dst, val)

    counts = []
    if count.symbolic:
        min_count = minimum(s, count)
        max_count = maximum(s, count)

        counts.append(min_count.value)

        if min_count.value != max_count.value:
            counts.append(max_count.value)
    else:
        counts.append(count.value)

    ss = []
    total_counts = len(counts)
    while len(counts) > 0:
        count_ = counts.pop()

        if total_counts > 1:
            s_ = s.fork()
        else:
            s_ = s

        s_.solver.add(count == bv.Constant(count.size, count_))

        s_.log.function_call(f, 'memset(dst={}, val={}, count={:x})', dst, val, count_)

        s_.memory.bulk_set(s_, dst.value, count_, val)

        f_ = cc(s_)
        ss += f_.ret(value=dst)

    return ss
Example #22
0
def op_bsh(i, s):
    a = operand_value(s, i.input0)
    b = operand_value(s, i.input1)
    dst = i.output

    operation_size = max(a.size, b.size, dst.size)

    a = a.resize(operation_size)
    b = b.resize(operation_size)

    # TODO: support symbolic shifts

    if b.value >= 0:
        result = a << b
    else:
        result = a >> bv.Constant(b.size, abs(b.value))
    result = result.resize(dst.size)

    s.registers[dst.name] = result
    return [s]
Example #23
0
def sys_mmap(s, cc):
    f = cc(s)

    addr = f.params[0]
    length = f.params[1]
    prot = f.params[2]
    flags = f.params[3]
    fd = f.params[4]
    offset = f.params[5]

    s.log.syscall(
        f, 'sys_mmap(addr={}, length={}, prot={}, flags={}, fd={}, offset={})',
        addr, length, prot, flags, fd, offset)

    if length.symbolic:
        raise NotImplementedError()

    ptr = bv.Constant(addr.size, s.memory.allocate(s, length.value))

    return f.ret(value=ptr)
Example #24
0
def realloc(s, cc):
    f = cc(s)

    ptr = f.params[0]
    size = f.params[1]

    if ptr.symbolic:
        raise NotImplementedError()

    sizes = []
    if size.symbolic:
        min_size = minimum(s, size)
        max_size = maximum(s, size)

        sizes.append(min_size.value)

        if min_size.value != max_size.value:
            sizes.append(max_size.value)
    else:
        sizes.append(size.value)

    ss = []
    total_sizes = len(sizes)
    while len(sizes) > 0:
        size_ = sizes.pop()

        if total_sizes > 1:
            s_ = s.fork()
        else:
            s_ = s

        s_.solver.add(size == bv.Constant(size.size, size_))
        ptr_ = s_.memory.reallocate(s_, ptr.value, size_)

        s_.log.function_call(f, 'realloc(ptr={}, size={:x}) [{:x}]', ptr, size_, ptr_)

        f_ = cc(s_)
        ss += f_.ret(value=ptr_)

    return ss
Example #25
0
 def return_address(self):
     esp = self.state.registers['esp']
     return self.state.read(esp + bv.Constant(32, 12), 32)
Example #26
0
 def __getitem__(self, index):
     return self.state.read(self.address + bv.Constant(32, (4 * index)),
                            32)
Example #27
0
def arbitrary(state, value):
    if state.solver.check(value == bv.Constant(value.size, 0xc01db33f)):
        return True
    else:
        return False
Example #28
0
 def __getitem__(self, index):
     esp = self.state.registers['esp']
     param_address = esp + bv.Constant(32, 4 + (4 * index))
     return self.state.read(param_address, 32)
Example #29
0
 def va_args(self, index):
     esp = self.state.registers['esp']
     address = esp + bv.Constant(32, 4 + (4 * index))
     return self.VaArgs(self.state, address)
Example #30
0
 def return_address(self):
     return bv.Constant(64, self.state.ip)