def postprocess_action(self): self._plugin.logger.debug("postprocess_action()") if len(self.actions): name, ea = self.actions.pop() if name == "MakeUnknown": flags = ida_bytes.get_full_flags(ea) if ida_bytes.is_unknown(flags): self._send_packet(evt.MakeUnknown(ea)) elif name == "MakeCode": flags = ida_bytes.get_full_flags(ea) if ida_bytes.is_code(flags): self._send_packet(evt.MakeCodeEvent(ea))
def _try_map_byte(memory, ea, seg_ref): """Try to map a byte into memory.""" seg = _find_segment_containing_ea(ea, seg_ref) if not seg: return False can_write = 0 != (seg.perm & ida_segment.SEGPERM_WRITE) can_exec = _is_executable_seg(seg) val = 0 if ida_bytes.has_value(ida_bytes.get_full_flags(ea)): val = ida_bytes.get_wide_byte(ea) & 0xFF flags = ida_bytes.get_full_flags(ea) memory.map_byte(ea, val, can_write, can_exec) return True
def extract_operand(inst_t, op_n, x_set): # There are three types of data storage locations: registers, stack variables, and memory variables full_flags = ida_bytes.get_full_flags(inst_t.ea) if ida_bytes.is_stkvar(full_flags, op_n): varname = get_stkvar_name(inst_t, op_n) if varname: x_set.add(varname) return operand = inst_t.ops[op_n] if operand.type == ida_ua.o_void: # o_void: No Operand. return if operand.type == ida_ua.o_mem: x_set.add(operand.addr) return if operand.type == ida_ua.o_reg: x_set.add(operand.reg) return if operand.type == ida_ua.o_phrase: x_set.add((operand.reg, operand.phrase)) return if operand.type == ida_ua.o_displ: x_set.add((operand.reg, operand.phrase, operand.addr)) return
def get_ea_name(ea, fromaddr=idc.BADADDR, true=False, user=False): """Get the name of an address. This function returns the name associated with the byte at the specified address. Arguments: ea: The linear address whose name to find. Options: fromaddr: The referring address. Default is BADADDR. Some addresses have a location-specific name (for example, labels within a function). If fromaddr is not BADADDR, then this function will try to retrieve the name of ea from fromaddr's perspective. The global name will be returned if no location-specific name is found. true: Retrieve the true name rather than the display name. Default is False. user: Return "" if the name is not a user name. Returns: The name of the address or "". """ if user and not idc.hasUserName(ida_bytes.get_full_flags(ea)): return "" if true: return ida_name.get_ea_name(fromaddr, ea) else: return idc.get_name( ea, ida_name.GN_VISIBLE | idc.calc_gtn_flags(fromaddr, ea))
def __process_exports(self): exports = list() for i in range(0, ida_entry.get_entry_qty()): ordinal = ida_entry.get_entry_ordinal(i) ea = ida_entry.get_entry(ordinal) flags = ida_bytes.get_full_flags(ea) type = 'unknown' if ida_bytes.is_func(flags): type = 'function' elif ida_bytes.is_data(flags): type = 'data' export = { 'ordinal': ordinal, 'rva': ea - self._base, 'name': ida_entry.get_entry_name(ordinal), 'type': type } exports.append(export) return exports
def create_object(obj, overwrite_names, offset, dummy_names=True, always_thumb=True): name = obj.get("name") addr = int(obj.get("addr")) addr = int(addr) size = int(obj.get("size")) if dummy_names: if IDAtools.is_dummy_name(name): return if type(addr) == int: if ida_bytes.is_unknown(ida_bytes.get_full_flags(addr)): if size: ok = idaapi.create_data(addr, idc.FF_BYTE, size, 0) else: ok = idc.create_byte(addr) if not ok: if not ok: reason = "Could not create data at {addr:#x}".format( addr=addr) print(reason) if overwrite_names and IDAtools.is_dummy_name_by_addr(addr): ok = idc.set_name(addr, name, idc.SN_CHECK) if not ok: reason = "Could not add name {name} at {addr:#x}".format( name=name, addr=addr) print(reason) IDAtools.ida_wait()
def extract_all_user_names(filename=None): """ Get all user-named labels inside IDA. Also prints into output window. :return: dictionary of all user named labels: label_name -> ea """ results = {} output = '' for ea, name in idautils.Names(): if ida_kernwin.user_cancelled(): return results if '_' in name: if name.split('_')[0] in ('def', 'sub', 'loc', 'jpt', 'j', 'nullsub'): continue flags = ida_bytes.get_full_flags(ea) if ida_bytes.has_user_name(flags): results[name] = ea output += '{} = 0x{:08x};\n'.format(name, ea) if filename is not None: with open(filename, 'w') as f: f.write(output) return results
def guess_dummy_type(self, interface_ea): if self.dummy: if is_struct(get_full_flags(interface_ea)): return t = guess_type(interface_ea) if t is not None: next(self.members()).type = t
def _process_stubs_section(segstart, make_thunk, next_stub): """Process all the functions in a __stubs section.""" segend = idc.get_segm_end(segstart) # We'll go through each address and check if it has a reference. If it does, it is likely a # stub. As long as the address doesn't already have a stub name, process it. for ea in idau.Addresses(segstart, segend, step=1): if idc.isRef(ida_bytes.get_full_flags(ea)) and not stub_name_target( idau.get_ea_name(ea)): _process_possible_stub(ea, make_thunk, next_stub)
def flags(self): """ Property for getting the flags of the element. Those flags are the one from ida such as returned by ``ida_bytes.get_full_flags``. :return: The flags for the element :rtype: int """ return ida_bytes.get_full_flags(self.ea)
def _function_name(ea): """Try to get the name of a function.""" try: flags = ida_bytes.get_full_flags(ea) if ida_bytes.has_name(flags): return ida_funcs.get_func_name(ea) except: pass return "sub_{:x}".format(ea)
def name(self): ea = self.address() try: flags = ida_bytes.get_full_flags(ea) if ida_bytes.has_name(flags): return ida_name.get_ea_name(ea) except: pass return ""
def _variable_name(ea): """Return the name of a variable.""" try: flags = ida_bytes.get_full_flags(ea) if ida_bytes.has_name(flags): return ida_name.get_ea_name(ea) except: pass return ""
def op_type_changed(self, ea, n): self._plugin.logger.debug("op_type_changed(ea = %x, n = %d)" % (ea, n)) def gather_enum_info(ea, n): id = ida_bytes.get_enum_id(ea, n)[0] serial = ida_enum.get_enum_idx(id) return id, serial extra = {} mask = ida_bytes.MS_0TYPE if not n else ida_bytes.MS_1TYPE flags = ida_bytes.get_full_flags(ea) self._plugin.logger.debug("op_type_changed: flags = 0x%X)" % flags) def is_flag(type): return flags & mask == mask & type if is_flag(ida_bytes.hex_flag()): op = "hex" elif is_flag(ida_bytes.dec_flag()): op = "dec" elif is_flag(ida_bytes.char_flag()): op = "chr" elif is_flag(ida_bytes.bin_flag()): op = "bin" elif is_flag(ida_bytes.oct_flag()): op = "oct" elif is_flag(ida_bytes.off_flag()): op = "offset" elif is_flag(ida_bytes.enum_flag()): op = "enum" id, serial = gather_enum_info(ea, n) ename = ida_enum.get_enum_name(id) extra["ename"] = Event.decode(ename) extra["serial"] = serial elif flags & ida_bytes.stroff_flag(): op = "struct" path = ida_pro.tid_array(1) delta = ida_pro.sval_pointer() path_len = ida_bytes.get_stroff_path(path.cast(), delta.cast(), ea, n) spath = [] for i in range(path_len): sname = ida_struct.get_struc_name(path[i]) spath.append(Event.decode(sname)) extra["delta"] = delta.value() extra["spath"] = spath elif is_flag(ida_bytes.stkvar_flag()): op = "stkvar" # FIXME: No hooks are called when inverting sign # elif ida_bytes.is_invsign(ea, flags, n): # op = 'invert_sign' else: return 0 # FIXME: Find a better way to do this self._send_packet(evt.OpTypeChangedEvent(ea, n, op, extra)) return 0
def instr_iter(self): """ Return a generator of :class:`BipInstr` corresponding to the instructions of the basicblock. This implementation will be just a little more performant than the :meth:`instr` property. :return: A generator of object :class:`BipInstr` . """ for h in idautils.Heads(self.ea, self.end): if idc.is_code(ida_bytes.get_full_flags(h)): yield bip.base.instr.BipInstr(h)
def instr(self): """ Return a list of :class:`BipInstr` corresponding to the instructions of the basicblock. :return: A list of object :class:`BipInstr` . """ return [ bip.base.instr.BipInstr(h) for h in idautils.Heads(self.ea, self.end) if idc.is_code(ida_bytes.get_full_flags(h)) ]
def is_dummy_name(self): """ Property for checking if the current name of this function is a "dummy" name (a name set by default by IDA when it does not know how to call an element) with a special prefix. This function will not recognize the ``aSTRING`` naming, see :meth:`~BipFunction.is_auto_name`, and :meth:`~BipFunction.is_ida_name`. :return: ``True`` if the function has a dummy name, ``False`` otherwise. """ return ida_bytes.has_dummy_name(ida_bytes.get_full_flags(self.ea))
def is_user_name(self): """ Property for checking if the current name is a "user name". In practice this check a flag that the API can avoid setting, so there is no garantee it is an actual user name. See :meth:`~BipFunction.is_ida_name` for checking if a name was generated by IDA. :return: ``True`` if the name is marked as set by a user, ``False`` otherwise. """ return ida_bytes.has_user_name(ida_bytes.get_full_flags(self.ea))
def is_auto_name(self): """ Property for checking if the current name of this function is an "auto-generated" name, those are the default name generated by IDA but without a special prefix (see :meth:`~BipFunction.is_dummy_name`) such as the one for the string. See also :meth:`~BipFunction.is_ida_name`. :return: ``True`` if the function has an auto-generated name, ``False`` otherwise. """ return ida_bytes.has_auto_name(ida_bytes.get_full_flags(self.ea))
def _has_code(self): """ Checks if any address in the changed data area has code in it :return: (int) address of the code start, or None. """ for i in xrange(self.data): maybe_start_of_item = ida_bytes.get_item_head(self.address + i) if ida_bytes.is_code( ida_bytes.get_full_flags(maybe_start_of_item)): return self.address + i return None
def get_conflict(self): """ :return: None if there's no conflict, empty string if there's no change, data if there's a change. """ # TODO: Fill docstring, plus, make the function return 0,1,2 and save the current data by itself. code_address = self._has_code() if code_address: return 'Code: 0x%x' % code_address num_of_elements = self._get_num_of_elements() data_undefined = True for i in xrange(self.data): ea_flags = ida_bytes.get_full_flags(self.address + i) if ea_flags & 0x400: # Data defined data_undefined = False if data_undefined: return None # No conflict # Iterate over all local data, and check if there's any conflict with the type conflict = '' for i in xrange(num_of_elements): current_address = self.address + ( i * self.TYPE_TO_SIZE[self.data_type]) current_address = ida_bytes.get_item_head(current_address) ea_flags = ida_bytes.get_full_flags(current_address) if not ida_bytes.is_data(ea_flags): conflict += 'unknown at 0x%x\n' % current_address continue current_data_type = ea_flags & ida_bytes.DT_TYPE if self.data_type != current_data_type: # Different data conflict += '%s at 0x%x\n' % ( self.TYPE_TO_NAME[current_data_type], current_address) if conflict: return conflict # TODO: Deal with the case it's just multiple type definitions in the area? return '' # No difference
def op_type_changed(self, ea, n): def gather_enum_info(ea, n): id = ida_bytes.get_enum_id(ea, n)[0] serial = ida_enum.get_enum_idx(id) return id, serial extra = {} mask = ida_bytes.MS_0TYPE if not n else ida_bytes.MS_1TYPE flags = ida_bytes.get_full_flags(ea) & mask def is_flag(type): return flags == mask & type if is_flag(ida_bytes.hex_flag()): op = 'hex' elif is_flag(ida_bytes.dec_flag()): op = 'dec' elif is_flag(ida_bytes.char_flag()): op = 'chr' elif is_flag(ida_bytes.bin_flag()): op = 'bin' elif is_flag(ida_bytes.oct_flag()): op = 'oct' elif is_flag(ida_bytes.enum_flag()): op = 'enum' id, serial = gather_enum_info(ea, n) ename = ida_enum.get_enum_name(id) extra['ename'] = Event.decode(ename) extra['serial'] = serial elif is_flag(flags & ida_bytes.stroff_flag()): op = 'struct' path = ida_pro.tid_array(1) delta = ida_pro.sval_pointer() path_len = ida_bytes.get_stroff_path(path.cast(), delta.cast(), ea, n) spath = [] for i in range(path_len): sname = ida_struct.get_struc_name(path[i]) spath.append(Event.decode(sname)) extra['delta'] = delta.value() extra['spath'] = spath elif is_flag(ida_bytes.stkvar_flag()): op = 'stkvar' # IDA hooks for is_invsign seems broken # Inverting sign don't trigger the hook # elif ida_bytes.is_invsign(ea, flags, n): # op = 'invert_sign' else: return 0 # FIXME: Find a better way self._send_event(OpTypeChangedEvent(ea, n, op, extra)) return 0
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 _convert_address_to_function(func): """Convert an address that IDA has classified incorrectly into a proper function.""" # If everything goes wrong, we'll try to restore this function. orig = idc.first_func_chunk(func) # If the address is not code, let's undefine whatever it is. if not ida_bytes.is_code(ida_bytes.get_full_flags(func)): if not is_mapped(func): # Well, that's awkward. return False item = ida_bytes.get_item_head(func) itemend = ida_bytes.get_item_end(func) if item != idc.BADADDR: _log(1, 'Undefining item {:#x} - {:#x}', item, itemend) ida_bytes.del_items(item, ida_bytes.DELIT_EXPAND) idc.create_insn(func) # Give IDA a chance to analyze the new code or else we won't be able to create a # function. #ida_auto.auto_wait() autoanalyze() idc.plan_and_wait(item, itemend) else: # Just try removing the chunk from its current function. IDA can add it to another function # automatically, so make sure it's removed from all functions by doing it in loop until it # fails. for i in range(1024): if not idc.remove_fchunk(func, func): break # Now try making a function. if ida_funcs.add_func(func) != 0: return True # This is a stubborn chunk. Try recording the list of chunks, deleting the original function, # creating the new function, then re-creating the original function. if orig != idc.BADADDR: chunks = list(idautils.Chunks(orig)) if ida_funcs.del_func(orig) != 0: # Ok, now let's create the new function, and recreate the original. if ida_funcs.add_func(func) != 0: if ida_funcs.add_func(orig) != 0: # Ok, so we created the functions! Now, if any of the original chunks are not # contained in a function, we'll abort and undo. if all(idaapi.get_func(start) for start, end in chunks): return True # Try to undo the damage. for start, _ in chunks: ida_funcs.del_func(start) # Everything we've tried so far has failed. If there was originally a function, try to restore # it. if orig != idc.BADADDR: _log(0, 'Trying to restore original function {:#x}', orig) ida_funcs.add_func(orig) return False
def get_conflict(self): """ :return: None if there's no conflict, empty string if there's no change, data if there's a change. """ # TODO: Fill docstring, plus, make the function return 0,1,2 and save the current data by itself. conflicts = "" conflict_flag = False for i in xrange(self.data): current_address = self.address + i head_address = ida_bytes.get_item_head(current_address) if ida_bytes.is_code(ida_bytes.get_full_flags(head_address)): conflict_flag = True ea_flags = ida_bytes.get_full_flags(head_address) if not ida_bytes.is_data(ea_flags): continue conflict_flag = True conflicts += '%s at 0x%x\n' % ( self.TYPE_TO_NAME[ea_flags & ida_bytes.DT_TYPE], head_address) if conflict_flag: return conflicts return None
def is_dummy_name_by_addr(addr): name = idc.get_name(addr) dummyList = { "", "sub_", "locret_", "loc_", "off_", "seg_", "asc_", "byte_", "word_", "dword_", "qword_", "byte3_", "xmmword", "_ymmword_", "packreal_", "flt_", "dbl_", "tbyte_", "stru_", "custdata_", "algn_", "unk_" } if ida_bytes.is_unknown(ida_bytes.get_full_flags(addr)): return True for items in dummyList: if name.startswith(items): return True return False
def __process_functions(self): functions = list() start = ida_ida.cvar.inf.min_ea end = ida_ida.cvar.inf.max_ea # find first function head chunk in the range chunk = ida_funcs.get_fchunk(start) if not chunk: chunk = ida_funcs.get_next_fchunk(start) while chunk and chunk.start_ea < end and (chunk.flags & ida_funcs.FUNC_TAIL) != 0: chunk = ida_funcs.get_next_fchunk(chunk.start_ea) func = chunk while func and func.start_ea < end: start_ea = func.start_ea func_flags = ida_bytes.get_full_flags(start_ea) func_name = ida_funcs.get_func_name(start_ea) func_name_demangled = ida_name.get_demangled_name( start_ea, 0xFFFF, 0, 0) func_autonamed = func_flags & ida_bytes.FF_LABL != 0 func_public = ida_name.is_public_name(start_ea) function = { 'start_rva': start_ea - self._base, 'name': func_name, 'name_demangled': func_name_demangled, 'is_public': func_public, 'is_autonamed': func_autonamed } # PE32/PE32+ only support binaries up to 2GB if function['start_rva'] >= 2**32: print('RVA out of range for function: ' + function['name'], file=sys.stderr) self.__process_function_typeinfo(function, func) function['labels'] = self.__process_function_labels(func) functions.append(function) func = ida_funcs.get_next_func(start_ea) return functions
def test_bipelt00(): # ea, flags, size assert BipElt(0x01800D325A).ea == 0x01800D325A assert BipElt(0x01800D325A).flags == ida_bytes.get_full_flags(0x01800D325A) assert BipElt(0x01800D325A).size == 4 assert BipElt(0x018015D260).size == 1 assert BipElt(0x018015D228).size == 8 # bytes assert BipElt(0x01800D325A).bytes == [0x48, 0x83, 0xC4, 0x60] BipElt(0x01800D325A).bytes = [0x90, 0x90, 0x90, 0x90] assert BipElt(0x01800D325A).bytes == [0x90, 0x90, 0x90, 0x90] assert BipElt(0x01800D325A).original_bytes == [0x48, 0x83, 0xC4, 0x60] BipElt(0x01800D325A).bytes = b"\xAA" * 4 assert BipElt(0x01800D325A).bytes == [0xAA, 0xAA, 0xAA, 0xAA] BipElt(0x01800D325A).bytes = [0x48, 0x83, 0xC4, 0x60] assert BipElt(0x01800D325A).bytes == [0x48, 0x83, 0xC4, 0x60] # name assert BipElt(0x01800D325A).name == 'loc_1800D325A' assert BipElt(0x01800D325A).is_dummy_name assert not BipElt(0x01800D325A).is_auto_name assert BipElt(0x01800D325A).is_ida_name assert not BipElt(0x01800D325A).is_user_name ie = BipElt(0x01800D325A) prevname = ie.name ie.name = "idaelt_test" assert ie.name == "idaelt_test" assert not BipElt(0x01800D325A).is_dummy_name assert not BipElt(0x01800D325A).is_auto_name assert not BipElt(0x01800D325A).is_ida_name assert BipElt(0x01800D325A).is_user_name ie.name = None assert BipElt(0x01800D325A).name == 'loc_1800D325A' assert BipElt(0x01800D325A).is_dummy_name assert not BipElt(0x01800D325A).is_auto_name assert BipElt(0x01800D325A).is_ida_name assert not BipElt(0x01800D325A).is_user_name assert BipElt(0x018014F7FF).is_auto_name assert not BipElt(0x018014F7FF).is_dummy_name assert BipElt(0x018014F7FF).is_ida_name assert BipElt(0x0180125828).demangle_name is None # TODO: need other binary for demangle name # color assert BipElt(0x01800D325A).color == idc.get_color(0x01800D325A, idc.CIC_ITEM) ie = BipElt(0x01800D325A) prevcolor = ie.color ie.color = 0xAABBCC assert ie.color == 0xAABBCC ie.color = prevcolor
def search_str_addr(s, start_ea=None, end_ea=None, down=True, nxt=True): """ Static method for searching a string. In practice this perform a search_bytes on the binary by encoding correctly the string passed in argument and returning only reference to data elements. .. warning:: This is different from idapython ``FindText`` method as this will only search for bytes in the binary (and more precisely the data)! It should also be way faster. .. todo:: this should allow to handle encoding. :param str s: The C string for which to search. If the string is NULL terminated the NULL byte must be included. :param start_ea: The address at which to start the search, if ``None`` the current address will be used. :param end_ea: The address at which to stop the search, if ``None`` the maximum or minimum (depending of searching up or down) will be used. :param down: If True (the default) search below the given address, if False search above. :param nxt: If True (the default) the current element will not be included in the search. :return: The address at which the string was found. It will always be data. If no matching element was found None will be return. """ # lets encode the string byt = " ".join(["{:X}".format(ord(c)) for c in s]) # we want to skip everything which is not data without making the # search, this should be faster curr_addr = BipElt.next_data_addr(start_ea, down=down) while curr_addr is not None: curr_addr = BipElt.search_bytes_addr(byt, start_ea=curr_addr, end_ea=end_ea, down=down, nxt=nxt) if curr_addr is None: return None # not found if idc.is_data(ida_bytes.get_full_flags(curr_addr)): return curr_addr # found! # lets continue curr_addr = BipElt.next_data_addr(curr_addr, down=down) return None # not found
def op_type_changed(self, ea, n): extra = {} mask = ida_bytes.MS_0TYPE if not n else ida_bytes.MS_1TYPE flags = ida_bytes.get_full_flags(ea) & mask if flags == mask & ida_bytes.hex_flag(): op = 'hex' elif flags == mask & ida_bytes.dec_flag(): op = 'dec' elif flags == mask & ida_bytes.char_flag(): op = 'chr' elif flags == mask & ida_bytes.bin_flag(): op = 'bin' elif flags == mask & ida_bytes.oct_flag(): op = 'oct' elif flags == mask & ida_bytes.enum_flag(): op = 'enum' enum_id = ida_bytes.get_enum_id(ea, n)[0] enum_serial = ida_enum.get_enum_idx(enum_id) ename = ida_enum.get_enum_name(enum_id) extra['ename'] = Unicoder.decode(ename) extra['serial'] = enum_serial elif flags == mask & ida_bytes.stroff_flag(): op = 'struct' path = ida_pro.tid_array(1) delta = ida_pro.sval_pointer() path_len = ida_bytes.get_stroff_path(path.cast(), delta.cast(), ea, n) spath = [] for i in range(path_len): sname = ida_struct.get_struc_name(path[i]) spath.append(Unicoder.decode(sname)) extra['delta'] = delta.value() extra['spath'] = spath elif flags == mask & ida_bytes.stkvar_flag(): op = 'stkvar' else: return 0 self._network.send_event( EventType.OPTYPECHANGED, ea=ea, n=n, op=Unicoder.decode(op), extra=extra, ) return 0
def _is_address_of_struct_field(ea): prev_head_ea = idc.prev_head(ea) if is_invalid_ea(prev_head_ea): return False prev_item_size = idc.get_item_size(prev_head_ea) if ea >= (prev_head_ea + prev_item_size): return False # Try to get a type for the last item head. flags = ida_bytes.get_full_flags(ea) ti = ida_nalt.opinfo_t() oi = ida_bytes.get_opinfo(ti, ea, 0, flags) if not oi: return False # Get the size of the struct, and keep going if the suze of the previous # item is a multiple of the struct's size (e.g. one struct or an array # of that struct). struct_size = idc.get_struc_size(oi.tid) if not struct_size or 0 != (prev_item_size % struct_size): return False # Figure out the offset of `ea` within its structure, which may belong to # an array of structures, and then check if that offset is associated with # a named field. arr_index = int((ea - prev_head_ea) / struct_size) struct_begin_ea = (arr_index & struct_size) + prev_head_ea off_in_struct = ea - struct_begin_ea if not idc.get_member_name(oi.tid, off_in_struct): return False field_begin_ea = struct_begin_ea + off_in_struct if field_begin_ea != ea: return False field_size = idc.GetMemberSize(oi.tid, off_in_struct) if not field_size: return False return True