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 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 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 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 == "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 _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 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 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 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 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 _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 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_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 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 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_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 _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 get_handler(mclib_jumper): """Retrieves the handler of the TL/DR API calls :param mclib_jumper: Address of the McLib jumper :type mclib_jumper: int :return: Handler of the TL/DR API calls :rtype: int """ handler = -1 insn = ida_ua.insn_t() ida_ua.decode_insn(insn, mclib_jumper) if insn.itype == ida_allins.ARM_adr and \ insn.ops[0].type == ida_ua.o_reg and \ insn.ops[0].reg == get_reg_num("PC") and \ insn.ops[1].type == ida_ua.o_imm: handler = insn.ops[1].value return handler
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 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 """ inslen = ida_ua.decode_insn(ea) if inslen == 0: return None return ida_ua.cmd.copy()
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 hint(self, ea, tag, val): val = val.strip() if not val: return None if tag == ida_lines.SCOLOR_REG: if val in self.regs: register = self.regs[val] return register["long_name"], register["purpose"] elif tag == ida_lines.SCOLOR_INSN: insn = ida_ua.insn_t() ida_ua.decode_insn(insn, ea) insn_bs = ida_bytes.get_bytes(insn.ea, insn.size) fmt = {2: "<H", 4: "<I", 8: "<Q"} insn_bs = struct.unpack(fmt.get(len(insn_bs)), insn_bs)[0] enc_type = "A64" if isinstance(self, AArch32): enc_type = "A32" if ida_segregs.get_sreg(ea, 20) > 0: enc_type = "T32" insn_enc = self.find_insn_enc( enc_type, insn_bs, insn.get_canon_mnem() ) if not insn_enc: return insn_name, tmpl_name = insn_enc insn = self.insns[insn_name] desc = insn["authored"] if tmpl_name in insn["templates"]: desc += "\n\n" + "\n".join(insn["templates"][tmpl_name]) return insn["heading"], desc elif tag == ida_lines.SCOLOR_KEYWORD: if val in self.data["keywords"]: return val, self.data["keywords"][val]
def __init__(self, insn_ea): """ :param insn_ea: """ if not ida_ua.can_decode(insn_ea): raise InstructionException("Cannot decode instruction @ %07X" % insn_ea) self.size = ida_ua.decode_insn(insn_ea) self.insn = idaapi.cmd self.ops = self.insn.ops self.itype = self.insn.itype self.ea = self.insn.ea
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 visit_expr(self, e): if not e.x or e.x.op != ida_hexrays.cot_helper: return 0 insn = ida_ua.insn_t() ida_ua.decode_insn(insn, e.ea) def make_reg(cp_reg): reg = ida_hexrays.carg_t() reg.op = ida_hexrays.cot_helper reg.helper = cp_reg reg.exflags = ida_hexrays.EXFL_ALONE return reg if e.x.helper in ["__mcr", "__mrc"]: cp_reg = plugin.arch.decode_mcr_mrc(insn)[0] if cp_reg: if e.x.helper == "__mcr": e.x.helper = "_WriteStatusReg" val = ida_hexrays.carg_t() e.a[2].swap(val) e.a.clear() e.a.push_back(make_reg(cp_reg)) e.a.push_back(val) else: e.x.helper = "_ReadStatusReg" e.a.clear() e.a.push_back(make_reg(cp_reg)) elif e.x.helper == "ARM64_SYSREG": cp_reg = plugin.arch.decode_msr_mrs(insn)[0] if cp_reg: e.replace_by(make_reg(cp_reg)) return 0
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
def dbg_trace(self, tid, ip): if ip in self._visited_addrs: return 1 self._visited_addrs.add(ip) if idc.is_unknown(ida_bytes.get_flags(ip)): ida_ua.create_insn(ip) else: idc.msg( 'Skipping explored EA at address 0x{0:X}\n'.format(ip) ) # print idc.generate_disasm_line(ip, 0) if ida_ua.decode_insn(ip) > 0: if 'ret' in ida_ua.cmd.get_canon_mnem().lower(): idc.msg('Found ret instruction, suspending execution\n') ida_dbg.suspend_process() else: idc.msg( 'Unable to decode instruction at address 0x{0:X}\n'.format(ip) ) ida_dbg.suspend_process() return 0