def get_dispatcher(handler): """Retrieves the dispatcher of the TL/DR API calls :param handler: Handler of the TL/DR API calls :type handler: int :return: Dispatcher for the TL/DR API calls :rtype: int """ func = ida_funcs.get_func(handler) insn = ida_ua.insn_t() ea = 0 branch_addr = -1 ea = func.start_ea while ea < func.end_ea: insn = ida_ua.insn_t() insn_len = max(1, ida_ua.decode_insn(insn, ea)) if insn.itype == ida_allins.ARM_bl and \ insn.ops[0].type == ida_ua.o_near: branch_addr = insn.ops[0].addr break ea += insn_len return branch_addr
def determine_api_number(ea, chunk_start, chunk_end): def get_reg_num(reg_name): reg_inf = ida_idp.reg_info_t() ida_idp.parse_reg_name(reg_inf, reg_name) return reg_inf.reg insn = ida_ua.insn_t() ida_ua.decode_insn(insn, ea) if insn.itype != ida_allins.ARM_ldr \ or insn.ops[0].type != ida_ua.o_reg: reg = -1 else: reg = insn.ops[0].reg reg_val = -1 ins_ea = chunk_start while ins_ea < chunk_end: insn = ida_ua.insn_t() ins_len = max(1, ida_ua.decode_insn(insn, ins_ea)) if insn.itype == ida_allins.ARM_mov \ and insn.ops[0].type == ida_ua.o_reg \ and insn.ops[0].reg == get_reg_num('R0') \ and insn.ops[1].type == ida_ua.o_imm: reg_val = insn.ops[1].value if insn.itype == ida_allins.ARM_bx \ and insn.ops[0].type == ida_ua.o_reg \ and (insn.ops[0].reg == reg or reg == -1): break ins_ea += ins_len return reg_val
def FillOutBlock(self): end_insn = ida_ua.insn_t() ida_ua.decode_insn(end_insn, self.end_ea) curr_insn_ea = self.start_ea while curr_insn_ea != self.end_ea + end_insn.size: # # Walk and add each address to the list of instruction addresses # curr_insn = ida_ua.insn_t() ida_ua.decode_insn(curr_insn, curr_insn_ea) self.instruction_addresses.append(curr_insn_ea) curr_insn_ea = curr_insn_ea + curr_insn.size
def analyze_block(block): """Analyze a basic bloc and return its successors, if it's correspond to a basic bloc treating the Driver case and the address for the DR/TL API table if one is loaded :param block: Basic block to analyze :type block: ida_gdl.BasicBlock :return: Successors Basic Blocks, if it deals with Secure Driver case, and the address of the table loaded if loaded :rtype: (Generator, bool, int) """ loaded_value = -1 is_dr_table = False insn = ida_ua.insn_t() insn_ea = block.start_ea insn_len = 0 while insn_ea < block.end_ea: insn_len = max(1, ida_ua.decode_insn(insn, insn_ea)) if insn.itype == ida_allins.ARM_sub and \ insn.ops[2].type == ida_ua.o_imm and \ insn.ops[2].value == 0x1000: is_dr_table = True if insn.itype == ida_allins.ARM_ldr and \ insn.ops[1].type == ida_ua.o_mem: pool_value = ida_bytes.get_dword(insn.ops[1].addr) value = ida_bytes.get_dword(pool_value) if value > 0x1000: loaded_value = pool_value insn_ea += insn_len return block.succs(), is_dr_table, loaded_value
def get_cmp(func_start, func_end): """Retrives the address of the CMP within the dispatching function :param func_start: Beginning of the dispatching function :type func_start: int :param func_end: Ending of the dispatching function :type func_end: int :return: Address of the CMP within the dispatching function :rtype: int """ cmp_addr = -1 insn_ea = func_start insn = ida_ua.insn_t() insn_len = 0 while insn_ea < func_end: insn_len = max(1, ida_ua.decode_insn(insn, insn_ea)) if insn.itype == ida_allins.ARM_cmp and \ insn.ops[1].type == ida_ua.o_imm and \ insn.ops[1].value == 0x1000: cmp_addr = insn_ea break insn_ea += insn_len return cmp_addr
def get_instruction(address: int) -> ida_ua.insn_t: """ Obtains insn_t object for instruction. """ insn_t = ida_ua.insn_t() if ida_ua.decode_insn(insn_t, address): return insn_t
def activate(self, ctx): cur_ea = ida_kernwin.get_screen_ea() pfn = ida_funcs.get_func(cur_ea) if pfn: v = ida_kernwin.get_current_viewer() result = ida_kernwin.get_highlight(v) if result: stkvar_name, _ = result frame = ida_frame.get_frame(cur_ea) sptr = ida_struct.get_struc(frame.id) mptr = ida_struct.get_member_by_name(sptr, stkvar_name) if mptr: fii = ida_funcs.func_item_iterator_t() ok = fii.set(pfn) while ok: ea = fii.current() F = ida_bytes.get_flags(ea) for n in range(ida_ida.UA_MAXOP): if not ida_bytes.is_stkvar(F, n): continue insn = ida_ua.insn_t() if not ida_ua.decode_insn(insn, ea): continue v = ida_frame.calc_stkvar_struc_offset( pfn, insn, n) if v >= mptr.soff and v < mptr.eoff: print("Found xref at 0x%08x, operand #%d" % (ea, n)) ok = fii.next_code() else: print("No stack variable named \"%s\"" % stkvar_name) else: print("Please position the cursor within a function")
def get_operands(self, ip=None) -> List[Operand]: """ Gets the Operand objects of all operands in the current instruction and returns them in a list. :param int ip: location of instruction pointer to pull operands from (defaults to current rip in context) :return: list of Operand objects """ if ip is None: ip = self.ip # Calling insn_t() and decode_insn() is somewhat expensive and this function gets called a LOT, # so we are going to cache the operand indices. try: indices = self._operand_indices[ip] except KeyError: indices = [] insn = ida_ua.insn_t() # NOTE: We can't trust the instruction length returned by decode_ins. ida_ua.decode_insn(insn, ip) for idx, op in enumerate(insn.ops): if op.type == ida_ua.o_void: break # no more operands # IDA will sometimes create hidden or "fake" operands. # These are there to represent things like an implicit EAX register. # To help avoid confusion to the opcode developer, these fake operands will not be included. # TODO: Checking shown() may not work as expected. # If things explode, go back to checking operand.is_hidden if op.shown(): indices.append((idx, op.type)) self._operand_indices[ip] = indices return [Operand(self, ip, idx, _type=type) for idx, type in indices]
def __call__(self): if self.op == 'hex': ida_bytes.op_hex(self.ea, self.n) if self.op == 'bin': ida_bytes.op_bin(self.ea, self.n) if self.op == 'dec': ida_bytes.op_dec(self.ea, self.n) if self.op == 'chr': ida_bytes.op_chr(self.ea, self.n) if self.op == 'oct': ida_bytes.op_oct(self.ea, self.n) if self.op == 'enum': id = ida_enum.get_enum(Event.encode(self.extra['ename'])) ida_bytes.op_enum(self.ea, self.n, id, self.extra['serial']) if self.op == 'struct': path_len = len(self.extra['spath']) path = ida_pro.tid_array(path_len) for i in xrange(path_len): sname = Event.encode(self.extra['spath'][i]) path[i] = ida_struct.get_struc_id(sname) insn = ida_ua.insn_t() ida_ua.decode_insn(insn, self.ea) ida_bytes.op_stroff(insn, self.n, path.cast(), path_len, self.extra['delta']) if self.op == 'stkvar': ida_bytes.op_stkvar(self.ea, self.n)
def _on_optypechanged(self, ea, n, op, extra): if op == 'hex': ida_bytes.op_hex(ea, n) if op == 'bin': ida_bytes.op_bin(ea, n) if op == 'dec': ida_bytes.op_dec(ea, n) if op == 'chr': ida_bytes.op_chr(ea, n) if op == 'oct': ida_bytes.op_oct(ea, n) if op == 'stkvar': ida_bytes.op_stkvar(ea, n) if op == 'enum': enum_id = ida_enum.get_enum(str(extra['ename'])) ida_bytes.op_enum(ea, n, enum_id, extra['serial']) if op == 'struct': path_length = len(extra['spath']) path = ida_pro.tid_array(path_length) for i in range(path_length): sname = str(extra['spath'][i]) path[i] = ida_struct.get_struc_id(sname) insn = ida_ua.insn_t() ida_ua.decode_insn(insn, ea) ida_bytes.op_stroff(insn, n, path.cast(), path_length, extra['delta'])
def decode_instruction(ea): """Read the bytes of an x86/amd64 instruction. This handles things like combining the bytes of an instruction with its prefix. IDA Pro sometimes treats these as separate.""" global _NOT_INST_EAS, _BAD_INSTRUCTION, PREFIX_ITYPES if ea in _NOT_INST_EAS: return _BAD_INSTRUCTION decoded_inst = ida_ua.insn_t() inslen = ida_ua.decode_insn(decoded_inst, ea) if inslen <= 0: _NOT_INST_EAS.add(ea) return _BAD_INSTRUCTION assert decoded_inst.ea == ea end_ea = ea + decoded_inst.size decoded_bytes = read_bytes_slowly(ea, end_ea) # We've got an instruction with a prefix, but the prefix is treated as # independent. if 1 == decoded_inst.size and decoded_inst.itype in PREFIX_ITYPES: decoded_inst, extra_bytes = decode_instruction(end_ea) decoded_bytes += extra_bytes return decoded_inst, decoded_bytes
def decode_instruction(ea): """Read the bytes of an x86/amd64 instruction. This handles things like combining the bytes of an instruction with its prefix. IDA Pro sometimes treats these as separate.""" global _NOT_INST_EAS, _BAD_INSTRUCTION, PREFIX_ITYPES if ea in _NOT_INST_EAS: return _BAD_INSTRUCTION decoded_inst = ida_ua.insn_t() inslen = ida_ua.decode_insn(decoded_inst, ea) if inslen <= 0: _NOT_INST_EAS.add(ea) return _BAD_INSTRUCTION assert decoded_inst.ea == ea end_ea = ea + decoded_inst.size decoded_bytes = read_bytes_slowly(ea, end_ea) # We've got an instruction with a prefix, but the prefix is treated as # independent. if 1 == decoded_inst.size and decoded_inst.itype in PREFIX_ITYPES: decoded_inst, extra_bytes = decode_instruction(end_ea) decoded_bytes += extra_bytes return decoded_inst, decoded_bytes
def get_operands(self, ip=None): """ Gets the Operand objects of all operands in the current instruction and returns them in a list. :param int ip: location of instruction pointer to pull operands from (defaults to current rip in context) :return: list of Operand objects """ if ip is None: ip = self.ip operands = [] cmd = ida_ua.insn_t() # NOTE: We can't trust the instruction length returned by decode_ins. ida_ua.decode_insn(cmd, ip) for idx, op in enumerate(cmd.ops): operand = Operand(self, ip, idx) # IDA will sometimes create hidden or "fake" operands. # These are there to represent things like an implicit EAX register. # To help avoid confusion to the opcode developer, these fake operands will not be included. if not operand.is_hidden: operands.append(operand) if operand.is_void: break # no more operands return operands
def _is_ret(self, x): if can_decode(x): insn = insn_t() inslen = decode_insn(insn, x) if inslen > 0 and is_ret_insn(insn): return True return False
def __call__(self): if self.op == "hex": ida_bytes.op_hex(self.ea, self.n) if self.op == "bin": ida_bytes.op_bin(self.ea, self.n) if self.op == "dec": ida_bytes.op_dec(self.ea, self.n) if self.op == "chr": ida_bytes.op_chr(self.ea, self.n) if self.op == "oct": ida_bytes.op_oct(self.ea, self.n) if self.op == "offset": ida_idc.op_plain_offset(self.ea, self.n, 0) if self.op == "enum": id = ida_enum.get_enum(self.extra["ename"]) ida_bytes.op_enum(self.ea, self.n, id, self.extra["serial"]) if self.op == "struct": path_len = len(self.extra["spath"]) path = ida_pro.tid_array(path_len) for i in range(path_len): sname = self.extra["spath"][i] path[i] = ida_struct.get_struc_id(sname) insn = ida_ua.insn_t() ida_ua.decode_insn(insn, self.ea) ida_bytes.op_stroff(insn, self.n, path.cast(), path_len, self.extra["delta"]) if self.op == "stkvar": ida_bytes.op_stkvar(self.ea, self.n)
def calls_to(self) -> Iterable[int]: """Iterates addresses that call this function.""" for ea in self.xrefs_to: insn = ida_ua.insn_t() ida_ua.decode_insn(insn, ea) if ida_idp.is_call_insn(insn): yield ea
def __init__(self, addr, size): self.address = addr self.start_ea = addr self.end_ea = addr + size self.size = size self.i = ida_ua.insn_t() self._decoded = False self._decode()
def op_stroff(*args): insn, n, path, path_len, delta = args import ida_ua if not isinstance(insn, ida_ua.insn_t): tmp = ida_ua.insn_t() ida_ua.decode_insn(tmp, insn) insn = tmp return _ida_bytes.op_stroff(insn, n, path, path_len, delta)
def _insn(self): if not self.__insn: insn = ida_ua.insn_t() ida_ua.decode_insn(insn, self.ip) if not insn: raise FunctionTracingError(f"Failed to decode instruction at 0x{self.ip:X}") self.__insn = insn return self.__insn
def _insn(self): if self.__insn: return self.__insn insn = ida_ua.insn_t() ida_ua.decode_insn(insn, self.ip) if not insn: raise FunctionTracingError("Failed to decode instruction at 0x:{:X}".format(self.ip)) self.__insn = insn return self.__insn
def __init__(self): # s+b teal Color Palette http://www.color-hex.com/color-palette/309 self.colormap = [0x007777, 0x006666, 0x005555, 0x004444, 0x003333] self.insn_colors = {ACC_READ: 0x00cc37, ACC_WRITE: 0xCC3700} self.ptrcol = 0xe2e2e2 self.txtcol = 0xb2b2b2 self.annotations = [] self.threshold = 9 self.insn = insn_t()
def doit(cur_ea): global stk #decode insn = ida_ua.insn_t() lenn = ida_ua.decode_insn(insn, cur_ea) #execute execute(insn) return ida_search.find_code(cur_ea, SEARCH_DOWN)
def processRefs(output): """ process all the xrefs that ida recognizes params: output: protobuf file path returns: """ refInf = refInf_pb2.RefList() # iterate over all valid terms for head in idautils.Heads(): is_code = False candidateRefs = None if idc.is_code(idc.get_full_flags(head)): is_code = True decoded_inst = ida_ua.insn_t() insn_len = ida_ua.decode_insn(decoded_inst, head) if insn_len > 0: candidateRefs = getCandidateRefsFromInsn(decoded_inst) if is_code and candidateRefs == None: continue for xref in idautils.XrefsFrom(head, 0): ref_from = head target_addr = xref.to # check if target_addr is in current instruction internal representation if is_code: if target_addr not in candidateRefs: continue else: ref_from = candidateRefs[target_addr] if is_invalid_ea(target_addr): continue logging.debug( "Ref: 0x%x -> 0x%x, type is %s" % (ref_from, target_addr, idautils.XrefTypeName(xref.type))) ref = refInf.ref.add() ref.ref_va = ref_from ref.target_va = target_addr # default value ref.ref_size = 8 target_is_code = idc.is_code(idc.get_full_flags(target_addr)) if is_code and target_is_code: ref.kind = 0 # c2c elif is_code and not target_is_code: ref.kind = 1 # c2d elif not is_code and target_is_code: ref.kind = 2 # d2c else: ref.kind = 3 # d2d ## save the protobuf result with open(output, 'wb') as pbOut: pbOut.write(refInf.SerializeToString())
def DecodeInstruction(ea): """ Decodes an instruction and returns an insn_t like class @param ea: address to decode @return: None or a new insn_t instance """ insn = ida_ua.insn_t() inslen = ida_ua.decode_insn(insn, ea) return insn if inslen > 0 else None
def DecodePreviousInstruction(ea): """ Decodes the previous instruction and returns an insn_t like class @param ea: address to decode @return: None or a new insn_t instance """ insn = ida_ua.insn_t() prev_addr = ida_ua.decode_prev_insn(insn, ea) return insn if prev_addr != ida_idaapi.BADADDR else None
def calls_from(self) -> Iterable[Tuple[int, int]]: """Iterates call address and callee address of the calls within this function.""" for ea in self.heads(): insn = ida_ua.insn_t() ida_ua.decode_insn(insn, ea) if ida_idp.is_call_insn(insn): for xref in idautils.XrefsFrom(ea, idaapi.XREF_FAR): func_ea = xref.to if func_ea: yield ea, func_ea
def DecodePrecedingInstruction(ea): """ Decode preceding instruction in the execution flow. @param ea: address to decode @return: (None or the decode instruction, farref) farref will contain 'true' if followed an xref, false otherwise """ insn = ida_ua.insn_t() prev_addr, farref = ida_ua.decode_preceding_insn(insn, ea) return (insn, farref) if prev_addr != ida_idaapi.BADADDR else (None, False)
def Callees(ea): pfn = ida_funcs.get_func(ea) callees = [] if pfn: for item in pfn: F = ida_bytes.get_flags(item) if ida_bytes.is_code(F): insn = ida_ua.insn_t() if ida_ua.decode_insn(insn, item): if ida_idp.is_call_insn(insn): if insn.ops[0].type in [ida_ua.o_near, ida_ua.o_far]: callees.append(insn.ops[0].addr) return list(dict.fromkeys(callees))
def _insn(self): """ Property which return an ``insn_t`` representing the instruction as provided by IDA. There is no reason to use this except for interfacing directly with IDA functions. This is use internally by other functions. """ i = ida_ua.insn_t() ida_ua.decode_insn( i, self.ea) # decode and not create for not changing the db return i
def CheckZFEmulatedCall(self, EffectiveAddress): ''' @brief Identify emulated function calls. @detail push <return address> 0000 JZ xxxxxxxx 0001 JNZ 0010 @returns The return address that is pushed to the stack for the CALL instruction ''' rtrn_addr = idc.BADADDR push_instr_ea = EffectiveAddress push_insn = ida_ua.insn_t() ida_ua.decode_insn(push_insn, push_instr_ea) if maze_deobf_utils.CheckValidTargettingInstr(push_insn, "push"): """ Valid PUSH instruction. """ jz_insn_ea = push_instr_ea + push_insn.size() jz_insn = ida_ua.insn_t() ida_ua.decode_insn(jz_insn, jz_insn_ea) if maze_deobf_utils.CheckValidTargettingInstr(push_insn, "push"): """ Valid PUSH instruction. """ return rtrn_addr
def decode_insn(ea): """ Decode instruction. :param ea: Linear address. :type ea: int :return: Instruction at ea. """ fn = _get_fn_by_version(ida_ua, 'decode_insn', 'decode_insn', idaapi) if idaapi.IDA_SDK_VERSION >= 700: insn = ida_ua.insn_t() fn(insn, ea) return insn fn(ea) return idaapi.cmd
def IsPrevInsnCall(ea): """ Given a return address, this function tries to check if previous instruction is a CALL instruction """ global CallPattern if ea == ida_idaapi.BADADDR or ea < 10: return None for delta, opcodes in CallPattern: # assume caller's ea caller = ea + delta # get the bytes bytes = [x for x in idautils.GetDataList(caller, len(opcodes), 1)] # do we have a match? is it a call instruction? if bytes == opcodes: insn = ida_ua.insn_t() if ida_ua.decode_insn(insn, caller) and ida_idp.is_call_insn(insn): return caller return None