diff --git a/GoogleUtilities.podspec b/GoogleUtilities.podspec index 7c76c47..563c8b4 100644 --- a/GoogleUtilities.podspec +++ b/GoogleUtilities.podspec @@ -36,7 +36,10 @@ other Google CocoaPods. They're not intended for direct public usage. } s.subspec 'Environment' do |es| - es.source_files = 'GoogleUtilities/Environment/**/*.[mh]' + es.source_files = [ + 'GoogleUtilities/Environment/**/*.[mh]', + 'third_party/IsAppEncrypted/**/*.[mh]' + ] es.public_header_files = 'GoogleUtilities/Environment/Public/GoogleUtilities/*.h' es.dependency 'PromisesObjC', '>= 1.2', '< 3.0' es.frameworks = [ diff --git a/GoogleUtilities/Environment/third_party/GULAppEnvironmentUtil.m b/GoogleUtilities/Environment/GULAppEnvironmentUtil.m similarity index 67% rename from GoogleUtilities/Environment/third_party/GULAppEnvironmentUtil.m rename to GoogleUtilities/Environment/GULAppEnvironmentUtil.m index 4fcaab5..70e648c 100644 --- a/GoogleUtilities/Environment/third_party/GULAppEnvironmentUtil.m +++ b/GoogleUtilities/Environment/GULAppEnvironmentUtil.m @@ -15,30 +15,16 @@ #import "GoogleUtilities/Environment/Public/GoogleUtilities/GULAppEnvironmentUtil.h" #import -#import -#import +#import #import #import -#import + +#import "third_party/IsAppEncrypted/Public/IsAppEncrypted.h" #if TARGET_OS_IOS #import #endif -/// The encryption info struct and constants are missing from the iPhoneSimulator SDK, but not from -/// the iPhoneOS or Mac OS X SDKs. Since one doesn't ever ship a Simulator binary, we'll just -/// provide the definitions here. -#if TARGET_OS_SIMULATOR && !defined(LC_ENCRYPTION_INFO) -#define LC_ENCRYPTION_INFO 0x21 -struct encryption_info_command { - uint32_t cmd; - uint32_t cmdsize; - uint32_t cryptoff; - uint32_t cryptsize; - uint32_t cryptid; -}; -#endif - @implementation GULAppEnvironmentUtil /// A key for the Info.plist to enable or disable checking if the App Store is running in a sandbox. @@ -50,86 +36,6 @@ static NSString *const kFIRAppStoreReceiptURLCheckEnabledKey = /// The file name of the sandbox receipt. This is available on iOS >= 8.0 static NSString *const kFIRAIdentitySandboxReceiptFileName = @"sandboxReceipt"; -/// The following copyright from Landon J. Fuller applies to the isAppEncrypted function. -/// -/// Copyright (c) 2017 Landon J. Fuller -/// All rights reserved. -/// -/// Permission is hereby granted, free of charge, to any person obtaining a copy of this software -/// and associated documentation files (the "Software"), to deal in the Software without -/// restriction, including without limitation the rights to use, copy, modify, merge, publish, -/// distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the -/// Software is furnished to do so, subject to the following conditions: -/// -/// The above copyright notice and this permission notice shall be included in all copies or -/// substantial portions of the Software. -/// -/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING -/// BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -/// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -/// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -/// -/// Comment from iPhone Dev Wiki -/// Crack Prevention: -/// App Store binaries are signed by both their developer and Apple. This encrypts the binary so -/// that decryption keys are needed in order to make the binary readable. When iOS executes the -/// binary, the decryption keys are used to decrypt the binary into a readable state where it is -/// then loaded into memory and executed. iOS can tell the encryption status of a binary via the -/// cryptid structure member of LC_ENCRYPTION_INFO MachO load command. If cryptid is a non-zero -/// value then the binary is encrypted. -/// -/// 'Cracking' works by letting the kernel decrypt the binary then siphoning the decrypted data into -/// a new binary file, resigning, and repackaging. This will only work on jailbroken devices as -/// codesignature validation has been removed. Resigning takes place because while the codesignature -/// doesn't have to be valid thanks to the jailbreak, it does have to be in place unless you have -/// AppSync or similar to disable codesignature checks. -/// -/// More information at Landon Fuller's blog -static BOOL IsAppEncrypted(void) { - const struct mach_header *executableHeader = NULL; - for (uint32_t i = 0; i < _dyld_image_count(); i++) { - const struct mach_header *header = _dyld_get_image_header(i); - if (header && header->filetype == MH_EXECUTE) { - executableHeader = header; - break; - } - } - - if (!executableHeader) { - return NO; - } - - BOOL is64bit = (executableHeader->magic == MH_MAGIC_64); - uintptr_t cursor = (uintptr_t)executableHeader + - (is64bit ? sizeof(struct mach_header_64) : sizeof(struct mach_header)); - const struct segment_command *segmentCommand = NULL; - uint32_t i = 0; - - while (i++ < executableHeader->ncmds) { - segmentCommand = (struct segment_command *)cursor; - - if (!segmentCommand) { - continue; - } - - if ((!is64bit && segmentCommand->cmd == LC_ENCRYPTION_INFO) || - (is64bit && segmentCommand->cmd == LC_ENCRYPTION_INFO_64)) { - if (is64bit) { - struct encryption_info_command_64 *cryptCmd = - (struct encryption_info_command_64 *)segmentCommand; - return cryptCmd && cryptCmd->cryptid != 0; - } else { - struct encryption_info_command *cryptCmd = (struct encryption_info_command *)segmentCommand; - return cryptCmd && cryptCmd->cryptid != 0; - } - } - cursor += segmentCommand->cmdsize; - } - - return NO; -} - static BOOL HasSCInfoFolder(void) { #if TARGET_OS_IOS || TARGET_OS_TV || TARGET_OS_WATCH NSString *bundlePath = [NSBundle mainBundle].bundlePath; @@ -339,13 +245,15 @@ static BOOL HasEmbeddedMobileProvision(void) { if (@available(iOS 14.0, *)) { // Early iOS 14 betas do not include isiOSAppOnMac (#6969) applePlatform = ([[NSProcessInfo processInfo] respondsToSelector:@selector(isiOSAppOnMac)] && - [NSProcessInfo processInfo].isiOSAppOnMac) ? @"ios_on_mac" : @"ios"; + [NSProcessInfo processInfo].isiOSAppOnMac) + ? @"ios_on_mac" + : @"ios"; } else { applePlatform = @"ios"; } -#else // defined(__IPHONE_14_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 140000 +#else // defined(__IPHONE_14_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 140000 applePlatform = @"ios"; -#endif // defined(__IPHONE_14_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 140000 +#endif // defined(__IPHONE_14_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 140000 #elif TARGET_OS_TV applePlatform = @"tvos"; @@ -355,13 +263,13 @@ static BOOL HasEmbeddedMobileProvision(void) { applePlatform = @"watchos"; #elif defined(TARGET_OS_VISION) && TARGET_OS_VISION applePlatform = @"visionos"; -#endif // TARGET_OS_MACCATALYST +#endif // TARGET_OS_MACCATALYST return applePlatform; } + (NSString *)appleDevicePlatform { - NSString* firebasePlatform = [GULAppEnvironmentUtil applePlatform]; + NSString *firebasePlatform = [GULAppEnvironmentUtil applePlatform]; #if TARGET_OS_IOS // This check is necessary because iOS-only apps running on iPad // will report UIUserInterfaceIdiomPhone via UI_USER_INTERFACE_IDIOM(). diff --git a/Package.swift b/Package.swift index 0d93545..146973b 100644 --- a/Package.swift +++ b/Package.swift @@ -102,9 +102,21 @@ let package = Package( ), .target( name: "GoogleUtilities-Environment", - dependencies: [.product(name: "FBLPromises", package: "Promises")], + dependencies: [ + .product(name: "FBLPromises", package: "Promises"), + .target(name: "third_party-IsAppEncrypted"), + ], path: "GoogleUtilities/Environment", - exclude: ["third_party/LICENSE"], + publicHeadersPath: "Public", + cSettings: [ + .headerSearchPath("../../"), + ] + ), + + .target( + name: "third_party-IsAppEncrypted", + path: "third_party/IsAppEncrypted", + exclude: ["LICENSE"], publicHeadersPath: "Public", cSettings: [ .headerSearchPath("../../"), diff --git a/third_party/IsAppEncrypted/IsAppEncrypted.m b/third_party/IsAppEncrypted/IsAppEncrypted.m new file mode 100644 index 0000000..e2f7275 --- /dev/null +++ b/third_party/IsAppEncrypted/IsAppEncrypted.m @@ -0,0 +1,104 @@ +// Copyright (c) 2017 Landon J. Fuller +// All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +// +// Comment from +// iPhone Dev +// Wiki Crack Prevention: +// App Store binaries are signed by both their developer and Apple. This +// encrypts the binary so that decryption keys are needed in order to make the +// binary readable. When iOS executes the binary, the decryption keys are used +// to decrypt the binary into a readable state where it is then loaded into +// memory and executed. iOS can tell the encryption status of a binary via the +// cryptid structure member of LC_ENCRYPTION_INFO MachO load command. If +// cryptid is a non-zero value then the binary is encrypted. +// +// 'Cracking' works by letting the kernel decrypt the binary then siphoning the +// decrypted data into a new binary file, resigning, and repackaging. This will +// only work on jailbroken devices as codesignature validation has been +// removed. Resigning takes place because while the codesignature doesn't have +// to be valid thanks to the jailbreak, it does have to be in place unless you +// have AppSync or similar to disable codesignature checks. +// +// More information at +// Landon Fuller's blog + +#import "third_party/IsAppEncrypted/Public/IsAppEncrypted.h" + +#import +#import + +/// The encryption info struct and constants are missing from the iPhoneSimulator SDK, but not from +/// the iPhoneOS or Mac OS X SDKs. Since one doesn't ever ship a Simulator binary, we'll just +/// provide the definitions here. +#if TARGET_OS_SIMULATOR && !defined(LC_ENCRYPTION_INFO) +#define LC_ENCRYPTION_INFO 0x21 +struct encryption_info_command { + uint32_t cmd; + uint32_t cmdsize; + uint32_t cryptoff; + uint32_t cryptsize; + uint32_t cryptid; +}; +#endif + +BOOL IsAppEncrypted(void) { + const struct mach_header *executableHeader = NULL; + for (uint32_t i = 0; i < _dyld_image_count(); i++) { + const struct mach_header *header = _dyld_get_image_header(i); + if (header && header->filetype == MH_EXECUTE) { + executableHeader = header; + break; + } + } + + if (!executableHeader) { + return NO; + } + + BOOL is64bit = (executableHeader->magic == MH_MAGIC_64); + uintptr_t cursor = (uintptr_t)executableHeader + + (is64bit ? sizeof(struct mach_header_64) : sizeof(struct mach_header)); + const struct segment_command *segmentCommand = NULL; + uint32_t i = 0; + + while (i++ < executableHeader->ncmds) { + segmentCommand = (struct segment_command *)cursor; + + if (!segmentCommand) { + continue; + } + + if ((!is64bit && segmentCommand->cmd == LC_ENCRYPTION_INFO) || + (is64bit && segmentCommand->cmd == LC_ENCRYPTION_INFO_64)) { + if (is64bit) { + struct encryption_info_command_64 *cryptCmd = + (struct encryption_info_command_64 *)segmentCommand; + return cryptCmd && cryptCmd->cryptid != 0; + } else { + struct encryption_info_command *cryptCmd = (struct encryption_info_command *)segmentCommand; + return cryptCmd && cryptCmd->cryptid != 0; + } + } + cursor += segmentCommand->cmdsize; + } + + return NO; +} diff --git a/GoogleUtilities/Environment/third_party/LICENSE b/third_party/IsAppEncrypted/LICENSE similarity index 96% rename from GoogleUtilities/Environment/third_party/LICENSE rename to third_party/IsAppEncrypted/LICENSE index 78dd6c9..6328f10 100644 --- a/GoogleUtilities/Environment/third_party/LICENSE +++ b/third_party/IsAppEncrypted/LICENSE @@ -1,5 +1,3 @@ -The following copyright from Landon J. Fuller applies to the isAppEncrypted function. - Copyright (c) 2017 Landon J. Fuller All rights reserved. diff --git a/third_party/IsAppEncrypted/Public/IsAppEncrypted.h b/third_party/IsAppEncrypted/Public/IsAppEncrypted.h new file mode 100644 index 0000000..b26bae2 --- /dev/null +++ b/third_party/IsAppEncrypted/Public/IsAppEncrypted.h @@ -0,0 +1,45 @@ +// Copyright (c) 2017 Landon J. Fuller +// All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +// +// Comment from +// iPhone Dev +// Wiki Crack Prevention: +// App Store binaries are signed by both their developer and Apple. This +// encrypts the binary so that decryption keys are needed in order to make the +// binary readable. When iOS executes the binary, the decryption keys are used +// to decrypt the binary into a readable state where it is then loaded into +// memory and executed. iOS can tell the encryption status of a binary via the +// cryptid structure member of LC_ENCRYPTION_INFO MachO load command. If +// cryptid is a non-zero value then the binary is encrypted. +// +// 'Cracking' works by letting the kernel decrypt the binary then siphoning the +// decrypted data into a new binary file, resigning, and repackaging. This will +// only work on jailbroken devices as codesignature validation has been +// removed. Resigning takes place because while the codesignature doesn't have +// to be valid thanks to the jailbreak, it does have to be in place unless you +// have AppSync or similar to disable codesignature checks. +// +// More information at +// Landon Fuller's blog + +#import + +BOOL IsAppEncrypted(void);