def _process_offset(offset, ea, next_offset): """Process an offset in a __got section.""" # Convert the address containing the offset into an offset in IDA, but continue if it fails. if not idc.OpOff(ea, 0, 0): _log(1, 'Could not convert {:#x} into an offset', ea) # Get the name to which the offset refers. name = idau.get_ea_name(offset, user=True) if not name: _log(3, 'Offset at address {:#x} has target {:#x} without a name', ea, offset) return False # Make sure this isn't an offset to another stub or to a jump function to another stub. See the # comment in _symbolicate_stub. if stub.symbol_references_stub(name): _log( 1, 'Offset at address {:#x} has target {:#x} (name {}) that references a stub', ea, offset, name) return False # Set the new name for the offset. symbol = next_offset(name) if symbol is None: _log(0, 'Could not generate offset symbol for {}: names exhausted', name) return False if not idau.set_ea_name(ea, symbol, auto=True): _log(2, 'Could not set name {} for offset at {:#x}', symbol, ea) return False return True
def _symbolicate_overrides_for_classinfo(classinfo, processed): """A recursive function to symbolicate vtable overrides for a class and its superclasses.""" # If we've already been processed, stop. if classinfo in processed: return # First propagate symbol information to our superclass. if classinfo.superclass: _symbolicate_overrides_for_classinfo(classinfo.superclass, processed) # Now symbolicate the superclass. for _, override, original in class_vtable_overrides(classinfo, methods=True): # Skip this method if the override already has a name and we can't rename it. override_name = idau.get_ea_name(override, user=True) if override_name and not _ok_to_rename_method(override, override_name): continue # Skip this method if the original does not have a name or if it's a bad name. original_name = idau.get_ea_name(original, user=True) if not original_name or _bad_name_dont_use_as_override(original_name): continue # Get the new override name if we substitute for the override class's name. new_name = _vtable_method_symbol_substitute_class(original_name, classinfo.classname) if not new_name: _log(0, 'Could not substitute class {} into method symbol {} for override {:#x}', classinfo.classname, original_name, override) continue # Now that we have the new name, set it. if override_name: _log(2, 'Renaming {} -> {}', override_name, new_name) if not idau.set_ea_name(override, new_name, rename=True): _log(0, 'Could not set name {} for method {:#x}', new_name, override) # We're done. processed.add(classinfo)
def _symbolicate_stub(stub, target, next_stub): """Set a symbol for a stub function.""" name = idau.get_ea_name(target, username=True) if not name: _log(3, 'Stub {:#x} has target {:#x} without a name', stub, target) return False # Sometimes the target of the stub is a thunk in another kext. This is sometimes OK, but makes # a right mess of things when that thunk is itself a jump function for another stub, and # especially when there are multiple such jump functions to that stub in that kext. # Autorenaming of thunks interacts poorly with autonaming of stubs (you get things like # 'j_TARGET___stub_2_0', which stub_name_target() no longer thinks of as a stub). Thus, if the # current thing has '__stub_' in it, don't rename. The reason we don't just extract the inner # stub reference is that these jump functions are really wrappers with different names and # semantics in the original code, so it's not appropriate for us to cover that up with a stub. if symbol_references_stub(name): _log( 1, 'Stub {:#x} has target {:#x} (name {}) that references another stub', stub, target, name) return False symbol = next_stub(name) if symbol is None: _log(0, 'Could not generate stub symbol for {}: names exhausted', name) return False if not idau.set_ea_name(stub, symbol, auto=True): _log(2, 'Could not set name {} for stub at {:#x}', symbol, stub) return False return True
def add_vtable_symbol(vtable, classname): """Add a symbol for the virtual method table at the specified address. Arguments: vtable: The address of the virtual method table. classname: The name of the C++ class with this virtual method table. Returns: True if the data was successfully converted into a vtable and the symbol was added. """ vtable_symbol = vtable_symbol_for_class(classname) if not idau.set_ea_name(vtable, vtable_symbol): _log(0, 'Address {:#x} already has name {} instead of vtable symbol {}' .format(vtable, idau.get_ea_name(vtable), vtable_symbol)) return False return True
def add_metaclass_symbol(metaclass, classname): """Add a symbol for the OSMetaClass instance at the specified address. Arguments: metaclass: The address of the OSMetaClass instance. classname: The name of the C++ class with this OSMetaClass instance. Returns: True if the OSMetaClass instance's symbol was created successfully. """ metaclass_symbol = metaclass_symbol_for_class(classname) if not idau.set_ea_name(metaclass, metaclass_symbol): _log(0, 'Address {:#x} already has name {} instead of OSMetaClass instance symbol {}' .format(metaclass, idau.get_ea_name(metaclass), metaclass_symbol)) return False return True