def struc_member_changed(self, sptr, mptr): #print(f"struc member changed: {sptr.id}, {mptr.id}") # struct pointer is actually a stack frame if sptr.is_frame(): stack_frame = sptr func_addr = idaapi.get_func_by_frame(stack_frame.id) try: all_var_info = compat.get_func_stack_var_info(func_addr) stack_var_info = all_var_info[compat.ida_to_angr_stack_offset( func_addr, mptr.soff)] except KeyError: l.debug( f"Failed to track an internal changing stack var: {mptr.id}." ) return 0 # find the properties of the changed stack var angr_offset = compat.ida_to_angr_stack_offset( func_addr, stack_var_info.stack_offset) size = stack_var_info.size type_str = stack_var_info.type new_name = stack_var_info.name #ida_struct.get_member_name(mptr.id) # do the change on a new thread sv = StackVariable(angr_offset, StackOffsetType.IDA, new_name, type_str, size, func_addr) self.binsync_state_change(self.controller.push_artifact, sv) else: self.ida_struct_changed(sptr.id) return 0
def struc_member_renamed(self, sptr, mptr): #print(f"struc member renamed: {sptr.id}: {mptr.id}") """ Handles renaming of two things: 1. Global Structs 2. Stack Variables :param sptr: Struct Pointer :param mptr: Member Pointer :return: """ # struct pointer is actually a stack frame if sptr.is_frame(): stack_frame = sptr func_addr = idaapi.get_func_by_frame(stack_frame.id) try: stack_var_info = compat.get_func_stack_var_info(func_addr)[ compat.ida_to_angr_stack_offset(func_addr, mptr.soff)] except KeyError: l.debug( f"Failed to track an internal changing stack var: {mptr.id}." ) return 0 # find the properties of the changed stack var angr_offset = compat.ida_to_angr_stack_offset( func_addr, stack_var_info.stack_offset) size = stack_var_info.size type_str = stack_var_info.type # TODO: correct this fix in the get_func_stack_var_info new_name = ida_struct.get_member_name(mptr.id) # do the change on a new thread sv = StackVariable(angr_offset, StackOffsetType.IDA, new_name, type_str, size, func_addr) self.binsync_state_change(self.controller.push_artifact, sv) # an actual struct else: self.ida_struct_changed(sptr.id) return 0
def add_auto_comment(self, ea, text): if ea is not None: prefix = "" if idaapi.get_struc(ea) is not None: if idc.GetStrucIdx(ea) == idc.BADADDR: prefix = "stackframe '%s'" % idc.GetFunctionName( idaapi.get_func_by_frame(ea)) else: prefix = "structure '%s'" % idc.GetStrucName(ea) elif idc.GetEnumIdx(ea) != idc.BADADDR: prefix = "enum '%s'" % idc.GetEnumName(ea) else: foffset = idc.GetFuncOffset(ea) if foffset is None: prefix = yatools.ea_to_hex(ea) else: prefix = "%s,%s" % (yatools.ea_to_hex(ea), foffset) self.auto_comments.add((prefix, text)) else: self.auto_comments.add(("", text))
def save_strucs(self, ida_model, memory_exporter): """ Structures : export modified structures and delete those who have been deleted """ for struc_id in self.structures_to_process: sidx = idc.GetStrucIdx(struc_id) if sidx is None or sidx == idc.BADADDR: # it is a deleted structure or a stackframe # in this last case we need to export the parent (function) eaFunc = idaapi.get_func_by_frame(struc_id) if eaFunc != idc.BADADDR: # OK, it is a stackframe ida_model.accept_struct(memory_exporter, eaFunc, struc_id) ida_model.accept_ea(memory_exporter, eaFunc) else: # it is a deleted structure ida_model.delete_struct(memory_exporter, struc_id) else: ida_model.accept_struct(memory_exporter, idc.BADADDR, struc_id) logger.debug("Walking members") """ Structure members : update modified ones, and remove deleted ones We iterate over members : -if the parent struc has been deleted, delete the member -otherwise, detect if the member has been updated or removed -updated : accept struc_member + accept_struct if not already exported! -removed : accept struc_member_deleted """ for (struc_id, member_set) in self.strucmember_to_process.iteritems(): ida_struc = idaapi.get_struc(struc_id) logger.debug("Walking struc 0x%08X" % struc_id) sidx = idc.GetStrucIdx(struc_id) is_stackframe = False struc_deleted = False if sidx is None or sidx == idc.BADADDR: f = idaapi.get_func_by_frame(struc_id) if f is not None and f != idc.BADADDR: is_stackframe = True else: struc_deleted = True stackframe_func_addr = idc.BADADDR if is_stackframe: eaFunc = idaapi.get_func_by_frame(struc_id) stackframe_func_addr = eaFunc ida_model.accept_function(memory_exporter, eaFunc) if struc_deleted: # The structure has been deleted : we need to delete the members # Note: at first sight, it is not a stackframe # TODO: handle function->stackframe deletion here for (member_id, offset) in member_set: ida_model.delete_struct_member(memory_exporter, idc.BADADDR, struc_id, offset) else: # The structure or stackframe has been modified for (member_id, offset) in member_set: ida_member = idaapi.get_member(ida_struc, offset) if ida_member is None: new_member_id = -1 else: new_member_id = ida_member.id if new_member_id == -1: # the member has been deleted : delete it ida_model.delete_struct_member(memory_exporter, stackframe_func_addr, struc_id, offset) elif offset > 0 and idc.GetMemberId( struc_id, offset - 1) == new_member_id: # the member was deleted, and replaced by a member starting above it ida_model.delete_struct_member(memory_exporter, stackframe_func_addr, struc_id, offset) else: # the member has just been modified ida_model.accept_struct_member(memory_exporter, stackframe_func_addr, ida_member.id)
def refs(self): """Return the (address, opnum, type) of all the references (code & data) to this structure within the database. If `opnum` is None, then the `address` has the structure applied to it. If `opnum` is defined, then the instruction at `address` references a field that is the specified structure. """ x, sid = idaapi.xrefblk_t(), self.id # grab first reference to structure ok = x.first_to(sid, 0) if not ok: return [] # collect rest of it's references refs = [(x.frm, x.iscode, x.type)] while x.next_to(): refs.append((x.frm, x.iscode, x.type)) # calculate the high-byte which is used to differentiate an address from a structure bits = math.trunc(math.ceil(math.log(idaapi.BADADDR) / math.log(2.0))) highbyte = 0xff << (bits - 8) # iterate through figuring out if sid is applied to an address or another structure res = [] for ref, _, _ in refs: # structure (probably a frame member) if ref & highbyte == highbyte: # get sptr, mptr name = idaapi.get_member_fullname(ref) mptr, _ = idaapi.get_member_by_fullname(name) if not isinstance(mptr, idaapi.member_t): cls = self.__class__ raise TypeError( "{:s} : Unexpected type {!r} for netnode '{:s}'". format('.'.join((__name__, cls.__name__)), mptr.__class__, name)) sptr = idaapi.get_sptr(mptr) # get frame, func_t frname, _ = name.split('.', 2) frid = internal.netnode.get(frname) ea = idaapi.get_func_by_frame(frid) f = idaapi.get_func(ea) # now find all xrefs to member within function xl = idaapi.xreflist_t() idaapi.build_stkvar_xrefs(xl, f, mptr) # now we can add it for xr in xl: ea, opnum, state = xr.ea, int( xr.opnum), instruction.op_state(ea, opnum) res.append( interface.OREF(ea, opnum, interface.ref_t.of_state(state))) continue # address res.append(interface.OREF(ref, None, interface.ref_t.of_state( '*'))) # using '*' to describe being applied to the an address return res
def refs(self): '''Return the (address, opnum, type) of all the references to this member within the database.''' mid = self.id # calculate the high-byte which is used to determine an address from a structure bits = int(math.ceil(math.log(idaapi.BADADDR) / math.log(2.0))) highbyte = 0xff << (bits - 8) # if structure is a frame.. if internal.netnode.name.get(self.__owner.id).startswith('$ '): name, mptr = self.fullname, self.ptr sptr = idaapi.get_sptr(mptr) # get frame, func_t frname, _ = name.split('.', 2) frid = internal.netnode.get(frname) ea = idaapi.get_func_by_frame(frid) f = idaapi.get_func(ea) # now find all xrefs to member within function xl = idaapi.xreflist_t() idaapi.build_stkvar_xrefs(xl, f, mptr) # now we can add it res = [] for xr in xl: ea, opnum = xr.ea, int(xr.opnum) res.append( interface.OREF( ea, opnum, interface.ref_t(xr.type, instruction.op_state(ea, opnum)))) # FIXME return res # otherwise, it's a structure..which means we need to specify the member to get refs for x = idaapi.xrefblk_t() ok = x.first_to(mid, 0) if not ok: return [] # collect all references available refs = [(x.frm, x.iscode, x.type)] while x.next_to(): refs.append((x.frm, x.iscode, x.type)) # now figure out which operand has the structure member applied to it res = [] for ea, _, t in refs: ops = ((idx, internal.netnode.sup.get(ea, 0xf + idx)) for idx in range(idaapi.UA_MAXOP) if internal.netnode.sup.get(ea, 0xf + idx) is not None) ops = ((idx, interface.node.sup_opstruct( val, idaapi.get_inf_structure().is_64bit())) for idx, val in ops) ops = (idx for idx, ids in ops if self.__owner.id in ids) # sanity res.extend( interface.OREF(ea, int(op), interface.ref_t.of(t)) for op in ops) return res
def save_strucs(self, memory_exporter): """ Structures : export modified structures and delete those who have been deleted """ for struc_id in self.structures_to_process: self.ida_model.clear_exported_struc_enum_id(struc_id) sidx = idc.GetStrucIdx(struc_id) if sidx is None or sidx == idc.BADADDR: # it is a deleted structure or a stackframe # in this last case we need to export the parent (function) eaFunc = idaapi.get_func_by_frame(struc_id) if eaFunc != idc.BADADDR: # OK, it is a stackframe self.ida_model.accept_struc( memory_exporter, 0, struc_id, ya.OBJECT_TYPE_STACKFRAME, ya.OBJECT_TYPE_STACKFRAME_MEMBER, stackframe_func_addr=eaFunc) self.ida_model.accept_ea(memory_exporter, 0, eaFunc) else: # it is a deleted structure self.ida_model.accept_deleted_struc(memory_exporter, struc_id) else: self.ida_model.accept_struc(memory_exporter, 0, struc_id) logger.debug("Walking members") """ Structure members : update modified ones, and remove deleted ones We iterate over members : -if the parent struc has been deleted, delete the member -otherwise, detect if the member has been updated or removed -updated : accept struc_member + accept_struc if not already exported! -removed : accept struc_member_deleted """ for (struc_id, member_set) in self.strucmember_to_process.iteritems(): ida_struc = idaapi.get_struc(struc_id) logger.debug("Walking struc 0x%08X" % struc_id) sidx = idc.GetStrucIdx(struc_id) is_stackframe = False struc_deleted = False if sidx is None or sidx == idc.BADADDR: f = idaapi.get_func_by_frame(struc_id) if f is not None and f != idc.BADADDR: is_stackframe = True else: struc_deleted = True if is_stackframe: strucmember_type = ya.OBJECT_TYPE_STACKFRAME_MEMBER struc_name = None struc_type = ya.OBJECT_TYPE_STACKFRAME eaFunc = idaapi.get_func_by_frame(struc_id) stackframe_func_addr = eaFunc func = idaapi.get_func(eaFunc) self.ida_model.accept_function(memory_exporter, 0, eaFunc, func) else: strucmember_type = ya.OBJECT_TYPE_STRUCT_MEMBER struc_type = ya.OBJECT_TYPE_STRUCT stackframe_func_addr = None if not struc_deleted: struc_name = idc.GetStrucName(struc_id) if struc_deleted: # The structure has been deleted : we need to delete the members # Note: at first sight, it is not a stackframe # TODO: handle function->stackframe deletion here for (member_id, offset) in member_set: self.ida_model.accept_deleted_strucmember(memory_exporter, struc_id, None, offset) else: # The structure or stackframe has been modified is_union = ida_struc.is_union() for (member_id, offset) in member_set: ida_member = idaapi.get_member(ida_struc, offset) if ida_member is None: new_member_id = -1 else: new_member_id = ida_member.id logger.debug("exporting member %s at offset 0x%02X (mid=0x%016X)" % (strucmember_type, offset, member_id)) self.ida_model.clear_exported_struc_member_id(new_member_id) if new_member_id == -1: # the member has been deleted : delete it self.ida_model.accept_deleted_strucmember( memory_exporter, struc_id, struc_name, offset, struc_type, strucmember_type) elif offset > 0 and idc.GetMemberId(struc_id, offset - 1) == new_member_id: # the member was deleted, and replaced by a member starting above it self.ida_model.accept_deleted_strucmember( memory_exporter, struc_id, struc_name, offset, struc_type, strucmember_type) elif new_member_id != member_id: # the member has been deleted and later recreated name = idaapi.get_member_name(new_member_id) self.ida_model.accept_struc_member( memory_exporter, 0, ida_struc, struc_id, is_union, offset, struc_name, name, struc_type, strucmember_type, stackframe_func_addr=stackframe_func_addr) else: # the member has just been modified name = idaapi.get_member_name(new_member_id) logger.debug("exporting member %s (%s) at offset 0x%02X (mid=0x%016X)" % (strucmember_type, name, offset, member_id)) self.ida_model.accept_struc_member( memory_exporter, 0, ida_struc, struc_id, is_union, offset, struc_name, name, struc_type, strucmember_type, stackframe_func_addr=stackframe_func_addr)