def getFormatString(addr): op_num = 1 # idc.get_operand_type Return value #define o_void 0 // No Operand ---------- #define o_reg 1 // General Register (al, ax, es, ds...) reg #define o_mem 2 // Direct Memory Reference (DATA) addr #define o_phrase 3 // Memory Ref [Base Reg + Index Reg] phrase #define o_displ 4 // Memory Reg [Base Reg + Index Reg + Displacement] phrase+addr #define o_imm 5 // Immediate Value value #define o_far 6 // Immediate Far Address (CODE) addr #define o_near 7 // Immediate Near Address (CODE) addr #define o_idpspec0 8 // IDP specific type #define o_idpspec1 9 // IDP specific type #define o_idpspec2 10 // IDP specific type #define o_idpspec3 11 // IDP specific type #define o_idpspec4 12 // IDP specific type #define o_idpspec5 13 // IDP specific type # 如果第二个不是立即数则下一个 if (idc.get_operand_type(addr, op_num) != 5): op_num = op_num + 1 if idc.get_operand_type(addr, op_num) != 5: return "get fail" op_string = print_operand( addr, op_num).split(" ")[0].split("+")[0].split("-")[0].replace("(", "") string_addr = idc.get_name_ea_simple(op_string) if string_addr == BADADDR: return "get fail" string = str(get_strlit_contents(string_addr, -1, STRTYPE_TERMCHR)) return [string_addr, string]
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 find_value(self, func_addr, instr_addr, register): """ Attempts to resolve the value of the given register at the given address. If the value cannot be resolved, None is returned. """ reg_num = idaapi.ph_get_regnames().index(register) # go back from the current instruction to the start of the function for instr_addr in list(instructions(func_addr, instr_addr))[::-1]: # look for instrucations that move a value into the desired register mnemonic = idc.GetMnem(instr_addr) if mnemonic == 'mov': op1_type = idc.get_operand_type(instr_addr, 0) op1_value = idc.get_operand_value(instr_addr, 0) if op1_type == idc.o_reg and op1_value == reg_num: op2_type = idc.get_operand_type(instr_addr, 1) op2_value = idc.get_operand_value(instr_addr, 1) # if this instruction sets the register to an immediate value if op2_type == idc.o_imm: # return that value return op2_value else: # it is not an immediate value, so we say we cannot # resolve the value return None # we did not find an allocation of the register, # so we return None to indicate that return None
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 handle_mov(ea, state): """Updates the stack based on a mov instruction. Used by create_stack :param ea: instruction location :param state: the current TraceState :return: None - updates stack or regs """ op1 = get_opnd_replacement(ea, POS_FIRST) if idc.get_operand_type(ea, POS_FIRST) != idc.o_reg: offset = get_operand_value_replacement(ea, POS_FIRST, state) set_stack(offset, ea, POS_SECOND, state) else: type_ = idc.get_operand_type(ea, POS_SECOND) val = None if type_ == idc.o_reg: val = state.get_reg_value(get_opnd_replacement(ea, POS_SECOND)) elif type_ == idc.o_mem: bytes = idc.get_bytes(idc.get_operand_value(ea, POS_SECOND), get_byte_size_of_operand(ea, POS_SECOND)) if bytes: val = 0 for x in range(len(bytes)): val += ord(bytes[x]) << (8 * x) elif type_ == idc.o_imm: val = idc.get_operand_value(ea, POS_SECOND) else: offset = get_operand_value_replacement(ea, POS_SECOND, state) val, ea = state.stack.get(offset, (None, ea)) state.set_reg_value(op1, val, ea)
def do_unpatch_call(va_callsite): size = idc.get_item_size(va_callsite) ida_xref.del_cref(va_callsite, fva_stub, 0) cmt = idc.get_cmt(va_callsite, 0) newcmt = cmt # Remove automated comments if newcmt.startswith(g_patched_call_cmt): newcmt = newcmt[newcmt.find('\n') + 1:] if newcmt.find('\n') == -1: newcmt = '' else: newcmt = newcmt[newcmt.find('\n') + 1:] if newcmt.startswith(g_cmt_pointed): if newcmt.find('\n') == -1: newcmt = '' else: newcmt = newcmt[newcmt.find('\n') + 1:] if newcmt != cmt: idc.set_cmt(va_callsite, newcmt, 0) if idc.get_operand_type(va_callsite, 0) == ida_ua.o_mem: patch_import(va_callsite, idc.BADADDR) elif idc.get_operand_type(va_callsite, 0) == ida_ua.o_reg: va_imp = self._get_imp_for_register_call(va_callsite) if va_imp: patch_pointer_width(va_imp, idc.BADADDR) else: revert_patch(va_callsite, size)
def set_types(self): ''' handle (EFI_BOOT_SERVICES *) type and (EFI_SYSTEM_TABLE *) for x64 images ''' RAX = 0 O_REG = 1 O_MEM = 2 EFI_BOOT_SERVICES = 'EFI_BOOT_SERVICES *' EFI_SYSTEM_TABLE = 'EFI_SYSTEM_TABLE *' empty = True for service in self.gBServices: for address in self.gBServices[service]: ea = address num_of_attempts = 10 for _ in range(num_of_attempts): ea = idc.prev_head(ea) if (idc.print_insn_mnem(ea) == 'mov' and idc.get_operand_type(ea, 1) == O_MEM): if (idc.get_operand_type(ea, 0) == O_REG and idc.get_operand_value(ea, 0) == RAX): gvar = idc.get_operand_value(ea, 1) gvar_type = idc.get_type(gvar) ''' if (EFI_SYSTEM_TABLE *) ''' if ((gvar_type != 'EFI_SYSTEM_TABLE *') and \ (idc.print_operand(address, 0).find('rax') == 1) ): if self._find_est(gvar, ea, address): print( '[ {0} ] Type ({type}) successfully applied' .format( '{addr:#010x}'.format(addr=gvar), type=EFI_SYSTEM_TABLE)) empty = False break ''' otherwise it (EFI_BOOT_SERVICES *) ''' if (gvar_type != 'EFI_BOOT_SERVICES *' and gvar_type != 'EFI_SYSTEM_TABLE *'): if idc.SetType(gvar, EFI_BOOT_SERVICES): empty = False idc.set_name( gvar, 'gBs_{addr:#x}'.format(addr=gvar)) print( '[ {0} ] Type ({type}) successfully applied' .format( '{addr:#010x}'.format(addr=gvar), type=EFI_BOOT_SERVICES)) break if empty: print(' * list is empty')
def calNconstants(bl): start = bl[0] end = bl[1] invoke_num = 0 inst_addr = start while inst_addr < end: optype1 = idc.get_operand_type(inst_addr, 0) optype2 = idc.get_operand_type(inst_addr, 1) if optype1 == 5 or optype2 == 5: invoke_num += 1 inst_addr = idc.next_head(inst_addr) return invoke_num
def set_types(self): """ handle (EFI_BOOT_SERVICES *) type """ RAX = 0 O_REG = 1 O_MEM = 2 EFI_BOOT_SERVICES = "EFI_BOOT_SERVICES *" empty = True for service in self.gBServices: for address in self.gBServices[service]: ea = address num_of_attempts = 10 for _ in range(num_of_attempts): ea = idc.prev_head(ea) if (idc.GetMnem(ea) == "mov" and idc.get_operand_type(ea, 1) == O_MEM): if (idc.get_operand_type(ea, 0) == O_REG and idc.get_operand_value(ea, 0) == RAX): gBs_var = idc.get_operand_value(ea, 1) gBs_var_type = idc.get_type(gBs_var) if (gBs_var_type == "EFI_BOOT_SERVICES *"): empty = False print("[{0}] EFI_BOOT_SERVICES->{1}".format( "{addr:#010x}".format(addr=address), service)) print("\t [address] {0}".format( "{addr:#010x}".format(addr=gBs_var))) print("\t [message] type already applied") break if idc.SetType(gBs_var, EFI_BOOT_SERVICES): empty = False idc.MakeName( gBs_var, "gBs_{addr:#x}".format(addr=gBs_var)) print("[{0}] EFI_BOOT_SERVICES->{1}".format( "{addr:#010x}".format(addr=address), service)) print("\t [address] {0}".format( "{addr:#010x}".format(addr=gBs_var))) print("\t [message] type successfully applied") else: empty = False print("[{0}] EFI_BOOT_SERVICES->{1}".format( "{addr:#010x}".format(addr=address), service)) print("\t [address] {0}".format( "{addr:#010x}".format(addr=gBs_var))) print("\t [message] type not applied") break if empty: print(" * list is empty")
def findRspRbpDifference(curr_ea): difference = 0 for i in range(0, 256): mnem = idc.print_insn_mnem(curr_ea) debug(mnem) idaapi.decode_insn(insn, curr_ea) if mnem == 'push': push_offset = 8 difference += push_offset elif mnem == 'sub': if idc.get_operand_value( curr_ea, 0 ) == OperandValueRegister.RSP and idc.get_operand_type( curr_ea, 1) == OperandType.IMMEDIATE_VALUE: rsp_substraction = idc.get_operand_value(curr_ea, 1) difference += rsp_substraction elif mnem == 'mov' or mnem == 'lea': #debug('type: ', idc.get_operand_type(curr_ea, 0), ' val: ', idc.get_operand_value(curr_ea, 0)) debug(idc.generate_disasm_line(curr_ea, 0)) if idc.get_operand_value(curr_ea, 0) == OperandValueRegister.RBP: debug( mnem, ' type: ', idc.get_operand_type(curr_ea, 1), ' val: ', 'bp: 0x{:X}'.format(idc.get_operand_value(curr_ea, 1))) #case 1: mov if mnem == 'mov': if idc.get_operand_type( curr_ea, 1 ) == OperandType.GENERAL_REG and idc.get_operand_value( curr_ea, 1) == OperandValueRegister.RSP: displacement = 0 #case 2: lea if mnem == 'lea': if idc.get_operand_type(curr_ea, 1) == OperandType.MEMORY_REG: if idc.get_operand_value(curr_ea, 1) > 0xF000000000000000: displacement = 0x10000000000000000 - idc.get_operand_value( curr_ea, 1) difference += displacement else: displacement = idc.get_operand_value( curr_ea, 1) difference -= displacement break curr_ea += insn.size return difference
def find_iat_ptrs(self, pe, image_base, size, get_word): """Find all likely IAT pointers""" iat_ptrs = [] next_offset = image_base while next_offset < image_base + size: offset = next_offset next_offset = ida_bytes.next_addr(offset) # Attempt to read the current instruction's effective memory address operand (if present) mnem = idc.print_insn_mnem(offset).lower() ptr = 0 if mnem in ["call", "push", "jmp"]: if idc.get_operand_type(offset, 0) == idc.o_mem: # Get memory offset for branch instructions ptr = idc.get_operand_value(offset, 0) elif mnem in ["mov", "lea"]: if idc.get_operand_type( offset, 0) == idc.o_reg and idc.get_operand_type( offset, 1) == idc.o_mem: # Get memory offset for mov/lea instructions ptr = idc.get_operand_value(offset, 1) # Does the instruction's memory address operand seem somewhat valid?! if ptr < 0x1000: continue # Resolve pointer from memory operand iat_offset = get_word(ptr) # Ignore offset if it is in our image if image_base <= iat_offset <= image_base + size: continue # Get module and API name for offset module, api = self.resolve_address(iat_offset) # Ignore the offset if it is in a debug segment or stack etc if api and module and module.endswith(".dll"): if not iat_offset in iat_ptrs: # Add IAT offset, address to patch, module name and API name to list iat_ptrs.append( (iat_offset, offset + idc.get_item_size(offset) - 4, module, api)) self.ret = iat_ptrs return self.ret
def set_types(self): """ handle (EFI_BOOT_SERVICES *) type and (EFI_SYSTEM_TABLE *) for x64 images """ REG_RAX = 0 EFI_BOOT_SERVICES = "EFI_BOOT_SERVICES *" EFI_SYSTEM_TABLE = "EFI_SYSTEM_TABLE *" empty = True for service in self.gBServices: for address in self.gBServices[service]: ea = address num_of_attempts = 10 for _ in range(num_of_attempts): ea = idc.prev_head(ea) if ( idc.print_insn_mnem(ea) == "mov" and idc.get_operand_type(ea, 1) == idc.o_mem ): if ( idc.get_operand_type(ea, 0) == idc.o_reg and idc.get_operand_value(ea, 0) == REG_RAX ): gvar = idc.get_operand_value(ea, 1) gvar_type = idc.get_type(gvar) # if (EFI_SYSTEM_TABLE *) if (gvar_type != "EFI_SYSTEM_TABLE *") and ( idc.print_operand(address, 0).find("rax") == 1 ): if self._find_est(gvar, ea, address): print( f"[ {gvar:016X} ] Type ({EFI_SYSTEM_TABLE}) successfully applied" ) empty = False break # otherwise it (EFI_BOOT_SERVICES *) if ( gvar_type != "EFI_BOOT_SERVICES *" and gvar_type != "EFI_SYSTEM_TABLE *" ): if idc.SetType(gvar, EFI_BOOT_SERVICES): empty = False idc.set_name(gvar, f"gBS_{gvar:X}") print( f"[ {gvar:016X} ] Type ({EFI_BOOT_SERVICES}) successfully applied" ) break if empty: print(" * list is empty")
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_opnd_replacement(ea, pos): """ A replacement for IDA's idc.print_operand that can de-alias register names""" # TODO: Support renames in other operand types if idc.get_operand_type(ea, pos) == idc.o_reg: return idaapi.get_reg_name(idc.get_operand_value(ea, pos), get_byte_size_of_operand(ea, pos)) else: return idc.print_operand(ea, pos)
def find_ref_loc(config, ea, ref): """ type config: Config type ea: idc.ea_t type ref: idc.ea_t """ logger = logging.getLogger("idb2pat:find_ref_loc") if ea == BADADDR: logger.debug("Bad parameter: ea") return BADADDR if ref == BADADDR: logger.debug("Bad parameter: ref") return BADADDR if idc.get_operand_type(ea, 0) == o_near: ref = (ref - ida_bytes.get_item_end(ea)) & ( (1 << config.pointer_size * 8) - 1) if ida_bytes.is_code(ida_bytes.get_full_flags(ea)): for i in zrange( ea, max(ea, 1 + ida_bytes.get_item_end(ea) - config.pointer_size)): if ida_bytes.get_dword(i) == ref: return i return BADADDR
def getConst(ea, offset): strings = [] consts = [] optype1 = idc.get_operand_type(ea, offset) if optype1 == idaapi.o_imm: imm_value = idc.get_operand_value(ea, offset) if 0<= imm_value <= 10: consts.append(imm_value) else: if idaapi.isLoaded(imm_value) and ida_segment.getseg(imm_value): str_value = idc.get_strlit_contents(imm_value) if str_value is None: str_value = idc.get_strlit_contents(imm_value+0x40000) if str_value is None: consts.append(imm_value) else: re = all(40 <= ord(c) < 128 for c in str_value) if re: strings.append(str_value) else: consts.append(imm_value) else: re = all(40 <= ord(c) < 128 for c in str_value) if re: strings.append(str_value) else: consts.append(imm_value) else: consts.append(imm_value) return strings, consts
def find_event_names(): event_names = [] #get address value of named address offset_name = 'CreateEventA' named_addr = ida_name.get_name_ea(BADADDR, offset_name) #get all unique xrefs to found named address xref_lst = [] for xref in idautils.XrefsTo(named_addr): if xref.frm not in xref_lst: xref_lst.append(xref.frm) #get addresses where arguments of called function are pushed for xref in xref_lst: args = idaapi.get_arg_addrs(xref) if idc.get_operand_type(args[3], 0) == idaapi.o_imm: # select last argument and read string to which it points op_val = idc.get_operand_value(args[3], 0) event_name = get_strlit_contents(op_val) if event_name != None: event_name = event_name.decode('ascii') event_names.append(event_name) return event_names
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 m64_mmpagingfile(self): """ The MmPagingFile pointer can be defined as PVOID *MMPAGING_FILE[16]. Support for locating this pointer is not mandatory, but essential to verify if an MMPAGING_FILE structure corresponds to a virtual store. Although this pointer was previously exported as nt!MmPagingFile in Windows 7, the pointer has not been exported by any Windows 10 kernel to date. This function traverses MmStorecheckPagefiles. The same signature as x86 could not be used due to compiler optimzations using the LEA instruction to get the address of the global variable. Disassembly snippet from Windows 10 1809 x64 shown below. MmStoreCheckPagefiles MmStoreCheckPagefiles proc near ; MmStoreCheckPagefiles mov r9d, cs:Count MmStoreCheckPagefiles+7 xor r8d, r8d MmStoreCheckPagefiles+A test r9d, r9d MmStoreCheckPagefiles+D jz short loc_14072F307 MmStoreCheckPagefiles+F lea eax, [r8+1] MmStoreCheckPagefiles+13 lea r10, unk_14043E5E0 """ (addr, name) = self.find_ida_name("MmStoreCheckPagefiles") for insn_addr, insn, op0, op1 in self.iter_fn(addr): if insn == "lea": if idc.get_operand_type(insn_addr, 1) == idc.o_mem: return idc.get_operand_value(insn_addr, 1) - idaapi.get_imagebase() self.logger.error("MmPagingFile could not be resolved.") return None
def handle_mov(self, state): """Updates the state of the stack string finding based on a mov instruction""" op1 = tracing.get_opnd_replacement(state.ea, POS_FIRST) if "[" in op1: offset = tracing.get_operand_value_replacement(state.ea, POS_FIRST, state) self.set_stack(offset, state.ea, POS_SECOND, state) else: reg = tracing.get_reg_fam(op1) type_ = idc.get_operand_type(state.ea, POS_SECOND) if reg: if type_ != idc.o_phrase and type_ != idc.o_displ: if type_ == idc.o_reg: reg2 = tracing.get_reg_fam(tracing.get_opnd_replacement(state.ea, POS_SECOND)) if reg2 and reg2[0] in state.regs: val = state.regs[reg2[0]][0] else: val = None else: val = idc.get_operand_value(state.ea, POS_SECOND) if val is not None: state.regs[reg[0]] = (val, state.ea) else: offset = tracing.get_operand_value_replacement(state.ea, POS_SECOND, state) value = state.stack.get(offset, None) if value is not None: state.regs[reg[0]] = value else: self.clear_reg_if_needed(reg, state.regs)
def parse_function_type(ea: int, end: Optional[int] = None) -> str: frame = idc.get_func_attr(ea, FUNCATTR_FRAME) if frame is None: return "" if end is None: # try to find end func = function_at(ea) if not func: return "?" end = prev_addr(get_func_attr(func, FUNCATTR_END)) end_addr = end mnem = GetDisasm(end_addr) if "ret" not in mnem: # it's not a real end, get instruction before... end_addr = prev_addr(end) if end_addr == BADADDR: # cannot get the real end return "" mnem = GetDisasm(end_addr) if "ret" not in mnem: # cannot get the real end return "" op = get_operand_type(end_addr, 0) if op == o_void: # retn has NO parameters return "__cdecl" # retn has parameters return "__stdcall"
def get_first_function(ea): """ see above, but returns the first pushed value """ maybe_start = idc.get_func_attr(ea, idc.FUNCATTR_START) limit = 0 if maybe_start == idc.BADADDR: limit = 10 cur_ea = ea limit_count = 0 while cur_ea != idc.BADADDR: # are we over limit or up to the func start? limit_count += 1 limit_exceeded = (limit > 0 and limit_count > limit) too_far = (maybe_start != idc.BADADDR and cur_ea < maybe_start) if limit_exceeded or too_far: LOG.error( "Failed to find string walking backwards from {:08X}".format( ea)) return None prev_ins = idautils.DecodePreviousInstruction(cur_ea) prev_ea = prev_ins.ea # did we find it? if idc.GetMnem(prev_ea) == 'push': if idc.get_operand_type(prev_ea, 0) in [idc.o_mem, idc.o_imm]: # push offset found! pushed_addr = idc.GetOperandValue(prev_ea, 0) # it's not data, then probably good if idc.isCode(idc.GetFlags(pushed_addr)): return pushed_addr cur_ea = prev_ea
def get_opcode_omem(self, offset): """Get opcode's direct memory address""" mnem = self.get_mnemonic(offset).lower() ptr = 0 if mnem in ["call", "push", "jmp"]: if idc.get_operand_type(offset, 0) == idc.o_mem: ptr = idc.get_operand_value(offset, 0) elif mnem in ["mov", "lea"]: if idc.get_operand_type(offset, 0) == idc.o_reg and idc.get_operand_type( offset, 1) == idc.o_mem: ptr = idc.get_operand_value(offset, 1) self.ret = ptr return self.ret
def lookForOpArgs(self, start, end): for head in idautils.Heads(start, end): try: for i in range(2): if using_ida7api: t = idc.get_operand_type(head, i) else: t = idc.GetOpType(head, i) if t == idc.o_imm: if using_ida7api: opval = idc.get_operand_value(head, i) insn = idautils.DecodeInstruction(head) opmask = OPERAND_MASK.get(insn.ops[i].dtype) if opmask: opval = opval & opmask else: opval = idc.GetOperandValue(head, i) if self.params.useXORSeed: opval = opval ^ self.params.XORSeed for h in self.params.hashTypes: hits = self.dbstore.getSymbolByTypeHash( h.hashType, opval) for sym in hits: logger.info("0x%08x: %s", head, str(sym)) self.addHit(head, sym) self.markupLine(head, sym, self.params.useDecompiler) except Exception as err: logger.exception("Exception: %s", str(err))
def set_jit_info(self, method_id, start): end = self.get_func_end(start) if (end < start or end - start > self.jit_max_size): return method = next((x for x in self.as3dump if x["id"] == method_id), None) if (method is None): return stackvars = self.get_stack_vars(start, end) save_eip = self.get_save_eip(method, stackvars) ea = start while (ea < end): if ("ebp" in idc.print_operand(ea, 0) and idc.get_operand_type(ea, 1) == idc.o_imm): op0 = idc.get_operand_value(ea, 0) op1 = idc.get_operand_value(ea, 1) if (op0 == save_eip): idc.set_cmt(ea, method["instructions"][op1], 0) ea += idc.get_item_size(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 set_types(self): """ handle (EFI_BOOT_SERVICES *) type and (EFI_SYSTEM_TABLE *) for x64 images """ RAX = 0 O_REG = 1 O_MEM = 2 EFI_BOOT_SERVICES = 'EFI_BOOT_SERVICES *' EFI_SYSTEM_TABLE = 'EFI_SYSTEM_TABLE *' empty = True for service in self.gBServices: for address in self.gBServices[service]: ea = address num_of_attempts = 10 for _ in range(num_of_attempts): ea = idc.prev_head(ea) if (idc.print_insn_mnem(ea) == 'mov' and idc.get_operand_type(ea, 1) == O_MEM): if (idc.get_operand_type(ea, 0) == O_REG and idc.get_operand_value(ea, 0) == RAX): gvar = idc.get_operand_value(ea, 1) gvar_type = idc.get_type(gvar) # if (EFI_SYSTEM_TABLE *) if ((gvar_type != 'EFI_SYSTEM_TABLE *') and (idc.print_operand( address, 0).find('rax') == 1)): if self._find_est(gvar, ea, address): print( f'[ {gvar:016X} ] Type ({EFI_SYSTEM_TABLE}) successfully applied' ) empty = False break # otherwise it (EFI_BOOT_SERVICES *) if (gvar_type != 'EFI_BOOT_SERVICES *' and gvar_type != 'EFI_SYSTEM_TABLE *'): if idc.SetType(gvar, EFI_BOOT_SERVICES): empty = False idc.set_name(gvar, f'gBS_{gvar:X}') print( f'[ {gvar:016X} ] Type ({EFI_BOOT_SERVICES}) successfully applied' ) break if empty: print(' * list is empty')
def can_be_ignored(instr_addr): """ Checks whether or not an instruction can be ignored. An instruction can be ignored if it does not actually an arithmetic or bitwise computation, although it has a mnemonic that falls into that category. Example: xor eax, eax """ # ignore instructions that are "abused" for non-arithmetic purposes if idc.GetMnem(instr_addr) in ['xor', 'sub']: same_op_type = idc.get_operand_type(instr_addr, 0) == idc.get_operand_type( instr_addr, 1) same_op_value = idc.get_operand_value(instr_addr, 0) == idc.get_operand_value( instr_addr, 1) if same_op_type and same_op_value: return True return False
def _emit_fnbytes(emit_instr_cb, header, footer, indent, fva=None, warn=True): """Emit function bytes in a format defined by the callback and headers/footers provided. Warns if any instruction operands are not consistent with position-independent code, in which case the user may need to templatize the position-dependent portions. """ fva = fva or idc.here() fva = idc.get_func_attr(fva, idc.FUNCATTR_START) va_end = idc.get_func_attr(fva, idc.FUNCATTR_END) # Operand types observed in position-independent code: optypes_position_independent = set([ ida_ua.o_reg, # 1: General Register (al,ax,es,ds...) ida_ua.o_phrase, # 3: Base + Index ida_ua.o_displ, # 4: Base + Index + Displacement ida_ua.o_imm, # 5: Immediate ida_ua.o_near, # 7: Immediate Near Address ]) # Notably missing because I want to note and handle these if/as they are # encountered: # ida_ua.o_idpspec0 = 8: FPP register # ida_ua.o_idpspec1 = 9: 386 control register # ida_ua.o_idpspec2 = 10: 386 debug register # ida_ua.o_idpspec3 = 11: 386 trace register va = fva nm = idc.get_name(fva) optypes_found = set() s = header.format(name=nm) while va not in (va_end, idc.BADADDR): size = idc.get_item_size(va) the_bytes = idc.get_bytes(va, size) for i in range(0, 8): optype = idc.get_operand_type(va, i) if optype: optypes_found.add(optype) s += indent + emit_instr_cb(va, the_bytes, size) va = idc.next_head(va) s += footer position_dependent = optypes_found - optypes_position_independent if position_dependent: msg = ('This code may have position-dependent operands (optype %s)' % (', '.join([str(o) for o in position_dependent]))) if warn: Warning(msg) else: logger.warn(msg) return s
def type(self): """ Property allowing to get the type of the operand. This type correspond to the :class:`BipOpType` value . Wrapper on ``idc.GetOpType`` (old) or ``idc.get_operand_type`` (new). :return: The type of the operand as defined in :class:`BipOpType` . :rtype: int """ return idc.get_operand_type(self.ea, self.opnum)
def get_stack_vars(self, start, end): stackvars = {} ea = start while (ea < end): if ("ebp" in idc.print_operand(ea, 0) and idc.get_operand_type(ea, 1) == idc.o_imm): op0 = idc.get_operand_value(ea, 0) op1 = idc.get_operand_value(ea, 1) if (op0 in stackvars): stackvars[op0]["values"].append(op1) else: stackvars[op0] = {"values": [], "hits": 0} ea += idc.get_item_size(ea) return stackvars
def lookForOpArgs(self, start, end): for head in idautils.Heads(start, end): try: for i in range(2): if using_ida7api: t = idc.get_operand_type(head, i) else: t = idc.GetOpType(head, i) if t == idc.o_imm: if using_ida7api: opval = idc.get_operand_value(head, i) else: opval = idc.GetOperandValue(head, i) for h in self.params.hashTypes: hits = self.dbstore.getSymbolByTypeHash(h.hashType, opval) for sym in hits: logger.info("0x%08x: %s", head, str(sym)) self.addHit(head, sym) self.markupLine(head, sym) except Exception, err: logger.exception("Exception: %s", str(err))
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))