├── README.md ├── insert_dylib.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcuserdata │ │ └── gengjianfeng.xcuserdatad │ │ └── UserInterfaceState.xcuserstate └── xcuserdata │ └── gengjianfeng.xcuserdatad │ └── xcschemes │ ├── insert_dylib.xcscheme │ └── xcschememanagement.plist └── insert_dylib └── main.m /README.md: -------------------------------------------------------------------------------- 1 | # insert_dylib 2 | 对ios可执行文件dylib注入 3 | 4 | 命令使用方式: 5 | ./insert_dylib @executable_path/xxxx.dylib xxxx 6 | -------------------------------------------------------------------------------- /insert_dylib.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | EBEF5B501D655D6B00201FBD /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = EBEF5B4F1D655D6B00201FBD /* main.m */; }; 11 | /* End PBXBuildFile section */ 12 | 13 | /* Begin PBXCopyFilesBuildPhase section */ 14 | EBEF5B4A1D655D6B00201FBD /* 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 | EBEF5B4C1D655D6B00201FBD /* insert_dylib */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = insert_dylib; sourceTree = BUILT_PRODUCTS_DIR; }; 27 | EBEF5B4F1D655D6B00201FBD /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 28 | /* End PBXFileReference section */ 29 | 30 | /* Begin PBXFrameworksBuildPhase section */ 31 | EBEF5B491D655D6B00201FBD /* Frameworks */ = { 32 | isa = PBXFrameworksBuildPhase; 33 | buildActionMask = 2147483647; 34 | files = ( 35 | ); 36 | runOnlyForDeploymentPostprocessing = 0; 37 | }; 38 | /* End PBXFrameworksBuildPhase section */ 39 | 40 | /* Begin PBXGroup section */ 41 | EBEF5B431D655D6B00201FBD = { 42 | isa = PBXGroup; 43 | children = ( 44 | EBEF5B4E1D655D6B00201FBD /* insert_dylib */, 45 | EBEF5B4D1D655D6B00201FBD /* Products */, 46 | ); 47 | sourceTree = ""; 48 | }; 49 | EBEF5B4D1D655D6B00201FBD /* Products */ = { 50 | isa = PBXGroup; 51 | children = ( 52 | EBEF5B4C1D655D6B00201FBD /* insert_dylib */, 53 | ); 54 | name = Products; 55 | sourceTree = ""; 56 | }; 57 | EBEF5B4E1D655D6B00201FBD /* insert_dylib */ = { 58 | isa = PBXGroup; 59 | children = ( 60 | EBEF5B4F1D655D6B00201FBD /* main.m */, 61 | ); 62 | path = insert_dylib; 63 | sourceTree = ""; 64 | }; 65 | /* End PBXGroup section */ 66 | 67 | /* Begin PBXNativeTarget section */ 68 | EBEF5B4B1D655D6B00201FBD /* insert_dylib */ = { 69 | isa = PBXNativeTarget; 70 | buildConfigurationList = EBEF5B531D655D6B00201FBD /* Build configuration list for PBXNativeTarget "insert_dylib" */; 71 | buildPhases = ( 72 | EBEF5B481D655D6B00201FBD /* Sources */, 73 | EBEF5B491D655D6B00201FBD /* Frameworks */, 74 | EBEF5B4A1D655D6B00201FBD /* CopyFiles */, 75 | ); 76 | buildRules = ( 77 | ); 78 | dependencies = ( 79 | ); 80 | name = insert_dylib; 81 | productName = insert_dylib; 82 | productReference = EBEF5B4C1D655D6B00201FBD /* insert_dylib */; 83 | productType = "com.apple.product-type.tool"; 84 | }; 85 | /* End PBXNativeTarget section */ 86 | 87 | /* Begin PBXProject section */ 88 | EBEF5B441D655D6B00201FBD /* Project object */ = { 89 | isa = PBXProject; 90 | attributes = { 91 | LastUpgradeCheck = 0730; 92 | ORGANIZATIONNAME = "耿建峰"; 93 | TargetAttributes = { 94 | EBEF5B4B1D655D6B00201FBD = { 95 | CreatedOnToolsVersion = 7.3.1; 96 | }; 97 | }; 98 | }; 99 | buildConfigurationList = EBEF5B471D655D6B00201FBD /* Build configuration list for PBXProject "insert_dylib" */; 100 | compatibilityVersion = "Xcode 3.2"; 101 | developmentRegion = English; 102 | hasScannedForEncodings = 0; 103 | knownRegions = ( 104 | en, 105 | ); 106 | mainGroup = EBEF5B431D655D6B00201FBD; 107 | productRefGroup = EBEF5B4D1D655D6B00201FBD /* Products */; 108 | projectDirPath = ""; 109 | projectRoot = ""; 110 | targets = ( 111 | EBEF5B4B1D655D6B00201FBD /* insert_dylib */, 112 | ); 113 | }; 114 | /* End PBXProject section */ 115 | 116 | /* Begin PBXSourcesBuildPhase section */ 117 | EBEF5B481D655D6B00201FBD /* Sources */ = { 118 | isa = PBXSourcesBuildPhase; 119 | buildActionMask = 2147483647; 120 | files = ( 121 | EBEF5B501D655D6B00201FBD /* main.m in Sources */, 122 | ); 123 | runOnlyForDeploymentPostprocessing = 0; 124 | }; 125 | /* End PBXSourcesBuildPhase section */ 126 | 127 | /* Begin XCBuildConfiguration section */ 128 | EBEF5B511D655D6B00201FBD /* Debug */ = { 129 | isa = XCBuildConfiguration; 130 | buildSettings = { 131 | ALWAYS_SEARCH_USER_PATHS = NO; 132 | CLANG_ANALYZER_NONNULL = YES; 133 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 134 | CLANG_CXX_LIBRARY = "libc++"; 135 | CLANG_ENABLE_MODULES = YES; 136 | CLANG_ENABLE_OBJC_ARC = YES; 137 | CLANG_WARN_BOOL_CONVERSION = YES; 138 | CLANG_WARN_CONSTANT_CONVERSION = YES; 139 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 140 | CLANG_WARN_EMPTY_BODY = YES; 141 | CLANG_WARN_ENUM_CONVERSION = YES; 142 | CLANG_WARN_INT_CONVERSION = YES; 143 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 144 | CLANG_WARN_UNREACHABLE_CODE = YES; 145 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 146 | CODE_SIGN_IDENTITY = "-"; 147 | COPY_PHASE_STRIP = NO; 148 | DEBUG_INFORMATION_FORMAT = dwarf; 149 | ENABLE_STRICT_OBJC_MSGSEND = YES; 150 | ENABLE_TESTABILITY = YES; 151 | GCC_C_LANGUAGE_STANDARD = gnu99; 152 | GCC_DYNAMIC_NO_PIC = NO; 153 | GCC_NO_COMMON_BLOCKS = YES; 154 | GCC_OPTIMIZATION_LEVEL = 0; 155 | GCC_PREPROCESSOR_DEFINITIONS = ( 156 | "DEBUG=1", 157 | "$(inherited)", 158 | ); 159 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 160 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 161 | GCC_WARN_UNDECLARED_SELECTOR = YES; 162 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 163 | GCC_WARN_UNUSED_FUNCTION = YES; 164 | GCC_WARN_UNUSED_VARIABLE = YES; 165 | MACOSX_DEPLOYMENT_TARGET = 10.11; 166 | MTL_ENABLE_DEBUG_INFO = YES; 167 | ONLY_ACTIVE_ARCH = YES; 168 | SDKROOT = macosx; 169 | }; 170 | name = Debug; 171 | }; 172 | EBEF5B521D655D6B00201FBD /* Release */ = { 173 | isa = XCBuildConfiguration; 174 | buildSettings = { 175 | ALWAYS_SEARCH_USER_PATHS = NO; 176 | CLANG_ANALYZER_NONNULL = YES; 177 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 178 | CLANG_CXX_LIBRARY = "libc++"; 179 | CLANG_ENABLE_MODULES = YES; 180 | CLANG_ENABLE_OBJC_ARC = YES; 181 | CLANG_WARN_BOOL_CONVERSION = YES; 182 | CLANG_WARN_CONSTANT_CONVERSION = YES; 183 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 184 | CLANG_WARN_EMPTY_BODY = YES; 185 | CLANG_WARN_ENUM_CONVERSION = YES; 186 | CLANG_WARN_INT_CONVERSION = YES; 187 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 188 | CLANG_WARN_UNREACHABLE_CODE = YES; 189 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 190 | CODE_SIGN_IDENTITY = "-"; 191 | COPY_PHASE_STRIP = NO; 192 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 193 | ENABLE_NS_ASSERTIONS = NO; 194 | ENABLE_STRICT_OBJC_MSGSEND = YES; 195 | GCC_C_LANGUAGE_STANDARD = gnu99; 196 | GCC_NO_COMMON_BLOCKS = YES; 197 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 198 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 199 | GCC_WARN_UNDECLARED_SELECTOR = YES; 200 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 201 | GCC_WARN_UNUSED_FUNCTION = YES; 202 | GCC_WARN_UNUSED_VARIABLE = YES; 203 | MACOSX_DEPLOYMENT_TARGET = 10.11; 204 | MTL_ENABLE_DEBUG_INFO = NO; 205 | SDKROOT = macosx; 206 | }; 207 | name = Release; 208 | }; 209 | EBEF5B541D655D6B00201FBD /* Debug */ = { 210 | isa = XCBuildConfiguration; 211 | buildSettings = { 212 | PRODUCT_NAME = "$(TARGET_NAME)"; 213 | }; 214 | name = Debug; 215 | }; 216 | EBEF5B551D655D6B00201FBD /* Release */ = { 217 | isa = XCBuildConfiguration; 218 | buildSettings = { 219 | PRODUCT_NAME = "$(TARGET_NAME)"; 220 | }; 221 | name = Release; 222 | }; 223 | /* End XCBuildConfiguration section */ 224 | 225 | /* Begin XCConfigurationList section */ 226 | EBEF5B471D655D6B00201FBD /* Build configuration list for PBXProject "insert_dylib" */ = { 227 | isa = XCConfigurationList; 228 | buildConfigurations = ( 229 | EBEF5B511D655D6B00201FBD /* Debug */, 230 | EBEF5B521D655D6B00201FBD /* Release */, 231 | ); 232 | defaultConfigurationIsVisible = 0; 233 | defaultConfigurationName = Release; 234 | }; 235 | EBEF5B531D655D6B00201FBD /* Build configuration list for PBXNativeTarget "insert_dylib" */ = { 236 | isa = XCConfigurationList; 237 | buildConfigurations = ( 238 | EBEF5B541D655D6B00201FBD /* Debug */, 239 | EBEF5B551D655D6B00201FBD /* Release */, 240 | ); 241 | defaultConfigurationIsVisible = 0; 242 | }; 243 | /* End XCConfigurationList section */ 244 | }; 245 | rootObject = EBEF5B441D655D6B00201FBD /* Project object */; 246 | } 247 | -------------------------------------------------------------------------------- /insert_dylib.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /insert_dylib.xcodeproj/project.xcworkspace/xcuserdata/gengjianfeng.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gengjf/insert_dylib/1f986ed52b9d999ca75123863a35ccc96dbc835c/insert_dylib.xcodeproj/project.xcworkspace/xcuserdata/gengjianfeng.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /insert_dylib.xcodeproj/xcuserdata/gengjianfeng.xcuserdatad/xcschemes/insert_dylib.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 39 | 40 | 41 | 42 | 43 | 44 | 54 | 56 | 62 | 63 | 64 | 65 | 66 | 67 | 73 | 75 | 81 | 82 | 83 | 84 | 86 | 87 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /insert_dylib.xcodeproj/xcuserdata/gengjianfeng.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | insert_dylib.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | EBEF5B4B1D655D6B00201FBD 16 | 17 | primary 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /insert_dylib/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // insert_dylib 4 | // 5 | // Created by gengjf025 on 16/8/18. 6 | // Copyright ©99bill 2016年 gengjf025. All rights reserved. 7 | // 8 | 9 | // ./insert_dylib @executable_path(表示加载bin所在目录)/inject.dylib test 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | #define IS_64_BIT(x) ((x) == MH_MAGIC_64 || (x) == MH_CIGAM_64) 23 | #define IS_LITTLE_ENDIAN(x) ((x) == FAT_CIGAM || (x) == MH_CIGAM_64 || (x) == MH_CIGAM) 24 | #define SWAP32(x, magic) (IS_LITTLE_ENDIAN(magic)? OSSwapInt32(x): (x)) 25 | 26 | __attribute__((noreturn)) void usage(void) { 27 | printf("Usage: insert_dylib [--inplace] [--weak] dylib_path binary_path [new_path]\n"); 28 | 29 | exit(1); 30 | } 31 | 32 | __attribute__((format(printf, 1, 2))) bool ask(const char *format, ...) { 33 | char *question; 34 | asprintf(&question, "%s [y/n] ", format); 35 | 36 | va_list args; 37 | va_start(args, format); 38 | vprintf(question, args); 39 | va_end(args); 40 | 41 | free(question); 42 | 43 | while(true) { 44 | char *line = NULL; 45 | size_t size; 46 | getline(&line, &size, stdin); 47 | 48 | switch(line[0]) { 49 | case 'y': 50 | case 'Y': 51 | return true; 52 | break; 53 | case 'n': 54 | case 'N': 55 | return false; 56 | break; 57 | default: 58 | printf("Please enter y or n: "); 59 | } 60 | } 61 | } 62 | 63 | void remove_code_signature(FILE *f, struct mach_header *mh, size_t header_offset, size_t commands_offset) { 64 | fseek(f, commands_offset, SEEK_SET); 65 | 66 | uint32_t ncmds = SWAP32(mh->ncmds, mh->magic); 67 | 68 | for(int i = 0; i < ncmds; i++) { 69 | struct load_command lc; 70 | fread(&lc, sizeof(lc), 1, f); 71 | 72 | if(SWAP32(lc.cmd, mh->magic) == LC_CODE_SIGNATURE) { 73 | if(i == ncmds - 1 && ask("LC_CODE_SIGNATURE load command found. Remove it?")) { 74 | fseek(f, -((long)sizeof(lc)), SEEK_CUR); 75 | 76 | struct linkedit_data_command ldc; 77 | fread(&ldc, sizeof(ldc), 1, f); 78 | 79 | uint32_t cmdsize = SWAP32(ldc.cmdsize, mh->magic); 80 | uint32_t dataoff = SWAP32(ldc.dataoff, mh->magic); 81 | uint32_t datasize = SWAP32(ldc.datasize, mh->magic); 82 | 83 | fseek(f, -((long)sizeof(ldc)), SEEK_CUR); 84 | 85 | char *zero = calloc(cmdsize, 1); 86 | fwrite(zero, cmdsize, 1, f); 87 | free(zero); 88 | 89 | fseek(f, header_offset + dataoff, SEEK_SET); 90 | 91 | zero = calloc(datasize, 1); 92 | fwrite(zero, datasize, 1, f); 93 | free(zero); 94 | 95 | mh->ncmds = SWAP32(ncmds - 1, mh->magic); 96 | mh->sizeofcmds = SWAP32(SWAP32(mh->sizeofcmds, mh->magic) - ldc.cmdsize, mh->magic); 97 | 98 | return; 99 | } else { 100 | printf("LC_CODE_SIGNATURE is not the last load command, so couldn't remove."); 101 | } 102 | } 103 | 104 | fseek(f, SWAP32(lc.cmdsize, mh->magic) - sizeof(lc), SEEK_CUR); 105 | } 106 | } 107 | 108 | bool insert_dylib(FILE *f, size_t header_offset, const char *dylib_path, bool weak) { 109 | fseek(f, header_offset, SEEK_SET); 110 | 111 | struct mach_header mh; 112 | fread(&mh, sizeof(struct mach_header), 1, f); 113 | 114 | if(mh.magic != MH_MAGIC_64 && mh.magic != MH_CIGAM_64 && mh.magic != MH_MAGIC && mh.magic != MH_CIGAM) { 115 | printf("Unknown magic: 0x%x\n", mh.magic); 116 | return false; 117 | } 118 | 119 | size_t commands_offset = header_offset + (IS_64_BIT(mh.magic)? sizeof(struct mach_header_64): sizeof(struct mach_header)); 120 | 121 | // 屏蔽了此处代码,如果将Mach-O中Load_Signature去掉,后面重签名会出错,需要保留 122 | // remove_code_signature(f, &mh, header_offset, commands_offset); 123 | 124 | size_t dylib_path_len = strlen(dylib_path); 125 | size_t dylib_path_size = (dylib_path_len & ~3) + 4; 126 | uint32_t cmdsize = (uint32_t)(sizeof(struct dylib_command) + dylib_path_size); 127 | 128 | struct dylib_command dylib_command = { 129 | .cmd = SWAP32(weak? LC_LOAD_WEAK_DYLIB: LC_LOAD_DYLIB, mh.magic), 130 | .cmdsize = SWAP32(cmdsize, mh.magic), 131 | .dylib = { 132 | .name = SWAP32(sizeof(struct dylib_command), mh.magic), 133 | .timestamp = 0, 134 | .current_version = 0, 135 | .compatibility_version = 0 136 | } 137 | }; 138 | 139 | uint32_t sizeofcmds = SWAP32(mh.sizeofcmds, mh.magic); 140 | 141 | fseek(f, commands_offset + sizeofcmds, SEEK_SET); 142 | char space[cmdsize]; 143 | 144 | fread(&space, cmdsize, 1, f); 145 | 146 | bool empty = true; 147 | for(int i = 0; i < cmdsize; i++) { 148 | if(space[i] != 0) { 149 | empty = false; 150 | break; 151 | } 152 | } 153 | 154 | if(!empty) { 155 | if(!ask("It doesn't seem like there is enough empty space. Continue anyway?")) { 156 | return false; 157 | } 158 | } 159 | 160 | fseek(f, -((long)cmdsize), SEEK_CUR); 161 | 162 | char *dylib_path_padded = calloc(dylib_path_size, 1); 163 | memcpy(dylib_path_padded, dylib_path, dylib_path_len); 164 | 165 | fwrite(&dylib_command, sizeof(dylib_command), 1, f); 166 | fwrite(dylib_path_padded, dylib_path_size, 1, f); 167 | 168 | free(dylib_path_padded); 169 | 170 | mh.ncmds = SWAP32(SWAP32(mh.ncmds, mh.magic) + 1, mh.magic); 171 | sizeofcmds += cmdsize; 172 | mh.sizeofcmds = SWAP32(sizeofcmds, mh.magic); 173 | 174 | fseek(f, header_offset, SEEK_SET); 175 | fwrite(&mh, sizeof(mh), 1, f); 176 | 177 | return true; 178 | } 179 | 180 | int main(int argc, const char *argv[]) { 181 | int inplace = false; 182 | int weak = false; 183 | 184 | struct option long_options[] = { 185 | {"inplace", no_argument, &inplace, true}, 186 | {"weak", no_argument, &weak, true} 187 | }; 188 | 189 | while(true) { 190 | int option_index = 0; 191 | 192 | int c = getopt_long(argc, (char *const *)argv, "", long_options, &option_index); 193 | 194 | if(c == -1) { 195 | break; 196 | } 197 | 198 | switch(c) { 199 | case 0: 200 | break; 201 | case '?': 202 | usage(); 203 | break; 204 | default: 205 | abort(); 206 | break; 207 | } 208 | } 209 | 210 | argv = &argv[optind - 1]; 211 | argc -= optind - 1; 212 | 213 | if(argc < 3 || argc > 4) { 214 | usage(); 215 | } 216 | 217 | const char *lc_name = weak? "LC_LOAD_WEAK_DYLIB": "LC_LOAD_DYLIB"; 218 | 219 | const char *dylib_path = argv[1]; 220 | const char *binary_path = argv[2]; 221 | 222 | struct stat s; 223 | 224 | if(stat(binary_path, &s) != 0) { 225 | perror(binary_path); 226 | exit(1); 227 | } 228 | 229 | if(stat(dylib_path, &s) != 0) { 230 | if(!ask("The provided dylib path doesn't exist. Continue anyway?")) { 231 | exit(1); 232 | } 233 | } 234 | 235 | bool binary_path_was_malloced = false; 236 | if(!inplace) { 237 | char *new_binary_path; 238 | if(argc == 4) { 239 | new_binary_path = (char *)argv[3]; 240 | } else { 241 | asprintf(&new_binary_path, "%s_patched", binary_path); 242 | binary_path_was_malloced = true; 243 | } 244 | 245 | if(stat(new_binary_path, &s) == 0) { 246 | if(!ask("%s already exists. Overwrite it?", new_binary_path)) { 247 | exit(1); 248 | } 249 | } 250 | 251 | if(copyfile(binary_path, new_binary_path, NULL, COPYFILE_DATA | COPYFILE_UNLINK)) { 252 | printf("Failed to create %s\n", new_binary_path); 253 | exit(1); 254 | } 255 | 256 | binary_path = new_binary_path; 257 | } 258 | 259 | FILE *f = fopen(binary_path, "r+"); 260 | 261 | if(!f) { 262 | printf("Couldn't open file %s\n", argv[1]); 263 | exit(1); 264 | } 265 | 266 | bool success = true; 267 | 268 | uint32_t magic; 269 | fread(&magic, sizeof(uint32_t), 1, f); 270 | 271 | switch(magic) { 272 | case FAT_MAGIC: 273 | case FAT_CIGAM: { 274 | fseek(f, 0, SEEK_SET); 275 | 276 | struct fat_header fh; 277 | fread(&fh, sizeof(struct fat_header), 1, f); 278 | 279 | uint32_t nfat_arch = SWAP32(fh.nfat_arch, magic); 280 | 281 | printf("Binary is a fat binary with %d archs.\n", nfat_arch); 282 | 283 | struct fat_arch archs[nfat_arch]; 284 | fread(&archs, sizeof(archs), 1, f); 285 | 286 | int fails = 0; 287 | 288 | for(int i = 0; i < nfat_arch; i++) { 289 | bool r = insert_dylib(f, SWAP32(archs[i].offset, magic), dylib_path, weak); 290 | if(!r) { 291 | printf("Failed to add %s to arch #%d!\n", lc_name, i + 1); 292 | fails++; 293 | } 294 | } 295 | 296 | if(fails == 0) { 297 | printf("Added %s to all archs in %s\n", lc_name, binary_path); 298 | } else if(fails == nfat_arch) { 299 | printf("Failed to add %s to any archs.\n", lc_name); 300 | success = false; 301 | } else { 302 | printf("Added %s to %d/%d archs in %s\n", lc_name, nfat_arch - fails, nfat_arch, binary_path); 303 | } 304 | 305 | break; 306 | } 307 | case MH_MAGIC_64: 308 | case MH_CIGAM_64: 309 | case MH_MAGIC: 310 | case MH_CIGAM: 311 | if(insert_dylib(f, 0, dylib_path, weak)) { 312 | printf("Added %s to %s\n", lc_name, binary_path); 313 | } else { 314 | printf("Failed to add %s!\n", lc_name); 315 | success = false; 316 | } 317 | break; 318 | default: 319 | printf("Unknown magic: 0x%x\n", magic); 320 | exit(1); 321 | } 322 | 323 | fclose(f); 324 | 325 | if(!success) { 326 | if(!inplace) { 327 | unlink(binary_path); 328 | } 329 | exit(1); 330 | } 331 | 332 | if(binary_path_was_malloced) { 333 | free((void *)binary_path); 334 | } 335 | 336 | return 0; 337 | } 338 | --------------------------------------------------------------------------------