def _get_default_concrete_value_by_type(type_, state=None): # pylint: disable=unused-argument if type_ in ['byte', 'char', 'short', 'int', 'boolean']: return BVV(0, 32) elif type_ == "long": return BVV(0, 64) elif type_ == 'float': return FPV(0, FSORT_FLOAT) elif type_ == 'double': return FPV(0, FSORT_DOUBLE) # not a primitive type # => treat it as a reference return SootNullConstant()
def _store_string_in_native_memory(self, string, addr=None): """ Store given string UTF-8 encoded and zero terminated in native memory. :param str string: String :param addr: Native store address. If not set, native memory is allocated. :return: Native address of the string. """ if addr is None: addr = self._allocate_native_memory(size=len(string)+1) else: # check if addr is symbolic if self.state.solver.symbolic(addr): l.error("Storing strings at symbolic addresses is not implemented. " "Continue execution with concretized address.") addr = self.state.solver.eval(addr) # warn if string is symbolic if self.state.solver.symbolic(string): l.warning('Support for symbolic strings, passed to native code, is limited. ' 'String will get concretized after `ReleaseStringUTFChars` is called.') # store chars one by one str_len = len(string) // 8 for idx in range(str_len): str_byte = StrSubstr(idx, 1, string) self.state.memory.store(addr+idx, str_byte) # store terminating zero self.state.memory.store(len(string), BVV(0, 8)) return addr
def run(self, f_p): self.argument_types = {0: SimTypeFd()} self.return_type = SimTypeInt(32, True) fileno = angr.SIM_PROCEDURES['posix']['fileno'] fd = self.inline_call(fileno, f_p).ret_expr # let's get the memory back for the file we're interested in and find # the newline fp = self.state.posix.get_file(fd) pos = fp.pos max_str_len = self.state.libc.max_str_len # if there exists a limit on the file size, let's respect that, the # limit cannot be symbolic limit = max_str_len if fp.size is None else self.state.se.max_int( fp.size - pos) # limit will always be concrete, if it's zero we EOF'd if limit != 0: data = fp.read_from(1) data = data.zero_extend(32 - data.size()) else: data = -1 #EOF data = BVV(data, 32) return data
def _get_role(self, no, key_addr, reg_name, key_name=None): """ Retrieve the role of a binary by inferring whether it is a setter or a getter :param no: node containing the call to a set or getter function :param key_addr: address of the keyword used to infer the role :param reg_name: register containing the key_addr :return: The role and the function used to infer it whether the role could be inferred, None and None otherwise """ p = self._current_p if not BinaryDependencyGraph.is_call(p.factory.block(no.addr)): return None # detect the role self._cpf_used = None f_addr = no.addr self._candidate_role_function = no.successors[0].addr # prepare the under-contrainted-based initial state # we do not allow untaint as we just want to see where the key data key is leading to self._core_taint = CoreTaint(p, interfunction_level=2, smart_call=False, follow_unsat=True, try_thumb=True, exit_on_decode_error=True, force_paths=True, allow_untaint=False, logger_obj=log) # the used register is not a parameter register if are_parameters_in_registers(p) and reg_name not in arg_reg_names(p): return Role.UNKNOWN self._current_par_name = reg_name self._current_key_addr = key_addr self._current_f_addr = f_addr s = get_initial_state(p, self._core_taint, f_addr) s = self._apply_taint(s, key_addr, key_name) # enter into the call sim = p.factory.simgr(s) sim.step() s = sim.active[0] if reg_name: setattr(s.regs, reg_name, BVV(key_addr, p.arch.bits)) summarized_f = prepare_function_summaries(p) self._f_arg_vals = [] self._set_f_vals = True self._core_taint.set_alarm(TIMEOUT_TAINT, n_tries=TIMEOUT_TRIES) try: self._core_taint.run(s, (), (), summarized_f=summarized_f, force_thumb=False, check_func=self._check_key_usage, init_bss=False) except TimeOutException: log.warning("Timeout Triggered") except Exception as e: log.warning(f"Exception in Coretaint: {str(e)}") self._core_taint.unset_alarm() return self._current_role
def _inet_pton(self, ct, caller_path, plt_path): """ inet_pton summary :param ct: core taint engine :param caller_path: angr path leading to the inet_path :param plt_path: angr path leading to the plt entry of inet_pton :return: """ p = ct.p new_state = plt_path.active[0] # move data key from argument to destination addr addr_str = getattr(plt_path.active[0].regs, arg_reg_name(p, 1)) cnt_str = get_string(p, addr_str.args[0], extended=True) # do the inet_pton conversion. # this is not exactly the conversion the inet_pton does, it's a trick we use to keep track of the addresses inet_pton_convesions[self._pton_counter] = cnt_str bits = p.arch.bits to_store = BVV(self._pton_counter, bits) self._pton_counter += 1 # store it! dst_mem = getattr(plt_path.active[0].regs, arg_reg_name(p, 2)) new_state.memory.store(dst_mem, to_store) # instead of a link register, we hook an unconstrained sim procedure self._p.hook(plt_path.addr, ReturnUnconstrained()) caller_path.step().step()
def get_default_value_by_type(type_, state=None): """ Java specify defaults values for primitive and reference types. This method returns the default value for a given type. :param str type_: Name of type. :return: Default value for this type. """ if type_ in ['byte', 'char', 'short', 'int', 'boolean']: return BVS('default_value_{}'.format(type_), 32) elif type_ == "long": return BVS('default_value_{}'.format(type_), 64) elif type_ == 'float': return FPS('default_value_{}'.format(type_), FSORT_FLOAT) elif type_ == 'double': return FPS('default_value_{}'.format(type_), FSORT_DOUBLE) elif state is not None: if type_ == 'java.lang.String': return SimSootValue_StringRef.new_string(state, StringS('default_value_{}'.format(type_), 1000)) if type_.endswith('[][]'): raise NotImplementedError # multiarray = SimSootExpr_NewMultiArray.new_array(self.state, element_type, size) # multiarray.add_default_value_generator(lambda s: SimSootExpr_NewMultiArray._generate_inner_array(s, element_type, sizes)) # return multiarray elif type_.endswith('[]'): array = SimSootExpr_NewArray.new_array(state, type_[:-2], BVV(2, 32)) return array else: return SimSootValue_ThisRef.new_object(state, type_, symbolic=True, init_object=False) else: # not a primitive type # => treat it as a reference return SootNullConstant()
def _get_default_symbolic_value_by_type(type_, state): if type_ in ['byte', 'char', 'short', 'int', 'boolean']: return BVS('default_value_{}'.format(type_), 32) if type_ == "long": return BVS('default_value_{}'.format(type_), 64) if type_ == 'float': return FPS('default_value_{}'.format(type_), FSORT_FLOAT) if type_ == 'double': return FPS('default_value_{}'.format(type_), FSORT_DOUBLE) if type_ == 'java.lang.String': return SimSootValue_StringRef.new_string( state, StringS('default_value_{}'.format(type_), 1000)) if type_.endswith('[][]'): raise NotImplementedError # multiarray = SimSootExpr_NewMultiArray.new_array(self.state, element_type, size) # multiarray.add_default_value_generator(lambda s: SimSootExpr_NewMultiArray._generate_inner_array(s, element_type, sizes)) # return multiarray if type_.endswith('[]'): array = SimSootExpr_NewArray.new_array(state, type_[:-2], BVV(2, 32)) return array return SimSootValue_ThisRef.new_object(state, type_, symbolic=True, init_object=False)
def run(self, fd): self.argument_types = {0: SimTypeFd()} self.return_type = SimTypeInt(32, True) # let's get the memory back for the file we're interested in and find # the newline # fd should be a FILE* but for now It is a int file descriptor fp = self.state.posix.get_file(fd) pos = fp.pos max_str_len = self.state.libc.max_str_len # if there exists a limit on the file size, let's respect that, the # limit cannot be symbolic limit = max_str_len if fp.size is None else self.state.se.max_int( fp.size - pos) # limit will always be concrete, if it's zero we EOF'd if limit != 0: data = fp.read_from(1) data = data.zero_extend(32 - data.size()) else: data = -1 #EOF data = BVV(data, 32) return data
def _read_memory(self, offset, bytes_read, state, start, end): # MemoryForwardMsg = RemoteMemoryReadMessage(self.origin, self.id, # 0x0, # Fake PC # start, # end - start) # self.avatar.queue.put(MemoryForwardMsg) # # r_id, r_value, r_success = self.origin.response_queue.get() # # if self.id != r_id: # raise("AvatarAngrMemory received mismatching id!") # if r_success != True: # raise Exception("AvatarAngrMemory remote memory request failed!") # # self.id += 1 # # int.from_bytes(bytes_read[start, start + end], byteorder='big') r_value = struct.unpack("<L", bytes_read[start-offset:end-offset])[0] # do your stuff return [(start, SimMemoryObject(BVV(r_value, (end-start)*8), start))]
def _apply_taint(self, state, key_addr, keyword=None): """ Apply the taint to the datakey :param state: the current initial state :param key_addr: the address of the datakey :param keyword: the keyword to taint (if we want to constraint the datakey) :return: the new state """ # taint the data key if self._discover_data_keys: size = len(self._current_data_key) else: size = self._core_taint.taint_buf_size t = self._core_taint.get_sym_val(name=self._core_taint.taint_buf, bits=(size * 8)).reversed if keyword: # reverse to make it LE bvv = BVV(keyword).reversed state.add_constraints(t == bvv) # we taint the used keyword to trace its use state.memory.store(key_addr, t) return state
def run(self, f_p): #additional code trace_data = ("_IO_getc", {"f_p": (f_p, f_p.symbolic)}) try: self.state.procedure_data.global_variables["trace"].append( trace_data) except KeyError: self.state.procedure_data.global_variables["trace"] = [] self.state.procedure_data.global_variables["trace"].append( trace_data) #end of additional code self.argument_types = {0: SimTypeFd()} self.return_type = SimTypeInt(32, True) fileno = simuvex.SimProcedures['libc.so.6']['fileno'] fd = self.inline_call(fileno, f_p).ret_expr # let's get the memory back for the file we're interested in and find # the newline fp = self.state.posix.get_file(fd) pos = fp.pos max_str_len = self.state.libc.max_str_len # if there exists a limit on the file size, let's respect that, the # limit cannot be symbolic limit = max_str_len if fp.size is None else self.state.se.max_int( fp.size - pos) # limit will always be concrete, if it's zero we EOF'd if limit != 0: data = fp.read_from(1) data = data.zero_extend(32 - data.size()) else: data = -1 #EOF data = BVV(data, 32) return data
def _search_value(self): if self._arm: armins = self._string_to_insn(self._insbytes) if not self._arm64: if not self._armthumb: # ARM instructions if armins & 0x0C000000 == 0x04000000: # LDR thoughtval = armins & 0xFFF if thoughtval != self.value: raise ValueNotFoundError imm12 = self._imm(12) self.patch_value_expression = imm12.zero_extend( self.bits - 12) self.patch_bytes_expression = claripy.Concat( BVV(armins >> 12, 20), imm12) self._test_values = (1, 0xfff) elif armins & 0x0E000000 == 0x02000000: # Data processing w/ immediate shiftval = (armins & 0xF00) >> 7 thoughtval = armins & 0xFF thoughtval = ror(thoughtval, shiftval, 32) if thoughtval != self.value: raise ValueNotFoundError shift = self._imm(4, 'shift') imm8 = self._imm(8) self.patch_value_expression = claripy.RotateRight( imm8.zero_extend(32 - 8), shift.zero_extend(32 - 4) * 2) self.patch_bytes_expression = claripy.Concat( BVV(armins >> 12, 20), shift, imm8) self._test_values = (1, 0xff, 0xff000000) elif armins & 0x0E400090 == 0x00400090: # LDRH thoughtval = (armins & 0xF) | ((armins & 0xF00) >> 4) if thoughtval != self.value: raise ValueNotFoundError hinib = self._imm(4, 'hinib') lonib = self._imm(4, 'lonib') self.patch_value_expression = claripy.Concat( hinib, lonib).zero_extend(self.bits - 8) self.patch_bytes_expression = claripy.Concat( BVV(armins >> 12, 20), hinib, BVV((armins >> 4) & 0xF, 4), lonib) self._test_values = (1, 0xff) elif armins & 0x0E000000 == 0x0C000000: # Coprocessor data transfer # i.e. FLD/FST thoughtval = armins & 0xFF thoughtval *= 4 if thoughtval != self.value: raise ValueNotFoundError imm8 = self._imm(8) self.patch_value_expression = imm8.zero_extend( self.bits - 8) << 2 self.patch_bytes_expression = claripy.Concat( BVV(armins >> 8, 24), imm8) self._test_values = (4, 0x3fc) else: raise ValueNotFoundError else: # THUMB instructions # https://ece.uwaterloo.ca/~ece222/ARM/ARM7-TDMI-manual-pt3.pdf if self._inslen == 2: # 16 bit instructions if armins & 0xF000 in (0x9000, 0xA000): # SP-relative LDR/STR, also SP-addiition # page 26, 28 # unsigned offsets only, 10 bit imm stored w/o last two bits thoughtval = armins & 0xFF thoughtval *= 4 if thoughtval != self.value: raise ValueNotFoundError imm8 = self._imm(8) self.patch_value_expression = imm8.zero_extend( self.bits - 8) << 2 self.patch_bytes_expression = claripy.Concat( BVV(armins >> 8, 8), imm8) self._test_values = (4, 0x3fc) elif armins & 0xFF00 == 0xB000: # Add/sub offset to SP # page 30 # uses sign bit, 9 bit imm stored w/o last two bits thoughtval = armins & 0x7F thoughtval *= 4 if thoughtval != self.value: raise ValueNotFoundError imm7 = self._imm(7) self.patch_value_expression = imm7.zero_extend( self.bits - 7) << 2 self.patch_bytes_expression = claripy.Concat( BVV(armins >> 7, 9), imm7) self._test_values = (4, 0x1fc) elif armins & 0xFC00 == 0x1C00: # ADD/SUB (immediate format) # page 7 # uses sign bit, 3 bit immediate thoughtval = (armins & 0x01C0) >> 6 if thoughtval != self.value: raise ValueNotFoundError imm3 = self._imm(3) self.patch_value_expression = imm3.zero_extend( self.bits - 3) self.patch_bytes_expression = claripy.Concat( BVV(armins >> 9, 7), imm3, BVV(armins & 0x3F, 6)) self._test_values = (1, 7) elif armins & 0xE000 == 0x2000: # Move/Compare/Add/Subtract immediate # page 9 # Unsigned 8 bit immediate thoughtval = armins & 0xFF if thoughtval != self.value: raise ValueNotFoundError imm8 = self._imm(8) self.patch_value_expression = imm8.zero_extend( self.bits - 8) self.patch_bytes_expression = claripy.Concat( BVV(armins >> 8, 8), imm8) self._test_values = (1, 0xff) elif armins & 0xF000 == 0x6000: # Register-relative LDR/STR # page 22 # unsigned 7 bit imm stored w/o last two bits thoughtval = ((armins >> 6) & 0x1F) << 2 if thoughtval != self.value: raise ValueNotFoundError imm5 = self._imm(5) self.patch_value_expression = imm5.zero_extend( self.bits - 5) << 2 self.patch_bytes_expression = claripy.Concat( BVV(armins >> 11, 5), imm5, BVV(armins & 0x3F, 6)) self._test_values = (4, 0x7c) elif armins & 0xF000 == 0x7000: # Register-relative LDRB/STRB # page 22 # unsigned 5 bit imm thoughtval = (armins >> 6) & 0x1F if thoughtval != self.value: raise ValueNotFoundError imm5 = self._imm(5) self.patch_value_expression = imm5.zero_extend( self.bits - 5) self.patch_bytes_expression = claripy.Concat( BVV(armins >> 11, 5), imm5, BVV(armins & 0x3F, 6)) self._test_values = (1, 0x1f) else: raise ValueNotFoundError elif self._inslen == 4: # 32 bit instructions # http://read.pudn.com/downloads159/doc/709030/Thumb-2SupplementReferenceManual.pdf if armins & 0xFE1F0000 == 0xF81F0000 or \ armins & 0xFE800000 == 0xF8800000: # Load/Store # page 66, formats 1-2 # imm12 with designated sign bit thoughtval = armins & 0xFFF if thoughtval != self.value: raise ValueNotFoundError imm12 = self._imm(12) self.patch_value_expression = imm12.zero_extend( self.bits - 12) self.patch_bytes_expression = claripy.Concat( BVV(armins >> 12, 20), imm12) self._test_values = (1, 0xfff) elif armins & 0xFE800900 == 0xF8000800: # Load/Store # page 66, formats 3-4 # imm8 with designated sign bit thoughtval = armins & 0xFF if thoughtval != self.value: raise ValueNotFoundError imm8 = self._imm(8) self.patch_value_expression = imm8.zero_extend( self.bits - 8) self.patch_bytes_expression = claripy.Concat( BVV(armins >> 8, 24), imm8) self._test_values = (1, 0xff) elif armins & 0xFE800900 == 0xF8000900: # Load/Store # page 66, formats 5-6 # imm8, sign extended thoughtval = armins & 0x7F if armins & 0x80 == 0x80: thoughtval = (thoughtval ^ 0x7F) + 1 if thoughtval != self.value: raise ValueNotFoundError imm8 = self._imm(8) self.patch_value_expression = imm8.sign_extend( self.bits - 8) self.patch_bytes_expression = claripy.Concat( BVV(armins >> 8, 24), imm8) self._test_values = (-0x80, 0x7f) elif armins & 0xFB408000 == 0xF2000000: # Add/Sub # page 53, format 2 # 12 bit immediate split into 3 bitfields thoughtval = armins & 0xFF thoughtval |= (armins & 0x7000) >> 4 thoughtval |= (armins & 0x04000000) >> 15 if thoughtval != self.value: raise ValueNotFoundError imm8 = self._imm(8) imm3 = self._imm(3) imm1 = self._imm(1) self.patch_value_expression = claripy.Concat( imm1, imm3, imm8).zero_extend(self.bits - 12) self.patch_bytes_expression = claripy.Concat( BVV(armins >> 27, 5), imm1, BVV((armins & 0x03FF8000) >> 15, 11), imm3, BVV((armins & 0xF00) >> 8, 4), imm8) self._test_values = (1, 0xfff) elif armins & 0xFB408000 == 0xF2400000: # Move # page 53, format 3 # 16 bit immediate split into 4 bitfields thoughtval = armins & 0xFF thoughtval |= (armins & 0x7000) >> 4 thoughtval |= (armins & 0x04000000) >> 15 thoughtval |= (armins & 0xF0000) >> 4 if thoughtval != self.value: raise ValueNotFoundError imm8 = self._imm(8) imm3 = self._imm(3) imm1 = self._imm(1) imm4 = self._imm(1) self.patch_value_expression = claripy.Concat( imm4, imm1, imm3, imm8).zero_extend(self.bits - 12) self.patch_bytes_expression = claripy.Concat( BVV(armins >> 27, 5), imm1, BVV((armins & 0x03F00000) >> 20, 6), imm4, BVV((armins & 0x00008000) >> 15, 1), imm3, BVV((armins & 0xF00) >> 8, 4), imm8) self._test_values = (1, 0xffff) elif armins & 0xFA008000 == 0xF0000000: # Data processing, modified 12 bit imm, aka EVIL # page 53 # wow. just. wow. imm12 = armins & 0xFF imm12 |= (armins & 0x7000) >> 4 imm12 |= (armins & 0x04000000) >> 15 # decoding algorithm from page 93 if imm12 & 0xC00 == 0: if imm12 & 0x300 == 0: thoughtval = imm12 elif imm12 & 0x300 == 0x100: thoughtval = imm12 & 0xFF thoughtval |= thoughtval << 16 elif imm12 & 0x300 == 0x200: thoughtval = (imm12 & 0xFF) << 8 thoughtval |= thoughtval << 16 elif imm12 & 0x300 == 0x300: thoughtval = imm12 & 0xFF thoughtval |= thoughtval << 8 thoughtval |= thoughtval << 16 else: thoughtval = ror(0x80 | (imm12 & 0x7F), imm12 >> 7, 32) if thoughtval != self.value: raise ValueNotFoundError imm12 = self._imm(12) ITE = claripy.If CAT = claripy.Concat ROR = claripy.RotateRight imm8 = imm12[7:0] imm7 = imm12[6:0] imm3 = imm12[10:8] imm1 = imm12[11] zero = BVV(0, 8) bit = BVV(1, 1) monster = ITE( imm12[11:10] == 0, ITE( imm12[9] == 0, ITE(imm12[8] == 0, imm12[7:0].zero_extend(32 - 8), CAT(zero, imm8, zero, imm8)), ITE(imm12[8] == 0, CAT(imm8, zero, imm8, zero), CAT(imm8, imm8, imm8, imm8))), ROR( CAT(bit, imm7).zero_extend(32 - 8), imm12[11:7].zero_extend(32 - 5))) self.patch_value_expression = monster self.patch_bytes_expression = claripy.Concat( BVV(armins >> 27, 5), imm1, BVV((armins & 0x03FF8000) >> 15, 11), imm3, BVV((armins & 0xF00) >> 8, 4), imm8) self._test_values = (0xff00ff00, 0x00ff00ff, 0xffffffff, 0xff, 0xff000000) else: raise ValueNotFoundError else: raise FidgetUnsupportedError( "You found a THUMB instruction longer than 32 bits??" ) else: self.bit_length = 64 # aarch64 instructions # can't find a reference doc?????? I'm pulling these from VEX, guest_arm64_toIR.c if armins & 0x7f800000 in (0x28800000, 0x29800000, 0x29000000): # LDP/SDP # line 4791 # 7 bit immediate signed offset, scaled by load size (from MSB) shift = 3 if armins & 0x80000000 else 2 simm7 = (armins & 0x3f8000) >> 15 simm7 = resign_int(simm7, 7) simm7 <<= shift if simm7 != self.value: raise ValueNotFoundError imm7 = self._imm(7) self.patch_value_expression = imm7.sign_extend(self.bits - 7) << shift self.patch_bytes_expression = claripy.Concat( BVV((armins & 0xffc00000) >> 22, 10), imm7, BVV(armins & 0x7fff, 15)) self._test_values = (-0x40 << shift, 0x3f << shift) elif (armins & 0x3f800000 == 0x39000000) or \ (armins & 0x3f800000 == 0x39800000 and \ ((armins >> 30) | ((armins >> 22) & 1)) in (4, 2, 3, 0, 1)): # LDR/STR, LDRS # line 4639, 5008 # 12 bit immediate unsigned offset, scaled by load size (from 2 MSB) shift = (armins & 0xc0000000) >> 30 offs = (armins & 0x3ffc00) >> 10 offs <<= shift if offs != self.value: raise ValueNotFoundError imm12 = self._imm(12) self.patch_value_expression = imm12.zero_extend( self.bits - 12) << shift self.patch_bytes_expression = claripy.Concat( BVV((armins & 0xffc00000) >> 22, 10), imm12, BVV(armins & 0x3ff, 10)) self._test_values = (1 << shift, 0xfff << shift) elif armins & 0x1f000000 == 0x11000000: # ADD/SUB imm # line 2403 # 12 bit shifted unsigned immediate if not armins & 0x80000000: self.bit_length = 32 shift = (armins >> 22) & 3 imm12 = (armins >> 10) & 0xfff imm12 <<= 12 * shift if imm12 != self.value: raise ValueNotFoundError shift = self._imm(1, 'shift') imm12 = self._imm(12) shift_full = shift.zero_extend(self.bits - 1) * 12 self.patch_value_expression = imm12.zero_extend( self.bits - 12) << shift_full self.patch_bytes_expression = claripy.Concat( BVV(armins >> 24, 8), BVV(0, 1), shift, imm12, BVV(armins & 0x3ff, 10)) self._test_values = (1, 0xfff, 0xfff000) elif armins & 0x3fa00000 == 0x38000000: # LDUR/STUR # Line 4680 # 9 bit signed immediate offset imm9 = (armins >> 12) & 0x1ff imm9 = resign_int(imm9, 9) if imm9 != self.value: raise ValueNotFoundError imm9 = self._imm(9) self.patch_value_expression = imm9.sign_extend(self.bits - 9) self.patch_bytes_expression = claripy.Concat( BVV(armins >> 21, 11), imm9, BVV(armins & 0xfff, 12)) self._test_values = (-0x100, 0xff) else: raise ValueNotFoundError if not self.sanity_check(): raise ValueNotFoundError else: insn = self._string_to_insn(self._insbytes) insn = BVV(insn, self._inslen * 8) for word_size in (64, 32, 16, 8): if word_size > self.bits: continue for bit_offset in xrange(0, insn.length - word_size + 1, 8): result = insn[bit_offset + word_size - 1:bit_offset] result = result.sign_extend(self.bits - word_size) if claripy.is_true(result == self.value): imm = self._imm(word_size) self.patch_value_expression = imm.sign_extend( self.bits - word_size) if bit_offset + word_size >= insn.length: acc = imm else: acc = claripy.Concat( insn[insn.length - 1:bit_offset + word_size], imm) if bit_offset != 0: acc = claripy.Concat(acc, insn[bit_offset - 1:0]) if self._project.arch.memory_endness == 'Iend_LE': self.patch_bytes_offset = bit_offset / 8 else: self.patch_bytes_offset = self._inslen - ( bit_offset + word_size) / 8 self.patch_bytes_size = word_size / 8 self.patch_bytes_expression = acc self._test_values = (-(1 << word_size) >> 1, ((1 << word_size) >> 1) - 1) if self.sanity_check(): break # found if self._project.arch.name == 'PPC64': # On PPC64, the lowest two bits of immediate values can be used for other things # Mask those out result = (result & ~3).sign_extend(self.bits - word_size) if not claripy.is_true(result == self.value): continue imm = self._imm(word_size - 2) self.patch_value_expression = claripy.Concat( imm, BVV(0, 2)).sign_extend(self.bits - word_size) if bit_offset + word_size >= insn.length: acc = imm else: acc = claripy.Concat( insn[insn.length - 1:bit_offset + word_size], imm) acc = claripy.Concat(acc, insn[bit_offset + 1:0]) if self._project.arch.memory_endness == 'Iend_LE': self.patch_bytes_offset = bit_offset / 8 else: self.patch_bytes_offset = self._inslen - ( bit_offset + word_size) / 8 self.patch_bytes_size = word_size / 8 self.patch_bytes_expression = acc self._test_values = (-(1 << word_size) >> 1, ((1 << word_size) >> 1) - 4) if self.sanity_check(): break # found else: # inner loop did not break: not found continue # inner loop broke: found break else: # outer loop did not break: inner loop did not break: not found raise ValueNotFoundError # outer loop broke: inner loop broke: found return
def state_blank(self, addr=None, **kwargs): # pylint: disable=arguments-differ if not kwargs.get('mode', None): kwargs['mode'] = self.project._default_analysis_mode if not kwargs.get('arch', None): kwargs['arch'] = self.arch if not kwargs.get('os_name', None): kwargs['os_name'] = self.name # enable support for string analysis if not kwargs.get('add_options', None): kwargs['add_options'] = [] kwargs['add_options'] += [options.STRINGS_ANALYSIS, options.COMPOSITE_SOLVER] if self.is_javavm_with_jni_support: # If the JNI support is enabled (i.e. JNI libs are loaded), the SimState # needs to support both the Vex and the Soot engine. Therefore we start with # an initialized native state and extend this with the Soot initializations. # Note: Setting `addr` to a `native address` (i.e. not an SootAddressDescriptor). # makes sure that the SimState is not in "Soot-mode". # TODO: use state_blank function from the native simos and not the super class state = super(SimJavaVM, self).state_blank(addr=0, **kwargs) native_addr_size = self.native_simos.arch.bits # Let the JNIEnv pointer point to the function table state.memory.store(addr=self.jni_env, data=BVV(self.jni_function_table, native_addr_size), endness=self.native_arch.memory_endness) # Initialize the function table # => Each entry usually contains the address of the function, but since we hook all functions # with SimProcedures, we store the address of the corresponding hook instead. # This, by construction, is exactly the address of the function table entry itself. for idx in range(len(jni_functions)): jni_function_addr = self.jni_function_table + idx * native_addr_size//8 state.memory.store(addr=jni_function_addr, data=BVV(jni_function_addr, native_addr_size), endness=self.native_arch.memory_endness) else: # w/o JNI support, we can just use a blank state state = SimState(project=self.project, **kwargs) if not self.project.entry and not addr: raise ValueError("Failed to init blank state. Project entry is not set/invalid" "and no address was provided.") # init state register state.regs._ip = addr if addr else self.project.entry state.regs._ip_binary = self.project.loader.main_object state.regs._invoke_return_target = None state.regs._invoke_return_variable = None # add empty stack frame state.memory.push_stack_frame() # create bottom of callstack new_frame = state.callstack.copy() new_frame.ret_addr = SootAddressTerminator() state.callstack.push(new_frame) # initialize class containing the current method state.javavm_classloader.get_class(state.addr.method.class_name, init_class=True, step_func=kwargs.get('step_function', None)) # initialize the Java environment # TODO move this to `state_full_init? self.init_static_field(state, "java.lang.System", "in", "java.io.InputStream") self.init_static_field(state, "java.lang.System", "out", "java.io.PrintStream") return state
def avatar_state(angr_factory, angr_target, options=frozenset(), add_options=None, remove_options=None, memory_backer=None, plugins=None, load_register_from=None, ram_file = None, **kwargs): ''' This method sets up a SimState which is usable for avatar and will be registered to the project's factory. Currently, setting up an avatar-state consists of four phases: 1) verifying that the state options dont include unsupported memory options. (AvatarStates only work on SimSymbolicMemory for now) 2) Setting up the memory plugin of the state 3) Creating the avatar plugin for the state 4) Creating the actual state ''' def generate_permissions_backer(): return None l = logging.getLogger('angr.factory') options = set(options) unsupported_options = set([o.ABSTRACT_MEMORY, o.FAST_MEMORY]) if options & unsupported_options: l.warning('Discarding user-defined memory options for avatar state') remove_options |= (options & unsupported_options) if add_options is not None: options |= add_options if remove_options is not None: options -= remove_options permissions_backer = angr_factory.project.loader.memory if memory_backer is None: memory_backer = angr_factory.project.loader.memory permissions_backer = generate_permissions_backer() page_size = angr_factory.project.loader.page_size #SimPagedMemory requires both pages and symbolic_addresses to be dicts #with the same keys pages = {} symbolic_addrs = {} def get_effective_ram_file(start, size, ram_files): # old interface if isinstance(ram_files, dict): return ram_files # new interface else: for f in ram_files: if f['start'] <= start < f['start'] + f['size']: return f # cannot find a ram file assert False for (start, end, mr) in angr_factory.origin.avatar.memory_ranges: if not start % page_size == 0: l.debug("Memory ranges starts at addres %x which is not page aligned (page size: %x)" % (start, page_size)) if not end % page_size == 0: l.debug("Memory ranges ends at addres %x which is not page aligned (page size: %x)" % (end, page_size)) # if mr.forwarded: if 'ram' in mr.name: page_num = start // page_size while page_num * page_size < end: effective_ram_file = get_effective_ram_file(page_num * page_size, page_size, ram_file) pages[page_num] = AvatarPage(page_num * page_size, page_size, origin=angr_factory.origin, ram_file = effective_ram_file) symbolic_addrs[page_num] = set() page_num += 1 memory_storage = SimPagedMemory(page_size=page_size, pages=pages, symbolic_addrs=symbolic_addrs, check_permissions=True, memory_backer=memory_backer, permissions_backer=permissions_backer) sim_memory = SimSymbolicMemory(mem=memory_storage, memory_id='mem', check_permissions=True) if plugins is None: plugins = {} if 'memory' in plugins: # if plugins.has_key('memory'): l.warning('Discarding user-defined memory plugin for avatar state') plugins['memory'] = sim_memory avatar_state = angr_factory.blank_state(remove_options=remove_options, add_options={o.EFFICIENT_STATE_MERGING,}, memory_backer=memory_backer, plugins=plugins, **kwargs) # avatar_state = angr_factory.blank_state(addr=0x1001, remove_options=remove_options) # avatar_state = angr_factory.blank_state(options=options, # add_options=add_options, # remove_options=remove_options, # memory_backer=memory_backer, # plugins=plugins, **kwargs) # avatar_state.globals['memcnt'] = 0 if load_register_from is not None: for reg in angr_target.avatar.arch.registers.keys(): try: value = BVV(load_register_from[reg], avatar_state.arch.bits) # if reg == 'cpsr': # print 'doing cpsr' avatar_state.registers.store(reg, value) except KeyError as e: l.warning("Register %s was not set." % str(e)) avatar_state.scratch.ins_addr = avatar_state.regs.ip avatar_state.scratch.bbl_addr = avatar_state.regs.ip avatar_state.scratch.stmt_idx = 0 avatar_state.history.jumpkind = 'Ijk_Boring' return avatar_state