def runForAllImages(dyldFile: BufferedReader, dyldCtx: DyldContext, statusBar: progressbar.ProgressBar, logger: logging.Logger, startIndex: int = 0, stopIndex: int = -1) -> None: total = dyldCtx.header.imagesCount for index, imageData in enumerate(dyldCtx.images[startIndex:], startIndex): if index == stopIndex: break # TODO: Imp sub caches imageOffset = dyldCtx.convertAddr(imageData.address) imagePath = dyldCtx.readString(imageData.pathFileOffset)[0:-1] imagePath = imagePath.decode("utf-8") imageName = imagePath.split("/")[-1] # Make a writable copy of the dyld file machoFile = mmap.mmap(dyldFile.fileno(), 0, access=mmap.ACCESS_COPY) machoCtx = MachOContext(machoFile, imageOffset) extractionCtx = ExtractionContext(dyldCtx, machoCtx, statusBar, logger) # Test space start slide_info.processSlideInfo(extractionCtx) linkedit_optimizer.optimizeLinkedit(extractionCtx) stub_fixer.fixStubs(extractionCtx) objc_fixer.fixObjC(extractionCtx) macho_offset.optimizeOffsets(extractionCtx) # Test space end logger.info(f"processed: ({index + 1}/{total}): {imageName}") pass statusBar.update(unit="Extractor", status="Done") pass
parser.add_argument( "-j", "--jobs", type=int, default=mp.cpu_count(), help="Number of jobs to run simultaneously." # noqa ) args = parser.parse_args(namespace=_DyldExtractorArgs) # create a list of images images: List[str] = [] with open(args.dyld_path, "rb") as f: dyldCtx = DyldContext(f) for index, image in enumerate(dyldCtx.images): imagePath = dyldCtx.readString(image.pathFileOffset)[0:-1] imagePath = imagePath.decode("utf-8") imageName = imagePath.split("/")[-1] images.append(imageName) pass summary = "" with mp.Pool(args.jobs, initializer=_workerInitializer) as pool: # create jobs for each image jobs: List[Tuple[str, mp.pool.AsyncResult]] = [] for index, imageName in enumerate(images): jobs.append((imageName, pool.apply_async(_imageRunner, (args.dyld_path, index)))) pass
def main(): args = getArguments() # Configure Logging level = logging.WARNING # default option 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 progressbar.streams.wrap_stderr() # needed for logging compatability logging.basicConfig( format= "{asctime}:{msecs:3.0f} [{levelname:^9}] {filename}:{lineno:d} : {message}", # noqa datefmt="%H:%M:%S", style="{", level=level) with open(args.dyld_path, "rb") as f: with mmap.mmap(f.fileno(), 0, access=mmap.ACCESS_READ) as dyldFile: dyldCtx = DyldContext(dyldFile) # enumerate images, create a map of paths and images imageMap = {} for imageData in dyldCtx.images: path = dyldCtx.readString(imageData.pathFileOffset) path = path[0:-1] # remove null terminator path = path.decode("utf-8") imageMap[path] = imageData # list images option if args.list_frameworks: imagePaths = imageMap.keys() # filter if needed if args.filter: filterTerm = args.filter.strip().lower() imagePaths = _filterImages(imagePaths, filterTerm) print("Listing Images\n--------------") for path in imagePaths: print(path) return # extract image option if args.extract: extractionTarget = args.extract.strip() targetPaths = _filterImages(imageMap.keys(), extractionTarget) if len(targetPaths) == 0: print(f"Unable to find image \"{extractionTarget}\"") return outputPath = args.output if outputPath is None: outputPath = pathlib.Path("binaries/" + extractionTarget) os.makedirs(outputPath.parent, exist_ok=True) print(f"Extracting {targetPaths[0]}") _extractImage(f, dyldCtx, imageMap[targetPaths[0]], outputPath) return