def frame(cls, ea): '''Iterate through each field within the frame belonging to the function `ea`.''' F = func.by(ea) # iterate through all of the frame's members try: res = func.frame(F) except internal.exceptions.MissingTypeOrAttribute: logging.info( u"{:s}.frame({:#x}) : Skipping function at {:#x} due to a missing frame." .format('.'.join([__name__, cls.__name__]), ea, ea)) return for member in res.members: # if ida has named it and there's no comment, then skip if lvarNameQ(member.name) and not member.comment: continue # if it's a structure, then the type is the structure name if isinstance(member.type, struc.structure_t): logging.debug( u"{:s}.frame({:#x}) : Storing structure-based type as name for field {:+#x} with tne type {!s}." .format('.'.join([__name__, cls.__name__]), ea, member.offset, internal.utils.string.repr(member.type))) type = member.type.name # otherwise, the type is a tuple that we can serializer else: type = member.type # otherwise, it's just a regular field. so we can just save what's important. yield member.offset, (member.name, type, member.comment) return
def apply_frame(ea, frame, **tagmap): F = fn.frame(ea) for offset, (name, type, comment) in frame.viewitems(): try: member = F.by_offset(offset) except LookupError: logging.warn( "{:s}.apply_frame({:x}, ...) : Unable to find frame member at {:+#x}. Skipping application of data to it. : {!r}" .format(__name__, ea, offset, (name, type, comment)), exc_info=True) continue if member.name != name: if any(not member.name.startswith(n) for n in ('arg_', 'var_', ' ')): print >> output, "{:x} : {:+x} : Renaming frame member with new name. : {!r} : {!r}".format( ea, offset, member.name, name) member.name = name d, state = map(internal.comment.decode, (comment, member.comment)) for k in d.viewkeys() & state.viewkeys(): if state[k] == d[k]: continue print >> output, "{:x} : {:+x} : Overwriting frame member tag with new value. : {!r} : {!r}".format( ea, offset, state[k], d[k]) mapstate = {tagmap.get(k, k): v for k, v in d.iteritems()} state.update(mapstate) member.comment = internal.comment.encode(state) if type is not None: member.type = type continue return
def frame(cls, ea): '''Iterate through each field within the frame belonging to the function `ea`.''' F = func.by(ea) # iterate through all of the frame's members try: res = func.frame(F) except internal.exceptions.MissingTypeOrAttribute: logging.info(u"{:s}.frame({:#x}) : Skipping function at {:#x} due to a missing frame.".format('.'.join((__name__, cls.__name__)), ea, ea)) return for member in res.members: # if ida has named it and there's no comment, then skip if lvarNameQ(member.name) and not member.comment: continue # if it's a structure, then the type is the structure name if isinstance(member.type, struc.structure_t): logging.debug(u"{:s}.frame({:#x}) : Storing structure-based type as name for field {:+#x} with tne type {!s}.".format('.'.join((__name__, cls.__name__)), ea, member.offset, internal.utils.string.repr(member.type))) type = member.type.name # otherwise, the type is a tuple that we can serializer else: type = member.type # otherwise, it's just a regular field. so we can just save what's important. yield member.offset, (member.name, type, member.comment) return
def frame(ea): for member in fn.frame(ea).members: if any(member.name.startswith(n) for n in ('arg_', 'var_', ' ')) and not member.comment: continue if isinstance(member.type, st.structure_t) or any( isinstance(n, st.structure_t) for n in member.type): logging.warn( "{:s}.frame({:#x}) : Skipping structure-based type for field {:+#x} : {!r}" .format(__name__, ea, member.offset, member.type)) yield member.offset, (member.name, None, member.comment) continue yield member.offset, (member.name, member.type, member.comment) return
def frame(cls, ea, frame, **tagmap): '''Apply the fields from `frame` back into the function at `ea`.''' tagmap_output = u", {:s}".format(u', '.join( u"{:s}={:s}".format(internal.utils.string.escape(k), internal.utils.string.escape(v)) for k, v in tagmap.items())) if tagmap else '' # nothing to do here, so we gtfo if not frame: return # grab the function's frame try: F = func.frame(ea) # if no frame exists for the function, we'll need to create it except internal.exceptions.MissingTypeOrAttribute: # first we figure out the bounds of our members in order to figure out the the lvars and args sizes framekeys = {item for item in frame.keys()} minimum, maximum = min(framekeys), max(framekeys) # calculate the size of regs by first finding everything that begins at offset 0 res = sorted(offset for offset in framekeys if offset >= 0) # now we look for anything near offset 0 that begins with a space (which should be a register) regs = 0 for offset in res: name, type, _ = frame[offset] if not name.startswith(' '): break # if type is a string, then treat it as a structure so we can calculate a size if isinstance(type, six.string_types): try: st = struc.by(type) except internal.exceptions.StructureNotFoundError: logging.fatal( u"{:s}.frame({:#x}, ...{:s}): Unable to find structure \"{:s}\" for member {:+#x} in order to calculate register size for function at {:+#x}. Using register size of {:+#x}." .format('.'.join([__name__, cls.__name__]), ea, tagmap_output, internal.utils.string.escape(type, '"'), offset, ea, regs)) break type = [(int, 1), st.size] # extract the size components and calculate the total number of bytes realtype, reallength = type if isinstance( type, builtins.list) else [type, 1] _, realsize = realtype cb = realsize * reallength # add it to the current aggregate of the register size regs += cb # finally we can create the frame logging.warning( u"{:s}.frame({:#x}, ...{:s}) : Creating a new frame for function {:#x} with the parameters lvars={:+#x} regs={:+#x} args={:+#x}." .format('.'.join([__name__, cls.__name__]), ea, tagmap_output, ea, abs(minimum), regs, abs(maximum))) F = func.frame.new(ea, abs(minimum), regs, abs(maximum) - regs) # iterate through our dictionary of members for offset, (name, type, comment) in frame.items(): # first try and locate the member try: member = F.members.by_offset(offset) except: member = None # if we didn't find a member, then try and add it with what we currently know if member is None: logging.warning( u"{:s}.frame({:#x}, ...{:s}) : Unable to find frame member at {:+#x}. Attempting to create the member with the name (\"{:s}\"), type ({!s}), and comment (\"{:s}\")." .format('.'.join([__name__, cls.__name__]), ea, tagmap_output, offset, internal.utils.string.escape(name, '"'), internal.utils.string.repr(type), internal.utils.string.escape(comment, '"'))) try: member = F.members.add(name, type, offset) except: logging.fatal( u"{:s}.frame({:#x}, ...{:s}) : Unable to add frame member at {:+#x}. Skipping application of the name (\"{:s}\"), type ({!s}), and comment (\"{:s}\") to it." .format('.'.join([__name__, cls.__name__]), ea, tagmap_output, offset, internal.utils.string.escape(name, '"'), internal.utils.string.repr(type), internal.utils.string.escape(comment, '"'))) continue # check if the name has changed or is different in some way if member.name != name: log = logging.info if lvarNameQ( member.name) else logging.warning log(u"{:s}.frame({:#x}, ...{:s}) : Renaming frame member {:+#x} from the name \"{:s}\" to \"{:s}\"." .format('.'.join([__name__, cls.__name__]), ea, tagmap_output, offset, internal.utils.string.escape(member.name, '"'), internal.utils.string.escape(name, '"'))) member.name = name # check what's going to be overwritten with different values prior to doing it state, res = (internal.comment.decode(cmt) for cmt in [member.comment, comment]) # transform the new tag state using the tagmap new = { tagmap.get(name, name): value for name, value in res.items() } # check if the tag mapping resulted in the deletion of a tag if len(new) != len(res): reskeys, newkeys = ({item for item in items.keys()} for items in [res, new]) for name in reskeys - newkeys: logging.warning( u"{:s}.frame({:#x}, ...{:s}) : Refusing requested tag mapping as it results in the tag \"{:s}\" overwriting tag \"{:s}\" for the frame member {:+#x}. The value {!s} would be overwritten by {!s}." .format( '.'.join([__name__, cls.__name__]), ea, tagmap_output, internal.utils.string.escape(name, '"'), internal.utils.string.escape(tagmap[name], '"'), offset, internal.utils.string.repr(res[name]), internal.utils.string.repr(res[tagmap[name]]))) pass # warn the user about what's going to be overwritten prior to doing it statekeys, newkeys = ({item for item in items.keys()} for items in [state, new]) for name in statekeys & newkeys: if state[name] == new[name]: continue logging.warning( u"{:s}.frame({:#x}, ...{:s}) : Overwriting tag \"{:s}\" for frame member {:+#x} with new value {!s}. The old value was {!s}." .format('.'.join([__name__, cls.__name__]), ea, tagmap_output, internal.utils.string.escape(name, '"'), offset, internal.utils.string.repr(new[name]), internal.utils.string.repr(state[name]))) # now we can update the current dictionary mapstate = { name: value for name, value in new.items() if state.get(name, dummy) != value } state.update(mapstate) # convert it back to a multi-lined comment and assign it member.comment = internal.comment.encode(state) # if the type is a string, then figure out which structure to use if isinstance(type, six.string_types): try: member.type = struc.by(type) except internal.exceptions.StructureNotFoundError: logging.warning( u"{:s}.frame({:#x}, ...{:s}): Unable to find structure \"{:s}\" for member at {:+#x}. Skipping it." .format('.'.join([__name__, cls.__name__]), ea, tagmap_output, internal.utils.string.escape(type, '"'), offset)) # otherwise, it's a pythonic tuple that we can just assign else: member.type = type continue return
def frame(cls, ea, frame, **tagmap): '''Apply the fields from `frame` back into the function at `ea`.''' tagmap_output = u", {:s}".format(u', '.join(u"{:s}={:s}".format(internal.utils.string.escape(k), internal.utils.string.escape(v)) for k, v in six.iteritems(tagmap))) if tagmap else '' # nothing to do here, so we gtfo if not frame: return # grab the function's frame try: F = func.frame(ea) # if no frame exists for the function, we'll need to create it except internal.exceptions.MissingTypeOrAttribute: # first we figure out the bounds of our members in order to figure out the the lvars and args sizes minimum, maximum = min(six.viewkeys(frame)), max(six.viewkeys(frame)) # calculate the size of regs by first finding everything that begins at offset 0 res = sorted(offset for offset in six.viewkeys(frame) if offset >= 0) # now we look for anything near offset 0 that begins with a space (which should be a register) regs = 0 for offset in res: name, type, _ = frame[offset] if not name.startswith(' '): break # if type is a string, then treat it as a structure so we can calculate a size if isinstance(type, basestring): try: st = struc.by(type) except internal.exceptions.StructureNotFoundError: logging.fatal(u"{:s}.frame({:#x}, ...{:s}): Unable to find structure \"{:s}\" for member {:+#x} in order to calculate register size for function at {:+#x}. Using register size of {:+#x}.".format('.'.join((__name__, cls.__name__)), ea, tagmap_output, internal.utils.string.escape(type, '"'), offset, ea, regs)) break type = [(int, 1), st.size] # extract the size components and calculate the total number of bytes realtype, reallength = type if isinstance(type, builtins.list) else [type, 1] _, realsize = realtype cb = realsize * reallength # add it to the current aggregate of the register size regs += cb # finally we can create the frame logging.warn(u"{:s}.frame({:#x}, ...{:s}) : Creating a new frame for function {:#x} with the parameters lvars={:+#x} regs={:+#x} args={:+#x}.".format('.'.join((__name__, cls.__name__)), ea, tagmap_output, ea, abs(minimum), regs, abs(maximum))) F = func.frame.new(ea, abs(minimum), regs, abs(maximum) - regs) # iterate through our dictionary of members for offset, (name, type, comment) in six.iteritems(frame): # first try and locate the member try: member = F.members.by_offset(offset) except: member = None # if we didn't find a member, then try and add it with what we currently know if member is None: logging.warn(u"{:s}.frame({:#x}, ...{:s}) : Unable to find frame member at {:+#x}. Attempting to create the member with the name (\"{:s}\"), type ({!s}), and comment (\"{:s}\").".format('.'.join((__name__, cls.__name__)), ea, tagmap_output, offset, internal.utils.string.escape(name, '"'), internal.utils.string.repr(type), internal.utils.string.escape(comment, '"'))) try: member = F.members.add(name, type, offset) except: logging.fatal(u"{:s}.frame({:#x}, ...{:s}) : Unable to add frame member at {:+#x}. Skipping application of the name (\"{:s}\"), type ({!s}), and comment (\"{:s}\") to it.".format('.'.join((__name__, cls.__name__)), ea, tagmap_output, offset, internal.utils.string.escape(name, '"'), internal.utils.string.repr(type), internal.utils.string.escape(comment, '"'))) continue # check if the name has changed or is different in some way if member.name != name: log = logging.info if lvarNameQ(member.name) else logging.warn log(u"{:s}.frame({:#x}, ...{:s}) : Renaming frame member {:+#x} from the name \"{:s}\" to \"{:s}\".".format('.'.join((__name__, cls.__name__)), ea, tagmap_output, offset, internal.utils.string.escape(member.name, '"'), internal.utils.string.escape(name, '"'))) member.name = name # check what's going to be overwritten with different values prior to doing it state, res = map(internal.comment.decode, (member.comment, comment)) # transform the new tag state using the tagmap new = { tagmap.get(name, name) : value for name, value in six.viewitems(res) } # check if the tag mapping resulted in the deletion of a tag if len(new) != len(res): for name in six.viewkeys(res) - six.viewkeys(new): logging.warn(u"{:s}.frame({:#x}, ...{:s}) : Refusing requested tag mapping as it results in the tag \"{:s}\" overwriting tag \"{:s}\" for the frame member {:+#x}. The value {!s} would be overwritten by {!s}.".format('.'.join((__name__, cls.__name__)), ea, tagmap_output, internal.utils.string.escape(name, '"'), internal.utils.string.escape(tagmap[name], '"'), offset, internal.utils.string.repr(res[name]), internal.utils.string.repr(res[tagmap[name]]))) pass # warn the user about what's going to be overwritten prior to doing it for name in six.viewkeys(state) & six.viewkeys(new): if state[name] == new[name]: continue logging.warn(u"{:s}.frame({:#x}, ...{:s}) : Overwriting tag \"{:s}\" for frame member {:+#x} with new value {!s}. The old value was {!s}.".format('.'.join((__name__, cls.__name__)), ea, tagmap_output, internal.utils.string.escape(name, '"'), offset, internal.utils.string.repr(new[name]), internal.utils.string.repr(state[name]))) # now we can update the current dictionary mapstate = { name : value for name, value in six.iteritems(new) if state.get(name, dummy) != value } state.update(mapstate) # convert it back to a multi-lined comment and assign it member.comment = internal.comment.encode(state) # if the type is a string, then figure out which structure to use if isinstance(type, basestring): try: member.type = struc.by(type) except internal.exceptions.StructureNotFoundError: logging.warn(u"{:s}.frame({:#x}, ...{:s}): Unable to find structure \"{:s}\" for member at {:+#x}. Skipping it.".format('.'.join((__name__, cls.__name__)), ea, tagmap_output, internal.utils.string.escape(type, '"'), offset)) # otherwise, it's a pythonic tuple that we can just assign else: member.type = type continue return
def frame(cls, ea, frame, **tagmap): '''Apply the fields from `frame` back into the function at `ea`.''' tagmap_output = ", {:s}".format(', '.join( "{:s}={:s}".format(k, v) for k, v in six.iteritems(tagmap))) if tagmap else '' F = func.frame(ea) for offset, (name, type, comment) in six.iteritems(frame): try: member = F.by_offset(offset) except internal.exceptions.MemberNotFoundError: logging.warn( "{:s}.frame({:#x}, ...{:s}) : Unable to find frame member at {:+#x}. Skipping application of the name ({!r}), type ({!r}), and comment ({!r}) to it." .format('.'.join((__name__, cls.__name__)), ea, tagmap_output, offset, name, type, comment)) continue if member.name != name: if any(not member.name.startswith(n) for n in ('arg_', 'var_', ' ')): logging.warn( "{:s}.frame({:#x}, ...{:s}) : Renaming frame member {:+#x} from the name {!r} to {!r}." .format('.'.join((__name__, cls.__name__)), ea, tagmap_output, offset, member.name, name)) member.name = name # check what's going to be overwritten with different values prior to doing it state, res = map(internal.comment.decode, (member.comment, comment)) # transform the new tag state using the tagmap new = { tagmap.get(name, name): value for name, value in six.viewitems(res) } # check if the tag mapping resulted in the deletion of a tag if len(new) != len(res): for name in six.viewkeys(res) - six.viewkeys(new): logging.warn( "{:s}.frame({:#x}, ...{:s}) : Refusing requested tag mapping as it results in the tag {!r} overwriting tag {!r} for the frame member {:+#x}. The value {!r} would be overwritten by {!r}." .format('.'.join((__name__, cls.__name__)), ea, tagmap_output, name, tagmap[name], offset, res[name], res[tagmap[name]])) pass # warn the user about what's going to be overwritten prior to doing it for name in six.viewkeys(state) & six.viewkeys(new): if state[name] == new[name]: continue logging.warn( "{:s}.frame({:#x}, ...{:s}) : Overwriting tag {!r} for frame member {:+#x} with new value {!r}. The old value was {!r}." .format('.'.join( (__name__, cls.__name__)), ea, tagmap_output, name, offset, new[name], state[name])) # now we can update the current dictionary mapstate = { name: value for name, value in six.iteritems(new) if state.get(name, dummy) != value } state.update(mapstate) # convert it back to a multi-lined comment and assign it member.comment = internal.comment.encode(state) # if the type is a string, then figure out which structure to use if isinstance(type, basestring): try: member.type = struc.by(type) except internal.exceptions.StructureNotFoundError: logging.warn( "{:s}.frame({:#x}, ...{:s}): Unable to find structure {!r} for member at {:+#x}. Skipping it." .format('.'.join((__name__, cls.__name__)), ea, tagmap_output, type, offset)) # otherwise, it's a pythonic tuple that we can just assign else: member.type = type continue return