def output(self, outctx): insn = outctx.insn mne = ida_ua.print_insn_mnem(insn.ea) if insn.itype in [ida_allins.ARM_msr, ida_allins.ARM_mrs]: if insn.ops[2].type > 0: cp_reg, gp_reg = self.decode_msr_mrs(insn) if cp_reg: if insn.itype == ida_allins.ARM_msr: return Arch.output_insn(outctx, mne, cp_reg, gp_reg) else: return Arch.output_insn(outctx, mne, gp_reg, cp_reg) else: fields = {5: "SPSel", 6: "DAIFSet", 7: "DAIFClr"} pstatefield = fields.get(insn.ops[0].value, None) if pstatefield: outctx.out_custom_mnem(mne.upper(), 16) outctx.out_register(pstatefield) outctx.out_printf(", ") imm = ida_ua.print_operand(insn.ea, 1) outctx.out_printf(imm) outctx.flush_outbuf() return True if insn.itype == ida_allins.ARM_sys: op1 = insn.ops[0].value crn = insn.ops[1].reg crm = insn.ops[2].reg op2 = insn.ops[3].value xt = insn.ops[4].reg ops = [1, op1, crn, crm, op2] gp_reg = ida_idp.ph.regnames[xt] cp_reg = self.find_reg_enc("SYS", ops) if cp_reg: mne, op = cp_reg.split() if xt == 160: return Arch.output_insn(outctx, mne, op) else: return Arch.output_insn(outctx, mne, op, gp_reg) return False
def matches(ea, reqs, gets): results = [] for offs, ins in reqs: mnem = ida_lines.tag_remove(ida_ua.print_insn_mnem(ea + offs) or '') if ins[0] != mnem: return None i = 0 for arg in ins[1:]: opnd = ida_lines.tag_remove( ida_ua.print_operand(ea + offs, i) or '') if opnd != arg and re.match('^' + arg + '$', opnd) is None: return None i += 1 for get in gets: if type(get) == tuple: reqi, opi, fun = get results += [fun(idc.get_operand_value(ea + reqs[reqi][0], opi))] else: results += [get] return results
def color_head(ea): flags = ida_bytes.get_flags(ea) if not ida_bytes.is_code(flags): return mnem = ida_ua.print_insn_mnem(ea) if mnem == 'call': logger.debug('call: 0x%x', ea) idc.set_color(ea, idc.CIC_ITEM, CALL_COLOR) elif mnem == 'xor': if idc.get_operand_value(ea, 0) != idc.get_operand_value(ea, 1): logger.debug('non-zero xor: 0x%x', ea) idc.set_color(ea, idc.CIC_ITEM, ENCRYPT_COLOR) elif mnem in ('sdit', 'sgdt', 'sldt', 'smsw', 'str', 'in', 'cpuid'): logger.debug('anti-vm: 0x%x', ea) idc.set_color(ea, idc.CIC_ITEM, ANTIANALYSIS_COLOR) elif mnem == 'in': if idc.get_operand_value(ea, 0) in ("3", "2D"): logger.debug('anti-debug: 0x%x', ea) idc.set_color(ea, idc.CIC_ITEM, ANTIANALYSIS_COLOR) elif mnem in ('rdtsc', 'icebp'): logger.debug('anti-debug: 0x%x', ea) idc.set_color(ea, idc.CIC_ITEM, ANTIANALYSIS_COLOR)
def output(self, outctx): insn = outctx.insn mne = ida_ua.print_insn_mnem(insn.ea) if insn.itype in [ida_allins.ARM_mcr, ida_allins.ARM_mrc]: cp_reg, gp_reg = self.decode_mcr_mrc(insn) if cp_reg: if insn.itype == ida_allins.ARM_mcr: return Arch.output_insn(outctx, mne, cp_reg, gp_reg) else: return Arch.output_insn(outctx, mne, gp_reg, cp_reg) if insn.itype in [ida_allins.ARM_mcrr, ida_allins.ARM_mrrc]: cp = insn.ops[0].specflag1 op3 = insn.ops[0].value rt = insn.ops[1].reg rt2 = insn.ops[1].specflag1 crm = insn.ops[1].specflag2 ops = [cp, op3, crm] gp_reg = "%s%s%s:%s%s%s" % ( ida_idp.ph.regnames[rt2], ida_lines.SCOLOR_OFF, ida_lines.SCOLOR_REG, ida_lines.SCOLOR_ON, ida_lines.SCOLOR_REG, ida_idp.ph.regnames[rt], ) cp_reg = self.find_reg_enc("MCRR|MRRC", ops) if cp_reg: if insn.itype == ida_allins.ARM_mcrr: return Arch.output_insn(outctx, mne, cp_reg, gp_reg) else: return Arch.output_insn(outctx, mne, gp_reg, cp_reg) return False
def idenLib(): global func_sigs global mainSigs # function sigs from the current binary func_bytes_addr = {} for addr, size in getFuncRanges(): f_bytes = getOpcodes(addr, size) func_bytes_addr[f_bytes] = addr # load sigs if not os.path.isdir(symEx_dir): print("[idenLib - FAILED] There is no {} directory".format(symEx_dir)) return if os.path.isfile(idenLibCache): func_sigs = pickle.load(open(idenLibCache, "rb")) if os.path.isfile(idenLibCacheMain): mainSigs = pickle.load(open(idenLibCacheMain, "rb")) else: idenLibProcessSignatures() # apply sigs counter = 0 mainDetected = False for sig_opcodes, addr in func_bytes_addr.items(): if func_sigs.has_key(sig_opcodes): func_name = func_sigs[sig_opcodes] current_name = ida_funcs.get_func_name(addr) if (current_name != func_name): digit = 1 while func_name in getNames(): func_name = func_name + str(digit) digit = digit + 1 ida_name.set_name(addr, func_name, ida_name.SN_NOCHECK) print("{}: {}".format(hex(addr), func_name)) counter = counter + 1 if mainSigs.has_key(sig_opcodes): # "main" sig callInstr = mainSigs[sig_opcodes][1] + addr if ida_ua.print_insn_mnem(callInstr) == "call": call_target = idc.get_operand_value(callInstr, 0) current_name = ida_funcs.get_func_name(call_target) func_name = mainSigs[sig_opcodes][0] if (current_name != func_name): ida_name.set_name(call_target, func_name, ida_name.SN_NOCHECK) print("{}: {}".format(hex(call_target), func_name)) counter = counter + 1 mainDetected = True if not mainDetected: for entry in idautils.Entries(): for sig_opcodes, name_funcRva_EntryRva in mainSigs.items(): callInstr = name_funcRva_EntryRva[2] + entry[2] # from EP if ida_ua.print_insn_mnem(callInstr) == "call": fromFunc = name_funcRva_EntryRva[1] func_start = callInstr - fromFunc func_opcodes = getOpcodes(func_start, MAX_FUNC_SIZE) if func_opcodes.startswith(sig_opcodes): call_target = idc.get_operand_value(callInstr, 0) current_name = ida_funcs.get_func_name(call_target) func_name = mainSigs[sig_opcodes][0] if (current_name != func_name): ida_name.set_name(call_target, func_name, ida_name.SN_NOCHECK) print("{}: {}".format(hex(call_target), func_name)) counter = counter + 1 mainDetected = True break print("[idenLib] Applied to {} function(s)".format(counter))
def execute(self, start=None, end=None, max_instructions=10000): """ "Execute" the instruction at IP and store results in the context. The RIP/EIP register will be set to the value supplied in IP so that it is correct. :param start: instruction address to start execution (defaults to currently set ip) :param end: instruction to stop execution (not including) (defaults to only run start) :param max_instructions: Maximum number of instructions to execute before raising an RuntimeError :raises RuntimeError: If maximum number of instructions get hit. """ if not start: start = self.ip # Set instruction pointer to where we are currently executing. self.ip = start # Extra processing if we are at the start of a function. func_obj = ida_funcs.get_func(self.ip) if func_obj.start_ea == self.ip: # Reset the sp_start self._sp_start = self.sp # Add the passed in arguments to the variables map. # (This also helps to standardize the argument names to "a*" instead of "arg_*") for arg in self.passed_in_args: addr = arg.addr # TODO: Support variables from registers? if addr is not None: if arg.is_stack: try: frame = ida_frame.get_frame(func_obj) if not frame: logger.warning( f"Failed to get frame for function argument: {repr(arg)}" ) continue # Getting member stack offset from name is more reliable then calculating # it from the address. member = ida_struct.get_member_by_name( frame, arg.name) if not member: logger.warning( f"Failed to get member for function argument: {repr(arg)}" ) continue self.variables.add(addr, frame_id=frame.id, stack_offset=member.soff) except ValueError: logger.warning( f"Failed to get stack information for function argument: {repr(arg)}" ) else: self.variables.add(addr) # If end is provided, recursively run execute() until ip is end. if end is not None: count = max_instructions prev_ecx = self.registers.ecx prev_ecx_count = count while self.ip != end: if ida_ua.print_insn_mnem(self.ip) == 'retn': return self.execute() # TODO: Re-enable this feature after rigorous testing. # # Dynamically allow more instructions to be executed if we detect we are in a loop # # and it is making progress. # # Ie. this will allow most while statements not to ding our max instruction quota. # if self.registers.ecx and (self.registers.ecx < prev_ecx or prev_ecx == 0): # if prev_ecx: # count += min(prev_ecx_count - count, 1000) # prev_ecx = self.registers.ecx # prev_ecx_count = count count -= 1 if not count: raise RuntimeError('Hit maximum number of instructions.') return # Determine if a rep* instruction and add termination condition. term_condition = None if idc.get_wide_byte(start) in (0xF2, 0xF3): insn = idc.GetDisasm( start) # IDA pro never has operands for rep opcodes. if insn.startswith("rep "): term_condition = lambda: self.registers.ecx == 0 term_condition.unconditional = True elif insn.startswith(("repe ", "repz ")): term_condition = lambda: self.registers.ecx == 0 or self.registers.zf == 0 term_condition.unconditional = False elif insn.startswith(("repne ", "repnz ")): term_condition = lambda: self.registers.ecx == 0 or self.registers.zf == 1 term_condition.unconditional = False # Emulate instruction. mnem = ida_ua.print_insn_mnem(start) # Log a header line for debug messages of this instruction. # This is simpler and faster then trying to include the information at each log line logger.debug("[0x%X %03X] :: %s", start, self.sp_diff, mnem) # Run any pre-hooks first. self.execute_instruction_hooks(start, mnem, pre=True) instruction = self.OPCODES.get(mnem) if instruction: operands = self.operands try: if term_condition: if self.emulator.disabled_rep: logger.debug("Ignoring rep instructions: DISABLED.") # As a safety measure, don't allow rep instructions to surpass # our max memory read limit. # Only do this check if the terminating condition is unconditional, otherwise # this number usually big because it expects zf to be toggled. elif term_condition.unconditional and self.registers.ecx > self.memory.MAX_MEM_READ: logger.warning( "Emulation attempted to read %s instruction %d times. " "Ignoring instruction.", mnem, self.registers.ecx) else: logger.debug("Emulating %s instruction %d times.", mnem, self.registers.ecx) count = 0 while not term_condition(): instruction(self, start, mnem, operands) self.registers.ecx -= 1 # Stop if we are iterating too much. count += 1 if count > self.memory.MAX_MEM_READ: logger.warning( "Looped too many times, exiting prematurely." ) break else: instruction(self, start, mnem, operands) except Exception: logger.exception("Failed to execute address 0x%X: %s", start, idc.GetDisasm(start)) else: logger.debug("%s instruction not implemented.", mnem) # Record executed instruction. self.executed_instructions.append(start) # Run any post-hooks self.execute_instruction_hooks(start, mnem, pre=False) # Add a blank space to help visually separate logs for each instruction. logger.debug(" ") # After execution, set instruction pointer to next instruction assuming # standard code flow and if no jump was made. if self.ip == start: self.ip = idc.next_head(start)
def get_mnem(ea): """ 获取操作符并去除末尾的 ".W" """ mnem = ida_ua.print_insn_mnem(ea).split('.')[0] return mnem