def readClass(machO, vmaddr, protoRefsMap): """Read a ``class_t`` at *vmaddr*, and returns a tuple of :class:`~objc.class_.Class` and pointer (possibly relocated) to superclass, if any.""" # typedef struct class_t { # struct class_t *isa; # struct class_t *superclass; # Cache cache; # IMP *vtable; # class_rw_t *data; # } class_t; origin = machO.origin machO_fromVM = machO.fromVM classT = machO.makeStruct('5^') (metaPtr, superPtr, _, _, classRo) = peekStruct(machO.file, classT, position=machO_fromVM(vmaddr)+origin) cls = _readClassRO(machO, None, protoRefsMap, machO_fromVM(classRo)+origin) metaClassRo = peekStruct(machO.file, classT, position=machO_fromVM(metaPtr)+origin)[4] cls = _readClassRO(machO, cls, protoRefsMap, machO_fromVM(metaClassRo)+origin) # if the superclass is 0 but the class is not a root class, it is possible # that the superclass is an external class. if not superPtr and not cls.isRoot: superPtr = vmaddr + machO.pointerWidth return (cls, superPtr)
def readClassName(machO, vmaddr): "Read the class name of the Objective-C class at *vmaddr*." origin = machO.origin machO_fromVM = machO.fromVM file = machO.file classT = machO.makeStruct('5^') classRoT = machO.makeStruct('3L~7^') classRo = peekStruct(file, classT, position=machO_fromVM(vmaddr)+origin)[4] namePtr = peekStruct(file, classRoT, position=machO_fromVM(classRo)+origin)[4] return machO.derefString(namePtr)
def readCategory(machO, vmaddr, classes, protoRefsMap): """Read a ``category_t`` at *vmaddr*, and returns a tuple of :class:`~objc.category.Category`, and the :class:`~objc.class_.Class` or :class:`~objc.class_.RemoteClass` it is patching.""" # typedef struct category_t { # const char *name; # struct class_t *cls; # struct method_list_t *instanceMethods; # struct method_list_t *classMethods; # struct protocol_list_t *protocols; # struct objc_property_list *instanceProperties; # } category_t; pos = machO.fromVM(vmaddr) + machO.origin (namePtr, clsPtr, instMethodsPtr, classMethodsPtr, protosPtr, propsPtr) = peekStruct(machO.file, machO.makeStruct('6^'), position=pos) name = machO.derefString(namePtr) if not clsPtr: clsPtr = vmaddr + machO.pointerWidth cls = classAt(machO, clsPtr, classes) cat = Category(name, cls) cat.addClassMethods(readMethodListAt(machO, classMethodsPtr, optional=False)) cat.addMethods(readMethodListAt(machO, instMethodsPtr, optional=False)) cat.addProperties(readPropertyListAt(machO, propsPtr)) protocolRefs = _readProtocolRefListAt(machO, protosPtr) connectProtocol(cat, protocolRefs, protoRefsMap) return cat
def analyze(self, machO): symtabStruct = machO.makeStruct('4L') nlistStruct = machO.makeStruct('LBBH^') (symoff, nsyms, stroff, _) = peekStruct(machO.file, symtabStruct) # Get all nlist structs origin = machO.origin nlists = peekStructs(machO.file, nlistStruct, count=nsyms, position=symoff + origin) # Now analyze the nlist structs symbols = [] for (ordinal, (idx, typ, sect, desc, value)) in enumerate(nlists): string = peekString(machO.file, position=stroff + idx + origin) libord = (desc >> 8) & 0xff # GET_LIBRARY_ORDINAL extern = bool(typ & 1) # N_EXT symtype = SYMTYPE_GENERIC if (typ & 0xe) else SYMTYPE_UNDEFINED isThumb = bool(desc & 8) # N_ARM_THUMB_DEF if isThumb: value &= ~1 symbol = Symbol(string, value, symtype, ordinal, libord, extern, isThumb) symbols.append(symbol) # add those symbols back into the Mach-O. machO.addSymbols(symbols)
def analyze(self, machO): symtabStruct = machO.makeStruct('4L') nlistStruct = machO.makeStruct('LBBH^') (symoff, nsyms, stroff, _) = peekStruct(machO.file, symtabStruct) # Get all nlist structs origin = machO.origin nlists = peekStructs(machO.file, nlistStruct, count=nsyms, position=symoff+origin) # Now analyze the nlist structs symbols = [] for (ordinal, (idx, typ, sect, desc, value)) in enumerate(nlists): string = peekString(machO.file, position=stroff+idx+origin) libord = (desc >> 8) & 0xff # GET_LIBRARY_ORDINAL extern = bool(typ & 1) # N_EXT symtype = SYMTYPE_GENERIC if (typ & 0xe) else SYMTYPE_UNDEFINED isThumb = bool(desc & 8) # N_ARM_THUMB_DEF if isThumb: value &= ~1 symbol = Symbol(string, value, symtype, ordinal, libord, extern, isThumb) symbols.append(symbol) # add those symbols back into the Mach-O. machO.addSymbols(symbols)
def analyze(self, machO): (rebaseOff, rebaseSize, bindOff, bindSize, weakBindOff, weakBindSize, lazyBindOff, lazyBindSize, exportOff, exportSize) = peekStruct(machO.file, machO.makeStruct('10L')) symbols = [] if bindSize: machO.seek(bindOff) _bind(machO, bindSize, symbols) if weakBindSize: machO.seek(weakBindOff) _bind(machO, weakBindSize, symbols) if lazyBindSize: machO.seek(lazyBindOff) _bind(machO, lazyBindSize, symbols) if exportSize: exportOff += machO.origin _recursiveProcessExportTrieNode(machO.file, exportOff, exportOff, exportOff + exportSize, "", symbols, machO) machO.addSymbols(symbols)
def analyze(self, machO): # Make sure the SYMTAB command is ready. if not all(lc.isAnalyzed for lc in machO.loadCommands.all( 'className', 'SymtabCommand')): return True (ilocalsym, nlocalsym, iextdefsym, nextdefsym, iundefsym, nundefsym, tocoff, ntoc, modtaboff, nmodtab, extrefsymoff, nextrefsyms, self.indirectsymoff, nindirectsyms, extreloff, nextrel, locreloff, nlocrel) = peekStruct(machO.file, machO.makeStruct('18L')) if nextrel: machO.provideAddresses(self._exrelIter(machO, extreloff, nextrel))
def f(machO, vmaddr): if not vmaddr: return [] f = machO.file ms = machO.makeStruct pos = machO.fromVM(vmaddr) + machO.origin stru = ms(fmt1) count = peekStruct(f, stru, position=pos)[-1] # use fmt1 to obtain the count tuples = peekStructs(f, ms(fmt2), count, position=pos+stru.size) # use fmt2 to obtain the structures lst = [method(machO, s) for s in tuples] lst.reverse() return lst
def _readClassRO(machO, cls, protoRefsMap, absfileoff): """Peek a ``class_ro_t`` at *absfileoff*. If *cls* is ``None``, read the class as normal class. Otherwise, read as meta class and insert the class methods. """ # typedef struct class_ro_t { # uint32_t flags; # uint32_t instanceStart; # uint32_t instanceSize; # #ifdef __LP64__ # uint32_t reserved; # #endif # # const uint8_t * ivarLayout; # # const char * name; # const method_list_t * baseMethods; # const protocol_list_t * baseProtocols; # const ivar_list_t * ivars; # # const uint8_t * weakIvarLayout; # const struct objc_property_list *baseProperties; # } class_ro_t; (flags, _, _, _, namePtr, methodsPtr, protosPtr, ivarsPtr, _, propsPtr) = peekStruct(machO.file, machO.makeStruct('3L~7^'), position=absfileoff) methods = readMethodListAt(machO, methodsPtr, optional=False) if cls is None: # not meta class. name = machO.derefString(namePtr) cls = Class(name, flags) cls.addMethods(methods) cls.addIvars(readIvarListAt(machO, ivarsPtr)) cls.addProperties(readPropertyListAt(machO, propsPtr)) protocolRefs = _readProtocolRefListAt(machO, protosPtr) connectProtocol(cls, protocolRefs, protoRefsMap) else: # is meta-class: prepend the class methods. cls.addClassMethods(methods) return cls
def prepareMethodDescriptionList(machO, vmaddr): """Peek a ``objc_method_description_list`` struct at *vmaddr*, and return the ``objc_method_description``\\s as an iterable of 2-tuples.""" # struct objc_method_description_list { # int count; # struct objc_method_description list[1]; # }; if not vmaddr: return tuple() absfileoff = machO.fromVM(vmaddr) + machO.origin stru = machO.makeStruct('i') count = peekStruct(machO.file, stru, position=absfileoff)[0] return peekStructs(machO.file, machO.makeStruct('2^'), count, position=absfileoff+stru.size)
def analyze(self, machO): # Make sure the SYMTAB command is ready. if not all(lc.isAnalyzed for lc in machO.loadCommands.all('className', 'SymtabCommand')): return True ( ilocalsym, nlocalsym, iextdefsym, nextdefsym, iundefsym, nundefsym, tocoff, ntoc, modtaboff, nmodtab, extrefsymoff, nextrefsyms, self.indirectsymoff, nindirectsyms, extreloff, nextrel, locreloff, nlocrel) = peekStruct(machO.file, machO.makeStruct('18L')) if nextrel: machO.provideAddresses(self._exrelIter(machO, extreloff, nextrel))
def readLists(machO, vmaddr, method): """Read a senital-terminated list at *vmaddr* using *method*, and concatenate the result. *method* should have signature:: f(machO, vmaddr) and returns an iterable. """ # struct old_method { # SEL method_name; # char *method_types; # IMP method_imp; # }; # # struct old_method_list { # struct old_method_list *obsolete; # # int method_count; # #ifdef __LP64__ # int space; # #endif # /* variable length structure */ # struct old_method method_list[1]; # }; retval = [] if vmaddr: loc = machO.origin + machO.fromVM(vmaddr) stru = machO.makeStruct('^') ptrSize = stru.size f = machO.file while True: ptr = peekStruct(f, stru, position=loc)[0] if ptr > 0: retval.extend(method(machO, ptr)) else: break loc += ptrSize return retval
def analyze(self, machO): (rebaseOff, rebaseSize, bindOff, bindSize, weakBindOff, weakBindSize, lazyBindOff, lazyBindSize, exportOff, exportSize) = peekStruct(machO.file, machO.makeStruct('10L')) symbols = [] if bindSize: machO.seek(bindOff) _bind(machO, bindSize, symbols) if weakBindSize: machO.seek(weakBindOff) _bind(machO, weakBindSize, symbols) if lazyBindSize: machO.seek(lazyBindOff) _bind(machO, lazyBindSize, symbols) if exportSize: exportOff += machO.origin _recursiveProcessExportTrieNode(machO.file, exportOff, exportOff, exportOff + exportSize, "", symbols) machO.addSymbols(symbols)
def analyze(self, machO): (offset, self.timestamp, self.version, self.minVersion) = peekStruct(machO.file, machO.makeStruct('4L')) self.name = peekString(machO.file, position=offset + machO.origin + self.offset - 8)
def readProtocol(machO, vmaddr): """Peek a ``protocol_t`` at *offset*. Returns a tuple of :class:`~objc.protocol.Protocol` and an iterable of protocol addresses it is adopting.""" # typedef struct protocol_t { # id isa; # const char *name; # struct protocol_list_t *protocols; # method_list_t *instanceMethods; # method_list_t *classMethods; # method_list_t *optionalInstanceMethods; # method_list_t *optionalClassMethods; # struct objc_property_list *instanceProperties; # } protocol_t; pos = machO.fromVM(vmaddr) + machO.origin (_, namePtr, protocolListPtr, instMethodsPtr, classMethodsPtr, optInstMethodsPtr, optClassMethodsPtr, propsPtr) = peekStruct(machO.file, machO.makeStruct('8^'), position=pos) name = machO.derefString(namePtr) protocolRefs = _readProtocolRefListAt(machO, protocolListPtr) proto = Protocol(name) proto.addClassMethods(readMethodListAt(machO, classMethodsPtr, optional=False)) proto.addClassMethods(readMethodListAt(machO, optClassMethodsPtr, optional=True)) proto.addMethods(readMethodListAt(machO, instMethodsPtr, optional=False)) proto.addMethods(readMethodListAt(machO, optInstMethodsPtr, optional=True)) proto.addProperties(readPropertyListAt(machO, propsPtr)) return (proto, protocolRefs)