def get_field_classname(self, idx): print("get_field_classname: addr = 0x%08X" % (self.ClassTypesTab + 2 + 4 * idx)) addr = self.ClassTypesTab + 2 + 4 * idx print("get_field_classname: ClsAddr = 0x%08X" % ida_bytes.get_wide_dword(addr)) return get_class_name( ida_bytes.get_wide_dword(ida_bytes.get_wide_dword(addr)))
def value(self): """ Property which return the value corresponding to the data of a numberable elements. This property works only if the :meth:`~BipData.is_numerable` and :meth:`~BipData.has_data` properties returned True. For getting value of an element which is not numerable use the :meth:`~BipElt.bytes` property. This property is link to the type defined or guessed by IDA and it is a good idea to assure you have the proper type before using it. :return: An integer representing the value of the data or ``None`` if the data element is not numerable or do not have data. """ if not self.has_data: return None elif self.is_unknown or self.is_byte: return ida_bytes.get_wide_byte(self.ea) elif self.is_word: return ida_bytes.get_wide_word(self.ea) elif self.is_dword: return ida_bytes.get_wide_dword(self.ea) elif self.is_qword: return ida_bytes.get_qword(self.ea) else: return None
def get_mem_string(cls, addr): """ 获取内存中的字符串 """ addr_t = addr dref = idautils.DataRefsFrom(addr_t) strs = [cls.strings[x] for x in dref if x in cls.strings] # 处理几种特殊情况 # LDR R1, =sub_xxxx # LDR R1, =loc_xxxx if idc.print_operand(addr, 1)[:5] in ['=sub_', '=loc_']: return [] # LDR R1, =unk_53B4B6 # .rodata:0053B4B6 http: # .rodata:0053B4BB //%s%s if strs != [] and strs[0].find('%') == -1: strs = [] dref = idautils.DataRefsFrom(addr_t) for x in dref: segname = ida_segment.get_segm_name(ida_segment.getseg(x)) if segname not in ['.text', '.bss']: strs.append(cls.get_string_from_mem(x)) # LDR R1, =(aFailedToGetAnI+0x22) # LDR R2, =(aSS - 0xCFA4) # ADD R2, PC, R2 if strs == []: dref = idautils.DataRefsFrom(addr_t) for x in dref: segname = ida_segment.get_segm_name(ida_segment.getseg(x)) if segname not in ['.text', '.bss']: strs.append(cls.get_string_from_mem(x)) elif len(list(idautils.DataRefsFrom(x))) == 0: reg_t = idc.print_operand(addr_t, 0) num1 = ida_bytes.get_wide_dword(x) while get_mnem(addr_t) != 'ADD' or (idc.print_operand(addr_t, 0) != reg_t and idc.print_operand(addr_t, 1) != 'PC'): addr_t = ida_bytes.next_head(addr_t, ida_idaapi.BADADDR) num2 = addr_t + 8 addr_t = num1 + num2 strs.append(cls.get_string_from_mem(addr_t)) # MOVW R1, #0x87B4 # MOVT.W R1, #0x52 if strs == [] and get_mnem(addr_t) == 'MOVW': reg_t = idc.print_operand(addr_t, 0) num1 = int(idc.print_operand(addr_t, 1).split('#')[1], 16) while get_mnem(addr_t) not in ['MOVTGT', 'MOVTLE', 'MOVT'] or idc.print_operand(addr_t, 0) != reg_t: addr_t = ida_bytes.next_head(addr_t, ida_idaapi.BADADDR) num2 = int(idc.print_operand(addr_t, 1).split('#')[1], 16) addr_t = (num2<<16) + num1 strs.append(cls.get_string_from_mem(addr_t)) return strs
def get_call_args_arm(ea, count_max=10): """ 获得函数调用参数(当前仅支持4个参数) """ args = {} mnem = ida_ua.ua_mnem(ea) if mnem != "BL" and mnem != "SVC" and mnem != "BLNE" and mnem != "BLHI" and mnem != "BLEQ": print( "Error: not a BL or SVC or BLNE or BLHI or BLEQ instruction at 0x%x" % ea) return None arg_inst_arm_mov = [ "MOV R0,", "MOV R1,", "MOV R2,", "MOV R3," ] arg_inst_arm_adr = [ "ADR R0,", "ADR R1,", "ADR R2,", "ADR R3," ] arg_inst_arm_ldr = [ "LDR R0,", "LDR R1,", "LDR R2,", "LDR R3," ] arg_inst_arm_adr2 = [ "ADREQ R0,", "ADREQ R1,", "ADDEQ R2,", "ADREQ R3," ] arg_inst_arm_mov2 = [ "MOVEQ R0,", "MOVEQ R1,", "MOVEQ R2,", "MOVEQ R3," ] arg_inst_arm_adr3 = [ "ADRNE R0,", "ADRNE R1,", "ADDNE R2,", "ADRNE R3," ] ea = ida_bytes.prev_head(ea, 0) count = 0 while count <= count_max: disasm_line = idc.generate_disasm_line(ea, 0) for i in range(len(arg_inst_arm_mov)): #print("'%s'" % arg_inst_arm_mov[i]) # 假设最接近调用的指令是赋值指令,忽略其他情况(如碰到另一个MOV reg) inst_list = [ arg_inst_arm_mov[i], arg_inst_arm_mov2[i], arg_inst_arm_adr[i], arg_inst_arm_adr2[i], arg_inst_arm_adr3[i] ] if any(inst in disasm_line for inst in inst_list): if i not in args.keys(): args[i] = idc.get_operand_value(ea, 1) print("Found argument %d: 0x%x" % (i, args[i])) elif arg_inst_arm_ldr[i] in disasm_line: if i not in args.keys(): addr = idc.get_operand_value(ea, 1) args[i] = ida_bytes.get_wide_dword(addr) print("Found argument %d: 0x%x" % (i, args[i])) ea = ida_bytes.prev_head(ea, 0) count += 1 return args
def ev_ana_insn(self, insn): t_reg = ida_idp.str2reg("T") t = ida_segregs.get_sreg(insn.ea, t_reg) if t==0 and ida_bytes.get_wide_dword(insn.ea) == 0xE7F001F2: insn.itype = ITYPE_BUGINSN insn.size = 4 elif t!=0 and ida_bytes.get_wide_word(insn.ea) == 0xde02: insn.itype = ITYPE_BUGINSN insn.size = 2 return insn.size
def _init_func_thunk_ctrl_flow(self): """Initializes the control flow redirections and targets using function thunks""" # We only support the ELF format for now inf = ida_idaapi.get_inf_structure() if inf.filetype != ida_ida.f_ELF: return # List the function thunks first input_file_path = ida_nalt.get_input_file_path() image_parser = create_elf_image_parser(input_file_path) function_thunk_list = image_parser.get_function_thunk_list() # Go through each function thunk, and look at its cross references; there # should always be only one user, which is the wrapper around the imported # function is_32_bit = image_parser.get_image_bitness() == 32 for function_thunk in function_thunk_list: thunk_va = function_thunk.start redirection_dest = (ida_bytes.get_wide_dword(thunk_va) if is_32_bit else ida_bytes.get_qword(thunk_va)) caller_address = ida_xref.get_first_cref_to(redirection_dest) if caller_address == ida_idaapi.BADADDR: continue redirection_source = idc.get_func_attr(caller_address, idc.FUNCATTR_START) caller_function_name = ida_funcs.get_func_name(redirection_source) if function_thunk.name in caller_function_name: print( "anvill: Redirecting the user {:x} of thunk {} at rva {:x} to {:x}" .format( redirection_source, function_thunk.name, function_thunk.start, redirection_dest, )) self.add_control_flow_redirection(redirection_source, redirection_dest) print( "anvill: Adding target list {:x} -> [{:x}, complete=True] for {}" .format(caller_address, redirection_dest, function_thunk.name)) self.set_control_flow_targets(caller_address, [redirection_dest], True)
def parse(self, addr): print("ClassRTTI: parse addr 0x%08X" % addr) self.addr = addr if get_field_table_addr(addr): self.FieldTable = FieldTable().parse(get_field_table_addr(addr)) self.ClassName = get_class_name(addr) self.InstanceSize = get_instance_size(addr) self.ParentAddr = get_parent_addr(addr) print("ClassRTTI: parse addr 0x%08X" % addr) if self.ParentAddr: self.Parent = ClassRTTI().parse( ida_bytes.get_wide_dword(self.ParentAddr)) return self
def _init_ctrl_flow_redirections(self): """Initializes the control flow redirections using function thunks""" # We only support the ELF format for now inf = ida_idaapi.get_inf_structure() if inf.filetype != ida_ida.f_ELF: return # List the function thunks first input_file_path = ida_nalt.get_input_file_path() image_parser = create_elf_image_parser(input_file_path) function_thunk_list = image_parser.get_function_thunk_list() # Go through each function thunk, and look at its cross references; there # should always be only one user, which is the wrapper around the imported # function # # Note that the __libc_start_main # thunk does not need redirection since # it's called directly without any wrapper function from the module entry # point is_32_bit = image_parser.get_image_bitness() == 32 for function_thunk in function_thunk_list: if function_thunk.name == "__libc_start_main": continue thunk_va = ida_nalt.get_imagebase() + function_thunk.start redirection_dest = ( ida_bytes.get_wide_dword(thunk_va) if is_32_bit else ida_bytes.get_qword(thunk_va) ) caller_address = ida_xref.get_first_cref_to(redirection_dest) if caller_address == ida_idaapi.BADADDR: continue redirection_source = idc.get_func_attr(caller_address, idc.FUNCATTR_START) print( "anvill: Redirecting the user {:x} of thunk {} at rva {:x} to {:x}".format( redirection_source, function_thunk.name, function_thunk.start, redirection_dest, ) ) self.add_control_flow_redirection(redirection_source, redirection_dest)
def get_dword(ea=None, original=False): """ Static method allowing to get the value of one dword at an address. :param ea: The address at which recuperating the value. If ``None`` the screen address is used. :param original: If True the value recuperated will be the original one (before a patch). Default: False. :return: An integer corresponding to the value at the address. """ if ea is None: ea = ida_kernwin.get_screen_ea() if original: return ida_bytes.get_original_dword(ea) else: return ida_bytes.get_wide_dword(ea)
def decode_msr_mrs(self, insn): x = ida_bytes.get_wide_dword(insn.ea) op0 = 2 + ((x >> 19) & 1) if insn.itype == ida_allins.ARM_msr: i, xt = 0, insn.ops[4].reg else: xt, i = insn.ops[0].reg, 1 op1 = insn.ops[i].value crn = insn.ops[i + 1].reg crm = insn.ops[i + 2].reg op2 = insn.ops[i + 3].value ops = [op0, op1, crn, crm, op2] gp_reg = ida_idp.ph.regnames[xt] cp_reg = self.find_reg_enc("MSR|MRS", ops) return cp_reg, gp_reg
def parse(self, addr): print("FieldTableEntryEx:parse addr = 0x%08X" % addr.get_curr_addr()) if type(addr) is byte_reader: reader = addr else: reader = byte_reader(addr) self.Flags = reader.get_byte() tp_ref = reader.get_dword() if tp_ref: self.TypeRef = TypeInfo().parse(ida_bytes.get_wide_dword(tp_ref)) self.Offset = reader.get_dword() self.Name = reader.get_delphi_string() self.AtrrDataLen = reader.get_word() if self.AtrrDataLen > 2: self.AtrrData = reader.get_bytes(self.AtrrDataLen - 2) return self
def get_ptr(ea=None): """ Recuperate the value of a pointer at an address. This will handle automatically the correct size of the pointer. :param int ea: the address at which get the pointer value. If ``None`` the screen address is used. :return: the pointer value """ if ea is None: ea = ida_kernwin.get_screen_ea() info = ida_idaapi.get_inf_structure() if info.is_64bit(): return ida_bytes.get_qword(ea) elif info.is_32bit(): return ida_bytes.get_wide_dword(ea) else: return ida_bytes.get_wide_word(ea)
def get_instance_size(cls_addr): return ida_bytes.get_wide_dword(cls_addr + vmtInstanceSize)
def var_len_args_run_info(self, args_rule, args): """ 获取变长参数函数的寄存器信息 """ run_info = {} fmt_t = '' for idx in range(len(args_rule) - 1): str_reg = 'R%s' % idx arg_t = args_rule[idx] if arg_t == 'none': # 跳过无关参数 continue elif arg_t == 'int': run_info[str_reg] = [hexstr(args[str_reg].ival), None] FELogger.console('%s: %s' % (str_reg, hexstr(args[str_reg].ival))) elif arg_t == 'str': arg_v = args[str_reg].ival if arg_v != 0: str_t = FEStrMgr.get_string_from_mem(arg_v) else: str_t = '' run_info[str_reg] = [hexstr(arg_v), repr(str_t)] FELogger.console('%s: %s => %s' % (str_reg, hexstr(arg_v), repr(str_t))) elif arg_t == 'fmt': arg_v = args[str_reg].ival fmt_t = FEStrMgr.get_string_from_mem(arg_v) run_info[str_reg] = [hexstr(arg_v), repr(fmt_t)] FELogger.console('%s: %s => %s' % (str_reg, hexstr(arg_v), repr(fmt_t))) else: run_info[str_reg] = [hexstr(args[str_reg].ival), None] FELogger.console('%s: %s' % (str_reg, hexstr(args[str_reg].ival))) # 判断是否包含格式字符串 if fmt_t != '': fmt_list = FEStrMgr.parse_format_string(str_t) args_num = len(fmt_list) + idx + 1 # 判断变长参数总个数 if idx + 1 == args_num: pass # n<=4 寄存器 elif idx + 1 < args_num and args_num <= 4: for jdx in range(len(fmt_list)): str_reg = 'R%s' % (idx + jdx + 1) if 's' in fmt_list[jdx]: arg_v = args[str_reg].ival str_t = FEStrMgr.get_string_from_mem(arg_v) run_info[str_reg] = [hexstr(arg_v), repr(str_t)] FELogger.console('%s: %s => %s' % (str_reg, hexstr(arg_v), repr(str_t))) else: run_info[str_reg] = [hexstr(args[str_reg].ival), None] FELogger.console('%s: %s' % (str_reg, hexstr(args[str_reg].ival))) # n>4 寄存器+栈 else: stack_num = args_num - 4 sp_addr = args[arm_regset.stack].ival for jdx in range(4 - idx - 1): str_reg = 'R%s' % (idx + jdx + 1) if 's' in fmt_list[jdx]: arg_v = args[str_reg].ival str_t = FEStrMgr.get_string_from_mem(arg_v) run_info[str_reg] = [hexstr(arg_v), repr(str_t)] FELogger.console('%s: %s => %s' % (str_reg, hexstr(arg_v), repr(str_t))) else: run_info[str_reg] = [hexstr(args[str_reg].ival), None] FELogger.console('%s: %s' % (str_reg, hexstr(args[str_reg].ival))) run_info[arm_regset.stack] = [] for kdx in range(stack_num): stack_v = ida_bytes.get_wide_dword(sp_addr) if 's' in fmt_list[jdx + kdx + 1]: if stack_v == 0: str_t = '' else: str_t = FEStrMgr.get_string_from_mem(stack_v) run_info[arm_regset.stack].append( [hexstr(sp_addr), hexstr(stack_v), repr(str_t)]) FELogger.console( 'stack: %s - %s => %s' % (hexstr(sp_addr), hexstr(stack_v), repr(str_t))) else: run_info[arm_regset.stack].append( [hexstr(sp_addr), hexstr(stack_v), None]) FELogger.console('stack: %s - %s' % (hexstr(sp_addr), hexstr(stack_v))) sp_addr += 4 else: pass return run_info
def get_class_name(cls_addr): class_name = ida_bytes.get_strlit_contents( ida_bytes.get_wide_dword(cls_addr + vmtClassName), ida_idaapi.BADADDR, ida_nalt.STRTYPE_PASCAL) return class_name
def parse_borland_class_rtti(addr): class_name = ida_bytes.get_strlit_contents( ida_bytes.get_wide_dword(addr + vmtClassName), ida_idaapi.BADADDR, ida_nalt.STRTYPE_PASCAL) print("Class name: %s" % class_name.decode()) ft = FieldTable().parse(get_field_table_addr(addr))
def get_field_table_addr(cls_addr): return ida_bytes.get_wide_dword(cls_addr + vmtFieldTable)
def get_parent_addr(cls_addr): return ida_bytes.get_wide_dword(cls_addr + vmtParent)
def get_dword(self, pos=None): if pos is None: pos = self.pos self.pos += 4 return ida_bytes.get_wide_dword(self.addr + pos)