def run(self, to_check, length): user_input = state.memory.load(to_check, length) return claripy.If(user_input == "WQNDNKKWAWOLXBAC", claripy.BVV(1, 32), claripy.BVV(0, 32))
def exec_branch(self, state): # pylint:disable=invalid-name """Execute forward from a state, queuing new states if needed.""" logger.debug("Constraints: %s", state.solver.constraints) def solution(variable): """Returns the solution. There must be one or we fail.""" solutions = state.solver.eval(variable, 2) if len(solutions) > 1: raise MultipleSolutionsError( "Multiple solutions for %s (%#x)" % (variable, self.code[state.pc])) solution = solutions[0] return solution if isinstance(solution, numbers.Number) else solution.value self.code.pc = state.pc while True: if state.pc >= len(self.code): return True op = self.code[state.pc] self.code.pc += 1 self.coverage[state.pc] += 1 logger.debug("NEW STEP") logger.debug("Memory: %s", state.memory) logger.debug("Stack: %s", state.stack) logger.debug("PC: %i, %#x", state.pc, op) assert self.code.pc == state.pc + 1 assert isinstance(op, numbers.Number) assert all( isinstance(i, claripy.ast.base.BV) for i in state.stack), "The stack musty only contains claripy BV's" # Trivial operations first if not self.code.is_valid_opcode(state.pc): raise utils.CodeError("Trying to execute PUSH data") elif op == 254: # INVALID opcode raise utils.CodeError("designed INVALID opcode") elif op == opcode_values.JUMPDEST: pass elif op == opcode_values.ADD: s0, s1 = ( state.stack_pop(), state.stack_pop(), ) # pylint:disable=invalid-name state.stack_push(s0 + s1) elif op == opcode_values.SUB: s0, s1 = ( state.stack_pop(), state.stack_pop(), ) # pylint:disable=invalid-name state.stack_push(s0 - s1) elif op == opcode_values.MUL: s0, s1 = ( state.stack_pop(), state.stack_pop(), ) # pylint:disable=invalid-name state.stack_push(s0 * s1) elif op == opcode_values.DIV: # We need to use claripy.LShR instead of a division if possible, # because the solver is bad dealing with divisions, better # with shifts. And we need shifts to handle the solidity ABI # for function selection. s0, s1 = ( state.stack_pop(), state.stack_pop(), ) # pylint:disable=invalid-name try: s1 = solution(s1) # pylint:disable=invalid-name except MultipleSolutionsError: state.stack_push(claripy.If(s1 == 0, BVV_0, s0 / s1)) else: if s1 == 0: state.stack_push(BVV_0) elif s1 == 1: state.stack_push(s0) elif s1 & (s1 - 1) == 0: exp = int(math.log(s1, 2)) state.stack_push(s0.LShR(exp)) else: state.stack_push(s0 / s1) elif op == opcode_values.SDIV: s0, s1 = ( state.stack_pop(), state.stack_pop(), ) # pylint:disable=invalid-name try: s1 = solution(s1) except MultipleSolutionsError: state.stack_push(claripy.If(s1 == 0, BVV_0, s0.SDiv(s1))) else: state.stack_push(BVV_0 if s1 == 0 else s0.SDiv(s1)) elif op == opcode_values.MOD: s0, s1 = ( state.stack_pop(), state.stack_pop(), ) # pylint:disable=invalid-name try: s1 = solution(s1) except MultipleSolutionsError: state.stack_push(claripy.If(s1 == 0, BVV_0, s0 % s1)) else: state.stack_push(BVV_0 if s1 == 0 else s0 % s1) elif op == opcode_values.SMOD: s0, s1 = ( state.stack_pop(), state.stack_pop(), ) # pylint:disable=invalid-name try: s1 = solution(s1) except MultipleSolutionsError: state.stack_push(claripy.If(s1 == 0, BVV_0, s0.SMod(s1))) else: state.stack_push(BVV_0 if s1 == 0 else s0.SMod(s1)) elif op == opcode_values.ADDMOD: s0, s1, s2 = state.stack_pop(), state.stack_pop( ), state.stack_pop() try: s2 = solution(s2) except MultipleSolutionsError: state.stack_push(claripy.If(s2 == 0, BVV_0, (s0 + s1) % s2)) else: state.stack_push(BVV_0 if s2 == 0 else (s0 + s1) % s2) elif op == opcode_values.MULMOD: s0, s1, s2 = state.stack_pop(), state.stack_pop( ), state.stack_pop() try: s2 = solution(s2) except MultipleSolutionsError: state.stack_push(claripy.If(s2 == 0, BVV_0, (s0 * s1) % s2)) else: state.stack_push(BVV_0 if s2 == 0 else (s0 * s1) % s2) elif op == opcode_values.SHL: shift, value = state.stack_pop(), state.stack_pop() state.stack_push(value << shift) elif op == opcode_values.SHR: shift, value = state.stack_pop(), state.stack_pop() state.stack_push(value.LShR(shift)) elif op == opcode_values.SAR: shift, value = state.stack_pop(), state.stack_pop() state.stack_push(claripy.RotateRight(value, shift)) elif op == opcode_values.EXP: base, exponent = state.stack_pop(), state.stack_pop() base_sol = solution(base) if base_sol == 2: state.stack_push(1 << exponent) else: try: exponent_sol = solution(exponent) except MultipleSolutionsError: state.stack_push(exponent) # restore stack state.stack_push(base) self.add_for_fuzzing(state, exponent, EXP_EXPONENT_FUZZ) return False else: state.stack_push( claripy.BVV(base_sol**exponent_sol, 256)) elif op == opcode_values.LT: s0, s1 = ( state.stack_pop(), state.stack_pop(), ) # pylint:disable=invalid-name state.stack_push(bool_to_bv(claripy.ULT(s0, s1))) elif op == opcode_values.GT: s0, s1 = ( state.stack_pop(), state.stack_pop(), ) # pylint:disable=invalid-name state.stack_push(bool_to_bv(claripy.UGT(s0, s1))) elif op == opcode_values.SLT: s0, s1 = ( state.stack_pop(), state.stack_pop(), ) # pylint:disable=invalid-name state.stack_push(bool_to_bv(claripy.SLT(s0, s1))) elif op == opcode_values.SGT: s0, s1 = ( state.stack_pop(), state.stack_pop(), ) # pylint:disable=invalid-name state.stack_push(bool_to_bv(claripy.SGT(s0, s1))) elif op == opcode_values.SIGNEXTEND: # TODO: Use Claripy's SignExt that should do exactly that. s0, s1 = ( state.stack_pop(), state.stack_pop(), ) # pylint:disable=invalid-name # s0 is the number of bits. s1 the number we want to extend. s0 = solution(s0) if s0 <= 31: sign_bit = 1 << (s0 * 8 + 7) state.stack_push( claripy.If( s1 & sign_bit == 0, s1 & (sign_bit - 1), s1 | ((1 << 256) - sign_bit), )) else: state.stack_push(s1) elif op == opcode_values.EQ: s0, s1 = state.stack_pop(), state.stack_pop() state.stack_push(bool_to_bv(s0 == s1)) elif op == opcode_values.ISZERO: state.stack_push(bool_to_bv(state.stack_pop() == BVV_0)) elif op == opcode_values.AND: s0, s1 = state.stack_pop(), state.stack_pop() state.stack_push(s0 & s1) elif op == opcode_values.OR: s0, s1 = state.stack_pop(), state.stack_pop() state.stack_push(s0 | s1) elif op == opcode_values.XOR: s0, s1 = state.stack_pop(), state.stack_pop() state.stack_push(s0 ^ s1) elif op == opcode_values.NOT: state.stack_push(~state.stack_pop()) elif op == opcode_values.BYTE: s0, s1 = ( state.stack_pop(), state.stack_pop(), ) # pylint:disable=invalid-name state.stack_push( s1.LShR(claripy.If(s0 > 31, 32, 31 - s0) * 8) & 0xFF) elif op == opcode_values.PC: state.stack_push(bvv(state.pc)) elif op == opcode_values.GAS: state.stack_push(state.env.gas) elif op == opcode_values.ADDRESS: state.stack_push(state.env.address) elif op == opcode_values.BALANCE: addr = solution(state.stack_pop()) if addr != solution(state.env.address): raise utils.InterpreterError( state, "Can only query balance of the current contract for now" ) state.stack_push(state.env.balance) elif op == opcode_values.ORIGIN: state.stack_push(state.env.origin) elif op == opcode_values.CALLER: state.stack_push(state.env.caller) elif op == opcode_values.CALLVALUE: state.stack_push(state.env.value) elif op == opcode_values.BLOCKHASH: block_num = state.stack_pop() if block_num not in state.env.block_hashes: state.env.block_hashes[block_num] = claripy.BVS( "blockhash[%s]" % block_num, 256) state.stack_push(state.env.block_hashes[block_num]) elif op == opcode_values.TIMESTAMP: state.stack_push(state.env.block_timestamp) elif op == opcode_values.NUMBER: state.stack_push(state.env.block_number) elif op == opcode_values.COINBASE: state.stack_push(state.env.coinbase) elif op == opcode_values.DIFFICULTY: state.stack_push(state.env.difficulty) elif op == opcode_values.POP: state.stack_pop() elif op == opcode_values.JUMP: addr = solution(state.stack_pop()) if addr >= len(self.code ) or self.code[addr] != opcode_values.JUMPDEST: raise utils.CodeError("Invalid jump (%i)" % addr) state.pc = addr self.add_branch(state) return False elif op == opcode_values.JUMPI: addr, condition = solution( state.stack_pop()), state.stack_pop() state_false = state.copy() state.solver.add(condition != BVV_0) state_false.solver.add(condition == BVV_0) state_false.pc += 1 self.add_branch(state_false) state.pc = addr if (state.pc >= len(self.code) or self.code[state.pc] != opcode_values.JUMPDEST): raise utils.CodeError("Invalid jump (%i)" % (state.pc - 1)) self.add_branch(state) return False elif opcode_values.PUSH1 <= op <= opcode_values.PUSH32: pushnum = op - opcode_values.PUSH1 + 1 raw_value = self.code.read(pushnum) state.pc += pushnum state.stack_push( bvv(int.from_bytes(raw_value, byteorder="big"))) elif opcode_values.DUP1 <= op <= opcode_values.DUP16: depth = op - opcode_values.DUP1 + 1 state.stack_push(state.stack[-depth]) elif opcode_values.SWAP1 <= op <= opcode_values.SWAP16: depth = op - opcode_values.SWAP1 + 1 temp = state.stack[-depth - 1] state.stack[-depth - 1] = state.stack[-1] state.stack[-1] = temp elif opcode_values.LOG0 <= op <= opcode_values.LOG4: depth = op - opcode_values.LOG0 mstart, msz = (state.stack_pop(), state.stack_pop()) topics = [state.stack_pop() for x in range(depth)] elif op == opcode_values.SHA3: start, length = solution(state.stack_pop()), solution( state.stack_pop()) memory = state.memory.read(start, length) state.stack_push(Sha3(memory)) elif op == opcode_values.STOP: return True elif op == opcode_values.RETURN: return True elif op == opcode_values.CALLDATALOAD: index = state.stack_pop() try: index_sol = solution(index) except MultipleSolutionsError: state.stack_push(index) # restore the stack self.add_for_fuzzing(state, index, CALLDATALOAD_INDEX_FUZZ) return False state.stack_push(state.env.calldata.read(index_sol, 32)) elif op == opcode_values.CALLDATASIZE: state.stack_push(state.env.calldata_size) elif op == opcode_values.CALLDATACOPY: old_state = state.copy() mstart, dstart, size = ( state.stack_pop(), state.stack_pop(), state.stack_pop(), ) mstart, dstart = solution(mstart), solution(dstart) try: size = solution(size) except MultipleSolutionsError: self.add_for_fuzzing(old_state, size, CALLDATACOPY_SIZE_FUZZ) return False state.memory.copy_from(state.env.calldata, mstart, dstart, size) elif op == opcode_values.CODESIZE: state.stack_push(bvv(len(self.code))) elif op == opcode_values.EXTCODESIZE: addr = state.stack_pop() if (addr == state.env.address).is_true(): state.stack_push(bvv(len(self.code))) else: # TODO: Improve that... It's clearly not constraining enough. state.stack_push(claripy.BVS("EXTCODESIZE[%s]" % addr, 256)) elif op == opcode_values.EXTCODECOPY: old_state = state.copy() addr = state.stack_pop() mem_start = solution(state.stack_pop()) code_start = solution(state.stack_pop()) size = state.stack_pop() try: size = solution(size) except MultipleSolutionsError: # TODO: Fuzz. # self.add_for_fuzzing(old_state, size, []) # return False raise state.memory.write( mem_start, size, claripy.BVS("EXTCODE[%s from %s]" % (addr, code_start), size * 8), ) elif op == opcode_values.CODECOPY: mem_start, code_start, size = [ solution(state.stack_pop()) for _ in range(3) ] for i in range(size): if code_start + i < len(state.env.code): state.memory.write( mem_start + i, 1, claripy.BVV(state.env.code[code_start + i], 8), ) else: state.memory.write(mem_start + i, 1, claripy.BVV(0, 8)) elif op == opcode_values.MLOAD: index = solution(state.stack_pop()) state.stack_push(state.memory.read(index, 32)) elif op == opcode_values.MSTORE: index, value = solution(state.stack_pop()), state.stack_pop() state.memory.write(index, 32, value) elif op == opcode_values.MSTORE8: index, value = solution(state.stack_pop()), state.stack_pop() state.memory.write(index, 1, value[7:0]) elif op == opcode_values.MSIZE: state.stack_push(bvv(state.memory.size())) elif op == opcode_values.SLOAD: state.pc += 1 key = state.stack_pop() for w_key, w_value in state.storage_written.items(): read_written = [w_key == key] if state.solver.satisfiable( extra_constraints=read_written): new_state = state.copy() new_state.solver.add(read_written) new_state.stack_push(w_value) self.add_branch(new_state) state.solver.add(w_key != key) if state.solver.satisfiable(): assert key not in state.storage_written if key not in state.storage_read: state.storage_read[key] = claripy.BVS( "storage[%s]" % key, 256) state.stack_push(state.storage_read[key]) self.add_branch(state) return elif op == opcode_values.SSTORE: state.pc += 1 key = state.stack_pop() value = state.stack_pop() for w_key, w_value in state.storage_written.items(): read_written = [w_key == key] if state.solver.satisfiable( extra_constraints=read_written): new_state = state.copy() new_state.solver.add(read_written) new_state.storage_written[w_key] = value self.add_branch(new_state) state.solver.add(w_key != key) if state.solver.satisfiable(): assert key not in state.storage_written state.storage_written[key] = value self.add_branch(state) return elif op == opcode_values.CALL: state.pc += 1 # pylint:disable=unused-variable gas, to_, value, meminstart, meminsz, memoutstart, memoutsz = ( state.stack_pop() for _ in range(7)) # First possibility: the call fails # (always possible with a call stack big enough) state_fail = state.copy() state_fail.stack_push(BVV_0) self.add_branch(state_fail) # Second possibility: success. state.calls.append((memoutsz, memoutstart, meminsz, meminstart, value, to_, gas)) memoutsz = solution(memoutsz) if memoutsz != 0: # If we expect some output, let's constraint the call to # be to a contract that we do control. Otherwise it could # return anything... state.solver.add(to_[159:0] == utils.DEFAULT_CALLER[159:0]) memoutstart = solution(memoutstart) state.memory.write( memoutstart, memoutsz, claripy.BVS("CALL_RETURN[%s]" % to_, memoutsz * 8), ) state.stack_push(BVV_1) self.add_branch(state) return False elif op == opcode_values.DELEGATECALL: state.pc += 1 # pylint:disable=unused-variable gas, to_, meminstart, meminsz, memoutstart, memoutsz = ( state.stack_pop() for _ in range(6)) # First possibility: the call fails # (always possible with a call stack big enough) state_fail = state.copy() state_fail.stack_push(BVV_0) self.add_branch(state_fail) # If the call is to a specific contract we don't control, # don't assume it could return anything, or even be successful. # So we say we need to be able to call an arbitrary contract. state.solver.add(to_[159:0] == utils.DEFAULT_CALLER[159:0]) # Second possibility: success. state.calls.append( (memoutsz, memoutstart, meminsz, meminstart, to_, gas)) memoutsz = solution(memoutsz) if memoutsz != 0: memoutstart = solution(memoutstart) state.memory.write( memoutstart, memoutsz, claripy.BVS("DELEGATECALL_RETURN[%s]" % to_, memoutsz * 8), ) state.stack_push(BVV_1) self.add_branch(state) return False elif op == opcode_values.RETURNDATASIZE: state.stack_push(claripy.BVS("RETURNDATASIZE", 256)) elif op == opcode_values.RETURNDATACOPY: old_state = state.copy() mem_start_position = solution(state.stack_pop()) returndata_start_position = solution(state.stack_pop()) size = state.stack_pop() try: size = solution(size) except MultipleSolutionsError: self.add_for_fuzzing(old_state, size, RETURNDATACOPY_SIZE_FUZZ) return False state.memory.write(mem_start_position, size, claripy.BVS("RETURNDATACOPY", size * 8)) elif op == opcode_values.SELFDESTRUCT: state.selfdestruct_to = state.stack[-1] return True elif op == opcode_values.REVERT: return False else: raise utils.InterpreterError(state, "Unknown opcode %#x" % op) state.pc += 1
def _perform_vex_expr_ITE(self, cond, ifTrue, ifFalse): return claripy.If(cond != 0, ifTrue, ifFalse)
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): argnum = startpos for component in self.components: if type(component) is bytes: sdata, _ = simfd.read_data(len(component), short_reads=False) self.state.add_constraints(sdata == component) elif isinstance(component, claripy.Bits): sdata, _ = simfd.read_data(len(component) // 8, short_reads=False) self.state.add_constraints(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.add_constraints( 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.add_constraints( 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.add_constraints(digit == digit_ascii[7:0]) self.state.memory.store( args(argnum), target_variable, endness=self.state.arch.memory_endness) argnum += 1 return argnum - startpos 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, _, match_indices = region.find( position, self.parser.state.solver.BVV(b'\n'), max_str_len, max_symbolic_bytes=max_sym_bytes) if not match_indices: # if no newline is found, mm is position + max_strlen mm = position + max_str_len # we're just going to concretize the length, load will do this anyways length = self.parser.state.solver.max_int(mm - position) else: # a newline is found, or a max length is specified with the specifier length = max(match_indices) 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.add_constraints(realsize == position - addr) return (argpos - startpos) - failed
def _fgeneric_minmax(cmp_op, a, b): a, b = a.raw_to_fp(), b.raw_to_fp() return claripy.If(cmp_op(a, b), a, b)
def _op_generic_CmpORD(self, args): x = args[0] y = args[1] s = self._from_size cond = x < y if self.is_signed else claripy.ULT(x, y) return claripy.If(x == y, claripy.BVV(0x2, s), claripy.If(cond, claripy.BVV(0x8, s), claripy.BVV(0x4, s)))
def if_builder(self, element, a, x): return claripy.If(element == int(x, 16), x, a)
def test_vsa_constraint_to_si(): # Set backend b = claripy.backend_vsa s = claripy.LightFrontend(claripy.backend_vsa) #pylint:disable=unused-variable SI = claripy.SI BVV = claripy.BVV claripy.vsa.strided_interval.allow_dsis = False # # If(SI == 0, 1, 0) == 1 # s1 = claripy.SI(bits=32, stride=1, lower_bound=0, upper_bound=2) ast_true = (claripy.If(s1 == BVV(0, 32), BVV(1, 1), BVV(0, 1)) == BVV(1, 1)) ast_false = (claripy.If(s1 == BVV(0, 32), BVV(1, 1), BVV(0, 1)) != BVV( 1, 1)) trueside_sat, trueside_replacement = b.constraint_to_si(ast_true) nose.tools.assert_equal(trueside_sat, True) nose.tools.assert_equal(len(trueside_replacement), 1) nose.tools.assert_true(trueside_replacement[0][0] is s1) # True side: claripy.SI<32>0[0, 0] nose.tools.assert_true( claripy.is_true(trueside_replacement[0][1] == claripy.SI( bits=32, stride=0, lower_bound=0, upper_bound=0))) falseside_sat, falseside_replacement = b.constraint_to_si(ast_false) nose.tools.assert_equal(falseside_sat, True) nose.tools.assert_equal(len(falseside_replacement), 1) nose.tools.assert_true(falseside_replacement[0][0] is s1) # False side; claripy.SI<32>1[1, 2] nose.tools.assert_true( claripy.is_true(falseside_replacement[0][1].identical( SI(bits=32, stride=1, lower_bound=1, upper_bound=2)))) # # If(SI == 0, 1, 0) <= 1 # s1 = SI(bits=32, stride=1, lower_bound=0, upper_bound=2) ast_true = (claripy.If(s1 == BVV(0, 32), BVV(1, 1), BVV(0, 1)) <= BVV( 1, 1)) ast_false = (claripy.If(s1 == BVV(0, 32), BVV(1, 1), BVV(0, 1)) > BVV( 1, 1)) trueside_sat, trueside_replacement = b.constraint_to_si(ast_true) nose.tools.assert_equal(trueside_sat, True) # Always satisfiable falseside_sat, falseside_replacement = b.constraint_to_si(ast_false) nose.tools.assert_equal(falseside_sat, False) # Not sat # # If(SI == 0, 20, 10) > 15 # s1 = SI(bits=32, stride=1, lower_bound=0, upper_bound=2) ast_true = (claripy.If(s1 == BVV(0, 32), BVV(20, 32), BVV(10, 32)) > BVV( 15, 32)) ast_false = (claripy.If(s1 == BVV(0, 32), BVV(20, 32), BVV(10, 32)) <= BVV( 15, 32)) trueside_sat, trueside_replacement = b.constraint_to_si(ast_true) nose.tools.assert_equal(trueside_sat, True) nose.tools.assert_equal(len(trueside_replacement), 1) nose.tools.assert_true(trueside_replacement[0][0] is s1) # True side: SI<32>0[0, 0] nose.tools.assert_true( claripy.is_true(trueside_replacement[0][1] == SI( bits=32, stride=0, lower_bound=0, upper_bound=0))) falseside_sat, falseside_replacement = b.constraint_to_si(ast_false) nose.tools.assert_equal(falseside_sat, True) nose.tools.assert_equal(len(falseside_replacement), 1) nose.tools.assert_true(falseside_replacement[0][0] is s1) # False side; SI<32>1[1, 2] nose.tools.assert_true( claripy.is_true(falseside_replacement[0][1].identical( SI(bits=32, stride=1, lower_bound=1, upper_bound=2)))) # # If(SI == 0, 20, 10) >= 15 # s1 = SI(bits=32, stride=1, lower_bound=0, upper_bound=2) ast_true = (claripy.If(s1 == BVV(0, 32), BVV(15, 32), BVV(10, 32)) >= BVV( 15, 32)) ast_false = (claripy.If(s1 == BVV(0, 32), BVV(15, 32), BVV(10, 32)) < BVV( 15, 32)) trueside_sat, trueside_replacement = b.constraint_to_si(ast_true) nose.tools.assert_equal(trueside_sat, True) nose.tools.assert_equal(len(trueside_replacement), 1) nose.tools.assert_true(trueside_replacement[0][0] is s1) # True side: SI<32>0[0, 0] nose.tools.assert_true( claripy.is_true(trueside_replacement[0][1] == SI( bits=32, stride=0, lower_bound=0, upper_bound=0))) falseside_sat, falseside_replacement = b.constraint_to_si(ast_false) nose.tools.assert_equal(falseside_sat, True) nose.tools.assert_equal(len(falseside_replacement), 1) nose.tools.assert_true(falseside_replacement[0][0] is s1) # False side; SI<32>0[0,0] nose.tools.assert_true( claripy.is_true(falseside_replacement[0][1].identical( SI(bits=32, stride=0, lower_bound=0, upper_bound=0)))) # # Extract(0, 0, Concat(BVV(0, 63), If(SI == 0, 1, 0))) == 1 # s2 = claripy.SI(bits=32, stride=1, lower_bound=0, upper_bound=2) ast_true = (claripy.Extract( 0, 0, claripy.Concat(BVV(0, 63), claripy.If(s2 == 0, BVV(1, 1), BVV(0, 1)))) == 1) ast_false = (claripy.Extract( 0, 0, claripy.Concat(BVV(0, 63), claripy.If(s2 == 0, BVV(1, 1), BVV(0, 1)))) != 1) trueside_sat, trueside_replacement = b.constraint_to_si(ast_true) nose.tools.assert_equal(trueside_sat, True) nose.tools.assert_equal(len(trueside_replacement), 1) nose.tools.assert_true(trueside_replacement[0][0] is s2) # True side: claripy.SI<32>0[0, 0] nose.tools.assert_true( claripy.is_true(trueside_replacement[0][1].identical( SI(bits=32, stride=0, lower_bound=0, upper_bound=0)))) falseside_sat, falseside_replacement = b.constraint_to_si(ast_false) nose.tools.assert_equal(falseside_sat, True) nose.tools.assert_equal(len(falseside_replacement), 1) nose.tools.assert_true(falseside_replacement[0][0] is s2) # False side; claripy.SI<32>1[1, 2] nose.tools.assert_true( claripy.is_true(falseside_replacement[0][1].identical( SI(bits=32, stride=1, lower_bound=1, upper_bound=2)))) # # Extract(0, 0, ZeroExt(32, If(SI == 0, BVV(1, 32), BVV(0, 32)))) == 1 # s3 = claripy.SI(bits=32, stride=1, lower_bound=0, upper_bound=2) ast_true = (claripy.Extract( 0, 0, claripy.ZeroExt(32, claripy.If(s3 == 0, BVV(1, 32), BVV(0, 32)))) == 1) ast_false = (claripy.Extract( 0, 0, claripy.ZeroExt(32, claripy.If(s3 == 0, BVV(1, 32), BVV(0, 32)))) != 1) trueside_sat, trueside_replacement = b.constraint_to_si(ast_true) nose.tools.assert_equal(trueside_sat, True) nose.tools.assert_equal(len(trueside_replacement), 1) nose.tools.assert_true(trueside_replacement[0][0] is s3) # True side: claripy.SI<32>0[0, 0] nose.tools.assert_true( claripy.is_true(trueside_replacement[0][1].identical( SI(bits=32, stride=0, lower_bound=0, upper_bound=0)))) falseside_sat, falseside_replacement = b.constraint_to_si(ast_false) nose.tools.assert_equal(falseside_sat, True) nose.tools.assert_equal(len(falseside_replacement), 1) nose.tools.assert_true(falseside_replacement[0][0] is s3) # False side; claripy.SI<32>1[1, 2] nose.tools.assert_true( claripy.is_true(falseside_replacement[0][1].identical( SI(bits=32, stride=1, lower_bound=1, upper_bound=2)))) # # Extract(0, 0, ZeroExt(32, If(Extract(32, 0, (SI & claripy.SI)) < 0, BVV(1, 1), BVV(0, 1)))) # s4 = claripy.SI(bits=64, stride=1, lower_bound=0, upper_bound=0xffffffffffffffff) ast_true = (claripy.Extract( 0, 0, claripy.ZeroExt( 32, claripy.If( claripy.Extract(31, 0, (s4 & s4)).SLT(0), BVV(1, 32), BVV(0, 32)))) == 1) ast_false = (claripy.Extract( 0, 0, claripy.ZeroExt( 32, claripy.If( claripy.Extract(31, 0, (s4 & s4)).SLT(0), BVV(1, 32), BVV( 0, 32)))) != 1) trueside_sat, trueside_replacement = b.constraint_to_si(ast_true) nose.tools.assert_equal(trueside_sat, True) nose.tools.assert_equal(len(trueside_replacement), 1) nose.tools.assert_true(trueside_replacement[0][0] is s4) # True side: claripy.SI<32>0[0, 0] nose.tools.assert_true( claripy.is_true(trueside_replacement[0][1].identical( SI(bits=64, stride=1, lower_bound=-0x8000000000000000, upper_bound=-1)))) falseside_sat, falseside_replacement = b.constraint_to_si(ast_false) nose.tools.assert_equal(falseside_sat, True) nose.tools.assert_equal(len(falseside_replacement), 1) nose.tools.assert_true(falseside_replacement[0][0] is s4) # False side; claripy.SI<32>1[1, 2] nose.tools.assert_true( claripy.is_true(falseside_replacement[0][1].identical( SI(bits=64, stride=1, lower_bound=0, upper_bound=0x7fffffffffffffff))))
def exec_branch(self, state): # pylint:disable=invalid-name """Execute forward from a state, queuing new states if needed.""" logger.debug("Constraints: %s", state.solver.constraints) def solution(variable): """Returns the solution. There must be one or we fail.""" solutions = state.solver.eval(variable, 2) if len(solutions) > 1: raise ValueError("Ambiguous solution for %s (%s)" % (variable, self.code[state.pc])) solution = solutions[0] return solution if isinstance(solution, numbers.Number) else solution.value state.score += 1 self.code.pc = state.pc while True: if state.pc >= len(self.code): return True op = self.code.next() self.coverage[state.pc] += 1 logger.debug("NEW STEP") logger.debug("Memory: %s", state.memory) logger.debug("Stack: %s", state.stack) logger.debug("PC: %i, %s", state.pc, op) assert self.code.pc == state.pc + 1 assert isinstance(op, numbers.Number) assert all( hasattr(i, "symbolic") for i in state.stack), "The stack musty only contains claripy BV's" # Trivial operations first if not self.code.is_valid_opcode(state.pc): raise utils.CodeError("Trying to execute PUSH data") elif op == 254: # INVALID opcode raise utils.CodeError("designed INVALID opcode") elif op == opcode_values.JUMPDEST: pass elif op == opcode_values.ADD: s0, s1 = ( not_bool(state.stack_pop()), not_bool(state.stack_pop()), ) # pylint:disable=invalid-name state.stack_push(s0 + s1) elif op == opcode_values.SUB: s0, s1 = ( not_bool(state.stack_pop()), not_bool(state.stack_pop()), ) # pylint:disable=invalid-name state.stack_push(s0 - s1) elif op == opcode_values.MUL: s0, s1 = ( not_bool(state.stack_pop()), not_bool(state.stack_pop()), ) # pylint:disable=invalid-name state.stack_push(s0 * s1) elif op == opcode_values.DIV: # We need to use claripy.LShR instead of a division if possible, # because the solver is bad dealing with divisions, better # with shifts. And we need shifts to handle the solidity ABI # for function selection. s0, s1 = ( state.stack_pop(), state.stack_pop(), ) # pylint:disable=invalid-name try: s1 = solution(s1) # pylint:disable=invalid-name except ValueError: state.stack_push(claripy.If(s1 == 0, BVV_0, s0 / s1)) else: if s1 == 0: state.stack_push(BVV_0) elif s1 == 1: state.stack_push(s0) elif s1 & (s1 - 1) == 0: exp = int(math.log(s1, 2)) state.stack_push(s0.LShR(exp)) else: state.stack_push(s0 / s1) elif op == opcode_values.SDIV: s0, s1 = ( state.stack_pop(), state.stack_pop(), ) # pylint:disable=invalid-name try: s1 = solution(s1) except ValueError: state.stack_push(claripy.If(s1 == 0, BVV_0, s0.SDiv(s1))) else: state.stack_push(BVV_0 if s1 == 0 else s0.SDiv(s1)) elif op == opcode_values.MOD: s0, s1 = ( state.stack_pop(), state.stack_pop(), ) # pylint:disable=invalid-name try: s1 = solution(s1) except ValueError: state.stack_push(claripy.If(s1 == 0, BVV_0, s0 % s1)) else: state.stack_push(BVV_0 if s1 == 0 else s0 % s1) elif op == opcode_values.SMOD: s0, s1 = ( state.stack_pop(), state.stack_pop(), ) # pylint:disable=invalid-name try: s1 = solution(s1) except ValueError: state.stack_push(claripy.If(s1 == 0, BVV_0, s0.SMod(s1))) else: state.stack_push(BVV_0 if s1 == 0 else s0.SMod(s1)) elif op == opcode_values.ADDMOD: s0, s1, s2 = state.stack_pop(), state.stack_pop( ), state.stack_pop() try: s2 = solution(s2) except ValueError: state.stack_push(claripy.If(s2 == 0, BVV_0, (s0 + s1) % s2)) else: state.stack_push(BVV_0 if s2 == 0 else (s0 + s1) % s2) elif op == opcode_values.MULMOD: s0, s1, s2 = state.stack_pop(), state.stack_pop( ), state.stack_pop() try: s2 = solution(s2) except ValueError: state.stack_push(claripy.If(s2 == 0, BVV_0, (s0 * s1) % s2)) else: state.stack_push(BVV_0 if s2 == 0 else (s0 * s1) % s2) elif op == opcode_values.EXP: base, exponent = solution(state.stack_pop()), state.stack_pop() if base == 2: state.stack_push(1 << exponent) else: exponent = solution(exponent) state.stack_push(claripy.BVV(base**exponent, 256)) elif op == opcode_values.LT: s0, s1 = ( not_bool(state.stack_pop()), not_bool(state.stack_pop()), ) # pylint:disable=invalid-name state.stack_push(claripy.ULT(s0, s1)) elif op == opcode_values.GT: s0, s1 = ( not_bool(state.stack_pop()), not_bool(state.stack_pop()), ) # pylint:disable=invalid-name state.stack_push(claripy.UGT(s0, s1)) elif op == opcode_values.SLT: s0, s1 = ( not_bool(state.stack_pop()), not_bool(state.stack_pop()), ) # pylint:disable=invalid-name state.stack_push(claripy.SLT(s0, s1)) elif op == opcode_values.SGT: s0, s1 = ( not_bool(state.stack_pop()), not_bool(state.stack_pop()), ) # pylint:disable=invalid-name state.stack_push(claripy.SGT(s0, s1)) elif op == opcode_values.SIGNEXTEND: s0, s1 = ( state.stack_pop(), state.stack_pop(), ) # pylint:disable=invalid-name # s0 is the number of bits. s1 the number we want to extend. s0 = solution(s0) if s0 <= 31: sign_bit = 1 << (s0 * 8 + 7) state.stack_push( claripy.If( s1 & sign_bit == 0, s1 & (sign_bit - 1), s1 | ((1 << 256) - sign_bit), )) else: state.stack_push(s1) elif op == opcode_values.EQ: s0, s1 = state.stack_pop(), state.stack_pop() if isinstance(s0, claripy.ast.Bool) and isinstance( s1, claripy.ast.Bool): state.stack_push(s0 == s1) else: state.stack_push(not_bool(s0) == not_bool(s1)) elif op == opcode_values.ISZERO: condition = state.stack_pop() if isinstance(condition, claripy.ast.Bool): state.stack_push(claripy.Not(condition)) else: state.stack_push(condition == BVV_0) elif op == opcode_values.AND: s0, s1 = make_consistent(state.stack_pop(), state.stack_pop()) if isinstance(s0, claripy.ast.Bool) and isinstance( s1, claripy.ast.Bool): state.stack_push(s0 and s1) else: state.stack_push(s0 & s1) elif op == opcode_values.OR: s0, s1 = make_consistent(state.stack_pop(), state.stack_pop()) if isinstance(s0, claripy.ast.Bool) and isinstance( s1, claripy.ast.Bool): state.stack_push(s0 or s1) else: state.stack_push(s0 | s1) elif op == opcode_values.XOR: s0, s1 = make_consistent(state.stack_pop(), state.stack_pop()) state.stack_push(s0 ^ s1) elif op == opcode_values.NOT: state.stack_push(~state.stack_pop()) elif op == opcode_values.BYTE: s0, s1 = ( state.stack_pop(), state.stack_pop(), ) # pylint:disable=invalid-name state.stack_push( s1.LShR(claripy.If(s0 > 31, 32, 31 - s0) * 8) & 0xFF) elif op == opcode_values.PC: state.stack_push(bvv(state.pc)) elif op == opcode_values.GAS: state.stack_push(state.env.gas) elif op == opcode_values.ADDRESS: state.stack_push(state.env.address) elif op == opcode_values.BALANCE: addr = solution(state.stack_pop()) if addr != solution(state.env.address): raise utils.InterpreterError( state, "Can only query balance of the current contract for now" ) state.stack_push(state.env.balance) elif op == opcode_values.ORIGIN: state.stack_push(state.env.origin) elif op == opcode_values.CALLER: state.stack_push(state.env.caller) elif op == opcode_values.CALLVALUE: state.stack_push(state.env.value) elif op == opcode_values.BLOCKHASH: block_num = state.stack_pop() if block_num not in state.env.block_hashes: state.env.block_hashes[block_num] = claripy.BVS( "blockhash[%s]" % block_num, 256) state.stack_push(state.env.block_hashes[block_num]) elif op == opcode_values.TIMESTAMP: state.stack_push(state.env.block_timestamp) elif op == opcode_values.NUMBER: state.stack_push(state.env.block_number) elif op == opcode_values.COINBASE: state.stack_push(state.env.coinbase) elif op == opcode_values.DIFFICULTY: state.stack_push(state.env.difficulty) elif op == opcode_values.POP: state.stack_pop() elif op == opcode_values.JUMP: addr = solution(state.stack_pop()) if addr >= len(self.code ) or self.code[addr] != opcode_values.JUMPDEST: raise utils.CodeError("Invalid jump (%i)" % addr) state.pc = addr self.add_branch(state) return False elif op == opcode_values.JUMPI: addr, condition = solution( state.stack_pop()), state.stack_pop() state_false = state.copy() if isinstance(condition, claripy.ast.Bool): state.solver.add(condition) state_false.solver.add(claripy.Not(condition)) else: state.solver.add(condition != 0) state_false.solver.add(condition == 0) state_false.pc += 1 self.add_branch(state_false) state.pc = addr if (state.pc >= len(self.code) or self.code[state.pc] != opcode_values.JUMPDEST): raise utils.CodeError("Invalid jump (%i)" % (state.pc - 1)) self.add_branch(state) return False elif opcode_values.PUSH1 <= op <= opcode_values.PUSH32: pushnum = op - opcode_values.PUSH1 + 1 raw_value = self.code.read(pushnum) state.pc += pushnum state.stack_push( bvv(int.from_bytes(raw_value, byteorder="big"))) elif opcode_values.DUP1 <= op <= opcode_values.DUP16: depth = op - opcode_values.DUP1 + 1 state.stack_push(state.stack[-depth]) elif opcode_values.SWAP1 <= op <= opcode_values.SWAP16: depth = op - opcode_values.SWAP1 + 1 temp = state.stack[-depth - 1] state.stack[-depth - 1] = state.stack[-1] state.stack[-1] = temp elif opcode_values.LOG0 <= op <= opcode_values.LOG4: depth = op - opcode_values.LOG0 mstart, msz = (state.stack_pop(), state.stack_pop()) topics = [state.stack_pop() for x in range(depth)] elif op == opcode_values.SHA3: start, length = solution(state.stack_pop()), solution( state.stack_pop()) memory = state.memory.read(start, length) state.stack_push(Sha3(memory)) elif op == opcode_values.STOP: return True elif op == opcode_values.RETURN: return True elif op == opcode_values.CALLDATALOAD: indexes = state.stack_pop() try: index = solution(indexes) except ValueError: # Multiple solutions, let's fuzz. state.stack_push(indexes) # restore the stack self.add_for_fuzzing(state, indexes, CALLDATASIZE_FUZZ) return False state.solver.add(state.env.calldata_size >= index + 32) state.stack_push(state.env.calldata.read(index, 32)) elif op == opcode_values.CALLDATASIZE: state.stack_push(state.env.calldata_size) elif op == opcode_values.CALLDATACOPY: old_state = state.copy() mstart, dstart, size = ( state.stack_pop(), state.stack_pop(), state.stack_pop(), ) mstart, dstart = solution(mstart), solution(dstart) try: size = solution(size) except ValueError: self.add_for_fuzzing(old_state, size, CALLDATASIZE_FUZZ) return False state.memory.copy_from(state.env.calldata, mstart, dstart, size) state.solver.add(state.env.calldata_size >= dstart + size) elif op == opcode_values.CODESIZE: state.stack_push(bvv(len(self.code))) elif op == opcode_values.EXTCODESIZE: addr = state.stack_pop() if (addr == state.env.address).is_true(): state.stack_push(bvv(len(self.code))) else: # TODO: Improve that... It's clearly not constraining enough. state.stack_push(claripy.BVS("EXTCODESIZE[%s]" % addr, 256)) elif op == opcode_values.CODECOPY: mem_start, code_start, size = [ solution(state.stack_pop()) for _ in range(3) ] for i in range(size): if code_start + i < len(state.env.code): state.memory.write( mem_start + i, 1, claripy.BVV(state.env.code[code_start + i], 8), ) else: state.memory.write(mem_start + i, 1, claripy.BVV(0, 8)) elif op == opcode_values.MLOAD: index = solution(state.stack_pop()) state.stack_push(state.memory.read(index, 32)) elif op == opcode_values.MSTORE: index, value = solution(state.stack_pop()), not_bool( state.stack_pop()) state.memory.write(index, 32, value) elif op == opcode_values.MSTORE8: index, value = solution(state.stack_pop()), not_bool( state.stack_pop()) state.memory.write(index, 1, value[7:0]) elif op == opcode_values.MSIZE: state.stack_push(bvv(state.memory.size())) elif op == opcode_values.SLOAD: # TODO: This is inaccurate, because the storage can change # in a single transaction. # See commit d98cab834f8f359f01ef805256d179f5529ebe30. key = state.stack_pop() if key in state.storage_written: state.stack_push(state.storage_written[key]) else: if key not in state.storage_read: state.storage_read[key] = claripy.BVS( "storage[%s]" % key, 256) state.stack_push(state.storage_read[key]) elif op == opcode_values.SSTORE: # TODO: This is inaccurate, because the storage can change # in a single transaction. # See commit d98cab834f8f359f01ef805256d179f5529ebe30. key = state.stack_pop() value = state.stack_pop() state.storage_written[key] = value elif op == opcode_values.CALL: state.pc += 1 # First possibility: the call fails # (always possible with a call stack big enough) state_fail = state.copy() state_fail.stack_push(claripy.BoolV(False)) self.add_branch(state_fail) # Second possibility: success. state.calls.append(state.stack[-7:]) # pylint:disable=unused-variable gas, to_, value, meminstart, meminsz, memoutstart, memoutsz = ( state.stack_pop() for _ in range(7)) if solution(memoutsz) != 0: raise utils.InterpreterError(state, "CALL seems to return data") if solution(meminsz) != 0: raise utils.InterpreterError(state, "CALL seems to take data") state.stack_push(claripy.BoolV(True)) self.add_branch(state) return False elif op == opcode_values.SELFDESTRUCT: state.selfdestruct_to = state.stack[-1] return True elif op == opcode_values.REVERT: return False else: raise utils.InterpreterError(state, "Unknown opcode %s" % op) state.pc += 1
def if_builder(self, element, a, x): return claripy.If(element == x, claripy.BVV(int(x, 16), 8 * 4), a)
def run(self, addr_str_to_check, length): #load the string from memory from the current state, self.state string = self.state.memory.load(addr_str_to_check, length) #return correct value from string comparison return claripy.If(string == keyword, claripy.BVV(1, 32), claripy.BVV(0, 32))
def generic_compare(args: Iterable[BV], comparison: Callable[[BV, BV], BV]) -> BV: return claripy.If(comparison(args[0], args[1]), claripy.BVV(1, 1), claripy.BVV(0, 1))
import claripy s = claripy.Solver() x = claripy.BVS('x', 8) y = claripy.BVV(65, 8) z = claripy.If(x == 1, x, y) s.add(claripy.ULT(x, 5)) s.add(z % 5 != 0) print s.eval(z, 10)
def bool_to_bv(b): return claripy.If(b, BVV_1, BVV_0)
def updateTimeFromDependencies(self, regs, memory): """ Sets the execution time to the max of the execution time and the time required to access the dependencies. The max function is symbolic so it can handle symbolic expressions with overlapping feasibility space Call this after all dependencies are known returns a tuple of two symbolic boolean expressions. The first expresses whether there was a pipeline bubble (wait on data dependency) The first expresses whether dual issuing is prevented (by either a bubble or the register being available only in the current moment) TODO low priority, optimisation only: This function gets called often but heavily relies on calls to the solver. Thus, if the constraints are complex, the function can significantly slow down the entire analysis. TODO: registers get processed in order... which is strange. if a register analysed first could actually increase execution time it gets added as a registers influencing maxtime. if another resgister takes longer the previous register is still seen as influencing max time (it could, but this isn't sure) basically: we should first see witch registers can influence time, and the registers that are left """ bubble = claripy.false dualPrevented = claripy.false regsInfluencingMaxTime = [] memsInfluencingMaxTime = [] #check whether we have to wait for a register for r in regs: if r in self.registers: compute = claripy.backends.z3.simplify( self.registers[r][0].SGT(self.totalExecutionTime)) satisfiability = self.state.se.satisfiable([compute]) if satisfiability: #actually wait for the register registerName = ( "register %s" % self.state.meta.factory.project.arch.capstone.reg_name( r)) if r != FLAGS_REGISTER else "flags register" if self.state.se.satisfiable([claripy.Not(compute)]): #symbolic maximum function: self.totalExecutionTime = claripy.If( compute, self.registers[r][0], self.totalExecutionTime) print("Symbolically waiting for %s..." % registerName) #print compute else: self.totalExecutionTime = self.registers[r][0] if settings.VERBOSE: print("Waiting for %s..." % registerName) regsInfluencingMaxTime.append(r) #check whether we have to wait for a memory for m in memory: if m in self.memory: compute = claripy.backends.z3.simplify(self.memory[m][0].SGT( self.totalExecutionTime)) satisfiability = self.state.se.satisfiable([compute]) if satisfiability: #actually wait for the memory if self.state.se.satisfiable([claripy.Not(compute)]): self.totalExecutionTime = claripy.If( compute, self.memory[m][0], self.totalExecutionTime) if m.concrete: print("Symbolically waiting for memory [0x%x]..." % m.args[0]) else: print("Symbolically waiting for memory [%s]..." % m) else: self.totalExecutionTime = self.memory[m][0] if settings.VERBOSE: if m.concrete: print("Waiting for memory [0x%x]..." % m.args[0]) else: print("Waiting for memory [%s]..." % m) memsInfluencingMaxTime.append(m) global type1violations global type2violations global type3violations #if we have multiple contenders for time-influences, we need to check whether some rule some others out if len(regsInfluencingMaxTime) + len(memsInfluencingMaxTime) > 1: if not self.state.se._solver.hasMultipleSolutions( self.totalExecutionTime ): #if execution time doesn't have multiple solutions, there's no need to process any further. regsInfluencingMaxTime = [] memsInfluencingMaxTime = [] else: #we know that execution time can take on multiple values, now we check which registers or memory dependencies can really slow it down. for r in regsInfluencingMaxTime: if not self.state.se._solver.satisfiable( [self.registers[r][0].SGT(self.totalExecutionTime)]): regsInfluencingMaxTime.remove(r) for m in memsInfluencingMaxTime: if not self.state.se._solver.satisfiable( [self.memory[m][0].SGT(self.totalExecutionTime)]): memsInfluencingMaxTime.remove(m) #determine whether any of the registers we're waiting for depends on a secret for r in regsInfluencingMaxTime: if self.registers[r][ 1] != None: #this value was updated to (insn.mnemonic, insn.address) in the pipelineModel step 4, if in step 3 it was computed that the latency depends on a secret, and has multiple timings. So if this condition is passed we know a timing channel exists -> raise warnings and register the violations vType = timingModel.violationType(self.registers[r][2], self.registers[r][3]) if vType != 0: print( "\033[93mWarning: Type %d violation at instruction: %s @ 0x%x\033[0m" % (vType, self.registers[r][1][0], self.registers[r][1][1])) if vType == 1: type1violations.append(self.registers[r][1]) elif vType == 2: type2violations.append(self.registers[r][1]) if not (self.state.options.__contains__( simuvex.o.CONSERVATIVE_WRITE_STRATEGY) and self.state.options.__contains__( simuvex.o.CONSERVATIVE_READ_STRATEGY)): print( "\033[93mFor better results you should probably run the analysis and with the initial states' options \"add_options={simuvex.o.CONSERVATIVE_WRITE_STRATEGY, simuvex.o.CONSERVATIVE_READ_STRATEGY}\"\033[0m" ) elif vType == 3: type3violations.append(self.registers[r][1]) import store store.violations.append( ("%s, @ 0x%x" % (self.registers[r][1][0], self.registers[r][1][1]), self.registers[r])) else: #unknow violation type print( "\033[93mWarning: violation of unknown type at instruction: %s @ 0x%x\033[0m" % (vType, self.registers[r][1][0], self.registers[r][1][1])) for m in memsInfluencingMaxTime: if self.memory[m][1] != None: vType = timingModel.violationType(self.memory[m][2], self.memory[m][3]) if vType != 0: print( "\033[93mWarning: Type %d violation at instruction: %s @ 0x%x\033[0m" % (vType, self.registers[r][1][0], self.registers[r][1][1])) if vType == 1: type1violations.append(self.memory[m][1]) elif vType == 2: type2violations.append(self.memory[m][1]) if not (self.state.options.__contains__( simuvex.o.CONSERVATIVE_WRITE_STRATEGY) and self.state.options.__contains__( simuvex.o.CONSERVATIVE_READ_STRATEGY)): print( "\033[93mFor better results you should probably run the analysis and with the initial states' options \"add_options={simuvex.o.CONSERVATIVE_WRITE_STRATEGY, simuvex.o.CONSERVATIVE_READ_STRATEGY}\"\033[0m" ) elif vType == 3: type3violations.append(self.memory[m][1]) import store store.violations.append( ("%s, @ 0x%x" % (self.registers[m][1][0], self.registers[m][1][1]), self.registers[m])) else: #unknow violation type print( "\033[93mWarning: violation of unknown type at instruction: %s @ 0x%x\033[0m" % (vType, self.registers[r][1][0], self.registers[r][1][1])) bubble = claripy.backends.z3.simplify(bubble) dualPrevented = claripy.backends.z3.simplify( claripy.Or(dualPrevented, bubble)) return (bubble, dualPrevented)
def test_vsa(): # Set backend b = claripy.backend_vsa SI = claripy.StridedInterval VS = claripy.ValueSet BVV = claripy.BVV # Disable the use of DiscreteStridedIntervalSet claripy.vsa.strided_interval.allow_dsis = False def is_equal(ast_0, ast_1): return ast_0.identical(ast_1) si1 = claripy.TSI(32, name="foo") nose.tools.assert_equal(si1.model.name, "foo") # Normalization si1 = SI(bits=32, stride=1, lower_bound=10, upper_bound=10) nose.tools.assert_equal(si1.model.stride, 0) # Integers si1 = claripy.SI(bits=32, stride=0, lower_bound=10, upper_bound=10) si2 = claripy.SI(bits=32, stride=0, lower_bound=10, upper_bound=10) si3 = claripy.SI(bits=32, stride=0, lower_bound=28, upper_bound=28) # Strided intervals si_a = claripy.SI(bits=32, stride=2, lower_bound=10, upper_bound=20) si_b = claripy.SI(bits=32, stride=2, lower_bound=-100, upper_bound=200) si_c = claripy.SI(bits=32, stride=3, lower_bound=-100, upper_bound=200) si_d = claripy.SI(bits=32, stride=2, lower_bound=50, upper_bound=60) si_e = claripy.SI(bits=16, stride=1, lower_bound=0x2000, upper_bound=0x3000) si_f = claripy.SI(bits=16, stride=1, lower_bound=0, upper_bound=255) si_g = claripy.SI(bits=16, stride=1, lower_bound=0, upper_bound=0xff) si_h = claripy.SI(bits=32, stride=0, lower_bound=0x80000000, upper_bound=0x80000000) nose.tools.assert_true(is_equal(si1, claripy.SI(bits=32, to_conv=10))) nose.tools.assert_true(is_equal(si2, claripy.SI(bits=32, to_conv=10))) nose.tools.assert_true(is_equal(si1, si2)) # __add__ si_add_1 = si1 + si2 nose.tools.assert_true( is_equal(si_add_1, claripy.SI(bits=32, stride=0, lower_bound=20, upper_bound=20))) si_add_2 = si1 + si_a nose.tools.assert_true( is_equal(si_add_2, claripy.SI(bits=32, stride=2, lower_bound=20, upper_bound=30))) si_add_3 = si_a + si_b nose.tools.assert_true( is_equal( si_add_3, claripy.SI(bits=32, stride=2, lower_bound=-90, upper_bound=220))) si_add_4 = si_b + si_c nose.tools.assert_true( is_equal( si_add_4, claripy.SI(bits=32, stride=1, lower_bound=-200, upper_bound=400))) # __add__ with overflow si_add_5 = si_h + 0xffffffff nose.tools.assert_true( is_equal( si_add_5, claripy.SI(bits=32, stride=0, lower_bound=0x7fffffff, upper_bound=0x7fffffff))) # __sub__ si_minus_1 = si1 - si2 nose.tools.assert_true( is_equal(si_minus_1, claripy.SI(bits=32, stride=0, lower_bound=0, upper_bound=0))) si_minus_2 = si_a - si_b nose.tools.assert_true( is_equal( si_minus_2, claripy.SI(bits=32, stride=2, lower_bound=-190, upper_bound=120))) si_minus_3 = si_b - si_c nose.tools.assert_true( is_equal( si_minus_3, claripy.SI(bits=32, stride=1, lower_bound=-300, upper_bound=300))) # __neg__ / __invert__ / bitwise not si_neg_1 = ~si1 nose.tools.assert_true(is_equal(si_neg_1, claripy.SI(bits=32, to_conv=-11))) si_neg_2 = ~si_b nose.tools.assert_true( is_equal( si_neg_2, claripy.SI(bits=32, stride=2, lower_bound=-201, upper_bound=99))) # __or__ si_or_1 = si1 | si3 nose.tools.assert_true(is_equal(si_or_1, claripy.SI(bits=32, to_conv=30))) si_or_2 = si1 | si2 nose.tools.assert_true(is_equal(si_or_2, claripy.SI(bits=32, to_conv=10))) si_or_3 = si1 | si_a # An integer | a strided interval nose.tools.assert_true( is_equal(si_or_3, claripy.SI(bits=32, stride=2, lower_bound=10, upper_bound=30))) si_or_3 = si_a | si1 # Exchange the operands nose.tools.assert_true( is_equal(si_or_3, claripy.SI(bits=32, stride=2, lower_bound=10, upper_bound=30))) si_or_4 = si_a | si_d # A strided interval | another strided interval nose.tools.assert_true( is_equal(si_or_4, claripy.SI(bits=32, stride=2, lower_bound=50, upper_bound=62))) si_or_4 = si_d | si_a # Exchange the operands nose.tools.assert_true( is_equal(si_or_4, claripy.SI(bits=32, stride=2, lower_bound=50, upper_bound=62))) si_or_5 = si_e | si_f # nose.tools.assert_true( is_equal( si_or_5, claripy.SI(bits=16, stride=1, lower_bound=0x2000, upper_bound=0x30ff))) si_or_6 = si_e | si_g # nose.tools.assert_true( is_equal( si_or_6, claripy.SI(bits=16, stride=1, lower_bound=0x2000, upper_bound=0x30ff))) # Shifting si_shl_1 = si1 << 3 nose.tools.assert_equal(si_shl_1.size(), 32) nose.tools.assert_true( is_equal(si_shl_1, claripy.SI(bits=32, stride=0, lower_bound=80, upper_bound=80))) # Multiplication si_mul_1 = si1 * 3 nose.tools.assert_equal(si_mul_1.size(), 32) nose.tools.assert_true( is_equal(si_mul_1, claripy.SI(bits=32, stride=0, lower_bound=30, upper_bound=30))) si_mul_2 = si_a * 3 nose.tools.assert_equal(si_mul_2.size(), 32) nose.tools.assert_true( is_equal(si_mul_2, claripy.SI(bits=32, stride=6, lower_bound=30, upper_bound=60))) si_mul_3 = si_a * si_b nose.tools.assert_equal(si_mul_3.size(), 32) nose.tools.assert_true( is_equal( si_mul_3, claripy.SI(bits=32, stride=2, lower_bound=-2000, upper_bound=4000))) # Division si_div_1 = si1 / 3 nose.tools.assert_equal(si_div_1.size(), 32) nose.tools.assert_true( is_equal(si_div_1, claripy.SI(bits=32, stride=0, lower_bound=3, upper_bound=3))) si_div_2 = si_a / 3 nose.tools.assert_equal(si_div_2.size(), 32) nose.tools.assert_true( is_equal(si_div_2, claripy.SI(bits=32, stride=1, lower_bound=3, upper_bound=6))) # Modulo si_mo_1 = si1 % 3 nose.tools.assert_equal(si_mo_1.size(), 32) nose.tools.assert_true( is_equal(si_mo_1, claripy.SI(bits=32, stride=0, lower_bound=1, upper_bound=1))) si_mo_2 = si_a % 3 nose.tools.assert_equal(si_mo_2.size(), 32) nose.tools.assert_true( is_equal(si_mo_2, claripy.SI(bits=32, stride=1, lower_bound=0, upper_bound=2))) # # Extracting the sign bit # # a negative integer si = claripy.SI(bits=64, stride=0, lower_bound=-1, upper_bound=-1) sb = si[63:63] nose.tools.assert_true(is_equal(sb, claripy.SI(bits=1, to_conv=1))) # non-positive integers si = claripy.SI(bits=64, stride=1, lower_bound=-1, upper_bound=0) sb = si[63:63] nose.tools.assert_true( is_equal(sb, claripy.SI(bits=1, stride=1, lower_bound=0, upper_bound=1))) # Extracting an integer si = claripy.SI(bits=64, stride=0, lower_bound=0x7fffffffffff0000, upper_bound=0x7fffffffffff0000) part1 = si[63:32] part2 = si[31:0] nose.tools.assert_true( is_equal( part1, claripy.SI(bits=32, stride=0, lower_bound=0x7fffffff, upper_bound=0x7fffffff))) nose.tools.assert_true( is_equal( part2, claripy.SI(bits=32, stride=0, lower_bound=0xffff0000, upper_bound=0xffff0000))) # Concatenating two integers si_concat = part1.concat(part2) nose.tools.assert_true(is_equal(si_concat, si)) # Extracting a claripy.SI si = claripy.SI(bits=64, stride=0x9, lower_bound=0x1, upper_bound=0xa) part1 = si[63:32] part2 = si[31:0] nose.tools.assert_true( is_equal( part1, claripy.SI(bits=32, stride=0, lower_bound=0x0, upper_bound=0x0))) nose.tools.assert_true( is_equal(part2, claripy.SI(bits=32, stride=9, lower_bound=1, upper_bound=10))) # Concatenating two claripy.SIs si_concat = part1.concat(part2) nose.tools.assert_true(is_equal(si_concat, si)) # Concatenating two SIs that are of different sizes si_1 = SI(bits=64, stride=1, lower_bound=0, upper_bound=0xffffffffffffffff) si_2 = SI(bits=32, stride=1, lower_bound=0, upper_bound=0xffffffff) si_concat = si_1.concat(si_2) nose.tools.assert_true( is_equal( si_concat, SI(bits=96, stride=1, lower_bound=0, upper_bound=0xffffffffffffffffffffffff))) # Zero-Extend the low part si_zeroextended = part2.zero_extend(32) nose.tools.assert_true( is_equal(si_zeroextended, claripy.SI(bits=64, stride=9, lower_bound=1, upper_bound=10))) # Sign-extension si_signextended = part2.sign_extend(32) nose.tools.assert_true( is_equal(si_signextended, claripy.SI(bits=64, stride=9, lower_bound=1, upper_bound=10))) # Extract from the result above si_extracted = si_zeroextended[31:0] nose.tools.assert_true( is_equal(si_extracted, claripy.SI(bits=32, stride=9, lower_bound=1, upper_bound=10))) # Union si_union_1 = si1.union(si2) nose.tools.assert_true( is_equal(si_union_1, claripy.SI(bits=32, stride=0, lower_bound=10, upper_bound=10))) si_union_2 = si1.union(si3) nose.tools.assert_true( is_equal( si_union_2, claripy.SI(bits=32, stride=18, lower_bound=10, upper_bound=28))) si_union_3 = si1.union(si_a) nose.tools.assert_true( is_equal(si_union_3, claripy.SI(bits=32, stride=2, lower_bound=10, upper_bound=20))) si_union_4 = si_a.union(si_b) nose.tools.assert_true( is_equal( si_union_4, claripy.SI(bits=32, stride=2, lower_bound=-100, upper_bound=200))) si_union_5 = si_b.union(si_c) nose.tools.assert_true( is_equal( si_union_5, claripy.SI(bits=32, stride=1, lower_bound=-100, upper_bound=200))) # Intersection si_intersection_1 = si1.intersection(si1) nose.tools.assert_true(is_equal(si_intersection_1, si2)) si_intersection_2 = si1.intersection(si2) nose.tools.assert_true( is_equal(si_intersection_2, claripy.SI(bits=32, stride=0, lower_bound=10, upper_bound=10))) si_intersection_3 = si1.intersection(si_a) nose.tools.assert_true( is_equal(si_intersection_3, claripy.SI(bits=32, stride=0, lower_bound=10, upper_bound=10))) si_intersection_4 = si_a.intersection(si_b) nose.tools.assert_true( is_equal(si_intersection_4, claripy.SI(bits=32, stride=2, lower_bound=10, upper_bound=20))) si_intersection_5 = si_b.intersection(si_c) nose.tools.assert_true( is_equal( si_intersection_5, claripy.SI(bits=32, stride=6, lower_bound=-100, upper_bound=200))) # Sign-extension si = claripy.SI(bits=1, stride=0, lower_bound=1, upper_bound=1) si_signextended = si.sign_extend(31) nose.tools.assert_true( is_equal( si_signextended, claripy.SI(bits=32, stride=0, lower_bound=0xffffffff, upper_bound=0xffffffff))) # Comparison between claripy.SI and BVV si = claripy.SI(bits=32, stride=1, lower_bound=-0x7f, upper_bound=0x7f) si.uninitialized = True bvv = BVV(0x30, 32) comp = (si < bvv) nose.tools.assert_equal(comp.model, MaybeResult()) # Better extraction # si = <32>0x1000000[0xcffffff, 0xdffffff]R si = claripy.SI(bits=32, stride=0x1000000, lower_bound=0xcffffff, upper_bound=0xdffffff) si_byte0 = si[7:0] si_byte1 = si[15:8] si_byte2 = si[23:16] si_byte3 = si[31:24] nose.tools.assert_true( is_equal( si_byte0, claripy.SI(bits=8, stride=0, lower_bound=0xff, upper_bound=0xff))) nose.tools.assert_true( is_equal( si_byte1, claripy.SI(bits=8, stride=0, lower_bound=0xff, upper_bound=0xff))) nose.tools.assert_true( is_equal( si_byte2, claripy.SI(bits=8, stride=0, lower_bound=0xff, upper_bound=0xff))) nose.tools.assert_true( is_equal( si_byte3, claripy.SI(bits=8, stride=1, lower_bound=0xc, upper_bound=0xd))) # Optimization on bitwise-and si_1 = claripy.SI(bits=32, stride=1, lower_bound=0x0, upper_bound=0xffffffff) si_2 = claripy.SI(bits=32, stride=0, lower_bound=0x80000000, upper_bound=0x80000000) si = si_1 & si_2 nose.tools.assert_true( is_equal( si, claripy.SI(bits=32, stride=0x80000000, lower_bound=0, upper_bound=0x80000000))) si_1 = claripy.SI(bits=32, stride=1, lower_bound=0x0, upper_bound=0x7fffffff) si_2 = claripy.SI(bits=32, stride=0, lower_bound=0x80000000, upper_bound=0x80000000) si = si_1 & si_2 nose.tools.assert_true( is_equal(si, claripy.SI(bits=32, stride=0, lower_bound=0, upper_bound=0))) # Concatenation: concat with zeros only increases the stride si_1 = claripy.SI(bits=8, stride=0xff, lower_bound=0x0, upper_bound=0xff) si_2 = claripy.SI(bits=8, stride=0, lower_bound=0, upper_bound=0) si = si_1.concat(si_2) nose.tools.assert_true( is_equal( si, claripy.SI(bits=16, stride=0xff00, lower_bound=0, upper_bound=0xff00))) # Extract from a reversed value si_1 = claripy.SI(bits=64, stride=0xff, lower_bound=0x0, upper_bound=0xff) si_2 = si_1.reversed[63:56] nose.tools.assert_true( is_equal( si_2, claripy.SI(bits=8, stride=0xff, lower_bound=0x0, upper_bound=0xff))) # # ValueSet # vs_1 = claripy.ValueSet(bits=32) nose.tools.assert_true(vs_1.model.is_empty, True) # Test merging two addresses vs_1.model.merge_si('global', si1) vs_1.model.merge_si('global', si3) nose.tools.assert_true( vs_1.model.get_si('global').identical( SI(bits=32, stride=18, lower_bound=10, upper_bound=28).model)) # Length of this ValueSet nose.tools.assert_equal(len(vs_1.model), 32) vs_1 = claripy.ValueSet(name='boo', bits=32) vs_2 = claripy.ValueSet(name='foo', bits=32) nose.tools.assert_true(vs_1.identical(vs_1)) nose.tools.assert_true(vs_2.identical(vs_2)) vs_1.model.merge_si('global', si1) nose.tools.assert_false(vs_1.identical(vs_2)) vs_2.model.merge_si('global', si1) nose.tools.assert_true(vs_1.identical(vs_2)) nose.tools.assert_true(claripy.is_true((vs_1 & vs_2) == vs_1)) vs_1.model.merge_si('global', si3) nose.tools.assert_false(vs_1.identical(vs_2)) # Subtraction # Subtraction of two pointers yields a concrete value vs_1 = claripy.ValueSet(name='foo', region='global', bits=32, val=0x400010) vs_2 = claripy.ValueSet(name='bar', region='global', bits=32, val=0x400000) si = vs_1 - vs_2 nose.tools.assert_is(type(si.model), StridedInterval) nose.tools.assert_true( si.identical( claripy.SI(bits=32, stride=0, lower_bound=0x10, upper_bound=0x10))) # # IfProxy # # max and min on IfProxy si = claripy.SI(bits=32, stride=1, lower_bound=0, upper_bound=0xffffffff) if_0 = claripy.If(si == 0, si, si - 1) max_val = b.max(if_0) min_val = b.min(if_0) nose.tools.assert_true(max_val, 0xffffffff) nose.tools.assert_true(min_val, -0x80000000) # identical nose.tools.assert_true(if_0.identical(if_0)) nose.tools.assert_false(if_0.identical(si)) if_0_copy = claripy.If(si == 0, si, si - 1) nose.tools.assert_true(if_0.identical(if_0_copy)) if_1 = claripy.If(si == 1, si, si - 1) nose.tools.assert_true(if_0.identical(if_1)) si = SI(bits=32, stride=0, lower_bound=1, upper_bound=1) if_0 = claripy.If(si == 0, si, si - 1) if_0_copy = claripy.If(si == 0, si, si - 1) nose.tools.assert_true(if_0.identical(if_0_copy)) if_1 = claripy.If(si == 1, si, si - 1) nose.tools.assert_false(if_0.identical(if_1)) if_1 = claripy.If(si == 0, si + 1, si - 1) nose.tools.assert_true(if_0.identical(if_1)) if_1 = claripy.If(si == 0, si, si) nose.tools.assert_false(if_0.identical(if_1)) # if_1 = And(VS_2, IfProxy(si == 0, 0, 1)) vs_2 = VS(region='global', bits=32, val=0xFA7B00B) si = claripy.SI(bits=32, stride=1, lower_bound=0, upper_bound=1) if_1 = (vs_2 & claripy.If( si == 0, claripy.SI(bits=32, stride=0, lower_bound=0, upper_bound=0), claripy.SI( bits=32, stride=0, lower_bound=0xffffffff, upper_bound=0xffffffff))) nose.tools.assert_true( claripy.is_true( if_1.model.trueexpr == VS(region='global', bits=32, val=0).model)) nose.tools.assert_true(claripy.is_true(if_1.model.falseexpr == vs_2.model)) # if_2 = And(VS_3, IfProxy(si != 0, 0, 1) vs_3 = claripy.ValueSet(region='global', bits=32, val=0xDEADCA7) si = claripy.SI(bits=32, stride=1, lower_bound=0, upper_bound=1) if_2 = (vs_3 & claripy.If( si != 0, claripy.SI(bits=32, stride=0, lower_bound=0, upper_bound=0), claripy.SI( bits=32, stride=0, lower_bound=0xffffffff, upper_bound=0xffffffff))) nose.tools.assert_true( claripy.is_true( if_2.model.trueexpr == VS(region='global', bits=32, val=0).model)) nose.tools.assert_true(claripy.is_true(if_2.model.falseexpr == vs_3.model)) # Something crazy is gonna happen... if_3 = if_1 + if_2 nose.tools.assert_true(claripy.is_true(if_3.model.trueexpr == vs_3.model)) nose.tools.assert_true(claripy.is_true(if_3.model.falseexpr == vs_2.model))
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)))
def check_state(self, state, path=None): """Check a reachable state for bugs""" logger.debug("Check state: %s", state) logger.debug("Constraints: %s", state.solver.constraints) solver = state.solver.branch() if path is None: path = [state] # Static read were we never wrote, but we know the key is not symbolic. # So we go and fetch it. for key, value in state.storage_read.items(): constraint = state.storage_read[key] == self._read_storage( state, key) solver.add(constraint) logger.debug("Add storage constraint: %s", constraint) for s in path: solver.add(list(s.env.extra_constraints())) solver.add([ s.env.caller == utils.DEFAULT_CALLER, s.env.origin == utils.DEFAULT_CALLER, ]) # Calls total_sent = sum(s.env.value for s in path) sent_constraints = [s.env.value < self.max_wei_to_send for s in path] total_received_by_me = utils.bvv(0) total_received = utils.bvv(0) for call in state.calls: # TODO: Improve delegatecall support! And make it clearer it's # delegatecall, not just based on the length. assert 6 <= len(call) <= 7 value, to, gas = call[-3:] # pylint: disable=unused-variable,invalid-name delegatecall = len(call) == 6 if delegatecall: if solver.satisfiable( extra_constraints=[to[159:0] == self.caller[159:0]]): logger.info("Found delegatecall bug.") solver.add(to[159:0] == self.caller[159:0]) return solver else: total_received_by_me += claripy.If( to[159:0] == self.caller[159:0], value, utils.bvv(0)) total_received += value solver.add(value <= total_sent + path[0].env.balance) final_balance = path[0].env.balance + total_sent - total_received # Suicide if state.selfdestruct_to is not None: constraints = [ final_balance >= self.min_wei_to_receive, state.selfdestruct_to[159:0] == self.caller[159:0], ] logger.debug("Check for selfdestruct bug with constraints %s", constraints) if solver.satisfiable(extra_constraints=constraints): logger.info("Found selfdestruct bug.") solver.add(constraints) return solver if total_received_by_me is utils.bvv(0): return logger.debug("Found calls back to caller: %s", total_received_by_me) solver.add(sent_constraints) solver.add([ claripy.SGE(final_balance, 0), total_received_by_me > total_sent, # I get more than what I sent? total_received_by_me > self.min_wei_to_receive, ]) if solver.satisfiable(): logger.info("Found call bug.") return solver
def skip_check_equal(state): buffer_addr = 0x0804A054 load_buffer_symbol = state.memory.load(buffer_addr, 16) check_str = 'XYMKBKUHNIQYNQXE' state.regs.eax = claripy.If(load_buffer_symbol == check_str, claripy.BVV(1, 32), claripy.BVV(0, 32))
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)
def test_some_vector_ops(): engine = HeavyVEXMixin(None) s = SimState(arch="AMD64") def translate(state, op, args): return engine._perform_vex_expr_Op(op, args) a = s.solver.BVV(0xFFFF0000000100020003000400050006, 128) b = s.solver.BVV(0x00020002000200020002000200020002, 128) calc_result = translate(s, "Iop_Sub16x8", (a, b)) correct_result = s.solver.BVV(0xFFFDFFFEFFFF00000001000200030004, 128) assert s.solver.is_true(calc_result == correct_result) calc_result = translate(s, "Iop_CmpEQ16x8", (a, b)) correct_result = s.solver.BVV(0x000000000000FFFF0000000000000000, 128) assert s.solver.is_true(calc_result == correct_result) calc_result = translate(s, "Iop_CmpEQ8x16", (a, b)) correct_result = s.solver.BVV(0x0000FF00FF00FFFFFF00FF00FF00FF00, 128) assert s.solver.is_true(calc_result == correct_result) calc_result = translate(s, "Iop_CmpGT16Sx8", (a, b)) correct_result = s.solver.BVV(0x0000000000000000FFFFFFFFFFFFFFFF, 128) assert s.solver.is_true(calc_result == correct_result) calc_result = translate(s, "Iop_CmpGT16Ux8", (a, b)) correct_result = s.solver.BVV(0xFFFF000000000000FFFFFFFFFFFFFFFF, 128) assert s.solver.is_true(calc_result == correct_result) calc_result = translate(s, "Iop_InterleaveLO16x8", (a, b)) correct_result = s.solver.BVV(0x00030002000400020005000200060002, 128) assert s.solver.is_true(calc_result == correct_result) calc_result = translate(s, "Iop_InterleaveLO8x16", (a, b)) correct_result = s.solver.BVV(0x00000302000004020000050200000602, 128) assert s.solver.is_true(calc_result == correct_result) calc_result = translate(s, "Iop_Min8Ux16", (a, b)) correct_result = s.solver.BVV(0x00020000000100020002000200020002, 128) assert s.solver.is_true(calc_result == correct_result) calc_result = translate(s, "Iop_Min8Sx16", (a, b)) correct_result = s.solver.BVV(0xFFFF0000000100020002000200020002, 128) assert s.solver.is_true(calc_result == correct_result) calc_result = translate(s, "Iop_QNarrowBin16Sto8Ux16", (a, b)) correct_result = s.solver.BVV(0x00000102030405060202020202020202, 128) assert s.solver.is_true(calc_result == correct_result) c = s.solver.BVV(0xFF008877, 32) d = s.solver.BVV(0x11111111, 32) calc_result = translate(s, "Iop_HAdd8Sx4", (c, d)) correct_result = s.solver.BVV(0x0808CC44, 32) assert s.solver.is_true(calc_result == correct_result) calc_result = translate(s, "Iop_QAdd8Sx4", (c, d)) correct_result = s.solver.BVV(0x1011997F, 32) assert s.solver.is_true(calc_result == correct_result) calc_result = translate(s, "Iop_QAdd8Ux4", (c, d)) correct_result = s.solver.BVV(0xFF119988, 32) assert s.solver.is_true(calc_result == correct_result) calc_result = translate(s, "Iop_QSub8Sx4", (c, d)) correct_result = s.solver.BVV(0xEEEF8066, 32) assert s.solver.is_true(calc_result == correct_result) calc_result = translate(s, "Iop_QSub8Ux4", (c, d)) correct_result = s.solver.BVV(0xEE007766, 32) assert s.solver.is_true(calc_result == correct_result) e = s.solver.BVV(0xFF00887766554433, 64) f = s.solver.BVV(0x0202000200020002, 64) calc_result = translate(s, "Iop_QNarrowBin16Sto8Ux8", (e, f)) correct_result = s.solver.BVV(0x0000FFFFFF020202, 64) assert s.solver.is_true(calc_result == correct_result) gg = claripy.BVV(0x111111112222222233333333FFFFFFFF, 128) h = claripy.BVV(0x1111111100000000FFFFFFFFFFFFFFFF, 128) calc_result = translate(s, "Iop_CmpEQ32Fx4", (gg, h)) correct_result = claripy.BVV(0xFFFFFFFF000000000000000000000000, 128) assert s.solver.is_true(calc_result == correct_result) calc_result = translate(s, "Iop_Clz32x4", (gg, )) correct_result = claripy.BVV(0x00000003000000020000000200000000, 128) assert s.solver.is_true(calc_result == correct_result) i = claripy.BVV(0x1001000000001000, 64) j = claripy.BVV(0x100000000000F000, 64) calc_result = translate(s, "Iop_Mull16Sx4", (i, j)) correct_result = claripy.BVV(0x10010000000000000000000FF000000, 128) assert s.solver.is_true(calc_result == correct_result) calc_result = translate(s, "Iop_Mull16Ux4", (i, j)) correct_result = claripy.BVV(0x100100000000000000000000F000000, 128) assert s.solver.is_true(calc_result == correct_result) k = claripy.BVV(0xE7, 8) ll = claripy.BVV(0x1234, 16) m = claripy.BVV(0x12345678, 32) calc_result = translate(s, "Iop_Dup8x8", (k, )) correct_result = claripy.BVV(0xE7E7E7E7E7E7E7E7, 64) assert s.solver.is_true(calc_result == correct_result) calc_result = translate(s, "Iop_Dup8x16", (k, )) correct_result = claripy.BVV(0xE7E7E7E7E7E7E7E7E7E7E7E7E7E7E7E7, 128) assert s.solver.is_true(calc_result == correct_result) calc_result = translate(s, "Iop_Dup16x4", (ll, )) correct_result = claripy.BVV(0x1234123412341234, 64) assert s.solver.is_true(calc_result == correct_result) calc_result = translate(s, "Iop_Dup16x8", (ll, )) correct_result = claripy.BVV(0x12341234123412341234123412341234, 128) assert s.solver.is_true(calc_result == correct_result) calc_result = translate(s, "Iop_Dup32x2", (m, )) correct_result = claripy.BVV(0x1234567812345678, 64) assert s.solver.is_true(calc_result == correct_result) calc_result = translate(s, "Iop_Dup32x4", (m, )) correct_result = claripy.BVV(0x12345678123456781234567812345678, 128) assert s.solver.is_true(calc_result == correct_result) n = claripy.BVV(0x0123456789ABCDEF, 64) o = claripy.BVV(0xAF, 8) p = claripy.BVV(0xDFEC, 16) q = claripy.BVV(0xBFCFDFEF, 32) r = claripy.BVV(0x0102030405060708, 64) ss = claripy.BVS("index", 8) # According to the source code of LibVex, the index is a U8 constant calc_result = translate(s, "Iop_GetElem8x8", (n, claripy.BVV(0, 8))) correct_result = claripy.BVV(0xEF, 8) assert s.solver.is_true(calc_result == correct_result) calc_result = translate(s, "Iop_GetElem8x8", (n, claripy.BVV(1, 8))) correct_result = claripy.BVV(0xCD, 8) assert s.solver.is_true(calc_result == correct_result) calc_result = translate(s, "Iop_GetElem8x8", (n, claripy.BVV(6, 8))) correct_result = claripy.BVV(0x23, 8) assert s.solver.is_true(calc_result == correct_result) calc_result = translate(s, "Iop_GetElem8x8", (n, claripy.BVV(7, 8))) correct_result = claripy.BVV(0x01, 8) assert s.solver.is_true(calc_result == correct_result) calc_result = translate(s, "Iop_GetElem16x4", (n, claripy.BVV(0, 8))) correct_result = claripy.BVV(0xCDEF, 16) assert s.solver.is_true(calc_result == correct_result) calc_result = translate(s, "Iop_GetElem16x4", (n, claripy.BVV(3, 8))) correct_result = claripy.BVV(0x0123, 16) assert s.solver.is_true(calc_result == correct_result) calc_result = translate(s, "Iop_GetElem32x2", (n, claripy.BVV(0, 8))) correct_result = claripy.BVV(0x89ABCDEF, 32) assert s.solver.is_true(calc_result == correct_result) calc_result = translate(s, "Iop_GetElem32x2", (n, claripy.BVV(1, 8))) correct_result = claripy.BVV(0x01234567, 32) assert s.solver.is_true(calc_result == correct_result) calc_result = translate(s, "Iop_SetElem8x8", (n, claripy.BVV(0, 8), o)) correct_result = claripy.BVV(0x0123456789ABCDAF, 64) assert s.solver.is_true(calc_result == correct_result) calc_result = translate(s, "Iop_SetElem8x8", (n, claripy.BVV(1, 8), o)) correct_result = claripy.BVV(0x0123456789ABAFEF, 64) assert s.solver.is_true(calc_result == correct_result) calc_result = translate(s, "Iop_SetElem8x8", (n, claripy.BVV(6, 8), o)) correct_result = claripy.BVV(0x01AF456789ABCDEF, 64) assert s.solver.is_true(calc_result == correct_result) calc_result = translate(s, "Iop_SetElem8x8", (n, claripy.BVV(7, 8), o)) correct_result = claripy.BVV(0xAF23456789ABCDEF, 64) assert s.solver.is_true(calc_result == correct_result) calc_result = translate(s, "Iop_SetElem16x4", (n, claripy.BVV(0, 8), p)) correct_result = claripy.BVV(0x0123456789ABDFEC, 64) assert s.solver.is_true(calc_result == correct_result) calc_result = translate(s, "Iop_SetElem16x4", (n, claripy.BVV(3, 8), p)) correct_result = claripy.BVV(0xDFEC456789ABCDEF, 64) assert s.solver.is_true(calc_result == correct_result) calc_result = translate(s, "Iop_SetElem32x2", (n, claripy.BVV(0, 8), q)) correct_result = claripy.BVV(0x01234567BFCFDFEF, 64) assert s.solver.is_true(calc_result == correct_result) calc_result = translate(s, "Iop_SetElem32x2", (n, claripy.BVV(1, 8), q)) correct_result = claripy.BVV(0xBFCFDFEF89ABCDEF, 64) assert s.solver.is_true(calc_result == correct_result) # Symbolic indexes calc_result = translate(ss, "Iop_GetElem8x8", (r, ss)) correct_result = claripy.If( ss == 7, claripy.BVV(0x01, 8), claripy.If( ss == 6, claripy.BVV(0x02, 8), claripy.If( ss == 5, claripy.BVV(0x03, 8), claripy.If( ss == 4, claripy.BVV(0x04, 8), claripy.If( ss == 3, claripy.BVV(0x05, 8), claripy.If( ss == 2, claripy.BVV(0x06, 8), claripy.If(ss == 1, claripy.BVV(0x07, 8), claripy.BVV(0x08, 8)), ), ), ), ), ), ) assert s.solver.is_true(calc_result == correct_result) calc_result = translate(s, "Iop_GetElem16x4", (r, ss)) correct_result = claripy.If( ss == 3, claripy.BVV(0x0102, 16), claripy.If( ss == 2, claripy.BVV(0x0304, 16), claripy.If(ss == 1, claripy.BVV(0x0506, 16), claripy.BVV(0x0708, 16)), ), ) assert s.solver.is_true(calc_result == correct_result) calc_result = translate(s, "Iop_GetElem32x2", (r, ss)) correct_result = claripy.If(ss == 1, claripy.BVV(0x01020304, 32), claripy.BVV(0x05060708, 32)) assert s.solver.is_true(calc_result == correct_result) r_slices = r.chop(8) calc_result = translate(s, "Iop_SetElem8x8", (r, ss, o)) correct_result = claripy.Concat( claripy.If(ss == 7, o, r_slices[0]), claripy.If(ss == 6, o, r_slices[1]), claripy.If(ss == 5, o, r_slices[2]), claripy.If(ss == 4, o, r_slices[3]), claripy.If(ss == 3, o, r_slices[4]), claripy.If(ss == 2, o, r_slices[5]), claripy.If(ss == 1, o, r_slices[6]), claripy.If(ss == 0, o, r_slices[7]), ) assert s.solver.is_true(calc_result == correct_result) r_slices = r.chop(16) calc_result = translate(s, "Iop_SetElem16x4", (r, ss, p)) correct_result = claripy.Concat( claripy.If(ss == 3, p, r_slices[0]), claripy.If(ss == 2, p, r_slices[1]), claripy.If(ss == 1, p, r_slices[2]), claripy.If(ss == 0, p, r_slices[3]), ) assert s.solver.is_true(calc_result == correct_result) r_slices = r.chop(32) calc_result = translate(s, "Iop_SetElem32x2", (r, ss, q)) correct_result = claripy.Concat( claripy.If(ss == 1, q, r_slices[0]), claripy.If(ss == 0, q, r_slices[1]), ) assert s.solver.is_true(calc_result == correct_result)
def run(self, to_check, length): string = self.state.memory.load(to_check, length) return claripy.If(string == evil, claripy.BVV(1, 32), claripy.BVV(0, 32))
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)))
def mag(value): mag_array = [0x0, 0x9908b0df] return claripy.If(value == 0, claripy.BVV(mag_array[0], 64), claripy.BVV(mag_array[1], 64))
def load(self, addr, condition=None, fallback=None, **kwargs): res = super().load(addr, condition=condition, **kwargs) if condition is not None and fallback is not None: res = claripy.If(condition, res, fallback) return res
def evaluate_binary(self, size_out: int, size_in: int, in1: BV, in2: BV) -> BV: # origin: ccall.py pc_actions_ADD res = in1 + in2 return claripy.If(claripy.ULT(res, in1), claripy.BVV(1, 1), claripy.BVV(0, 1))
def test_some_vector_ops(): engine = HeavyVEXMixin(None) s = SimState(arch='AMD64') def translate(state, op, args): return engine._perform_vex_expr_Op(op, args) a = s.solver.BVV(0xffff0000000100020003000400050006, 128) b = s.solver.BVV(0x00020002000200020002000200020002, 128) calc_result = translate(s, 'Iop_Sub16x8', (a, b)) correct_result = s.solver.BVV(0xfffdfffeffff00000001000200030004, 128) nose.tools.assert_true(s.solver.is_true(calc_result == correct_result)) calc_result = translate(s, 'Iop_CmpEQ16x8', (a, b)) correct_result = s.solver.BVV(0x000000000000ffff0000000000000000, 128) nose.tools.assert_true(s.solver.is_true(calc_result == correct_result)) calc_result = translate(s, 'Iop_CmpEQ8x16', (a, b)) correct_result = s.solver.BVV(0x0000ff00ff00ffffff00ff00ff00ff00, 128) nose.tools.assert_true(s.solver.is_true(calc_result == correct_result)) calc_result = translate(s, 'Iop_CmpGT16Sx8', (a, b)) correct_result = s.solver.BVV(0x0000000000000000ffffffffffffffff, 128) nose.tools.assert_true(s.solver.is_true(calc_result == correct_result)) calc_result = translate(s, 'Iop_CmpGT16Ux8', (a, b)) correct_result = s.solver.BVV(0xffff000000000000ffffffffffffffff, 128) nose.tools.assert_true(s.solver.is_true(calc_result == correct_result)) calc_result = translate(s, 'Iop_InterleaveLO16x8', (a, b)) correct_result = s.solver.BVV(0x00030002000400020005000200060002, 128) nose.tools.assert_true(s.solver.is_true(calc_result == correct_result)) calc_result = translate(s, 'Iop_InterleaveLO8x16', (a, b)) correct_result = s.solver.BVV(0x00000302000004020000050200000602, 128) nose.tools.assert_true(s.solver.is_true(calc_result == correct_result)) calc_result = translate(s, 'Iop_Min8Ux16', (a, b)) correct_result = s.solver.BVV(0x00020000000100020002000200020002, 128) nose.tools.assert_true(s.solver.is_true(calc_result == correct_result)) calc_result = translate(s, 'Iop_Min8Sx16', (a, b)) correct_result = s.solver.BVV(0xffff0000000100020002000200020002, 128) nose.tools.assert_true(s.solver.is_true(calc_result == correct_result)) calc_result = translate(s, 'Iop_QNarrowBin16Sto8Ux16', (a, b)) correct_result = s.solver.BVV(0x00000102030405060202020202020202, 128) nose.tools.assert_true(s.solver.is_true(calc_result == correct_result)) c = s.solver.BVV(0xff008877, 32) d = s.solver.BVV(0x11111111, 32) calc_result = translate(s, 'Iop_HAdd8Sx4', (c, d)) correct_result = s.solver.BVV(0x0808cc44, 32) nose.tools.assert_true(s.solver.is_true(calc_result == correct_result)) calc_result = translate(s, 'Iop_QAdd8Sx4', (c, d)) correct_result = s.solver.BVV(0x1011997f, 32) nose.tools.assert_true(s.solver.is_true(calc_result == correct_result)) calc_result = translate(s, 'Iop_QAdd8Ux4', (c, d)) correct_result = s.solver.BVV(0xff119988, 32) nose.tools.assert_true(s.solver.is_true(calc_result == correct_result)) calc_result = translate(s, 'Iop_QSub8Sx4', (c, d)) correct_result = s.solver.BVV(0xeeef8066, 32) nose.tools.assert_true(s.solver.is_true(calc_result == correct_result)) calc_result = translate(s, 'Iop_QSub8Ux4', (c, d)) correct_result = s.solver.BVV(0xee007766, 32) nose.tools.assert_true(s.solver.is_true(calc_result == correct_result)) e = s.solver.BVV(0xff00887766554433, 64) f = s.solver.BVV(0x0202000200020002, 64) calc_result = translate(s, 'Iop_QNarrowBin16Sto8Ux8', (e, f)) correct_result = s.solver.BVV(0x0000ffffff020202, 64) nose.tools.assert_true(s.solver.is_true(calc_result == correct_result)) gg = claripy.BVV(0x111111112222222233333333ffffffff, 128) h = claripy.BVV(0x1111111100000000ffffffffffffffff, 128) calc_result = translate(s, 'Iop_CmpEQ32Fx4', (gg, h)) correct_result = claripy.BVV(0xffffffff000000000000000000000000, 128) nose.tools.assert_true(s.solver.is_true(calc_result == correct_result)) calc_result = translate(s, 'Iop_Clz32x4', (gg, )) correct_result = claripy.BVV(0x00000003000000020000000200000000, 128) nose.tools.assert_true(s.solver.is_true(calc_result == correct_result)) i = claripy.BVV(0x1001000000001000, 64) j = claripy.BVV(0x100000000000f000, 64) calc_result = translate(s, 'Iop_Mull16Sx4', (i, j)) correct_result = claripy.BVV(0x10010000000000000000000ff000000, 128) nose.tools.assert_true(s.solver.is_true(calc_result == correct_result)) calc_result = translate(s, 'Iop_Mull16Ux4', (i, j)) correct_result = claripy.BVV(0x100100000000000000000000f000000, 128) nose.tools.assert_true(s.solver.is_true(calc_result == correct_result)) k = claripy.BVV(0xe7, 8) ll = claripy.BVV(0x1234, 16) m = claripy.BVV(0x12345678, 32) calc_result = translate(s, 'Iop_Dup8x8', (k, )) correct_result = claripy.BVV(0xe7e7e7e7e7e7e7e7, 64) nose.tools.assert_true(s.solver.is_true(calc_result == correct_result)) calc_result = translate(s, 'Iop_Dup8x16', (k, )) correct_result = claripy.BVV(0xe7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7, 128) nose.tools.assert_true(s.solver.is_true(calc_result == correct_result)) calc_result = translate(s, 'Iop_Dup16x4', (ll, )) correct_result = claripy.BVV(0x1234123412341234, 64) nose.tools.assert_true(s.solver.is_true(calc_result == correct_result)) calc_result = translate(s, 'Iop_Dup16x8', (ll, )) correct_result = claripy.BVV(0x12341234123412341234123412341234, 128) nose.tools.assert_true(s.solver.is_true(calc_result == correct_result)) calc_result = translate(s, 'Iop_Dup32x2', (m, )) correct_result = claripy.BVV(0x1234567812345678, 64) nose.tools.assert_true(s.solver.is_true(calc_result == correct_result)) calc_result = translate(s, 'Iop_Dup32x4', (m, )) correct_result = claripy.BVV(0x12345678123456781234567812345678, 128) nose.tools.assert_true(s.solver.is_true(calc_result == correct_result)) n = claripy.BVV(0x0123456789abcdef, 64) o = claripy.BVV(0xaf, 8) p = claripy.BVV(0xdfec, 16) q = claripy.BVV(0xbfcfdfef, 32) r = claripy.BVV(0x0102030405060708, 64) ss = claripy.BVS('index', 8) # According to the source code of LibVex, the index is a U8 constant calc_result = translate(s, 'Iop_GetElem8x8', (n, claripy.BVV(0, 8))) correct_result = claripy.BVV(0xef, 8) nose.tools.assert_true(s.solver.is_true(calc_result == correct_result)) calc_result = translate(s, 'Iop_GetElem8x8', (n, claripy.BVV(1, 8))) correct_result = claripy.BVV(0xcd, 8) nose.tools.assert_true(s.solver.is_true(calc_result == correct_result)) calc_result = translate(s, 'Iop_GetElem8x8', (n, claripy.BVV(6, 8))) correct_result = claripy.BVV(0x23, 8) nose.tools.assert_true(s.solver.is_true(calc_result == correct_result)) calc_result = translate(s, 'Iop_GetElem8x8', (n, claripy.BVV(7, 8))) correct_result = claripy.BVV(0x01, 8) nose.tools.assert_true(s.solver.is_true(calc_result == correct_result)) calc_result = translate(s, 'Iop_GetElem16x4', (n, claripy.BVV(0, 8))) correct_result = claripy.BVV(0xcdef, 16) nose.tools.assert_true(s.solver.is_true(calc_result == correct_result)) calc_result = translate(s, 'Iop_GetElem16x4', (n, claripy.BVV(3, 8))) correct_result = claripy.BVV(0x0123, 16) nose.tools.assert_true(s.solver.is_true(calc_result == correct_result)) calc_result = translate(s, 'Iop_GetElem32x2', (n, claripy.BVV(0, 8))) correct_result = claripy.BVV(0x89abcdef, 32) nose.tools.assert_true(s.solver.is_true(calc_result == correct_result)) calc_result = translate(s, 'Iop_GetElem32x2', (n, claripy.BVV(1, 8))) correct_result = claripy.BVV(0x01234567, 32) nose.tools.assert_true(s.solver.is_true(calc_result == correct_result)) calc_result = translate(s, 'Iop_SetElem8x8', (n, claripy.BVV(0, 8), o)) correct_result = claripy.BVV(0x0123456789abcdaf, 64) nose.tools.assert_true(s.solver.is_true(calc_result == correct_result)) calc_result = translate(s, 'Iop_SetElem8x8', (n, claripy.BVV(1, 8), o)) correct_result = claripy.BVV(0x0123456789abafef, 64) nose.tools.assert_true(s.solver.is_true(calc_result == correct_result)) calc_result = translate(s, 'Iop_SetElem8x8', (n, claripy.BVV(6, 8), o)) correct_result = claripy.BVV(0x01af456789abcdef, 64) nose.tools.assert_true(s.solver.is_true(calc_result == correct_result)) calc_result = translate(s, 'Iop_SetElem8x8', (n, claripy.BVV(7, 8), o)) correct_result = claripy.BVV(0xaf23456789abcdef, 64) nose.tools.assert_true(s.solver.is_true(calc_result == correct_result)) calc_result = translate(s, 'Iop_SetElem16x4', (n, claripy.BVV(0, 8), p)) correct_result = claripy.BVV(0x0123456789abdfec, 64) nose.tools.assert_true(s.solver.is_true(calc_result == correct_result)) calc_result = translate(s, 'Iop_SetElem16x4', (n, claripy.BVV(3, 8), p)) correct_result = claripy.BVV(0xdfec456789abcdef, 64) nose.tools.assert_true(s.solver.is_true(calc_result == correct_result)) calc_result = translate(s, 'Iop_SetElem32x2', (n, claripy.BVV(0, 8), q)) correct_result = claripy.BVV(0x01234567bfcfdfef, 64) nose.tools.assert_true(s.solver.is_true(calc_result == correct_result)) calc_result = translate(s, 'Iop_SetElem32x2', (n, claripy.BVV(1, 8), q)) correct_result = claripy.BVV(0xbfcfdfef89abcdef, 64) nose.tools.assert_true(s.solver.is_true(calc_result == correct_result)) # Symbolic indexes calc_result = translate(ss, 'Iop_GetElem8x8', (r, ss)) correct_result = claripy.If( ss == 7, claripy.BVV(0x01, 8), claripy.If( ss == 6, claripy.BVV(0x02, 8), claripy.If( ss == 5, claripy.BVV(0x03, 8), claripy.If( ss == 4, claripy.BVV(0x04, 8), claripy.If( ss == 3, claripy.BVV(0x05, 8), claripy.If( ss == 2, claripy.BVV(0x06, 8), claripy.If(ss == 1, claripy.BVV(0x07, 8), claripy.BVV(0x08, 8)))))))) nose.tools.assert_true(s.solver.is_true(calc_result == correct_result)) calc_result = translate(s, 'Iop_GetElem16x4', (r, ss)) correct_result = claripy.If( ss == 3, claripy.BVV(0x0102, 16), claripy.If( ss == 2, claripy.BVV(0x0304, 16), claripy.If(ss == 1, claripy.BVV(0x0506, 16), claripy.BVV(0x0708, 16)))) nose.tools.assert_true(s.solver.is_true(calc_result == correct_result)) calc_result = translate(s, 'Iop_GetElem32x2', (r, ss)) correct_result = claripy.If(ss == 1, claripy.BVV(0x01020304, 32), claripy.BVV(0x05060708, 32)) nose.tools.assert_true(s.solver.is_true(calc_result == correct_result)) r_slices = r.chop(8) calc_result = translate(s, 'Iop_SetElem8x8', (r, ss, o)) correct_result = claripy.Concat(claripy.If(ss == 7, o, r_slices[0]), claripy.If(ss == 6, o, r_slices[1]), claripy.If(ss == 5, o, r_slices[2]), claripy.If(ss == 4, o, r_slices[3]), claripy.If(ss == 3, o, r_slices[4]), claripy.If(ss == 2, o, r_slices[5]), claripy.If(ss == 1, o, r_slices[6]), claripy.If(ss == 0, o, r_slices[7])) nose.tools.assert_true(s.solver.is_true(calc_result == correct_result)) r_slices = r.chop(16) calc_result = translate(s, 'Iop_SetElem16x4', (r, ss, p)) correct_result = claripy.Concat(claripy.If(ss == 3, p, r_slices[0]), claripy.If(ss == 2, p, r_slices[1]), claripy.If(ss == 1, p, r_slices[2]), claripy.If(ss == 0, p, r_slices[3])) nose.tools.assert_true(s.solver.is_true(calc_result == correct_result)) r_slices = r.chop(32) calc_result = translate(s, 'Iop_SetElem32x2', (r, ss, q)) correct_result = claripy.Concat( claripy.If(ss == 1, q, r_slices[0]), claripy.If(ss == 0, q, r_slices[1]), ) nose.tools.assert_true(s.solver.is_true(calc_result == correct_result))