def visit_expr(self, i): if i.op != idaapi.cot_call: return 0 node = i.x if node.op == idaapi.cot_cast: node = node.x if node.op != idaapi.cot_memptr: return 0 offset = node.m node = node.x type = node.type.get_pointed_object() if type is None: return 0 member = idaapi.udt_member_t() member.offset = offset * 8 type.find_udt_member(member, idaapi.STRMEM_OFFSET) if member.name != self.method_name: return 0 self.need_update = infer_function_signature(self.cfunc, i, self.index_interface, self.index_output) return 0
def get_virtual_func_address(name, tinfo=None, offset=None): """ :param name: method name :param tinfo: class tinfo :param offset: virtual table offset :return: address of the method """ address = idc.LocByName(name) if address != idaapi.BADADDR: return address address = demangled_names.get(name, idaapi.BADADDR) if address != idaapi.BADADDR: return address + idaapi.get_imagebase() if tinfo is None or offset is None: return offset *= 8 udt_member = idaapi.udt_member_t() while tinfo.is_struct(): address = demangled_names.get(tinfo.dstr() + '::' + name, idaapi.BADADDR) if address != idaapi.BADADDR: return address + idaapi.get_imagebase() udt_member.offset = offset tinfo.find_udt_member(idaapi.STRMEM_OFFSET, udt_member) tinfo = udt_member.type offset = offset - udt_member.offset
def structure_info_create(vtbs): for vtb in vtbs: vtb_name = "vtb_" + (hex(vtb.get("vtb_start_addr"))[2:-1]).upper() # 创建结构体 udt_data = idaapi.udt_type_data_t() # 函数名称记录列表 func_name_records_list = [] # 添加结构体的成员 for mem in vtb.get('vtb_func_lists'): # 创建成员 udt_member = idaapi.udt_member_t() udt_member.type = ptr_type("DWORD") udt_member.name = name_filter(mem.get('func_name')) # 如果名字为空,需要进行特殊的处理 # MEMORY[xxxx] # print udt_member.name if udt_member.name == None or udt_member.name == "": udt_member.name = "memory_" + (hex( mem.get("func_addr"))[2:]).upper() # 防止函数名称重复 if udt_member.name in func_name_records_list: udt_member.name += "1" func_name_records_list.append(udt_member.name) # print udt_member.name # 插入结构体 udt_data.push_back(udt_member) build_structure_in_ida(udt_data, vtb_name)
def get_fields_at_offset(tinfo, offset): """ Given tinfo and offset of the structure or union, returns list of all tinfo at that offset. This function helps to find appropriate structures by type of the offset """ result = [] if offset == 0: result.append(tinfo) udt_data = idaapi.udt_type_data_t() tinfo.get_udt_details(udt_data) udt_member = idaapi.udt_member_t() udt_member.offset = offset * 8 idx = tinfo.find_udt_member(idaapi.STRMEM_OFFSET, udt_member) if idx != -1: while idx < tinfo.get_udt_nmembers( ) and udt_data[idx].offset <= offset * 8: udt_member = udt_data[idx] if udt_member.offset == offset * 8: if udt_member.type.is_ptr(): result.append(idaapi.get_unk_type(Const.EA_SIZE)) result.append(udt_member.type) result.append(idaapi.dummy_ptrtype(Const.EA_SIZE, False)) elif not udt_member.type.is_udt(): result.append(udt_member.type) if udt_member.type.is_array(): if (offset - udt_member.offset / 8 ) % udt_member.type.get_array_element().get_size() == 0: result.append(udt_member.type.get_array_element()) elif udt_member.type.is_udt(): result.extend( get_fields_at_offset(udt_member.type, offset - udt_member.offset / 8)) idx += 1 return result
def get_udt_member(self): udt_member = idaapi.udt_member_t() udt_member.type = self.get_ptr_tinfo() udt_member.offset = self.offset udt_member.name = self.name udt_member.size = const.EA_SIZE return udt_member
def get_virtual_func_address(name, tinfo=None, offset=None): """ :param name: method name :param tinfo: class tinfo :param offset: virtual table offset :return: address of the method """ # address = idaapi.BADADDR # if name in idautils.Functions(): address = idc.LocByName(name) #f*****g idaapi. It's function work incorrectly. This returned 0xFF005BE7 instead BADADDR in some cases. get_name_ea problem. if address != idaapi.BADADDR: return address address = Cache.demangled_names.get(name, idaapi.BADADDR) if address != idaapi.BADADDR: return address + idaapi.get_imagebase() if tinfo is None or offset is None: return offset *= 8 udt_member = idaapi.udt_member_t() while tinfo.is_struct(): address = Cache.demangled_names.get(tinfo.dstr() + '::' + name, idaapi.BADADDR) if address != idaapi.BADADDR: return address + idaapi.get_imagebase() udt_member.offset = offset tinfo.find_udt_member(idaapi.STRMEM_OFFSET, udt_member) tinfo = udt_member.type offset = offset - udt_member.offset
def call_found(obj, ctx): import ida_typeinf import idc_bc695 import ida_xref call = ctx.get_expr('call_expr')[0] expr = ctx.get_expr('ref')[0] print type(expr) print '[*] Offset: %#x' % expr.m print '[*] First op type: %s' % expr.x.type.dstr().split(' ')[0] print '[*] Address %#x' % call.ea # vtab.sub_XXXX(...) if expr.x.op == idaapi.cot_memref: vtable_tinfo = expr.x.type.get_pointed_object() # vtab->sub_XXXX(...) else: vtable_tinfo = expr.x.type if vtable_tinfo.is_ptr(): vtable_tinfo = vtable_tinfo.get_pointed_object() udt_member = idaapi.udt_member_t() udt_member.offset = expr.m * 8 vtable_tinfo.find_udt_member(udt_member, idaapi.STRMEM_OFFSET) from_addr = call.ea to_addr = idc_bc695.LocByName(udt_member.name) print '[*] Function: %s' % udt_member.name print 'ida_xref.add_cref(%#x, %#x, %d)' % (call.ea, to_addr, ida_xref.fl_CN | ida_xref.XREF_USER) print ida_xref.add_cref(call.ea, to_addr, ida_xref.fl_CN | ida_xref.XREF_USER)
def activate(self, ctx): hx_view = idaapi.get_widget_vdui(ctx.widget) ri = self.extract_recast_info(hx_view.cfunc, hx_view.item) if not ri: return 0 if isinstance(ri, RecastLocalVariable): hx_view.set_lvar_type(ri.local_variable, ri.recast_tinfo) elif isinstance(ri, RecastGlobalVariable): idaapi.apply_tinfo2(ri.global_variable_ea, ri.recast_tinfo, idaapi.TINFO_DEFINITE) elif isinstance(ri, RecastArgument): if ri.recast_tinfo.is_array(): ri.recast_tinfo.convert_array_to_ptr() helper.set_func_argument(ri.func_tinfo, ri.arg_idx, ri.recast_tinfo) idaapi.apply_tinfo2(ri.func_ea, ri.func_tinfo, idaapi.TINFO_DEFINITE) elif isinstance(ri, RecastReturn): cfunc = helper.decompile_function(ri.func_ea) if not cfunc: return 0 func_tinfo = idaapi.tinfo_t() cfunc.get_func_type(func_tinfo) helper.set_func_return(func_tinfo, ri.recast_tinfo) idaapi.apply_tinfo2(cfunc.entry_ea, func_tinfo, idaapi.TINFO_DEFINITE) elif isinstance(ri, RecastStructure): tinfo = idaapi.tinfo_t() tinfo.get_named_type(idaapi.cvar.idati, ri.structure_name) ordinal = idaapi.get_type_ordinal(idaapi.cvar.idati, ri.structure_name) if ordinal == 0: return 0 udt_member = idaapi.udt_member_t() udt_member.offset = ri.field_offset * 8 idx = tinfo.find_udt_member(idaapi.STRMEM_OFFSET, udt_member) if udt_member.offset != ri.field_offset * 8: print("[Info] Can't handle with arrays yet") elif udt_member.type.get_size() != ri.recast_tinfo.get_size(): print("[Info] Can't recast different sizes yet") else: udt_data = idaapi.udt_type_data_t() tinfo.get_udt_details(udt_data) udt_data[idx].type = ri.recast_tinfo tinfo.create_udt(udt_data, idaapi.BTF_STRUCT) tinfo.set_numbered_type(idaapi.cvar.idati, ordinal, idaapi.NTF_REPLACE, ri.structure_name) else: raise NotImplementedError hx_view.refresh_view(True) return 0
def is_structure_offset(self, tinfo, offset): # Checks if structure tinfo contains a member at given offset # TODO:array checking udt_member = idaapi.udt_member_t() udt_member.offset = offset * 8 if offset >= 0 and tinfo.find_udt_member(idaapi.STRMEM_OFFSET, udt_member) != -1: if udt_member.type.is_udt(): return self.is_structure_offset(udt_member.type, offset - udt_member.offset / 8) return udt_member.offset == offset * 8 return False
def analyze_type(self, tinfo): """ parse type tinfo; adding unknown members to the local types as necessary return True if new types were added """ # print "analyze_type : "+str(tinfo) has_new_type = False if str(tinfo) in self.seen: return False else: self.seen.add(str(tinfo)) self.import_name(str(tinfo)) has_new_type = True # Struct or union ? Walk members if tinfo.is_udt(): # Hack to avoid problems with: # typedef struct _TOTO TOTO # IDA considers both _TOTO and TOTO as structs # this hack seems to fix it (maybe we could use # get_next_type_name) # print "---\t %s %s" % (tinfo.get_final_type_name(), str(tinfo)) if tinfo.get_final_type_name() == str(tinfo): # print "adding to structs" self.structs.add(str(tinfo)) u = idaapi.udt_member_t() # struct members for idx in range(0, tinfo.get_udt_nmembers()): u.offset = idx tinfo.find_udt_member(u, idaapi.STRMEM_INDEX) # print "member :"+str(u.type) # Recurse base type has_new_type = self.analyze_type(u.type) or has_new_type # AND also without pointer # to handle both shitty cases like : # - PVOID (pointer but not to struct) # - COMPLEX_STRUCT * if u.type.is_ptr_or_array(): no_ptr = u.type no_ptr.remove_ptr_or_array() has_new_type = self.analyze_type(no_ptr) or has_new_type # Some types are "proxies" like typedef # but IDA doesn't seem to be offer a way to # differenciate them easily next_t = tinfo.get_next_type_name() if next_t is not None and next_t not in self.seen: # print "import next: "+next_t self.import_name(next_t) has_new_type = True return has_new_type
def get_udt_member(self, offset=0): udt_member = idaapi.udt_member_t() tid = self.import_to_structures() if tid != idaapi.BADADDR: udt_member.name = self.name tmp_tinfo = idaapi.create_typedef(self.vtable_name) tmp_tinfo.create_ptr(tmp_tinfo) udt_member.type = tmp_tinfo udt_member.offset = self.offset - offset udt_member.size = const.EA_SIZE return udt_member
def get_udt_member(self, array_size=0, offset=0): udt_member = idaapi.udt_member_t() udt_member.name = "field_{0:X}".format(self.offset - offset) if self.name[:6] == "field_" else self.name udt_member.type = self.tinfo if array_size: tmp = idaapi.tinfo_t(self.tinfo) tmp.create_array(self.tinfo, array_size) udt_member.type = tmp udt_member.offset = self.offset - offset udt_member.size = self.size return udt_member
def get_udt_member(self, array_size=0, offset=0): udt_member = idaapi.udt_member_t() udt_member.name = "{}_{:x}".format( get_operand_size_type(self.tinfo), self.offset - offset) if re.match(r'(byte|(d|q|t|dq|)word|float|(d|dd)ouble)_', self.name) else self.name udt_member.type = self.tinfo if array_size: tmp = idaapi.tinfo_t(self.tinfo) tmp.create_array(self.tinfo, array_size) udt_member.type = tmp udt_member.offset = self.offset - offset udt_member.size = self.size return udt_member
def tinfo(self): udt = idaapi.udt_type_data_t() for m in self.members: new_member = idaapi.udt_member_t() new_member.name = m.name new_member.type = m.tinfo new_member.size = m.size new_member.offset = m.offset udt.push_back(new_member) final_tinfo = idaapi.tinfo_t() if final_tinfo.create_udt(udt, idaapi.BTF_STRUCT): return final_tinfo
def create_padding_udt_member(offset, size): # type: (long, long) -> idaapi.udt_member_t """ Creates internal IDA structure with name gap_XXX and appropriate size and offset """ udt_member = idaapi.udt_member_t() udt_member.name = "gap_{0:X}".format(offset) udt_member.offset = offset udt_member.size = size if size == 1: udt_member.type = const.BYTE_TINFO else: array_data = idaapi.array_type_data_t() array_data.base = 0 array_data.elem_type = const.BYTE_TINFO array_data.nelems = size tmp_tinfo = idaapi.tinfo_t() tmp_tinfo.create_array(array_data) udt_member.type = tmp_tinfo return udt_member
def check(cfunc, ctree_item): if ctree_item.citype != idaapi.VDI_EXPR: return item = ctree_item.it.to_specific_type if item.op != idaapi.cot_memptr: return parent = cfunc.body.find_parent_of(ctree_item.it).to_specific_type if parent.op != idaapi.cot_idx or parent.y.op != idaapi.cot_num: return idx = parent.y.n._value struct_type = item.x.type.get_pointed_object() udt_member = idaapi.udt_member_t() udt_member.offset = item.m * 8 struct_type.find_udt_member(idaapi.STRMEM_OFFSET, udt_member) if udt_member.name[0:3] != "gap": return return struct_type, udt_member.offset // 8, idx
def get_padding_member(offset, size): udt_member = idaapi.udt_member_t() if size == 1: udt_member.name = "gap_{0:X}".format(offset) udt_member.type = Const.BYTE_TINFO udt_member.size = Const.BYTE_TINFO.get_size() udt_member.offset = offset return udt_member array_data = idaapi.array_type_data_t() array_data.base = 0 array_data.elem_type = Const.BYTE_TINFO array_data.nelems = size tmp_tinfo = idaapi.tinfo_t() tmp_tinfo.create_array(array_data) udt_member.name = "gap_{0:X}".format(offset) udt_member.type = tmp_tinfo udt_member.size = size udt_member.offset = offset return udt_member
def load_struct(self): name = "" while True: name = idaapi.ask_str(name, idaapi.HIST_TYPE, "Enter type:") if name is None: return sid = idc.get_struc_id(name) if sid != idc.BADADDR: break self.default_name = name sid = idc.get_struc_id(name) if sid == idc.BADADDR: print(("Invalid Struct Name: %s" % name)) return tif = get_tinfo(name) sys.modules["__main__"].tif = tif nmembers = tif.get_udt_nmembers() for index in range(nmembers): u = idaapi.udt_member_t() u.offset = index if tif.find_udt_member(u, idaapi.STRMEM_INDEX) != -1: sys.modules["__main__"].udt = u member = Member(u.offset // 8, u.type, None) member.name = u.name # member.cmt = u.cmt # u.cmt doesn't work, so we will do something ugly _typename = tif.get_type_name() name_sid = idc.get_struc_id(_typename) member.cmt = idc.get_member_cmt( name_sid, u.offset // 8, 0) or "imported from {}".format(name) self.add_row(member)
def get_virtual_func_addresses(name, tinfo=None, offset=None): """ Returns set of possible addresses of virtual function by its name. If there're symbols in binary and name is the name of an overloaded function, then returns list of all address of this overloaded function. TODO: After implementing inheritance return set of methods of all child classes :param name: method name, can be mangled :param tinfo: class tinfo to which this method belong :param offset: virtual table offset :return: list of possible addresses """ address = idc.LocByName(name) if address != idaapi.BADADDR: return [address] raw_addresses = cache.demangled_names.get(name) if raw_addresses: addresses = [ea + idaapi.get_imagebase() for ea in raw_addresses] return addresses if tinfo is None or offset is None: return [] offset *= 8 udt_member = idaapi.udt_member_t() while tinfo.is_struct(): address = cache.demangled_names.get(tinfo.dstr() + '::' + name, idaapi.BADADDR) if address != idaapi.BADADDR: return [address + idaapi.get_imagebase()] udt_member.offset = offset tinfo.find_udt_member(idaapi.STRMEM_OFFSET, udt_member) tinfo = udt_member.type offset = offset - udt_member.offset
def create_padding_udt_member(offset, size): # type: (long, long) -> idaapi.udt_member_t """ Creates internal IDA structure with name gap_XXX and appropriate size and offset """ udt_member = idaapi.udt_member_t() udt_member.name = "gap_{0:X}".format(offset) udt_member.offset = offset udt_member.size = size if size == 1: udt_member.type = const.BYTE_TINFO else: if size < 1 or size > 0xffffffff: print( "HexRaysPyTools::core::helper::create_padding_udt_member: size is out of uint32 range (offset:{} size:{})" .format(offset, size)) array_data = idaapi.array_type_data_t() array_data.base = 0 array_data.elem_type = const.BYTE_TINFO array_data.nelems = size tmp_tinfo = idaapi.tinfo_t() tmp_tinfo.create_array(array_data) udt_member.type = tmp_tinfo return udt_member
def activate(self, ctx): hx_view = idaapi.get_tform_vdui(ctx.widget) result = self.check(hx_view.cfunc, hx_view.item) if result is None: return struct_tinfo, offset, idx = result ordinal = struct_tinfo.get_ordinal() struct_name = struct_tinfo.dstr() if (offset + idx) % 2: default_field_type = "_BYTE" elif (offset + idx) % 4: default_field_type = "_WORD" else: default_field_type = "_DWORD" declaration = idaapi.asktext( 0x10000, "{0} field_{1:X}".format(default_field_type, offset + idx), "Enter new structure member:" ) if declaration is None: return result = self.__parse_declaration(declaration) if result is None: return field_tinfo, field_name = result field_size = field_tinfo.get_size() udt_data = idaapi.udt_type_data_t() udt_member = idaapi.udt_member_t() struct_tinfo.get_udt_details(udt_data) udt_member.offset = offset * 8 struct_tinfo.find_udt_member(idaapi.STRMEM_OFFSET, udt_member) gap_size = udt_member.size // 8 gap_leftover = gap_size - idx - field_size if gap_leftover < 0: print "[ERROR] Too big size for the field. Type with maximum {0} bytes can be used".format(gap_size - idx) return iterator = udt_data.find(udt_member) iterator = udt_data.erase(iterator) if gap_leftover > 0: udt_data.insert(iterator, TemporaryStructureModel.get_padding_member(offset + idx + field_size, gap_leftover)) udt_member = idaapi.udt_member_t() udt_member.offset = offset * 8 + idx udt_member.name = field_name udt_member.type = field_tinfo udt_member.size = field_size iterator = udt_data.insert(iterator, udt_member) if idx > 0: udt_data.insert(iterator, TemporaryStructureModel.get_padding_member(offset, idx)) struct_tinfo.create_udt(udt_data, idaapi.BTF_STRUCT) struct_tinfo.set_numbered_type(idaapi.cvar.idati, ordinal, idaapi.BTF_STRUCT, struct_name) hx_view.refresh_view(True)
def get_member_name(tinfo, offset): udt_member = idaapi.udt_member_t() udt_member.offset = offset * 8 tinfo.find_udt_member(idaapi.STRMEM_OFFSET, udt_member) return udt_member.name
def activate(self, ctx): hx_view = idaapi.get_tform_vdui(ctx.form) result = self.check(hx_view.cfunc, hx_view.item) if result: if result[0] == RECAST_LOCAL_VARIABLE: tinfo, lvar = result[1:] if hx_view.set_lvar_type(lvar, tinfo): hx_view.refresh_view(True) elif result[0] == RECAST_GLOBAL_VARIABLE: tinfo, address = result[1:] if idaapi.apply_tinfo2(address, tinfo, idaapi.TINFO_DEFINITE): hx_view.refresh_view(True) elif result[0] == RECAST_ARGUMENT: arg_index, func_tinfo, arg_tinfo, address = result[1:] func_data = idaapi.func_type_data_t() func_tinfo.get_func_details(func_data) func_data[arg_index].type = arg_tinfo new_func_tinfo = idaapi.tinfo_t() new_func_tinfo.create_func(func_data) if idaapi.apply_tinfo2(address, new_func_tinfo, idaapi.TINFO_DEFINITE): hx_view.refresh_view(True) elif result[0] == RECAST_RETURN: return_type, func_address = result[1:] try: cfunc = idaapi.decompile( func_address) if func_address else hx_view.cfunc except idaapi.DecompilationFailure: print "[ERROR] Ida failed to decompile function" return function_tinfo = idaapi.tinfo_t() cfunc.get_func_type(function_tinfo) func_data = idaapi.func_type_data_t() function_tinfo.get_func_details(func_data) func_data.rettype = return_type function_tinfo.create_func(func_data) if idaapi.apply_tinfo2(cfunc.entry_ea, function_tinfo, idaapi.TINFO_DEFINITE): hx_view.refresh_view(True) elif result[0] == RECAST_STRUCTURE: structure_name, field_offset, new_type = result[1:] tinfo = idaapi.tinfo_t() tinfo.get_named_type(idaapi.cvar.idati, structure_name) ordinal = idaapi.get_type_ordinal(idaapi.cvar.idati, structure_name) if ordinal: udt_member = idaapi.udt_member_t() udt_member.offset = field_offset * 8 idx = tinfo.find_udt_member(idaapi.STRMEM_OFFSET, udt_member) if udt_member.offset != field_offset * 8: print "[Info] Can't handle with arrays yet" elif udt_member.type.get_size() != new_type.get_size(): print "[Info] Can't recast different sizes yet" else: udt_data = idaapi.udt_type_data_t() tinfo.get_udt_details(udt_data) udt_data[idx].type = new_type tinfo.create_udt(udt_data, idaapi.BTF_STRUCT) tinfo.set_numbered_type(idaapi.cvar.idati, ordinal, idaapi.NTF_REPLACE, structure_name) hx_view.refresh_view(True)
def hexrays_events_callback(*args): global potential_negatives hexrays_event = args[0] if hexrays_event == idaapi.hxe_populating_popup: form, popup, hx_view = args[1:] item = hx_view.item # current ctree_item_t if Actions.RecastItemRight.check(hx_view.cfunc, item): idaapi.attach_action_to_popup(form, popup, Actions.RecastItemRight.name, None) if Actions.RecastItemLeft.check(hx_view.cfunc, item): idaapi.attach_action_to_popup(form, popup, Actions.RecastItemLeft.name, None) if Actions.RenameOther.check(hx_view.cfunc, item): idaapi.attach_action_to_popup(form, popup, Actions.RenameOther.name, None) if Actions.RenameInside.check(hx_view.cfunc, item): idaapi.attach_action_to_popup(form, popup, Actions.RenameInside.name, None) if Actions.RenameOutside.check(hx_view.cfunc, item): idaapi.attach_action_to_popup(form, popup, Actions.RenameOutside.name, None) if hx_view.item.get_lvar() and Helper.is_legal_type(hx_view.item.get_lvar().type()): idaapi.attach_action_to_popup(form, popup, Actions.ShallowScanVariable.name, None) idaapi.attach_action_to_popup(form, popup, Actions.DeepScanVariable.name, None) idaapi.attach_action_to_popup(form, popup, Actions.RecognizeShape.name, None) if item.citype == idaapi.VDI_FUNC: # If we clicked on function if not hx_view.cfunc.entry_ea == idaapi.BADADDR: # Probably never happen idaapi.attach_action_to_popup(form, popup, Actions.AddRemoveReturn.name, None) idaapi.attach_action_to_popup(form, popup, Actions.ConvertToUsercall.name, None) idaapi.attach_action_to_popup(form, popup, Actions.DeepScanReturn.name, None) elif item.citype == idaapi.VDI_LVAR: # If we clicked on argument local_variable = hx_view.item.get_lvar() # idaapi.lvar_t if local_variable.is_arg_var: idaapi.attach_action_to_popup(form, popup, Actions.RemoveArgument.name, None) elif item.citype == idaapi.VDI_EXPR: if item.e.op == idaapi.cot_num: # number_format = item.e.n.nf # idaapi.number_format_t # print "(number) flags: {0:#010X}, type_name: {1}, opnum: {2}".format( # number_format.flags, # number_format.type_name, # number_format.opnum # ) idaapi.attach_action_to_popup(form, popup, Actions.GetStructureBySize.name, None) elif item.e.op == idaapi.cot_var: # Check if we clicked on variable that is a pointer to a structure that is potentially part of # containing structure if item.e.v.idx in potential_negatives: idaapi.attach_action_to_popup(form, popup, Actions.SelectContainingStructure.name, None) if Actions.ResetContainingStructure.check(hx_view.cfunc.get_lvars()[item.e.v.idx]): idaapi.attach_action_to_popup(form, popup, Actions.ResetContainingStructure.name, None) elif hexrays_event == idaapi.hxe_double_click: hx_view = args[1] item = hx_view.item if item.citype == idaapi.VDI_EXPR and item.e.op == idaapi.cot_memptr: # Look if we double clicked on expression that is member pointer. Then get tinfo_t of the structure. # After that remove pointer and get member name with the same offset if item.e.x.op == idaapi.cot_memref and item.e.x.x.op == idaapi.cot_memptr: vtable_tinfo = item.e.x.type.get_pointed_object() method_offset = item.e.m class_tinfo = item.e.x.x.x.type.get_pointed_object() vtable_offset = item.e.x.x.m elif item.e.x.op == idaapi.cot_memptr: vtable_tinfo = item.e.x.type.get_pointed_object() method_offset = item.e.m class_tinfo = item.e.x.x.type.get_pointed_object() vtable_offset = item.e.x.m else: return 0 udt_member = idaapi.udt_member_t() udt_member.offset = method_offset * 8 vtable_tinfo.find_udt_member(idaapi.STRMEM_OFFSET, udt_member) func_ea = Helper.get_virtual_func_address(udt_member.name, class_tinfo, vtable_offset) if func_ea: idaapi.open_pseudocode(func_ea, 0) return 1 elif hexrays_event == idaapi.hxe_maturity: cfunc, level_of_maturity = args[1:] if level_of_maturity == idaapi.CMAT_BUILT: # print '=' * 40 # print '=' * 15, "LEVEL", level_of_maturity, '=' * 16 # print '=' * 40 # print cfunc # First search for CONTAINING_RECORD made by Ida visitor = NegativeOffsets.SearchVisitor(cfunc) visitor.apply_to(cfunc.body, None) negative_lvars = visitor.result # Second get saved information from comments lvars = cfunc.get_lvars() for idx in xrange(len(lvars)): result = NegativeOffsets.parse_lvar_comment(lvars[idx]) if result and result.tinfo.equals_to(lvars[idx].type().get_pointed_object()): negative_lvars[idx] = result # Third make an analysis of local variables that a structure pointers and have reference that pass # through structure boundaries. This variables will be considered as potential pointers to substructure # and will get a menu on right click that helps to select Containing Structure from different libraries structure_pointer_variables = {} for idx in set(range(len(lvars))) - set(negative_lvars.keys()): if lvars[idx].type().is_ptr(): pointed_tinfo = lvars[idx].type().get_pointed_object() if pointed_tinfo.is_udt(): structure_pointer_variables[idx] = pointed_tinfo if structure_pointer_variables: visitor = NegativeOffsets.AnalyseVisitor(structure_pointer_variables, potential_negatives) visitor.apply_to(cfunc.body, None) if negative_lvars: visitor = NegativeOffsets.ReplaceVisitor(negative_lvars) visitor.apply_to(cfunc.body, None) elif level_of_maturity == idaapi.CMAT_TRANS2: # print '=' * 40 # print '=' * 15, "LEVEL", level_of_maturity, '=' * 16 # print '=' * 40 # print cfunc visitor = SpaghettiVisitor() visitor.apply_to(cfunc.body, None) return 0
def hexrays_events_callback(*args): if fDebug: pydevd.settrace('localhost', port=31337, stdoutToServer=True, stderrToServer=True, suspend=False) hexrays_event = args[0] from HexRaysPyTools.Config import hex_pytools_config if hexrays_event == idaapi.hxe_populating_popup: form, popup, hx_view = args[1:] item = hx_view.item # current ctree_item_t for ac in hex_pytools_config.actions_refs.values(): if ac.ForPopup and hex_pytools_config[ac.name] and ac.check(hx_view.cfunc,item): idaapi.attach_action_to_popup(form, popup, ac.name, None) # if Actions.RecastStructMember.check(hx_view.cfunc,item): # if hex_pytools_config[Actions.RecastStructMember.name]: # idaapi.attach_action_to_popup(form, popup, Actions.RecastStructMember.name, None) # # if Actions.SimpleCreateStruct.check(hx_view.cfunc,item): # if hex_pytools_config[Actions.SimpleCreateStruct.name]: # idaapi.attach_action_to_popup(form, popup, Actions.SimpleCreateStruct.name, None) # # if Actions.RecastItemRight.check(hx_view.cfunc, item): # if hex_pytools_config[Actions.RecastItemRight.name]: # idaapi.attach_action_to_popup(form, popup, Actions.RecastItemRight.name, None) # # if Actions.RecastItemLeft.check(hx_view.cfunc, item): # if hex_pytools_config[Actions.RecastItemLeft.name]: # idaapi.attach_action_to_popup(form, popup, Actions.RecastItemLeft.name, None) # # if Actions.RenameOther.check(hx_view.cfunc, item): # if hex_pytools_config[Actions.RenameOther.name]: # idaapi.attach_action_to_popup(form, popup, Actions.RenameOther.name, None) # # if Actions.RenameInside.check(hx_view.cfunc, item): # if hex_pytools_config[Actions.RenameInside.name]: # idaapi.attach_action_to_popup(form, popup, Actions.RenameInside.name, None) # # if Actions.RenameOutside.check(hx_view.cfunc, item): # if hex_pytools_config[Actions.RenameOutside.name]: # idaapi.attach_action_to_popup(form, popup, Actions.RenameOutside.name, None) # # if Actions.SwapThenElse.check(hx_view.cfunc, item): # if hex_pytools_config[Actions.SwapThenElse.name]: # idaapi.attach_action_to_popup(form, popup, Actions.SwapThenElse.name, None) # # if Actions.ShallowScanVariable.check(hx_view.cfunc, item): # if hex_pytools_config[Actions.ShallowScanVariable.name]: # idaapi.attach_action_to_popup(form, popup, Actions.ShallowScanVariable.name, None) # if hex_pytools_config[Actions.DeepScanVariable.name]: # idaapi.attach_action_to_popup(form, popup, Actions.DeepScanVariable.name, None) # if hex_pytools_config[Actions.RecognizeShape.name]: # idaapi.attach_action_to_popup(form, popup, Actions.RecognizeShape.name, None) # # if Actions.CreateNewField.check(hx_view.cfunc, item): # if hex_pytools_config[Actions.CreateNewField.name]: # idaapi.attach_action_to_popup(form, popup, Actions.CreateNewField.name, None) # # if Actions.CreateVtable.check(hx_view.cfunc, item): # if hex_pytools_config[Actions.CreateVtable.name]: # idaapi.attach_action_to_popup(form, popup, Actions.CreateVtable.name, None) # # if Actions.AddRemoveReturn.check(hx_view.cfunc, item) and hex_pytools_config[Actions.AddRemoveReturn.name]: # idaapi.attach_action_to_popup(form, popup, Actions.AddRemoveReturn.name, None) # if Actions.ConvertToUsercall.check(hx_view.cfunc, item) and hex_pytools_config[Actions.ConvertToUsercall.name]: # idaapi.attach_action_to_popup(form, popup, Actions.ConvertToUsercall.name, None) # if Actions.DeepScanReturn.check(hx_view.cfunc, item) and hex_pytools_config[Actions.DeepScanReturn.name]: # idaapi.attach_action_to_popup(form, popup, Actions.DeepScanReturn.name, None) # # if Actions.RemoveArgument.check(hx_view.cfunc,item) and hex_pytools_config[Actions.RemoveArgument.name]: # idaapi.attach_action_to_popup(form, popup, Actions.RemoveArgument.name, None) # # if Actions.GetStructureBySize.check(hx_view.cfunc,item) and hex_pytools_config[Actions.GetStructureBySize.name]: # idaapi.attach_action_to_popup(form, popup, Actions.GetStructureBySize.name, None) # # if Actions.SelectContainingStructure.check(hx_view.cfunc,item) and hex_pytools_config[Actions.SelectContainingStructure.name]: # idaapi.attach_action_to_popup(form, popup, Actions.SelectContainingStructure.name, None) # # if Actions.ResetContainingStructure.check(hx_view.cfunc,item): # if hex_pytools_config[Actions.ResetContainingStructure.name]: # idaapi.attach_action_to_popup(form, popup, Actions.ResetContainingStructure.name, None) elif hexrays_event == idaapi.hxe_double_click: hx_view = args[1] item = hx_view.item if item.citype == idaapi.VDI_EXPR and item.e.op == idaapi.cot_memptr: # Look if we double clicked on expression that is member pointer. Then get tinfo_t of the structure. # After that remove pointer and get member name with the same offset if item.e.x.op == idaapi.cot_memref and item.e.x.x.op == idaapi.cot_memptr: vtable_tinfo = item.e.x.type.get_pointed_object() method_offset = item.e.m class_tinfo = item.e.x.x.x.type.get_pointed_object() vtable_offset = item.e.x.x.m elif item.e.x.op == idaapi.cot_memptr: vtable_tinfo = item.e.x.type.get_pointed_object() method_offset = item.e.m class_tinfo = item.e.x.x.type.get_pointed_object() vtable_offset = item.e.x.m else: return 0 #print vtable_tinfo.get_type_name() #print method_offset udt_member = idaapi.udt_member_t() udt_member.offset = method_offset * 8 vtable_tinfo.find_udt_member(idaapi.STRMEM_OFFSET, udt_member) func_ea = Helper.get_virtual_func_address(udt_member.name, class_tinfo, vtable_offset) if func_ea: idaapi.open_pseudocode(func_ea, 0) return 1 n = Netnode("$ VTables") vt_name = vtable_tinfo.get_type_name() if vt_name in n: l = n[vt_name] #print l info = idaapi.get_inf_structure() if info.is_32bit(): ptr_size = 4 elif info.is_64bit(): ptr_size = 8 else: ptr_size = 2 if method_offset%ptr_size == 0 and method_offset/ptr_size < len(l): idaapi.open_pseudocode(l[method_offset/ptr_size] + idaapi.get_imagebase(), 0) elif hexrays_event == idaapi.hxe_maturity: cfunc, level_of_maturity = args[1:] if level_of_maturity == idaapi.CMAT_BUILT: # print '=' * 40 # print '=' * 15, "LEVEL", level_of_maturity, '=' * 16 # print '=' * 40 # print cfunc # First search for CONTAINING_RECORD made by Ida visitor = NegativeOffsets.SearchVisitor(cfunc) visitor.apply_to(cfunc.body, None) negative_lvars = visitor.result # Second get saved information from comments lvars = cfunc.get_lvars() for idx in xrange(len(lvars)): result = NegativeOffsets.parse_lvar_comment(lvars[idx]) if result and result.tinfo.equals_to(lvars[idx].type().get_pointed_object()): negative_lvars[idx] = result # Third make an analysis of local variables that a structure pointers and have reference that pass # through structure boundaries. This variables will be considered as potential pointers to substructure # and will get a menu on right click that helps to select Containing Structure from different libraries structure_pointer_variables = {} for idx in set(range(len(lvars))) - set(negative_lvars.keys()): if lvars[idx].type().is_ptr(): pointed_tinfo = lvars[idx].type().get_pointed_object() if pointed_tinfo.is_udt(): structure_pointer_variables[idx] = pointed_tinfo if structure_pointer_variables: visitor = NegativeOffsets.AnalyseVisitor(structure_pointer_variables, potential_negatives) visitor.apply_to(cfunc.body, None) if negative_lvars: visitor = NegativeOffsets.ReplaceVisitor(negative_lvars) visitor.apply_to(cfunc.body, None) elif level_of_maturity == idaapi.CMAT_TRANS1: visitor = SwapThenElseVisitor(cfunc.entry_ea) visitor.apply_to(cfunc.body, None) elif level_of_maturity == idaapi.CMAT_TRANS2: return 0 # print '=' * 15, "LEVEL", level_of_maturity, '=' * 16 # print '=' * 40 # print cfunc visitor = SpaghettiVisitor() visitor.apply_to(cfunc.body, None) return 0
def activate(self, ctx): hx_view = idaapi.get_widget_vdui(ctx.widget) if not self.check(hx_view): return item = hx_view.item.it.to_specific_type parent = hx_view.cfunc.body.find_parent_of(item).to_specific_type if parent.op != idaapi.cot_idx or parent.y.op != idaapi.cot_num: idx = 0 else: idx = parent.y.numval() struct_tinfo = item.x.type struct_tinfo.remove_ptr_or_array() offset = item.m ordinal = struct_tinfo.get_ordinal() struct_name = struct_tinfo.dstr() if (offset + idx) % 2: default_field_type = "_BYTE" elif (offset + idx) % 4: default_field_type = "_WORD" elif (offset + idx) % 8: default_field_type = "_DWORD" else: default_field_type = "_QWORD" if const.EA64 else "_DWORD" declaration = idaapi.ask_text( 0x10000, "{0} field_{1:X}".format(default_field_type, offset + idx), "Enter new structure member:" ) if declaration is None: return result = self.parse_declaration(declaration) if result is None: logger.warn("Bad member declaration") return field_tinfo, field_name = result field_size = field_tinfo.get_size() udt_data = idaapi.udt_type_data_t() udt_member = idaapi.udt_member_t() struct_tinfo.get_udt_details(udt_data) udt_member.offset = offset * 8 struct_tinfo.find_udt_member(udt_member, idaapi.STRMEM_OFFSET) gap_size = udt_member.size // 8 gap_leftover = gap_size - idx - field_size if gap_leftover < 0: logger.error("Too big size for the field. Type with maximum {0} bytes can be used".format(gap_size - idx)) return iterator = udt_data.find(udt_member) iterator = udt_data.erase(iterator) if gap_leftover > 0: udt_data.insert(iterator, helper.create_padding_udt_member(offset + idx + field_size, gap_leftover)) udt_member = idaapi.udt_member_t() udt_member.offset = offset * 8 + idx udt_member.name = field_name udt_member.type = field_tinfo udt_member.size = field_size iterator = udt_data.insert(iterator, udt_member) if idx > 0: udt_data.insert(iterator, helper.create_padding_udt_member(offset, idx)) struct_tinfo.create_udt(udt_data, idaapi.BTF_STRUCT) struct_tinfo.set_numbered_type(idaapi.cvar.idati, ordinal, idaapi.BTF_STRUCT, struct_name) hx_view.refresh_view(True)