├── .gitignore ├── DyldExtractor.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist └── xcshareddata │ └── xcschemes │ └── DyldExtractor.xcscheme ├── DyldExtractor └── main.cpp ├── LICENSE.txt ├── Makefile └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | 3 | xcuserdata/ 4 | *.xcscmblueprint 5 | *.xccheckout 6 | build/ 7 | DerivedData/ 8 | *.moved-aside 9 | *.pbxuser 10 | !default.pbxuser 11 | *.mode1v3 12 | !default.mode1v3 13 | *.mode2v3 14 | !default.mode2v3 15 | *.perspectivev3 16 | !default.perspectivev3 17 | -------------------------------------------------------------------------------- /DyldExtractor.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 55; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | FACF7576273E9CFA009BF59D /* main.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FACF7575273E9CFA009BF59D /* main.cpp */; }; 11 | /* End PBXBuildFile section */ 12 | 13 | /* Begin PBXCopyFilesBuildPhase section */ 14 | FACF7570273E9CFA009BF59D /* CopyFiles */ = { 15 | isa = PBXCopyFilesBuildPhase; 16 | buildActionMask = 2147483647; 17 | dstPath = /usr/share/man/man1/; 18 | dstSubfolderSpec = 0; 19 | files = ( 20 | ); 21 | runOnlyForDeploymentPostprocessing = 1; 22 | }; 23 | /* End PBXCopyFilesBuildPhase section */ 24 | 25 | /* Begin PBXFileReference section */ 26 | FACF7572273E9CFA009BF59D /* DyldExtractor */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = DyldExtractor; sourceTree = BUILT_PRODUCTS_DIR; }; 27 | FACF7575273E9CFA009BF59D /* main.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = main.cpp; sourceTree = ""; }; 28 | FACF757D273EB5A3009BF59D /* Makefile */ = {isa = PBXFileReference; explicitFileType = sourcecode.make; path = Makefile; sourceTree = ""; usesTabs = 1; }; 29 | FACF757E273EBA7A009BF59D /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; 30 | /* End PBXFileReference section */ 31 | 32 | /* Begin PBXFrameworksBuildPhase section */ 33 | FACF756F273E9CFA009BF59D /* Frameworks */ = { 34 | isa = PBXFrameworksBuildPhase; 35 | buildActionMask = 2147483647; 36 | files = ( 37 | ); 38 | runOnlyForDeploymentPostprocessing = 0; 39 | }; 40 | /* End PBXFrameworksBuildPhase section */ 41 | 42 | /* Begin PBXGroup section */ 43 | FACF7569273E9CFA009BF59D = { 44 | isa = PBXGroup; 45 | children = ( 46 | FACF757E273EBA7A009BF59D /* README.md */, 47 | FACF757D273EB5A3009BF59D /* Makefile */, 48 | FACF7574273E9CFA009BF59D /* DyldExtractor */, 49 | FACF7573273E9CFA009BF59D /* Products */, 50 | ); 51 | sourceTree = ""; 52 | }; 53 | FACF7573273E9CFA009BF59D /* Products */ = { 54 | isa = PBXGroup; 55 | children = ( 56 | FACF7572273E9CFA009BF59D /* DyldExtractor */, 57 | ); 58 | name = Products; 59 | sourceTree = ""; 60 | }; 61 | FACF7574273E9CFA009BF59D /* DyldExtractor */ = { 62 | isa = PBXGroup; 63 | children = ( 64 | FACF7575273E9CFA009BF59D /* main.cpp */, 65 | ); 66 | path = DyldExtractor; 67 | sourceTree = ""; 68 | }; 69 | /* End PBXGroup section */ 70 | 71 | /* Begin PBXNativeTarget section */ 72 | FACF7571273E9CFA009BF59D /* DyldExtractor */ = { 73 | isa = PBXNativeTarget; 74 | buildConfigurationList = FACF7579273E9CFA009BF59D /* Build configuration list for PBXNativeTarget "DyldExtractor" */; 75 | buildPhases = ( 76 | FACF756E273E9CFA009BF59D /* Sources */, 77 | FACF756F273E9CFA009BF59D /* Frameworks */, 78 | FACF7570273E9CFA009BF59D /* CopyFiles */, 79 | ); 80 | buildRules = ( 81 | ); 82 | dependencies = ( 83 | ); 84 | name = DyldExtractor; 85 | productName = DyldExtractor; 86 | productReference = FACF7572273E9CFA009BF59D /* DyldExtractor */; 87 | productType = "com.apple.product-type.tool"; 88 | }; 89 | /* End PBXNativeTarget section */ 90 | 91 | /* Begin PBXProject section */ 92 | FACF756A273E9CFA009BF59D /* Project object */ = { 93 | isa = PBXProject; 94 | attributes = { 95 | BuildIndependentTargetsInParallel = 1; 96 | LastUpgradeCheck = 1310; 97 | TargetAttributes = { 98 | FACF7571273E9CFA009BF59D = { 99 | CreatedOnToolsVersion = 13.1; 100 | }; 101 | }; 102 | }; 103 | buildConfigurationList = FACF756D273E9CFA009BF59D /* Build configuration list for PBXProject "DyldExtractor" */; 104 | compatibilityVersion = "Xcode 13.0"; 105 | developmentRegion = en; 106 | hasScannedForEncodings = 0; 107 | knownRegions = ( 108 | en, 109 | Base, 110 | ); 111 | mainGroup = FACF7569273E9CFA009BF59D; 112 | productRefGroup = FACF7573273E9CFA009BF59D /* Products */; 113 | projectDirPath = ""; 114 | projectRoot = ""; 115 | targets = ( 116 | FACF7571273E9CFA009BF59D /* DyldExtractor */, 117 | ); 118 | }; 119 | /* End PBXProject section */ 120 | 121 | /* Begin PBXSourcesBuildPhase section */ 122 | FACF756E273E9CFA009BF59D /* Sources */ = { 123 | isa = PBXSourcesBuildPhase; 124 | buildActionMask = 2147483647; 125 | files = ( 126 | FACF7576273E9CFA009BF59D /* main.cpp in Sources */, 127 | ); 128 | runOnlyForDeploymentPostprocessing = 0; 129 | }; 130 | /* End PBXSourcesBuildPhase section */ 131 | 132 | /* Begin XCBuildConfiguration section */ 133 | FACF7577273E9CFA009BF59D /* Debug */ = { 134 | isa = XCBuildConfiguration; 135 | buildSettings = { 136 | ALWAYS_SEARCH_USER_PATHS = NO; 137 | CLANG_ANALYZER_NONNULL = YES; 138 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 139 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++17"; 140 | CLANG_CXX_LIBRARY = "libc++"; 141 | CLANG_ENABLE_MODULES = YES; 142 | CLANG_ENABLE_OBJC_ARC = YES; 143 | CLANG_ENABLE_OBJC_WEAK = YES; 144 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 145 | CLANG_WARN_BOOL_CONVERSION = YES; 146 | CLANG_WARN_COMMA = YES; 147 | CLANG_WARN_CONSTANT_CONVERSION = YES; 148 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 149 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 150 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 151 | CLANG_WARN_EMPTY_BODY = YES; 152 | CLANG_WARN_ENUM_CONVERSION = YES; 153 | CLANG_WARN_INFINITE_RECURSION = YES; 154 | CLANG_WARN_INT_CONVERSION = YES; 155 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 156 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 157 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 158 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 159 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 160 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 161 | CLANG_WARN_STRICT_PROTOTYPES = YES; 162 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 163 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 164 | CLANG_WARN_UNREACHABLE_CODE = YES; 165 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 166 | COPY_PHASE_STRIP = NO; 167 | DEBUG_INFORMATION_FORMAT = dwarf; 168 | ENABLE_STRICT_OBJC_MSGSEND = YES; 169 | ENABLE_TESTABILITY = YES; 170 | GCC_C_LANGUAGE_STANDARD = gnu11; 171 | GCC_DYNAMIC_NO_PIC = NO; 172 | GCC_NO_COMMON_BLOCKS = YES; 173 | GCC_OPTIMIZATION_LEVEL = 0; 174 | GCC_PREPROCESSOR_DEFINITIONS = ( 175 | "DEBUG=1", 176 | "$(inherited)", 177 | ); 178 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 179 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 180 | GCC_WARN_UNDECLARED_SELECTOR = YES; 181 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 182 | GCC_WARN_UNUSED_FUNCTION = YES; 183 | GCC_WARN_UNUSED_VARIABLE = YES; 184 | MACOSX_DEPLOYMENT_TARGET = 12.0; 185 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; 186 | MTL_FAST_MATH = YES; 187 | ONLY_ACTIVE_ARCH = YES; 188 | SDKROOT = macosx; 189 | }; 190 | name = Debug; 191 | }; 192 | FACF7578273E9CFA009BF59D /* Release */ = { 193 | isa = XCBuildConfiguration; 194 | buildSettings = { 195 | ALWAYS_SEARCH_USER_PATHS = NO; 196 | CLANG_ANALYZER_NONNULL = YES; 197 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 198 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++17"; 199 | CLANG_CXX_LIBRARY = "libc++"; 200 | CLANG_ENABLE_MODULES = YES; 201 | CLANG_ENABLE_OBJC_ARC = YES; 202 | CLANG_ENABLE_OBJC_WEAK = YES; 203 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 204 | CLANG_WARN_BOOL_CONVERSION = YES; 205 | CLANG_WARN_COMMA = YES; 206 | CLANG_WARN_CONSTANT_CONVERSION = YES; 207 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 208 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 209 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 210 | CLANG_WARN_EMPTY_BODY = YES; 211 | CLANG_WARN_ENUM_CONVERSION = YES; 212 | CLANG_WARN_INFINITE_RECURSION = YES; 213 | CLANG_WARN_INT_CONVERSION = YES; 214 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 215 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 216 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 217 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 218 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 219 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 220 | CLANG_WARN_STRICT_PROTOTYPES = YES; 221 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 222 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 223 | CLANG_WARN_UNREACHABLE_CODE = YES; 224 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 225 | COPY_PHASE_STRIP = NO; 226 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 227 | ENABLE_NS_ASSERTIONS = NO; 228 | ENABLE_STRICT_OBJC_MSGSEND = YES; 229 | GCC_C_LANGUAGE_STANDARD = gnu11; 230 | GCC_NO_COMMON_BLOCKS = YES; 231 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 232 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 233 | GCC_WARN_UNDECLARED_SELECTOR = YES; 234 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 235 | GCC_WARN_UNUSED_FUNCTION = YES; 236 | GCC_WARN_UNUSED_VARIABLE = YES; 237 | MACOSX_DEPLOYMENT_TARGET = 12.0; 238 | MTL_ENABLE_DEBUG_INFO = NO; 239 | MTL_FAST_MATH = YES; 240 | SDKROOT = macosx; 241 | }; 242 | name = Release; 243 | }; 244 | FACF757A273E9CFA009BF59D /* Debug */ = { 245 | isa = XCBuildConfiguration; 246 | buildSettings = { 247 | CODE_SIGN_ENTITLEMENTS = DyldExtractor/DyldExtractor.entitlements; 248 | CODE_SIGN_IDENTITY = "-"; 249 | CODE_SIGN_STYLE = Automatic; 250 | DEVELOPMENT_TEAM = ""; 251 | ENABLE_HARDENED_RUNTIME = NO; 252 | PRODUCT_NAME = "$(TARGET_NAME)"; 253 | }; 254 | name = Debug; 255 | }; 256 | FACF757B273E9CFA009BF59D /* Release */ = { 257 | isa = XCBuildConfiguration; 258 | buildSettings = { 259 | CODE_SIGN_ENTITLEMENTS = DyldExtractor/DyldExtractor.entitlements; 260 | CODE_SIGN_IDENTITY = "-"; 261 | CODE_SIGN_STYLE = Automatic; 262 | DEVELOPMENT_TEAM = ""; 263 | ENABLE_HARDENED_RUNTIME = NO; 264 | PRODUCT_NAME = "$(TARGET_NAME)"; 265 | }; 266 | name = Release; 267 | }; 268 | /* End XCBuildConfiguration section */ 269 | 270 | /* Begin XCConfigurationList section */ 271 | FACF756D273E9CFA009BF59D /* Build configuration list for PBXProject "DyldExtractor" */ = { 272 | isa = XCConfigurationList; 273 | buildConfigurations = ( 274 | FACF7577273E9CFA009BF59D /* Debug */, 275 | FACF7578273E9CFA009BF59D /* Release */, 276 | ); 277 | defaultConfigurationIsVisible = 0; 278 | defaultConfigurationName = Release; 279 | }; 280 | FACF7579273E9CFA009BF59D /* Build configuration list for PBXNativeTarget "DyldExtractor" */ = { 281 | isa = XCConfigurationList; 282 | buildConfigurations = ( 283 | FACF757A273E9CFA009BF59D /* Debug */, 284 | FACF757B273E9CFA009BF59D /* Release */, 285 | ); 286 | defaultConfigurationIsVisible = 0; 287 | defaultConfigurationName = Release; 288 | }; 289 | /* End XCConfigurationList section */ 290 | }; 291 | rootObject = FACF756A273E9CFA009BF59D /* Project object */; 292 | } 293 | -------------------------------------------------------------------------------- /DyldExtractor.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /DyldExtractor.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /DyldExtractor.xcodeproj/xcshareddata/xcschemes/DyldExtractor.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 43 | 45 | 51 | 52 | 53 | 54 | 60 | 62 | 68 | 69 | 70 | 71 | 73 | 74 | 77 | 78 | 79 | -------------------------------------------------------------------------------- /DyldExtractor/main.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License 3 | * 4 | * Copyright (c) 2021 Cyandev. All rights reserved. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | #include 26 | #include 27 | #include 28 | 29 | #include 30 | #include 31 | 32 | static const char * const prog_version = "1.15.0"; 33 | static const char * const default_extractor_path = "/usr/lib/dsc_extractor.bundle"; 34 | 35 | static const char *g_cmdline; 36 | static bool g_verbose = false; 37 | 38 | static void printUsage() { 39 | std::cout << "OVERVIEW: dyld shared cache extractor (" << prog_version << ")\n\n"; 40 | std::cout << "USAGE: " << g_cmdline << " [-v] [-d arg] [-l arg]\n\n"; 41 | std::cout << "OPTIONS:\n"; 42 | std::cout << "\t-v print verbose messages\n"; 43 | std::cout << "\t-d set destination path for the extracted files\n"; 44 | std::cout << "\t-l set path to dsc_extractor library\n"; 45 | std::cout << std::endl; 46 | } 47 | 48 | static void printError(const std::string &error) { 49 | std::cout << "error: " << g_cmdline << ": " << error << std::endl; 50 | } 51 | 52 | static void printVerbose(const std::string &str) { 53 | if (g_verbose) { 54 | std::cout << "[!] " << str << std::endl; 55 | } 56 | } 57 | 58 | struct ErrorReporting { 59 | inline bool hasError() const { return _has_error; } 60 | inline const std::string &error() const { return _error; } 61 | protected: 62 | bool _has_error = true; 63 | std::string _error; 64 | }; 65 | 66 | struct Options : public ErrorReporting { 67 | explicit Options(int argc, const char *argv[]) : argc(argc), argv(argv) { 68 | if (argc < 2) { 69 | _error = "the cache file must be specified"; 70 | return; 71 | } 72 | 73 | _input_path = argv[1]; 74 | 75 | for (int i = 2; i < argc; ++i) { 76 | std::string opt = argv[i]; 77 | if (opt == "-v") { 78 | _verbose = true; 79 | } else if (opt == "-d") { 80 | if (!getOptionValue(i, opt, _dest_path, _has_dest_path)) { 81 | return; 82 | } 83 | } else if (opt == "-l") { 84 | if (!getOptionValue(i, opt, _library_path, _has_library_path)) { 85 | return; 86 | } 87 | } else { 88 | _error = "unknown option: " + opt; 89 | return; 90 | } 91 | } 92 | 93 | // Parsed ok. 94 | _has_error = false; 95 | } 96 | 97 | inline const std::string &inputPath() const { return _input_path; } 98 | 99 | inline bool verbose() const { return _verbose; } 100 | 101 | inline bool hasDestPath() const { return _has_dest_path; } 102 | inline const std::string &destPath() const { return _dest_path; } 103 | 104 | inline bool hasLibraryPath() const { return _has_library_path; } 105 | inline const std::string &libraryPath() const { return _library_path; } 106 | 107 | private: 108 | bool getOptionValue(int &i, 109 | const std::string &opt, 110 | std::string &out_value, 111 | bool &out_option) { 112 | int next_idx = i + 1; 113 | if (next_idx >= argc) { 114 | _error = "value must be specified for option: " + opt; 115 | return false; 116 | } 117 | 118 | out_value = argv[next_idx]; 119 | out_option = true; 120 | 121 | // Make the parser skip the next arg. 122 | i = next_idx; 123 | 124 | return true; 125 | } 126 | 127 | int argc; 128 | const char **argv; 129 | 130 | std::string _input_path; 131 | bool _verbose = false; 132 | bool _has_dest_path = false; 133 | std::string _dest_path; 134 | bool _has_library_path = false; 135 | std::string _library_path; 136 | }; 137 | 138 | struct Extractor : public ErrorReporting { 139 | Extractor(const std::string &input, 140 | const std::string &library, 141 | const std::string &dest) 142 | : _input_path(input), _dest_path(dest) 143 | { 144 | printVerbose("loading the extractor library..."); 145 | auto lib_handle = dlopen(library.c_str(), RTLD_NOW); 146 | if (!lib_handle) { 147 | _error = "failed to load the extractor library: " + library; 148 | return; 149 | } 150 | 151 | auto extract_func = dlsym(lib_handle, "dyld_shared_cache_extract_dylibs_progress"); 152 | if (!extract_func) { 153 | _error = "failed to resolve the extract function"; 154 | return; 155 | } 156 | 157 | _extract_func = reinterpret_cast(extract_func); 158 | 159 | _has_error = false; 160 | printVerbose("library loaded!"); 161 | } 162 | 163 | bool extract() { 164 | printVerbose("verifying the cache file, this may take a minute"); 165 | 166 | auto sema = dispatch_semaphore_create(1); 167 | 168 | __block bool first_progress_report = true; 169 | int result = _extract_func(_input_path.c_str(), _dest_path.c_str(), 170 | ^(unsigned int current, unsigned int total) { 171 | dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER); 172 | 173 | if (first_progress_report) { 174 | printVerbose("the cache file seems to be good!"); 175 | first_progress_report = false; 176 | } 177 | std::cout << "extracting files... (" << current << "/" << total << ")\r"; 178 | std::cout.flush(); 179 | 180 | dispatch_semaphore_signal(sema); 181 | }); 182 | 183 | std::cout << std::endl; 184 | 185 | return result == 0; 186 | } 187 | 188 | private: 189 | using ProgressBlock = void (^)(unsigned current, unsigned total); 190 | using ExtractFunc = int (*)(const char* shared_cache_file_path, 191 | const char* extraction_root_path, 192 | ProgressBlock progress); 193 | 194 | ExtractFunc _extract_func; 195 | 196 | std::string _input_path; 197 | std::string _dest_path; 198 | }; 199 | 200 | int main(int argc, const char *argv[]) { 201 | g_cmdline = argv[0]; 202 | 203 | // Parse arguments. 204 | Options opts(argc, argv); 205 | if (opts.hasError()) { 206 | printUsage(); 207 | printError(opts.error()); 208 | return 1; 209 | } 210 | 211 | g_verbose = opts.verbose(); 212 | 213 | // Resolve the destination path (user specified or current working directory). 214 | std::string dest_path = ([&]() { 215 | if (opts.hasDestPath()) { 216 | return opts.destPath(); 217 | } 218 | 219 | char *cwd = getcwd(nullptr, 0); 220 | if (!cwd) { 221 | printError("failed to get current working directory"); 222 | abort(); 223 | } 224 | std::string cwd_str = cwd; 225 | free(cwd); 226 | 227 | return cwd_str; 228 | })(); 229 | printVerbose("extracted files will be in " + dest_path); 230 | 231 | // Prepare and start the actual extraction. 232 | Extractor extractor(opts.inputPath(), 233 | opts.hasLibraryPath() ? opts.libraryPath() : default_extractor_path, 234 | dest_path); 235 | if (extractor.hasError()) { 236 | printError(extractor.error()); 237 | return 1; 238 | } 239 | if (extractor.extract()) { 240 | std::cout << "done, have fun!" << std::endl; 241 | } else { 242 | std::cout << "extract failed!" << std::endl; 243 | return 1; 244 | } 245 | 246 | return 0; 247 | } 248 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Cyandev. All rights reserved. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | CC = clang++ 2 | CFLAGS = -Wall -O3 -std=gnu++1z -fno-stack-protector -fno-common 3 | RM = rm -f 4 | 5 | ALL_FILE = main.o dyld_extractor 6 | 7 | all: dyld_extractor 8 | 9 | dyld_extractor: main.o 10 | $(CC) main.o -o dyld_extractor 11 | 12 | main.o: ./DyldExtractor/main.cpp 13 | $(CC) $(CFLAGS) -c ./DyldExtractor/main.cpp -o main.o 14 | 15 | clean: 16 | $(RM) $(ALL_FILE) 17 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DyldExtractor 2 | 3 | A command-line tool to extract dylib files from the **dyld shared cache** file. 4 | 5 | Starting with macOS 11, standalone binaries of system libraries are not shipped with the system anymore. That means we cannot reverse-engineer those system libraries / frameworks directly. Fortunately, dyld provided a utility bundle for extracting image files from the cache file. This tool is just a wrapper of that utility bundle. 6 | 7 | ## Build 8 | 9 | Clone the repo and build it with make: 10 | 11 | ```shell 12 | git clone https://github.com/unixzii/DyldExtractor.git 13 | cd DyldExtractor && make 14 | ``` 15 | 16 | ## Usage 17 | 18 | ``` 19 | OVERVIEW: dyld shared cache extractor 20 | 21 | USAGE: ./dyld_extractor [-v] [-d arg] [-l arg] 22 | 23 | OPTIONS: 24 | -v print verbose messages 25 | -d set destination path for the extracted files 26 | -l set path to dsc_extractor library 27 | ``` 28 | 29 | ## Notes for iOS 30 | 31 | To extract iOS's dyld shared cache files, you may need to specify a different dsc_extractor library with `-l` option. The library can usually be found at `/path/to/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/usr/lib/dsc_extractor.bundle`. 32 | --------------------------------------------------------------------------------