def get_branch_type(self): if self.bbl == None: return -1 addr = self.addr while addr != self.bbl.end_ea: mnem = idc.print_insn_mnem(addr).lower() if mnem.startswith("call"): if op_type[idc.get_operand_type(addr,0)] != "o_near" and\ op_type[idc.get_operand_type(addr,0)] != "o_far": return ICALL else: return CALL addr = idc.next_head(addr) addr = idc.prev_head(self.bbl.end_ea) mnem = idc.print_insn_mnem(addr).lower() if mnem in u_jumps or mnem in c_jumps: if op_type[idc.get_operand_type(addr,0)] != "o_near" and\ op_type[idc.get_operand_type(addr,0)] != "o_far": return IJMP else: if mnem in u_jumps: return JMP else: return CJMP elif self.bbl.type >= 2 and self.bbl.type <= 5: return RET return NA
def get_protocols(self): """found UEFI protocols information in idb""" for service_name in self.gBServices: for address in self.gBServices[service_name]: ea, found = address, False if self.arch == 'x86': for _ in range(1, 25): ea = idc.prev_head(ea) if (idc.get_operand_value(ea, 0) > self.base and idc.print_insn_mnem(ea) == 'push'): found = True break if self.arch == 'x64': for _ in range(1, 16): ea = idc.prev_head(ea) if (idc.get_operand_value(ea, 1) > self.base and idc.print_insn_mnem(ea) == 'lea'): found = True break if not found: continue for xref in idautils.DataRefsFrom(ea): if idc.print_insn_mnem(xref): continue if not check_guid(xref): continue cur_guid = get_guid(xref) record = { 'address': xref, 'service': service_name, 'guid': cur_guid, } if not self.Protocols['all'].count(record): self.Protocols['all'].append(record)
def decrypt_all_strings(decrypt_string_func_ea): global STRING_DICTIONARY for ref in idautils.CodeRefsTo(decrypt_string_func_ea, 1): # this function can be better. I hate it rn but oh well prev_instruction_ea = 0x472DAC if ref == translate_ea( 0x1db3) else idc.prev_head(ref) if idc.print_insn_mnem( prev_instruction_ea) == 'push' or idc.print_insn_mnem( prev_instruction_ea) == 'lea': encrypted_blob_ea = idc.get_operand_value( prev_instruction_ea, 1) if ref == translate_ea(0x1db3) else idc.get_operand_value( prev_instruction_ea, 0) length = int.from_bytes(idaapi.get_bytes(encrypted_blob_ea - 4, 4), 'little') #print(hex(prev_instruction_ea) + " and " + hex(encrypted_blob_ea) + " and " + hex(length)) encrypted_blob = [ x for x in idaapi.get_bytes(encrypted_blob_ea, length) ] encrypted_blob = decrypt_config(encrypted_blob, length) string = '' for each in encrypted_blob: if each != 0: string += chr(each) STRING_DICTIONARY[translate_ea_to_offset( encrypted_blob_ea)] = string return
def get_FULL_CONFIG(): global config_extract_ea, FULL_CONFIG # get FULL_CONFIG size curr_ea = config_extract_ea stop_bytes = 0 # this should be 0xDEADBEEF FULL_CONFIG_ea = 0 while True: next_instruction_ea = idc.next_head(curr_ea) if idc.print_insn_mnem(next_instruction_ea) == 'cmp': stop_bytes = idc.get_operand_value(next_instruction_ea, 1) break elif idc.print_insn_mnem(next_instruction_ea) == 'lea': FULL_CONFIG_ea = idc.get_operand_value(next_instruction_ea, 1) curr_ea = next_instruction_ea config_length = 0 while True: if int.from_bytes(idaapi.get_bytes(FULL_CONFIG_ea + config_length, 4), 'little') == stop_bytes: break config_length += 1 FULL_CONFIG = [ each_byte for each_byte in idaapi.get_bytes(FULL_CONFIG_ea, config_length) ] FULL_CONFIG = decrypt_config(FULL_CONFIG, config_length)
def find_all_ioctls(): """ From the currently selected address attempts to traverse all blocks inside the current function to find all immediate values which are used for a comparison/sub immediately before a jz. Returns a list of address, second operand pairs. """ ioctls = [] # Find the currently selected function and get a list of all of it's basic blocks addr = idc.get_screen_ea() f = idaapi.get_func(addr) fc = idaapi.FlowChart(f, flags=idaapi.FC_PREDS) for block in fc: # grab the last two instructions in the block last_inst = idc.prev_head(block.end_ea) penultimate_inst = idc.prev_head(last_inst) # If the penultimate instruction is cmp or sub against an immediate value immediately preceding a 'jz' # then it's a decent guess that it's an IOCTL code (if this is a dispatch function) if idc.print_insn_mnem(penultimate_inst) in [ 'cmp', 'sub' ] and idc.get_operand_type(penultimate_inst, 1) == 5: if idc.print_insn_mnem(last_inst) == 'jz': value = get_operand_value(penultimate_inst) ioctls.append((penultimate_inst, value)) ioctl_tracker.add_ioctl(penultimate_inst, value) return ioctls
def run(self, arg=0): print("hell2") idaapi.msg("run() called with %d!\n" % arg) heads = Heads(get_segm_start(get_screen_ea()), get_segm_end(get_screen_ea())) funcCalls = [] xor = [] antiVM = [] for i in heads: # Color the Calls off-white if print_insn_mnem(i) == "call": funcCalls.append(i) # Color Anti-VM instructions Red and print their location elif print_insn_mnem(i) in ("sidt", "sgdt", "sldt", "smsw", "str", "in", "cpuid"): antiVM.append(i) # Color non-zeroing out xor instructions Orange elif print_insn_mnem(i) == "xor" and (print_operand(i,0) != print_operand(i,1)): xor.append(i) print("Number of calls: %d" % (len(funcCalls))) for i in funcCalls: set_color(i, CIC_ITEM, 0xc7fdff) print("Number of potential Anti-VM instructions: %d" % (len(antiVM))) for i in antiVM: print("Anti-VM potential at %x" % i) set_color(i, CIC_ITEM, 0x0000ff) print("Number of xor: %d" % (len(xor))) for i in xor: set_color(i, CIC_ITEM, 0x00a5ff)
def resolve_all_APIs(resolve_ea, mode): if resolve_ea is None: print('resolve fails..') return for ref in idautils.CodeRefsTo(resolve_ea, 1): # only 1 ref curr_ea = ref while True: prev_instruction_ea = idc.prev_head(curr_ea) if mode == 1: if idc.print_insn_mnem(prev_instruction_ea) == 'push': hash_val = idc.get_operand_value(prev_instruction_ea, 0) if hash_val in export_hashes: print(hex(ref) + ' : ' + export_hashes[hash_val]) idc.set_cmt(ref, export_hashes[hash_val], 0) break else: if idc.print_insn_mnem(prev_instruction_ea) == 'mov': hash_val = idc.get_operand_value(prev_instruction_ea, 1) print(hex(hash_val)) if hash_val in export_hashes: print(hex(ref) + ' : ' + export_hashes[hash_val]) idc.set_cmt(ref, export_hashes[hash_val], 0) break curr_ea = prev_instruction_ea
def hand_register(line, start_ea, reg_target): current = line while (current >= start_ea): current = idc.prev_head(current) if (idc.print_insn_mnem(current) == 'jmp'): return hand_block(line, current, reg_target) if (idc.print_operand(current, 0) == reg_target) and (idc.print_insn_mnem(current) in ['mov', 'lea']): return idc.print_operand(current, 1)
def test_basic(strings_exe): """Tests some basic functionality and stability.""" strings_exe = str(strings_exe) with kordesii.IDA(strings_exe): import idc from kordesii.utils import utils from kordesii.utils import ida_re assert idc.get_input_file_path() == strings_exe assert idc.print_insn_mnem(0x00401525) == 'mov' assert utils.get_function_addr('GetProcAddress') == 0x40a028 assert utils.get_string(0x0040C000) == b'Idmmn!Vnsme ' regex = ida_re.Pattern(b'Idmmn!Vnsme') match = regex.search() assert match assert match.start() == 0x0040C000 assert match.group() == b'Idmmn!Vnsme' # Ensure we can only start one at a time. with pytest.raises(ValueError): kordesii.IDA(r'C:\dummy.exe').start() pass # Ensure we can't use modules after closing. with pytest.raises(AttributeError): idc.print_insn_mnem(0x00401525) # Now test that we can spin it up again. with kordesii.IDA(strings_exe): # import idc # reimporting is not required. assert idc.get_input_file_path() == strings_exe # Now test manually starting and stopping. ida = kordesii.IDA(strings_exe) ida.start() import idc assert idc.get_input_file_path() == strings_exe ida.stop() # can't access imports outside with pytest.raises(AttributeError): idc.get_input_file_path() # now try starting the same instance again. ida.start() assert idc.get_input_file_path() == strings_exe ida.stop() # Try opening a file that is not actually an exe. # It should still work, just not be very helpful. with kordesii.IDA(__file__): assert idc.get_input_file_path() == __file__ assert idc.print_insn_mnem(0x00401525) == ''
def parse_function(ea): func = ida_funcs.func_t(ea) res = ida_funcs.find_func_bounds(func, ida_funcs.FIND_FUNC_DEFINE) if res == ida_funcs.FIND_FUNC_UNDEF: idc.ask_yn(1, 'can not find func bounds.') exit(0) addr = func.start_ea hit_count = 0 gnm_name = '' packet_count = 0 while addr < func.end_ea: if idc.print_insn_mnem(addr) == 'call': sub_name = idc.print_operand(addr, 0) if 'SetAllocatedNodes@SchedulerProxy' in sub_name: arg_addrs = ida_typeinf.get_arg_addrs(addr) gnm_name_arg_addr = arg_addrs[1] if idc.print_insn_mnem(gnm_name_arg_addr) != 'lea': idc.ask_yn( 1, 'gnm name not passed by lea: {:X}'.format( gnm_name_arg_addr)) exit(0) name_addr = idc.get_operand_value(gnm_name_arg_addr, 1) gnm_name = idc.get_strlit_contents(name_addr).decode('ascii') hit_count += 1 if 'set_packet_count' in sub_name: # we need to manually set set_packet_count function's type (press key Y) # or get_arg_addrs will return None arg_addrs = ida_typeinf.get_arg_addrs(addr) packet_count_arg_addr = arg_addrs[1] packet_count_inst = idc.print_insn_mnem(packet_count_arg_addr) if packet_count_inst == 'mov': op_type = idc.get_operand_type(packet_count_arg_addr, 1) if op_type == idc.o_imm: packet_count = idc.get_operand_value( packet_count_arg_addr, 1) else: packet_count = 0 elif packet_count_inst == 'lea': packet_count = 0 else: idc.ask_yn( 1, 'packet count passed by {} at {:X}'.format( packet_count_inst, packet_count_arg_addr)) exit(0) hit_count += 1 if hit_count == 2: break addr = idc.next_head(addr) return gnm_name, packet_count
def get_stacked_bytes(dec_func_addr): func_stacked_bytes_addr_dict = {} xrefs = idautils.CodeRefsTo(dec_func_addr, 0) for xref in xrefs: prev_addr = idc.prev_head(xref) prev_addr_2 = idc.prev_head(prev_addr) if idc.print_insn_mnem(prev_addr_2) == "call": func_name = idc.print_operand(prev_addr_2, 0) func_addr = idc.get_name_ea_simple(func_name) func_stacked_bytes_addr_dict[xref] = func_addr # enc_mod_addr = list(set(enc_mod_addr)) # [Debug] Get unique functions only for xref, stacked_bytes_addr in func_stacked_bytes_addr_dict.items(): print(f"Address: {hex(stacked_bytes_addr)}") func_ea = idc.get_func_attr(stacked_bytes_addr, idc.FUNCATTR_START) bytes_collected = bytearray() # Collected stack string store here for ins in idautils.FuncItems(func_ea): if ida_bytes.is_code(ida_bytes.get_full_flags(ins)): if idc.print_insn_mnem(ins) == "mov": if idc.get_operand_type(ins, 1) == idc.o_imm: # disasm = idc.GetDisasm(ins) # [Debug] hex_str_len = len( idc.print_operand(ins, 1).lstrip("0").rstrip("h")) const_hex_byte = idc.print_operand( ins, 1).lstrip("0").rstrip("h") if hex_str_len != 8: # Skip if const hex byte less than 8 append_zero = "0" * (8 - hex_str_len) const_hex_byte = append_zero + const_hex_byte # print(struct.pack("<I", int(const_hex_byte, 16))) # [Debug] # else: # print(struct.pack("<I", int(const_hex_byte, 16))) # [Debug] bytes_collected += struct.pack("<I", int(const_hex_byte, 16)) if len(bytes_collected) >= 1: cmt_str = "" if dec_func_addr == 0x10001253: # fn_name_addr print(f"{decode_fnname(bytes_collected[4:])}") cmt_str = decode_fnname(bytes_collected[4:]) elif dec_func_addr == 0x1000122B: # mod_name_addr print(f"{decode_modname(bytes_collected[4:])}") cmt_str = decode_modname(bytes_collected[4:]) idc.set_cmt(xref, cmt_str, 1) # Comment near xref decoder function else: print(f"[-] {hex(stacked_bytes_addr)} addr error")
def add_bp_to_virtual_calls(cur_addr, end): while cur_addr < end: if cur_addr == idc.BADADDR: break elif idc.print_insn_mnem(cur_addr) == 'call' or idc.print_insn_mnem( cur_addr) == 'BLR': if True in [ idc.print_operand(cur_addr, 0).find(reg) != -1 for reg in REGISTERS ]: # idc.GetOpnd(cur_addr, 0) in REGISTERS: cond, bp_address = vtableAddress.write_vtable2file(cur_addr) if cond != '': bp_vtable = AddBP.add(bp_address, cond) cur_addr = idc.next_head(cur_addr)
def get_con2_var_or_num(i_cnt, cur_addr): """ :param i_cnt: the register of the virtual call :param cur_addr: the current address in the memory :return: "success" string and the address of the vtable's location. if it fails it sends the reason and -1 """ start_addr = idc.get_func_attr(cur_addr, idc.FUNCATTR_START) virt_call_addr = cur_addr cur_addr = idc.prev_head(cur_addr) dct_arch = get_arch_dct() if dct_arch == -1: return 'Wrong Architechture', "-1", cur_addr while cur_addr >= start_addr: if idc.print_insn_mnem( cur_addr)[:3] == dct_arch["opcode"] and idc.print_operand( cur_addr, 0) == i_cnt: # TODO lea ? opnd2 = idc.print_operand(cur_addr, 1) place = opnd2.find(dct_arch["separator"]) if place != -1: # if the function is not the first in the vtable register = opnd2[opnd2.find('[') + 1:place] if opnd2.find('*') == -1: offset = opnd2[place + dct_arch["val_offset"]:opnd2.find(']')] else: offset = "*" return register, offset, cur_addr else: offset = "0" if opnd2.find(']') != -1: register = opnd2[opnd2.find('[') + 1:opnd2.find(']')] else: register = opnd2 return register, offset, cur_addr elif idc.print_insn_mnem(cur_addr)[:4] == "call": intr_func_name = idc.print_operand(cur_addr, 0) # In case the code has CFG -> ignores the function call before the virtual calls if "guard_check_icall_fptr" not in intr_func_name: if "nullsub" not in intr_func_name: # intr_func_name = idc.Demangle(intr_func_name, idc.GetLongPrm(idc.INF_SHORT_DN)) print( "Warning! At address 0x%08x: The vtable assignment might be in another function (Maybe %s)," " could not place BP." % (virt_call_addr, intr_func_name)) cur_addr = start_addr cur_addr = idc.prev_head(cur_addr) return "out of the function", "-1", cur_addr return '', 0, cur_addr
def getBBconsts(bl): strings = [] consts = [] start = bl[0] end = bl[1] invoke_num = 0 inst_addr = start while inst_addr < end: opcode = idc.print_insn_mnem(inst_addr) if opcode in ['la','jalr','call', 'jal']: inst_addr = idc.next_head(inst_addr) continue strings_src, consts_src = getConst(inst_addr, 0) strings_dst, consts_dst = getConst(inst_addr, 1) strings += strings_src strings += strings_dst consts += consts_src consts += consts_dst try: strings_dst, consts_dst = getConst(inst_addr, 2) consts += consts_dst strings += strings_dst except: pass inst_addr = idc.next_head(inst_addr) return strings, consts
def find_main_x86(self): start = ida_ida.inf_get_start_ea() fn = idaapi.get_func(start) f_start, f_end = fn.start_ea, fn.end_ea eas = list(idautils.Heads(f_start, f_end)) mnem = idc.print_insn_mnem(eas[-1]) if mnem == 'jmp': return idc.get_operand_value(eas[-1], 0) elif mnem == 'call': for i in range(len(list(eas)) - 2, -1, -1): mnem = idc.print_insn_mnem(eas[i]) if mnem == 'push': return idc.get_operand_value(eas[i], 0) else: print(idc.GetDisasm(eas[-1])) return 0
def main(): for func in idautils.Functions(): #get function flags flags = idc.get_func_attr(func, FUNCATTR_FLAGS) # skip library & thunk functions if flags & FUNC_LIB or flags & FUNC_THUNK: continue dism_addr = list(idautils.FuncItems(func)) for ea in dism_addr: mnem = idc.print_insn_mnem(ea) if mnem == "call": highlight_insn(ea, CALL_COLOR) elif mnem == "rdtsc": highlight_insn(ea, ANITDEBUG_COLOR, "Possible Anti-Debugging") elif mnem == "xor": op1 = idc.print_operand(ea, 0) op2 = idc.print_operand(ea, 1) if op1 == op2: highlight_insn(ea, DEFAULT_COLOR, "{} = 0".format(op1)) else: highlight_insn(ea, XOR_COLOR, "Possible enc/dec") highlight_anti_debug()
def replace_sym_const(ea, api): for arg_n in api_list[api].keys(): # Calling Convention: cdecl, stdcall push_cnt = 0 ea_search = ea while push_cnt < arg_n: ea_search = idc.prev_head(ea_search) op = idc.print_insn_mnem(ea_search) if op == "push": push_cnt += 1 operand = idc.print_operand(ea_search, 0) if operand.isdigit(): operand = int(idc.print_operand(ea_search, 0)) else: continue enum_name = api + "_" + str(arg_n) const = api_list[api][arg_n][operand] enum_id = ida_enum.get_enum(enum_name) if enum_id == BADADDR: # add new enum enum_qty = ida_enum.get_enum_qty() enum_id = ida_enum.add_enum(enum_qty, enum_name, 0) symbolic_id = ida_enum.get_enum_member_by_name(const) if symbolic_id == BADADDR: # add new enum member ida_enum.add_enum_member(enum_id, const, operand, 0xffffffff) ida_bytes.op_enum(ea_search, 0, enum_id, 0)
def find_ehfuncinfo_addr(self): for eh_addr in self.frmhdlr_xref: addr_ = eh_addr for i in range(0, self.MAX_SEARCH): addr_ = idc.prev_head(addr_) mnem = idc.print_insn_mnem(addr_) ### locate the ehfuncInfo address if mnem == 'mov' and idc.get_operand_type( addr_, 0) == o_reg and idc.get_operand_type( addr_, 1) == o_imm: op1 = idc.print_operand(addr_, 0) op2 = idc.print_operand(addr_, 1) ## eh function info address eh_func_info_addr = get_operand_value(addr_, 1) #print(hex(addr_), mnem, op1, op2,hex(eh_func_info_addr)) ### locate the ptryBlockMapAddr for ad in idautils.XrefsTo(addr_, flags=0): seh_init_addr = ad.frm print( "[+] seh_frame_addr: {} ehFuncInfo_struct_addr: {}\n------------------------------------------------------------------" .format(hex(addr_), hex(eh_func_info_addr))) ### locate the xref of the _cxxframehandler ehfuncinfo self.parse_func_info_entry(seh_init_addr, addr_, eh_func_info_addr) return
def disassemble_func(address): func_dis = {} symbolic_calls = {} inst_num = 0 flags = get_func_flags(address) last_addr = address asm = '' for addr in FuncItems(address): ins = DecodeInstruction(addr) # print('decoded') byte_instr = get_bytes(addr, ins.size) asm = asm + str(binascii.hexlify(byte_instr)) inst_num = inst_num + 1 last_addr = addr if idc.print_insn_mnem(addr) in ["call"]: # print('Call:'+str(ins)) call_address = idc.get_operand_value(addr, 0) # print(call_address) start_addr = first_func_chunk(call_address) symbolic_calls[start_addr] = idc.get_func_name(call_address) func_dis['bytecode'] = asm func_dis['symbolic_calls'] = symbolic_calls func_dis['start_address'] = first_fusnc_chunk(address) func_dis['end_address'] = last_addr func_dis['segment_address'] = get_segm_start(address) func_dis['segment_name'] = SegName(address) func_dis['name'] = idc.get_func_name(address) func_dis['inst_numbers'] = inst_num # attenzione sta cosa ci da la roba riconosciuta con flirt. func_dis['library_flag'] = flags & FUNC_LIB return func_dis
def format_args(call_addr, fmt_num, index): func = idaapi.get_func(call_addr) start = func.start_ea string = "" # 这里i是指对应在整个调用中的参数的位置, # !! 从1开始因为测试的时候考虑printf第一个格式化字符串,后面的就是后推一个, # !! 应该snprintf参数解析错误的bug就是这里, 应该..1改成format_function_offset_dict[func_name]就好了 for i in range(index + 1, fmt_num + index + 1): # 只查寄存器传递的,push传递的还没考虑, if (i >= 6): break # 从调用位置向上遍历查找对应的传参寄存器 line = call_addr reg = arg_reg[i] while line >= start: line = prev_head(line) line_arg = idc.print_operand(line, 0) # !! 只比较寄存器存在bug (add rdi, 0x10), 可能被认为是0x10是参数, if reg == line_arg: idc.set_color(line, CIC_ITEM, 0x00fff0) # 如果是寄存器传寄存器(mov rdi, rax;), 调用函数尝试回溯rax, if (idc.get_operand_type(line, 1) != 1) and (idc.print_insn_mnem(line) in ['mov', 'lea']): string += ", '%s'" % (idc.print_operand(line, 1)) else: string += ", '%s'" % (hand_register( line, start, idc.print_operand(line, 1))) break return string
def get_code_refs(self): xrefs = list(idautils.CodeRefsTo(self.addr, 1)) if len(xrefs) < 2: mnem = idc.print_insn_mnem(self.addr).lower() if mnem == "nop" or mnem == "jmp": return 9999 return len(xrefs)
def cfg_construct(func): func_start = func.startEA func_end = func.endEA cfg = nx.DiGraph() seq_blocks, main_blocks = obtain_block_sequence(func) i = 0 visited = {} for bl in seq_blocks: start = seq_blocks[bl][0] end = seq_blocks[bl][1] src_node = (start, end) if end in seq_blocks and idc.print_insn_mnem( idc.PrevHead(end)) != 'jmp': next_start = seq_blocks[end][0] next_end = seq_blocks[end][1] next_node = (next_start, next_end) cfg.add_edge(src_node, next_node) if start == func_start: cfg.add_node(src_node, c='start') start_node = src_node if end == func_end: cfg.add_node(src_node, c='end') refs = idautils.CodeRefsFrom(PrevHead(end), 0) for ref in refs: #print ref if ref in seq_blocks: dst_node = (seq_blocks[ref][0], seq_blocks[ref][1]) cfg.add_edge(src_node, dst_node) return cfg, start_node
def is_conformant_instr(va, mnems, op_specs): """Check if instruction at @va conforms to operand specifications list. Args: va (numbers.Integral): Virtual address of instruction to assess. mnems (str or iterable of str): Optional instruction mnemonic(s) to check for. op_specs (iterable of OpSpec): Iterable containing zero or more operand specification tuples (operand position, type, and name). Returns: True if conformant False if nonconformant """ if (not mnems) and (not op_specs): msg = 'Must specify either a mnemonic or an operand specification list' raise ValueError(msg) mnem_current = idc.print_insn_mnem(va) if mnems: if isinstance(mnems, basestring): if mnem_current != mnems: return False else: if mnem_current not in mnems: return False for spec in op_specs: if not is_conformant_operand(va, spec): return False return True
def _does_instruction_match(self, ea, instruction, regex=False): i = 0 op_cnt = 0 op_ok_cnt = 0 match = False insn_t = idaapi.insn_t() ins_size = idaapi.decode_insn(insn_t, ea) mnem = idc.print_insn_mnem(ea) if (not instruction.mnem) or (instruction.mnem == mnem) or ( regex and re.match(instruction.mnem, mnem)): for operand in instruction.operands: if operand: op_cnt += 1 op = idc.print_operand(ea, i) if regex: if re.match(operand, op): op_ok_cnt += 1 elif operand == op: op_ok_cnt += 1 i += 1 if op_cnt == op_ok_cnt: match = True return match
def _is_bad_instruction(self, ea, bad_instructions=['j', 'b'], no_clobber=[]): bad = False mnem = idc.print_insn_mnem(ea) if mnem and mnem[0] in bad_instructions: bad = True else: if idaapi.IDA_SDK_VERSION < 700: for register in no_clobber: if (idaapi.insn_t_get_canon_feature(idaapi.cmd.itype) & idaapi.CF_CHG1) == idaapi.CF_CHG1: if idc.print_operand(ea, 0) == register: bad = True else: insn = idaapi.insn_t() #insn.itype = idaapi.cmd.itype # ml for register in no_clobber: if (insn.get_canon_feature() & idaapi.CF_CHG1) == idaapi.CF_CHG1: if idc.print_operand(ea, 0) == register: bad = True return bad
def track_register(self, ea, target_dest_reg): f_start = idc.get_func_attr(ea, idc.FUNCATTR_START) f_end = idc.get_func_attr(ea, idc.FUNCATTR_END) curr_ea = ea dst = None src = None target = target_dest_reg.lower() target_dest_reg = target_dest_reg.lower() target_value = None target_ea = idc.BADADDR target_type = None previous_call = None ret_dict = {} while curr_ea != idc.BADADDR: #instruction = idc.GetDisasm(curr_ea) # print "0x%08x %s" % (curr_ea, instruction) # looking for the previous place this register was assigned a value mnem = idc.print_insn_mnem(curr_ea).lower() dst = idc.print_operand(curr_ea, 0).lower() src = idc.print_operand(curr_ea, 1).lower() if dst == target and self.is_set_argument_instr(mnem): target = src target_value = src target_ea = curr_ea # print " new target set %s (type=%d)" % (target, idc.get_operand_type(curr_ea, 1)) if target.startswith("="): break if dst == target == "r0" and self.is_call_instr(mnem): target_value = "<return from previous call>" previous_call = curr_ea break # step to previous instruction curr_ea = idc.prev_head(curr_ea - 1, f_start) if target_value: # print ">>> 0x%08x, %s is set to %s @ 0x%08x" % (ea, target_dest_reg, target_value, target_ea) ret_dict = { "target": target_dest_reg, "value": target_value, "target_ea": target_ea, "ea": ea } if previous_call: ret_dict["previous_call"] = previous_call return ret_dict # fall through if nothing is found return {}
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(): if idc.print_insn_mnem(ea) == "call": for xref in idautils.XrefsFrom(ea, idaapi.XREF_FAR): func_ea = xref.to if func_ea: yield ea, func_ea
def get_sequences(start, end): seq = [] inst_addr = start while inst_addr <= end: opcode = idc.print_insn_mnem(inst_addr) seq.append(opcode) inst_addr = idc.next_head(inst_addr) return seq
def getDispatchCode(ea): # get dispatch code out of an instruction first, second = (idc.print_operand(ea, 0), idc.get_operand_value(ea, 1)) if first == 'eax': return second raise ValueError( "Search resulted in address %08x, but instruction '%s' does fulfill requested constraints" % (ea, idc.print_insn_mnem(ea)))
def handle_test(ea, state): """ If a test of a register against itself occurs and the next instruction is a jnz, then the register can be set to zero (code is followed linearly, jumps are ignored), unless the next instruction is a jmp. :param ea: instruction location :param state: the current TraceState """ if idc.get_operand_type(ea, POS_FIRST) == idc.o_reg and idc.get_operand_type(ea, POS_SECOND) == idc.o_reg: op1 = get_opnd_replacement(ea, POS_FIRST) op2 = get_opnd_replacement(ea, POS_SECOND) next_ea = ea + idc.get_item_size(ea) if op1 == op2 and idc.print_insn_mnem(next_ea) == 'jnz': next_ea += idc.get_item_size(next_ea) if not idc.print_insn_mnem(next_ea).startswith('j'): state.set_reg_value(op1, 0, ea)
def run(self): logger.debug('Starting up') try: here = idc.here() logger.info('Using ea: 0x%08x', here) if using_ida7api: mnem = idc.print_insn_mnem(here) else: mnem = idc.GetMnem(here) if not mnem.startswith('call'): logger.info('Not running at a call instruction. Bailing out now') return if using_ida7api: optype = idc.get_operand_type(here, 0) else: optype = idc.GetOpType(here, 0) if optype == idc.o_near: logger.info("Cannot (or shouldn't) run when call optype is o_near") return dlg = ApplyCalleeTypeWidget() oldTo = idaapi.set_script_timeout(0) res = dlg.exec_() idaapi.set_script_timeout(oldTo) if res == QtWidgets.QDialog.Accepted: logger.debug('Dialog accepted. Input type: %d', dlg.inputType) else: logger.debug('Dialog rejected') return tinfo = None #check user input type if dlg.inputType == dlg.USER_TYPE: decl = self.convertUserType(str(dlg.getUserText())) tinfo = self.getUserDeclType(decl) elif dlg.inputType == dlg.STANDARD_TYPE: tinfo = self.getBuiltinGlobalType() elif dlg.inputType == dlg.LOCAL_TYPE: tinfo = self.getLocalType() else: logger.info('Bad user input type') return if tinfo is None: logger.debug('Bailing due to null tinfo') return #logger.info('Deserialize result: %r', ret) #not 100% sure if i need to explicitly convert from func to funcptr - seemed # to pretty much work without this, but doing it just to be sure if not tinfo.is_funcptr(): logger.debug('Converting to func pointer') tinfo.create_ptr(tinfo) typename = idaapi.print_tinfo('', 0, 0, idaapi.PRTYPE_1LINE, tinfo, '', '') logger.info('Applying tinfo: "%s"', str(typename)) #both applying callee type & setting op type -> not sure if both are needed? # set op type causes change in hexrays decompilation # apply callee type updates ida's stack analysis ret = idaapi.apply_callee_tinfo(here, tinfo) if using_ida7api: ret = idaapi.set_op_tinfo(here, 0, tinfo) else: ret = idaapi.set_op_tinfo2(here, 0, tinfo) logger.debug('set_op_tinfo2 result: %r', ret) except Exception, err: logger.exception("Exception caught: %s", str(err))