def extract_data(self, app: Bundle, result_path: str) -> bool: # Metadata is stored in a dictionary, which is later serialised to the disk. dependencies_metadata = dict() if not isinstance(app, Application): self.log_error("Supplied app {} is not an application".format( app.filepath)) return False app_base = os.path.realpath(app.filepath) + "/" executable = app.executable() app_dependencies = executable.application_libraries( ) if executable else [] for dependency in app_dependencies: dependency_bundle = Bundle.from_binary(dependency) # Relative path component from the underlying app to the dependency. dependency_rel = fs.path_remove_prefix(dependency, app_base) dependency_infos = None if dependency_bundle: # Use Info.plist from bundle dependency_infos = dependency_bundle.info_dictionary() else: # Try to instead use embedded information if lief.is_macho(dependency): dependency_infos = common.extract_embedded_info( lief_extensions.macho_parse_quick(dependency)) if dependency_infos: # Record entry along with further information dependencies_metadata[ dependency_rel] = DependenciesExtractor._extract_dependency_infos( dependency_infos) else: # Just record the path to the dependency dependencies_metadata[dependency_rel] = {} # Store the information to the filesystem with open(os.path.join(result_path, "dependencies.json"), "w") as outfile: json.dump(dependencies_metadata, outfile, indent=4) return True
def test_bundle_from_binary(self): # For single-file utility, this function should return None, because the file is not # part of any bundle self.assertIsNone(Bundle.from_binary("/bin/ls")) self.assertIsNone(Bundle.from_binary("/bin/ln")) # For binaries that are part of a bundle but not the main executable in such a bundle, # the function is also supposed to return None # Note: iTunes is used here, because it comes pre-installed on macOS # and it has the most complicated dependencies of any installed app, thus # it can be used for many different purposes self.assertIsNone(Bundle.from_binary("/Applications/iTunes.app/Contents/MacOS/iTunesASUHelper")) # For non-existent binaries, the function should throw a ValueError with self.assertRaises(ValueError): # This binary surely does not exist Bundle.from_binary("/bin/useful_test03837246") # If the main executable is supplied, the corresponding bundle should be found self.assertEqual( Bundle.from_binary( "/Applications/iTunes.app/Contents/MacOS/iTunes" ).filepath, "/Applications/iTunes.app") # This should also work for other types of bundles self.assertEqual( Bundle.from_binary( "/Applications/iTunes.app/Contents/Frameworks/iPodUpdater.framework/Versions/A/iPodUpdater" ).filepath, "/Applications/iTunes.app/Contents/Frameworks/iPodUpdater.framework" ) self.assertEqual( Bundle.from_binary( "/Applications/iTunes.app/Contents/PlugIns/iTunesStorageExtension.appex/Contents/MacOS/iTunesStorageExtension" ).filepath, "/Applications/iTunes.app/Contents/PlugIns/iTunesStorageExtension.appex" )