def listImages(filterTerm: bytes = b""): """ Prints all the images in the cache with an optional filter term. """ with open(DYLD_PATH, "rb") as dyldFile: dyld = Dyld.DyldFile(dyldFile) for image in dyld.images: dyldFile.seek(image.pathFileOffset) path = b"" while True: data = dyldFile.read(1) path += data if data == b"\x00": break if filterTerm.lower() in path.lower(): print(str(path) + ": " + str(dyld.images.index(image)))
def runOnce(imageIndex: int, path: str) -> None: """ Decache an image at the imageIndex, and save it to the path. """ with open(DYLD_PATH, "rb") as dyldFile: dyld = Dyld.DyldFile(dyldFile) image = dyld.images[imageIndex] imageOff = dyld.convertAddr(image.address) macho = MachO.MachoFile.parse(dyldFile, imageOff) # comment or uncomment lines below to enable or disable modules. Though some do rely on each other. # rebuild the linkedit segment, which includes symbols print("LinkeditConverter") LinkeditConverter(macho, dyld).convert() # remove extra data in pointers and generate rebase data print("RebaseConverter") RebaseConverter(macho, dyld).convert() # fix references to selectors print("SelectorConverter") SelectorConverter(macho, dyld).convert() # fix stubs and references to stubs print("StubConverter") StubConverter(macho, dyld).convert() # fix and decache ObjC info print("ObjCConverter") ObjCConverter(macho, dyld).convert() # changes file offsets so that the final MachO file is not GBs big print("OffsetConverter") OffsetConverter(macho).convert() # save the converted image to a file print("Writer") MachO.Writer(macho).writeToPath(path)
def extract(framework: str, out: str): with open(DYLD_PATH, "rb") as dyldFile: dyld = Dyld.DyldFile(dyldFile) for image in dyld.images: dyldFile.seek(image.pathFileOffset) path = b"" while True: data = dyldFile.read(1) if data != b"\x00": path += data else: break # if framework.lower() == str(os.path.basename( path.decode("utf-8"))).lower(): runOnce(dyld.images.index(image), out) elif framework in path.decode("utf-8"): pass else: pass
def runAllImages(): """ Test a module with all images in the cache """ with open(DYLD_PATH, "rb") as dyldFile: dyld = Dyld.DyldFile(dyldFile) totalImages = len(dyld.images) for i in range(1, totalImages): image = dyld.images[i] imagePath = dyld.readString(image.pathFileOffset) imageName = imagePath.split(b"/")[-1].decode("utf-8") print("{}/{}: {}".format(i, totalImages, imageName)) imageOff = dyld.convertAddr(image.address) macho = MachO.MachoFile.parse(dyldFile, imageOff) # LinkeditConverter(macho, dyld).convert() # RebaseConverter(macho, dyld).convert() SelectorConverter(macho, dyld).convert()
if args.verbosity == 0: # Set the log level so high that it doesn't do anything level = 100 elif args.verbosity == 2: level = logging.INFO elif args.verbosity == 3: level = logging.DEBUG logging.basicConfig( format= "%(asctime)s:%(msecs)03d %(filename)s [%(levelname)-8s] : %(message)s", datefmt="%H:%M:%S", level=level) with open(args.dyld_path, mode="rb") as dyldFileHandle: dyldFile = Dyld.DyldFile(dyldFileHandle) images = enumerateImages(dyldFile) # List Images option if args.list_frameworks: if args.filter: filterTerm = args.filter.lower() images = [x for x in images if filterTerm in x[2].lower()] print("Listing images") print(f"Index| {'Name':40} | Path") for image in images: print(f"{image[0]:4} | {image[1]:40} | {image[2]}") # Extract image Option elif args.framework: