├── .gitignore ├── .gitmodules ├── README.md ├── app2dylib.xcodeproj ├── project.pbxproj └── project.xcworkspace │ └── contents.xcworkspacedata ├── makefile └── src ├── app2dylib_template.h └── main.mm /.gitignore: -------------------------------------------------------------------------------- 1 | app2dylib 2 | 3 | 4 | # svn 5 | *.svn* 6 | 7 | # mac 8 | __MACOSX 9 | *.DS_Store* 10 | *._* 11 | *.lock 12 | *.Spotlight-V100 13 | *.Trashes 14 | *ehthumbs.db 15 | *Thumbs.db 16 | 17 | # Python 18 | *.pyc 19 | __pycache__/ 20 | 21 | 22 | # Vim 23 | *.swp 24 | *.swo 25 | *.swn 26 | 27 | # Xcode 28 | *~.nib 29 | build/ 30 | *.pbxuser 31 | !default.pbxuser 32 | *.mode1v3 33 | !default.mode1v3 34 | *.mode2v3 35 | !default.mode2v3 36 | *.perspectivev3 37 | !default.perspectivev3 38 | xcuserdata 39 | *.xccheckout 40 | *.xcscmblueprint 41 | *.moved-aside 42 | DerivedData 43 | *.hmap 44 | *.ipa 45 | *.xcuserstate 46 | 47 | # generated files 48 | bin/ 49 | gen/ 50 | 51 | # built application files 52 | *.apk 53 | *.ap_ 54 | 55 | # files for the dex VM 56 | *.dex 57 | 58 | # Java class files 59 | *.class 60 | 61 | # Local configuration file (sdk path, etc) 62 | local.properties 63 | 64 | # Eclipse project files 65 | .classpath 66 | .project 67 | .settings/ 68 | 69 | # Proguard folder generated by Eclipse 70 | proguard/ 71 | 72 | # Intellij project files 73 | *.iml 74 | *.ipr 75 | *.iws 76 | .idea/ 77 | 78 | #Pod 79 | Pods/ 80 | !podfile 81 | !podfile.lock 82 | 83 | # Gradle files 84 | .gradle 85 | build/ 86 | 87 | # Ignore Gradle GUI config 88 | gradle-app.setting 89 | 90 | # Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored) 91 | !gradle-wrapper.jar 92 | 93 | #Android studio For eclipse 94 | #build.gradle 95 | #gradle/ 96 | #gradlew 97 | #gradlew.bat 98 | #.gradle/ 99 | # 100 | 101 | 102 | 103 | #tweak 104 | _/ 105 | .theos/ 106 | obj/ 107 | *.deb 108 | 109 | 110 | 111 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "class-dump"] 2 | path = class-dump 3 | url = https://github.com/0xced/class-dump 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # app2dylib 2 | A reverse engineering tool to convert iOS app to dylib 3 | 4 | 5 | # Usage 6 | 7 | ``` 8 | 9 | git clone --recursive https://github.com/tobefuturer/app2dylib.git 10 | cd app2dylib && make 11 | ./app2dylib 12 | 13 | ``` 14 | 15 | example : 16 | 17 | ``` 18 | 19 | ./app2dylib /tmp/AlipayWallet -o /tmp/libAlipayApp.dylib 20 | 21 | ``` 22 | 23 | You can use libAlipayApp.dylib as a normal dynamic library. 24 | 25 | Call OC method or call C function like this: 26 | 27 | ``` 28 | 29 | #import 30 | #import 31 | 32 | #import 33 | #import 34 | #import 35 | 36 | int main(int argc, char * argv[]) { 37 | NSString * dylibName = @"libAlipayApp"; 38 | NSString * path = [[NSBundle mainBundle] pathForResource:dylibName ofType:@"dylib"]; 39 | if (dlopen(path.UTF8String, RTLD_NOW) == NULL){ 40 | NSLog(@"dlopen failed ,error %s", dlerror()); 41 | return 0; 42 | }; 43 | 44 | uint32_t dylib_count = _dyld_image_count(); 45 | uint64_t slide = 0; 46 | for (int i = 0; i < dylib_count; i ++) { 47 | const char * name = _dyld_get_image_name(i); 48 | if ([[NSString stringWithUTF8String:name] isEqualToString:path]) { 49 | slide = _dyld_get_image_vmaddr_slide(i); 50 | } 51 | } 52 | assert(slide != 0); 53 | 54 | 55 | Class c = NSClassFromString(@"aluSecurity"); 56 | NSString * plain = @"alipay"; 57 | NSString * pubkey = @"MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDZ6i9VNEGEaZaYE7XffA9XRj15cp/ZKhHYY43EEva8LIhCWi29EREaF4JjZVMwFpUAfrL+9gpA7NMQmaMRHbrz1KHe2Ho4HpUhEac8M9zUbNvaDKSlhx0lq/15TQP+57oQbfJ9oKKd+he4Yd6jpBI3UtGmwJyN/T1S0DQ0aXR8OQIDAQAB"; 58 | NSString * cipher = [c performSelector:NSSelectorFromString(@"rsaEncryptText:pubKey:") withObject:plain withObject:pubkey]; 59 | NSLog(@"ciphertext: %@", cipher); 60 | 61 | typedef int (*BASE64_ENCODE_FUNC_TYPE) (char * output, int * output_size , char * input, int input_length); 62 | 63 | /** get function pointer*/ 64 | BASE64_ENCODE_FUNC_TYPE base64_encode = (BASE64_ENCODE_FUNC_TYPE)(slide + 0xa798e4); 65 | char output[1000] = {0}; 66 | int length = 1000; 67 | char * input = "alipay"; 68 | base64_encode(output, & length, input, (int)strlen(input)); 69 | NSLog(@"base64 length: %d , %s", length, output); 70 | 71 | } 72 | 73 | 74 | ``` 75 | -------------------------------------------------------------------------------- /app2dylib.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 8F54CA371DA4298500221131 /* main.mm in Sources */ = {isa = PBXBuildFile; fileRef = 8F54CA361DA4298500221131 /* main.mm */; }; 11 | 8F54CA521DA4363200221131 /* libMachObjC.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 8F54CA421DA429A600221131 /* libMachObjC.a */; }; 12 | /* End PBXBuildFile section */ 13 | 14 | /* Begin PBXContainerItemProxy section */ 15 | 8F54CA411DA429A600221131 /* PBXContainerItemProxy */ = { 16 | isa = PBXContainerItemProxy; 17 | containerPortal = 8F54CA381DA429A600221131 /* class-dump.xcodeproj */; 18 | proxyType = 2; 19 | remoteGlobalIDString = 013D1F1113A5AE5A00BF0A67; 20 | remoteInfo = MachObjC; 21 | }; 22 | 8F54CA431DA429A600221131 /* PBXContainerItemProxy */ = { 23 | isa = PBXContainerItemProxy; 24 | containerPortal = 8F54CA381DA429A600221131 /* class-dump.xcodeproj */; 25 | proxyType = 2; 26 | remoteGlobalIDString = 01EB825F13A590D9003EDE60; 27 | remoteInfo = "class-dump"; 28 | }; 29 | 8F54CA451DA429A600221131 /* PBXContainerItemProxy */ = { 30 | isa = PBXContainerItemProxy; 31 | containerPortal = 8F54CA381DA429A600221131 /* class-dump.xcodeproj */; 32 | proxyType = 2; 33 | remoteGlobalIDString = 013D1EFB13A5A0F100BF0A67; 34 | remoteInfo = deprotect; 35 | }; 36 | 8F54CA471DA429A600221131 /* PBXContainerItemProxy */ = { 37 | isa = PBXContainerItemProxy; 38 | containerPortal = 8F54CA381DA429A600221131 /* class-dump.xcodeproj */; 39 | proxyType = 2; 40 | remoteGlobalIDString = 01B02CFF13A5B0DC0047BC53; 41 | remoteInfo = formatType; 42 | }; 43 | 8F54CA491DA429A600221131 /* PBXContainerItemProxy */ = { 44 | isa = PBXContainerItemProxy; 45 | containerPortal = 8F54CA381DA429A600221131 /* class-dump.xcodeproj */; 46 | proxyType = 2; 47 | remoteGlobalIDString = 0165B8B11827137D00CC647F; 48 | remoteInfo = UnitTests; 49 | }; 50 | 8F9B90F71DA5028700F54214 /* PBXContainerItemProxy */ = { 51 | isa = PBXContainerItemProxy; 52 | containerPortal = 8F54CA381DA429A600221131 /* class-dump.xcodeproj */; 53 | proxyType = 1; 54 | remoteGlobalIDString = 013D1F1013A5AE5A00BF0A67; 55 | remoteInfo = MachObjC; 56 | }; 57 | /* End PBXContainerItemProxy section */ 58 | 59 | /* Begin PBXCopyFilesBuildPhase section */ 60 | 8F54CA291DA4292900221131 /* CopyFiles */ = { 61 | isa = PBXCopyFilesBuildPhase; 62 | buildActionMask = 2147483647; 63 | dstPath = /usr/share/man/man1/; 64 | dstSubfolderSpec = 0; 65 | files = ( 66 | ); 67 | runOnlyForDeploymentPostprocessing = 1; 68 | }; 69 | /* End PBXCopyFilesBuildPhase section */ 70 | 71 | /* Begin PBXFileReference section */ 72 | 8F54CA2B1DA4292900221131 /* app2dylib */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = app2dylib; sourceTree = BUILT_PRODUCTS_DIR; }; 73 | 8F54CA361DA4298500221131 /* main.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = main.mm; sourceTree = ""; }; 74 | 8F54CA381DA429A600221131 /* class-dump.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = "class-dump.xcodeproj"; path = "class-dump/class-dump.xcodeproj"; sourceTree = ""; }; 75 | 8F54CA5A1DA441E000221131 /* app2dylib_template.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = app2dylib_template.h; sourceTree = ""; }; 76 | /* End PBXFileReference section */ 77 | 78 | /* Begin PBXFrameworksBuildPhase section */ 79 | 8F54CA281DA4292900221131 /* Frameworks */ = { 80 | isa = PBXFrameworksBuildPhase; 81 | buildActionMask = 2147483647; 82 | files = ( 83 | 8F54CA521DA4363200221131 /* libMachObjC.a in Frameworks */, 84 | ); 85 | runOnlyForDeploymentPostprocessing = 0; 86 | }; 87 | /* End PBXFrameworksBuildPhase section */ 88 | 89 | /* Begin PBXGroup section */ 90 | 8F54CA221DA4292900221131 = { 91 | isa = PBXGroup; 92 | children = ( 93 | 8F54CA381DA429A600221131 /* class-dump.xcodeproj */, 94 | 8F54CA351DA4296700221131 /* src */, 95 | 8F54CA2C1DA4292900221131 /* Products */, 96 | ); 97 | sourceTree = ""; 98 | }; 99 | 8F54CA2C1DA4292900221131 /* Products */ = { 100 | isa = PBXGroup; 101 | children = ( 102 | 8F54CA2B1DA4292900221131 /* app2dylib */, 103 | ); 104 | name = Products; 105 | sourceTree = ""; 106 | }; 107 | 8F54CA351DA4296700221131 /* src */ = { 108 | isa = PBXGroup; 109 | children = ( 110 | 8F54CA361DA4298500221131 /* main.mm */, 111 | 8F54CA5A1DA441E000221131 /* app2dylib_template.h */, 112 | ); 113 | path = src; 114 | sourceTree = ""; 115 | }; 116 | 8F54CA391DA429A600221131 /* Products */ = { 117 | isa = PBXGroup; 118 | children = ( 119 | 8F54CA421DA429A600221131 /* libMachObjC.a */, 120 | 8F54CA441DA429A600221131 /* class-dump */, 121 | 8F54CA461DA429A600221131 /* deprotect */, 122 | 8F54CA481DA429A600221131 /* formatType */, 123 | 8F54CA4A1DA429A600221131 /* UnitTests.xctest */, 124 | ); 125 | name = Products; 126 | sourceTree = ""; 127 | }; 128 | /* End PBXGroup section */ 129 | 130 | /* Begin PBXNativeTarget section */ 131 | 8F54CA2A1DA4292900221131 /* app2dylib */ = { 132 | isa = PBXNativeTarget; 133 | buildConfigurationList = 8F54CA321DA4292900221131 /* Build configuration list for PBXNativeTarget "app2dylib" */; 134 | buildPhases = ( 135 | 8F54CA271DA4292900221131 /* Sources */, 136 | 8F54CA281DA4292900221131 /* Frameworks */, 137 | 8F54CA291DA4292900221131 /* CopyFiles */, 138 | ); 139 | buildRules = ( 140 | ); 141 | dependencies = ( 142 | 8F9B90F81DA5028700F54214 /* PBXTargetDependency */, 143 | ); 144 | name = app2dylib; 145 | productName = app2dylib; 146 | productReference = 8F54CA2B1DA4292900221131 /* app2dylib */; 147 | productType = "com.apple.product-type.tool"; 148 | }; 149 | /* End PBXNativeTarget section */ 150 | 151 | /* Begin PBXProject section */ 152 | 8F54CA231DA4292900221131 /* Project object */ = { 153 | isa = PBXProject; 154 | attributes = { 155 | LastUpgradeCheck = 0800; 156 | ORGANIZATIONNAME = Jun; 157 | TargetAttributes = { 158 | 8F54CA2A1DA4292900221131 = { 159 | CreatedOnToolsVersion = 8.0; 160 | ProvisioningStyle = Automatic; 161 | }; 162 | }; 163 | }; 164 | buildConfigurationList = 8F54CA261DA4292900221131 /* Build configuration list for PBXProject "app2dylib" */; 165 | compatibilityVersion = "Xcode 3.2"; 166 | developmentRegion = English; 167 | hasScannedForEncodings = 0; 168 | knownRegions = ( 169 | en, 170 | ); 171 | mainGroup = 8F54CA221DA4292900221131; 172 | productRefGroup = 8F54CA2C1DA4292900221131 /* Products */; 173 | projectDirPath = ""; 174 | projectReferences = ( 175 | { 176 | ProductGroup = 8F54CA391DA429A600221131 /* Products */; 177 | ProjectRef = 8F54CA381DA429A600221131 /* class-dump.xcodeproj */; 178 | }, 179 | ); 180 | projectRoot = ""; 181 | targets = ( 182 | 8F54CA2A1DA4292900221131 /* app2dylib */, 183 | ); 184 | }; 185 | /* End PBXProject section */ 186 | 187 | /* Begin PBXReferenceProxy section */ 188 | 8F54CA421DA429A600221131 /* libMachObjC.a */ = { 189 | isa = PBXReferenceProxy; 190 | fileType = archive.ar; 191 | path = libMachObjC.a; 192 | remoteRef = 8F54CA411DA429A600221131 /* PBXContainerItemProxy */; 193 | sourceTree = BUILT_PRODUCTS_DIR; 194 | }; 195 | 8F54CA441DA429A600221131 /* class-dump */ = { 196 | isa = PBXReferenceProxy; 197 | fileType = "compiled.mach-o.executable"; 198 | path = "class-dump"; 199 | remoteRef = 8F54CA431DA429A600221131 /* PBXContainerItemProxy */; 200 | sourceTree = BUILT_PRODUCTS_DIR; 201 | }; 202 | 8F54CA461DA429A600221131 /* deprotect */ = { 203 | isa = PBXReferenceProxy; 204 | fileType = "compiled.mach-o.executable"; 205 | path = deprotect; 206 | remoteRef = 8F54CA451DA429A600221131 /* PBXContainerItemProxy */; 207 | sourceTree = BUILT_PRODUCTS_DIR; 208 | }; 209 | 8F54CA481DA429A600221131 /* formatType */ = { 210 | isa = PBXReferenceProxy; 211 | fileType = "compiled.mach-o.executable"; 212 | path = formatType; 213 | remoteRef = 8F54CA471DA429A600221131 /* PBXContainerItemProxy */; 214 | sourceTree = BUILT_PRODUCTS_DIR; 215 | }; 216 | 8F54CA4A1DA429A600221131 /* UnitTests.xctest */ = { 217 | isa = PBXReferenceProxy; 218 | fileType = wrapper.cfbundle; 219 | path = UnitTests.xctest; 220 | remoteRef = 8F54CA491DA429A600221131 /* PBXContainerItemProxy */; 221 | sourceTree = BUILT_PRODUCTS_DIR; 222 | }; 223 | /* End PBXReferenceProxy section */ 224 | 225 | /* Begin PBXSourcesBuildPhase section */ 226 | 8F54CA271DA4292900221131 /* Sources */ = { 227 | isa = PBXSourcesBuildPhase; 228 | buildActionMask = 2147483647; 229 | files = ( 230 | 8F54CA371DA4298500221131 /* main.mm in Sources */, 231 | ); 232 | runOnlyForDeploymentPostprocessing = 0; 233 | }; 234 | /* End PBXSourcesBuildPhase section */ 235 | 236 | /* Begin PBXTargetDependency section */ 237 | 8F9B90F81DA5028700F54214 /* PBXTargetDependency */ = { 238 | isa = PBXTargetDependency; 239 | name = MachObjC; 240 | targetProxy = 8F9B90F71DA5028700F54214 /* PBXContainerItemProxy */; 241 | }; 242 | /* End PBXTargetDependency section */ 243 | 244 | /* Begin XCBuildConfiguration section */ 245 | 8F54CA301DA4292900221131 /* Debug */ = { 246 | isa = XCBuildConfiguration; 247 | buildSettings = { 248 | ALWAYS_SEARCH_USER_PATHS = NO; 249 | CLANG_ANALYZER_NONNULL = YES; 250 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 251 | CLANG_CXX_LIBRARY = "libc++"; 252 | CLANG_ENABLE_MODULES = YES; 253 | CLANG_ENABLE_OBJC_ARC = YES; 254 | CLANG_WARN_BOOL_CONVERSION = YES; 255 | CLANG_WARN_CONSTANT_CONVERSION = YES; 256 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 257 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 258 | CLANG_WARN_EMPTY_BODY = YES; 259 | CLANG_WARN_ENUM_CONVERSION = YES; 260 | CLANG_WARN_INFINITE_RECURSION = YES; 261 | CLANG_WARN_INT_CONVERSION = YES; 262 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 263 | CLANG_WARN_SUSPICIOUS_MOVES = YES; 264 | CLANG_WARN_UNREACHABLE_CODE = YES; 265 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 266 | CODE_SIGN_IDENTITY = "-"; 267 | COPY_PHASE_STRIP = NO; 268 | DEBUG_INFORMATION_FORMAT = dwarf; 269 | ENABLE_STRICT_OBJC_MSGSEND = YES; 270 | ENABLE_TESTABILITY = YES; 271 | GCC_C_LANGUAGE_STANDARD = gnu99; 272 | GCC_DYNAMIC_NO_PIC = NO; 273 | GCC_NO_COMMON_BLOCKS = YES; 274 | GCC_OPTIMIZATION_LEVEL = 0; 275 | GCC_PREPROCESSOR_DEFINITIONS = ( 276 | "DEBUG=1", 277 | "$(inherited)", 278 | ); 279 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 280 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 281 | GCC_WARN_UNDECLARED_SELECTOR = YES; 282 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 283 | GCC_WARN_UNUSED_FUNCTION = YES; 284 | GCC_WARN_UNUSED_VARIABLE = YES; 285 | MACOSX_DEPLOYMENT_TARGET = 10.11; 286 | MTL_ENABLE_DEBUG_INFO = YES; 287 | ONLY_ACTIVE_ARCH = YES; 288 | SDKROOT = macosx; 289 | }; 290 | name = Debug; 291 | }; 292 | 8F54CA311DA4292900221131 /* Release */ = { 293 | isa = XCBuildConfiguration; 294 | buildSettings = { 295 | ALWAYS_SEARCH_USER_PATHS = NO; 296 | CLANG_ANALYZER_NONNULL = YES; 297 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 298 | CLANG_CXX_LIBRARY = "libc++"; 299 | CLANG_ENABLE_MODULES = YES; 300 | CLANG_ENABLE_OBJC_ARC = YES; 301 | CLANG_WARN_BOOL_CONVERSION = YES; 302 | CLANG_WARN_CONSTANT_CONVERSION = YES; 303 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 304 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 305 | CLANG_WARN_EMPTY_BODY = YES; 306 | CLANG_WARN_ENUM_CONVERSION = YES; 307 | CLANG_WARN_INFINITE_RECURSION = YES; 308 | CLANG_WARN_INT_CONVERSION = YES; 309 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 310 | CLANG_WARN_SUSPICIOUS_MOVES = YES; 311 | CLANG_WARN_UNREACHABLE_CODE = YES; 312 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 313 | CODE_SIGN_IDENTITY = "-"; 314 | COPY_PHASE_STRIP = NO; 315 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 316 | ENABLE_NS_ASSERTIONS = NO; 317 | ENABLE_STRICT_OBJC_MSGSEND = YES; 318 | GCC_C_LANGUAGE_STANDARD = gnu99; 319 | GCC_NO_COMMON_BLOCKS = YES; 320 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 321 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 322 | GCC_WARN_UNDECLARED_SELECTOR = YES; 323 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 324 | GCC_WARN_UNUSED_FUNCTION = YES; 325 | GCC_WARN_UNUSED_VARIABLE = YES; 326 | MACOSX_DEPLOYMENT_TARGET = 10.11; 327 | MTL_ENABLE_DEBUG_INFO = NO; 328 | SDKROOT = macosx; 329 | }; 330 | name = Release; 331 | }; 332 | 8F54CA331DA4292900221131 /* Debug */ = { 333 | isa = XCBuildConfiguration; 334 | buildSettings = { 335 | PRODUCT_NAME = "$(TARGET_NAME)"; 336 | USER_HEADER_SEARCH_PATHS = "$(SRCROOT)/class-dump/Source/**"; 337 | }; 338 | name = Debug; 339 | }; 340 | 8F54CA341DA4292900221131 /* Release */ = { 341 | isa = XCBuildConfiguration; 342 | buildSettings = { 343 | PRODUCT_NAME = "$(TARGET_NAME)"; 344 | USER_HEADER_SEARCH_PATHS = "$(SRCROOT)/class-dump/Source/**"; 345 | }; 346 | name = Release; 347 | }; 348 | /* End XCBuildConfiguration section */ 349 | 350 | /* Begin XCConfigurationList section */ 351 | 8F54CA261DA4292900221131 /* Build configuration list for PBXProject "app2dylib" */ = { 352 | isa = XCConfigurationList; 353 | buildConfigurations = ( 354 | 8F54CA301DA4292900221131 /* Debug */, 355 | 8F54CA311DA4292900221131 /* Release */, 356 | ); 357 | defaultConfigurationIsVisible = 0; 358 | defaultConfigurationName = Release; 359 | }; 360 | 8F54CA321DA4292900221131 /* Build configuration list for PBXNativeTarget "app2dylib" */ = { 361 | isa = XCConfigurationList; 362 | buildConfigurations = ( 363 | 8F54CA331DA4292900221131 /* Debug */, 364 | 8F54CA341DA4292900221131 /* Release */, 365 | ); 366 | defaultConfigurationIsVisible = 0; 367 | defaultConfigurationName = Release; 368 | }; 369 | /* End XCConfigurationList section */ 370 | }; 371 | rootObject = 8F54CA231DA4292900221131 /* Project object */; 372 | } 373 | -------------------------------------------------------------------------------- /app2dylib.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /makefile: -------------------------------------------------------------------------------- 1 | 2 | .PHONY:app2dylib 3 | 4 | TMP_FILE := libMachObjC.a app2dylib.dSYM/ build/ 5 | 6 | restore-symbol: 7 | rm -f app2dylib 8 | xcodebuild -project "app2dylib.xcodeproj" -target "app2dylib" -configuration "Release" CONFIGURATION_BUILD_DIR="$(shell pwd)" -jobs 4 build 9 | rm -rf $(TMP_FILE) 10 | 11 | 12 | clean: 13 | rm -rf app2dylib $(TMP_FILE) 14 | 15 | -------------------------------------------------------------------------------- /src/app2dylib_template.h: -------------------------------------------------------------------------------- 1 | // 2 | // app2dylib_template.h 3 | // app2dylib 4 | // 5 | // Created by EugeneYang on 16/10/5. 6 | // Copyright © 2016年 Jun. All rights reserved. 7 | // 8 | 9 | #ifndef app2dylib_template_h 10 | #define app2dylib_template_h 11 | 12 | 13 | #import 14 | #include 15 | #include 16 | #import "CDFile.h" 17 | #import "CDMachOFile.h" 18 | #import "CDLCSymbolTable.h" 19 | #import "CDLCSegment.h" 20 | #import "CDSymbol.h" 21 | #import "CDLCDynamicSymbolTable.h" 22 | #import "CDLCLinkeditData.h" 23 | #import "CDClassDump.h" 24 | #import "CDFatFile.h" 25 | #import "CDLCDyldInfo.h" 26 | #import "CDSection.h" 27 | 28 | #define round(v,r) ( (v + (r-1) ) & (-r) ) 29 | 30 | extern NSMutableSet * rebasePointerSet; 31 | 32 | 33 | #define PAGEZERO_SIZE_AFTER_MODIFY 0x4000 34 | 35 | 36 | 37 | 38 | 39 | template 40 | void app2dylib(NSString *inpath, NSString * outpath){ 41 | 42 | 43 | NSMutableData * outData = [[NSMutableData alloc] initWithContentsOfFile:inpath]; 44 | 45 | CDFile * ofile = [CDFile fileWithContentsOfFile:inpath searchPathState:nil]; 46 | 47 | CDMachOFile * machOFile = (CDMachOFile *)ofile; 48 | CDLCSegment * pagezeroSeg = [machOFile segmentWithName:@"__PAGEZERO"]; 49 | [machOFile.dyldInfo performSelector:@selector(logRebaseInfo)]; 50 | 51 | auto seg_cmd = (segment_command_t *)((char *)outData.mutableBytes + pagezeroSeg.commandOffset); 52 | const uint64 PAGEZERO_SIZE_DELTA = seg_cmd -> vmsize - PAGEZERO_SIZE_AFTER_MODIFY; 53 | 54 | auto header = (mach_header_t * )outData.mutableBytes; 55 | header -> filetype = MH_DYLIB; 56 | header -> flags = MH_NOUNDEFS | MH_DYLDLINK | MH_TWOLEVEL | MH_NO_REEXPORTED_DYLIBS; 57 | 58 | for (CDLCSegment *seg in [machOFile segments]) { 59 | auto seg_cmd = (segment_command_t *)((char *)outData.mutableBytes + seg.commandOffset); 60 | assert([seg.name isEqualToString:pagezeroSeg.name] || seg_cmd -> vmaddr > PAGEZERO_SIZE_DELTA); 61 | seg_cmd -> vmaddr -= PAGEZERO_SIZE_DELTA; 62 | 63 | 64 | char * segment_end = (char *)seg_cmd + (seg.cmdsize); 65 | for (auto sec = (section_t *)(seg_cmd + 1); (char *)sec < (char*)segment_end; sec += 1) { 66 | assert(sec -> addr > PAGEZERO_SIZE_DELTA); 67 | sec -> addr -= PAGEZERO_SIZE_DELTA; 68 | } 69 | } 70 | 71 | auto __pagezero_seg_cmd = (segment_command_t *) ((char *)outData.mutableBytes + sizeof(mach_header_t)); 72 | __pagezero_seg_cmd -> vmaddr = 0; 73 | __pagezero_seg_cmd -> vmsize = PAGEZERO_SIZE_AFTER_MODIFY; 74 | __pagezero_seg_cmd -> maxprot = 0x3; 75 | __pagezero_seg_cmd -> initprot = 0x3; 76 | strcpy(__pagezero_seg_cmd -> segname, "__ZERO"); 77 | 78 | 79 | 80 | NSString * dylibName = [outpath lastPathComponent]; 81 | 82 | NSString * dylibPath = nil; 83 | 84 | if(machOFile.minVersionIOS != nil && machOFile.minVersionMacOSX == nil) { 85 | dylibPath = [@"@executable_path" stringByAppendingPathComponent:dylibName]; 86 | } 87 | 88 | if(machOFile.minVersionIOS == nil && machOFile.minVersionMacOSX != nil) { 89 | dylibPath = [@"@executable_path/../Resources" stringByAppendingPathComponent:dylibName]; 90 | } 91 | 92 | if(!dylibPath){ 93 | NSLog(@"Mach-o file must have a Load Command named LC_VERSION_MIN_MACOSX or LC_VERSION_MIN_IPHONEOS!"); 94 | exit(1); 95 | } 96 | 97 | CDLCDyldInfo *dyldInfo = machOFile.dyldInfo; 98 | uint32 dylib_cmd_size = round((int)dylibPath.length + 1,8) + sizeof(dylib_command_t); 99 | auto dylib_cmd = (dylib_command_t *)((char *)outData.mutableBytes + dyldInfo.commandOffset); 100 | char *loadcmd_end = (char *)outData.mutableBytes + sizeof(mach_header_t) + header -> sizeofcmds; 101 | 102 | { 103 | CDLCSegment *TEXT_seg = [machOFile segmentWithName:@"__TEXT"]; 104 | CDSection *text_sec = [TEXT_seg sectionWithName:@"__text"]; 105 | 106 | uint64_t fileOffset_text_sec = [text_sec fileOffsetForAddress:text_sec.addr]; 107 | 108 | uint64_t need_space = sizeof(mach_header_t) + header -> sizeofcmds + dylib_cmd_size; 109 | if (fileOffset_text_sec < need_space) { 110 | NSLog(@"It seem there is not empty sapce to insert dylib_command"); 111 | exit(1); 112 | } 113 | } 114 | 115 | 116 | long movesize = loadcmd_end - (char *)dylib_cmd; 117 | void *moveto = (char * )dylib_cmd + dylib_cmd_size; 118 | memmove(moveto, dylib_cmd, movesize); 119 | 120 | dylib_cmd -> cmd = LC_ID_DYLIB; 121 | dylib_cmd -> cmdsize = dylib_cmd_size; 122 | dylib_cmd -> dylib.name.offset = sizeof(dylib_command_t); 123 | dylib_cmd -> dylib.timestamp = 1; 124 | dylib_cmd -> dylib.current_version = 0x10000; 125 | dylib_cmd -> dylib.compatibility_version = 0x10000; 126 | strcpy((char *)dylib_cmd + sizeof(dylib_command_t), dylibPath.UTF8String); 127 | 128 | 129 | header -> ncmds += 1; 130 | header -> sizeofcmds += dylib_cmd_size; 131 | 132 | 133 | for (NSNumber * num in rebasePointerSet) { 134 | uint64_t addr = [num unsignedLongLongValue]; 135 | uint64_t offset = [machOFile dataOffsetForAddress:addr]; 136 | auto locationToFix = (IntTypeForPointer *) ((char *)outData.mutableBytes + (uint32_t)offset); 137 | (* locationToFix) -= PAGEZERO_SIZE_DELTA; 138 | } 139 | 140 | 141 | 142 | char * nlistsData = (char *)outData.mutableBytes + machOFile.symbolTable.symoff; 143 | 144 | 145 | nlist_t * list = (nlist_t * )nlistsData; 146 | for (int i = 0; i < machOFile.symbolTable.nsyms; i ++){ 147 | if(((list[i].n_type & N_TYPE) == N_SECT) && (list[i].n_sect != NO_SECT)){ 148 | if (list[i].n_value > PAGEZERO_SIZE_DELTA) { 149 | list[i].n_value -= PAGEZERO_SIZE_DELTA; 150 | } 151 | } 152 | } 153 | 154 | 155 | NSError * err = nil; 156 | [outData writeToFile:outpath options:NSDataWritingWithoutOverwriting error:&err]; 157 | 158 | if (!err) { 159 | chmod(outpath.UTF8String, 0755); 160 | }else{ 161 | NSLog(@"Write file error : %@", err); 162 | return; 163 | } 164 | 165 | 166 | 167 | } 168 | 169 | 170 | 171 | #endif /* app2dylib_template_h */ 172 | -------------------------------------------------------------------------------- /src/main.mm: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // restore-symbol 4 | // 5 | // Created by EugeneYang on 16/8/16. 6 | // 7 | // 8 | 9 | #import 10 | #include 11 | #include 12 | #import "CDFile.h" 13 | #import "CDMachOFile.h" 14 | #import "CDLCSymbolTable.h" 15 | #import "CDLCSegment.h" 16 | #import "CDSymbol.h" 17 | #import "CDLCDynamicSymbolTable.h" 18 | #import "CDLCLinkeditData.h" 19 | #import "CDClassDump.h" 20 | #import "CDFatFile.h" 21 | #import "CDLCDyldInfo.h" 22 | #import "CDSection.h" 23 | 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | 31 | 32 | #import "app2dylib_template.h" 33 | 34 | 35 | 36 | 37 | NSMutableSet* rebasePointerSet = nil; 38 | 39 | 40 | @implementation CDLCDyldInfo (app2dylib) 41 | 42 | //categories overwrite the original method(empty implement) to get callback for every rebase address 43 | - (void)rebaseAddress:(uint64_t)address type:(uint8_t)type; 44 | { 45 | if (self.machOFile.uses64BitABI) { 46 | [rebasePointerSet addObject:[NSNumber numberWithUnsignedLongLong:address]]; 47 | } 48 | } 49 | 50 | @end 51 | 52 | 53 | #define APP2DYLIB_BASE_VERSION "1.0 (64 bit)" 54 | 55 | 56 | void print_usage(void) 57 | { 58 | NSLog(@ 59 | "\n" 60 | "app2dylib %s\n" 61 | "\n" 62 | "Usage: app2dylib -o \n" 63 | "\n" 64 | " app-mach-o-file : an executable file for app (decrypted)\n" 65 | "\n" 66 | , 67 | APP2DYLIB_BASE_VERSION 68 | ); 69 | } 70 | 71 | 72 | 73 | 74 | 75 | 76 | int main(int argc, char * argv[]) { 77 | 78 | 79 | NSString * inpath = nil; 80 | 81 | NSString * outpath = nil; 82 | 83 | int ch; 84 | 85 | struct option longopts[] = { 86 | { "output", required_argument, NULL, 'o' }, 87 | { NULL, 0, NULL, 0 }, 88 | }; 89 | 90 | 91 | while ( (ch = getopt_long(argc, argv, "o:", longopts, NULL)) != -1) { 92 | switch (ch) { 93 | case 'o': 94 | outpath = [NSString stringWithUTF8String:optarg]; 95 | break; 96 | default: 97 | break; 98 | } 99 | } 100 | 101 | if (optind < argc) { 102 | inpath = [NSString stringWithUTF8String:argv[optind]]; 103 | } 104 | 105 | 106 | if (inpath.length == 0 || outpath.length == 0) { 107 | print_usage(); 108 | exit(1); 109 | } 110 | 111 | NSFileManager *fileManager = [NSFileManager defaultManager]; 112 | 113 | if (![fileManager fileExistsAtPath:inpath]) { 114 | NSLog(@"%@ not exist.", inpath); 115 | exit(1); 116 | } 117 | 118 | 119 | rebasePointerSet = [NSMutableSet set]; 120 | 121 | CDFile * ofile = [CDFile fileWithContentsOfFile:inpath searchPathState:nil]; 122 | 123 | 124 | if ([ofile isKindOfClass:[CDFatFile class]] ) { 125 | NSLog(@"app2dylib supports armv7 and arm64 archtecture, but not support fat file. Please use lipo to thin the image file first."); 126 | exit(1); 127 | } 128 | 129 | 130 | 131 | 132 | CDMachOFile * machOFile = (CDMachOFile *)ofile; 133 | if ((machOFile.flags & MH_PIE) == 0){ 134 | NSLog(@"%@ is not a position-independent executable, can\'t convert to dylib.", inpath); 135 | exit(1); 136 | } 137 | 138 | const bool Is32Bit = ! machOFile.uses64BitABI; 139 | if (Is32Bit) { 140 | app2dylib< uint32_t , struct mach_header, struct segment_command, struct section, struct nlist, struct dylib_command>(inpath, outpath); 141 | } else { 142 | app2dylib< uint64_t , struct mach_header_64, struct segment_command_64, struct section_64, struct nlist_64, struct dylib_command>(inpath, outpath); 143 | } 144 | 145 | NSLog(@"Remember to codesign the generated dylib."); 146 | fprintf(stderr,"=========== Finish ============\n"); 147 | } 148 | --------------------------------------------------------------------------------