├── Makefile ├── OldABI.h ├── OldABI.swift ├── OldABI.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ ├── xcshareddata │ │ └── IDEWorkspaceChecks.plist │ └── xcuserdata │ │ └── charlotte.xcuserdatad │ │ └── UserInterfaceState.xcuserstate └── xcuserdata │ └── charlotte.xcuserdatad │ └── xcschemes │ └── xcschememanagement.plist ├── packaging └── control ├── patchfind.h ├── patchfind.m └── tests └── main.swift /Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: all deb-ios-rootless deb-ios-rootful 2 | 3 | ifneq ($(ONLY_TAG),) 4 | VERSION := $(shell git describe --tags --abbrev=0 | sed 's/^v//g') 5 | else 6 | VERSION := $(shell git describe --tags --always | sed 's/-/~/' | sed 's/-/\./g' | sed 's/\.g/\./g' | sed 's/^v//g') 7 | endif 8 | 9 | COMMON_OPTIONS = BUILD_DIR="build/" CODE_SIGNING_ALLOWED="NO" CODE_SIGNING_REQUIRED="NO" CODE_SIGN_IDENTITY="" -configuration $(CONFIGURATION) 10 | 11 | ifneq ($(RELEASE),) 12 | CONFIGURATION = Release 13 | DEB_VERSION = $(VERSION) 14 | else 15 | CONFIGURATION = Debug 16 | DEB_VERSION = $(VERSION)+debug 17 | endif 18 | 19 | ifneq ($(MAC),) 20 | $(error macOS is not supported yet) 21 | COMMON_OPTIONS += -destination 'generic/platform=macOS' 22 | else 23 | COMMON_OPTIONS += -destination 'generic/platform=iOS' 24 | endif 25 | 26 | ifneq ($(MAC),) 27 | PRODUCTS_DIR = build/$(CONFIGURATION)-macosx 28 | else 29 | PRODUCTS_DIR = build/$(CONFIGURATION)-iphoneos 30 | endif 31 | 32 | STAGE_DIR = work-$(ARCHITECTURE)/stage 33 | INSTALL_ROOT = $(STAGE_DIR)/$(INSTALL_PREFIX) 34 | 35 | # TODO: maybe split each scheme into its own target? 36 | 37 | all: deb 38 | 39 | clean: 40 | xcodebuild -scheme OldABI $(COMMON_OPTIONS) clean 41 | 42 | build-ios: 43 | xcodebuild -scheme OldABI $(COMMON_OPTIONS) 44 | 45 | build-macos: 46 | # TODO 47 | $(error macOS is not supported yet) 48 | 49 | deb-ios-rootful: ARCHITECTURE = iphoneos-arm 50 | deb-ios-rootful: INSTALL_PREFIX = 51 | 52 | deb-ios-rootless: ARCHITECTURE = iphoneos-arm64 53 | deb-ios-rootless: INSTALL_PREFIX = /var/jb 54 | 55 | deb-ios-rootful deb-ios-rootless: build-ios 56 | @rm -rf work-$(ARCHITECTURE) 57 | @mkdir -p $(STAGE_DIR) 58 | 59 | @# Because BSD install does not support -D 60 | @mkdir -p $(INSTALL_ROOT)/usr/lib/ellekit 61 | 62 | @install -m644 $(PRODUCTS_DIR)/OldABI.dylib $(INSTALL_ROOT)/usr/lib/ellekit/OldABI.dylib 63 | 64 | @ldid -S $(INSTALL_ROOT)/usr/lib/ellekit/OldABI.dylib 65 | 66 | @mkdir -p $(STAGE_DIR)/DEBIAN 67 | @sed -e "s|@DEB_VERSION@|$(DEB_VERSION)|g" -e "s|@DEB_ARCH@|$(ARCHITECTURE)|g" packaging/control >$(STAGE_DIR)/DEBIAN/control 68 | 69 | @mkdir -p packages 70 | dpkg-deb -Zzstd --root-owner-group -b $(STAGE_DIR) packages/oldabi_$(DEB_VERSION)_$(ARCHITECTURE).deb 71 | 72 | @rm -rf work-$(ARCHITECTURE) 73 | 74 | deb-ios: deb-ios-rootful deb-ios-rootless 75 | 76 | deb-macos: build-macos 77 | # TODO 78 | $(error macOS is not supported yet) 79 | 80 | ifneq ($(MAC),) 81 | deb: deb-macos 82 | else 83 | deb: deb-ios 84 | endif 85 | 86 | ifneq ($(MAC),) 87 | build: build-macos 88 | else 89 | build: build-ios 90 | endif 91 | -------------------------------------------------------------------------------- /OldABI.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef OldABI_h 3 | #define OldABI_h 4 | 5 | #include 6 | #include "patchfind.h" 7 | 8 | #endif /* OldABI_h */ 9 | -------------------------------------------------------------------------------- /OldABI.swift: -------------------------------------------------------------------------------- 1 | 2 | import Foundation 3 | import MachO 4 | 5 | typealias FileHandleC = UnsafeMutablePointer 6 | extension FileHandleC { 7 | @inline(__always) 8 | func readData(ofLength count: Int) -> UnsafeMutableRawPointer { 9 | let alloc = malloc(count) 10 | fread(alloc, 1, count, self) 11 | return alloc! 12 | } 13 | 14 | @discardableResult @inline(__always) 15 | func seek(toFileOffset offset: UInt64) -> UnsafeMutablePointer { 16 | var pos: fpos_t = .init(offset) 17 | fsetpos(self, &pos) 18 | return self 19 | } 20 | 21 | @inline(__always) 22 | var offsetInFile: UInt64 { 23 | var pos: fpos_t = 0 24 | fgetpos(self, &pos) 25 | return .init(pos) 26 | } 27 | 28 | @inline(__always) 29 | func close() { 30 | fclose(self) 31 | } 32 | } 33 | 34 | let ekhandle = dlopen("/var/jb/usr/lib/libellekit.dylib", RTLD_NOW); 35 | 36 | let hookMemory = { 37 | unsafeBitCast(dlsym(ekhandle, "MSHookMemory"), to: (@convention (c) (UnsafeRawPointer, UnsafeRawPointer, size_t) -> Void).self) 38 | }() 39 | 40 | let hookFunction = { 41 | unsafeBitCast(dlsym(ekhandle, "MSHookFunction"), to: (@convention (c) (UnsafeRawPointer, UnsafeRawPointer, UnsafeMutablePointer?) -> Void).self) 42 | }() 43 | 44 | func oneshot_fix_oldabi() { 45 | for image in 0..<_dyld_image_count() { 46 | if String(cString: _dyld_get_image_name(image)) == "/usr/lib/libobjc.A.dylib" || 47 | String(cString: _dyld_get_image_name(image)) == "/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation" { 48 | var bytes: [UInt8] = [ 49 | 0x00, 0x18, 0xC1, 0xDA 50 | ] 51 | 52 | var mask: [UInt8] = [ 53 | 0x00, 0xFC, 0xFF, 0xFF 54 | ] 55 | 56 | while true { 57 | let autda = patchfind_find(Int32(image), &bytes, &mask, 4) 58 | 59 | if let autda { 60 | hookMemory(autda, [ 61 | CFSwapInt32(0xF047C1DA) // xpacd x16 62 | ], 4) 63 | } else { 64 | break 65 | } 66 | } 67 | } 68 | } 69 | } 70 | 71 | func looksLegacy(_ path: UnsafePointer) -> Bool { 72 | guard let handle = fopen(path, "r") else { 73 | return false 74 | } 75 | 76 | defer { handle.close() } 77 | 78 | let machHeaderPointer = handle 79 | .readData(ofLength: MemoryLayout.size) 80 | 81 | defer { machHeaderPointer.deallocate() } 82 | 83 | if machHeaderPointer.assumingMemoryBound(to: mach_header_64.self).pointee.magic == FAT_CIGAM { 84 | // we have a fat binary 85 | // get our current cpu subtype 86 | let nslices = handle 87 | .seek(toFileOffset: 0x4) 88 | .readData(ofLength: MemoryLayout.size) 89 | .assumingMemoryBound(to: UInt32.self) 90 | .pointee.bigEndian 91 | 92 | for i in 0...size) 96 | .assumingMemoryBound(to: fat_arch.self) 97 | 98 | let slice = slice_ptr.pointee 99 | 100 | defer { slice_ptr.deallocate() } 101 | 102 | if slice.cputype.bigEndian == CPU_TYPE_ARM64 { 103 | 104 | let slice_ptr = handle 105 | .seek(toFileOffset: UInt64(8 + (Int(i) * 20))) 106 | .readData(ofLength: MemoryLayout.size) 107 | .assumingMemoryBound(to: fat_arch.self) 108 | 109 | let slice = slice_ptr.pointee 110 | 111 | defer { slice_ptr.deallocate() } 112 | 113 | if slice.cpusubtype == 0x2000080 { // new abi 114 | return false 115 | } 116 | 117 | if slice.cpusubtype == 0x2000000 { // old abi 118 | return true 119 | } 120 | } 121 | } 122 | } 123 | 124 | return false 125 | } 126 | 127 | typealias dlopen_body = @convention(c) (UnsafePointer, Int32) -> UnsafeRawPointer 128 | 129 | let orig: UnsafeMutablePointer = .allocate(capacity: 8) 130 | 131 | @_cdecl("dlopen_hook_oldabi") 132 | func dlopen_hook_oldabi(_ path: UnsafePointer, _ loadtype: Int32) -> UnsafeRawPointer { 133 | if looksLegacy(path) { 134 | oneshot_fix_oldabi() 135 | } 136 | 137 | return unsafeBitCast(orig.pointee, to: dlopen_body.self)(path, loadtype) 138 | } 139 | 140 | struct Info: Codable { 141 | var CFBundleExecutable: String? 142 | } 143 | 144 | func fixupPreferences() throws { 145 | let bundlePath = ("/var/jb/Library/PreferenceBundles/" as NSString).resolvingSymlinksInPath 146 | let files = try FileManager.default.contentsOfDirectory(atPath: bundlePath) 147 | for file in files { 148 | if file.hasSuffix(".bundle") { 149 | let info = bundlePath+"/"+file+"/Info.plist" 150 | if FileManager.default.fileExists(atPath: info), 151 | let infoData = try? Data(contentsOf: NSURL.fileURL(withPath: info)), 152 | let infoRoot = try? PropertyListDecoder().decode(Info.self, from: infoData), 153 | let exec = infoRoot.CFBundleExecutable, 154 | looksLegacy(bundlePath+"/"+file+"/"+exec) { 155 | oneshot_fix_oldabi() 156 | } 157 | } 158 | } 159 | } 160 | 161 | @_cdecl("swift_ctor") 162 | public func ctor() { 163 | let whitelist = [ 164 | "/System/Library/CoreServices/SpringBoard.app/SpringBoard", 165 | "/Applications/", 166 | "/usr/sbin/mediaserverd", 167 | "/usr/libexec/backboardd", 168 | "/usr/libexec/nfcd" 169 | ].map { 170 | ProcessInfo.processInfo.arguments[0].hasPrefix($0) 171 | }.contains(true) 172 | 173 | if !whitelist && !(ProcessInfo.processInfo.arguments.first?.contains("/procursus/Applications/") == true) { 174 | return 175 | } 176 | 177 | if ProcessInfo.processInfo.arguments.first?.contains("/Applications/Preferences.app/Preferences") == true { 178 | try? fixupPreferences() 179 | } 180 | 181 | let repcl: @convention(c) (UnsafePointer, Int32) -> UnsafeRawPointer = dlopen_hook_oldabi 182 | let repptr = unsafeBitCast(repcl, to: UnsafeMutableRawPointer.self) 183 | 184 | hookFunction(dlsym(dlopen(nil, RTLD_NOW), "dlopen"), repptr, orig) 185 | } 186 | -------------------------------------------------------------------------------- /OldABI.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 56; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 9E5D8B0629DE46080068D078 /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E5D8B0529DE46080068D078 /* main.swift */; }; 11 | 9EF3204B29D4CD8C00175976 /* OldABI.h in Headers */ = {isa = PBXBuildFile; fileRef = 9EF3204929D4CD8C00175976 /* OldABI.h */; }; 12 | 9EF3204C29D4CD8C00175976 /* OldABI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9EF3204A29D4CD8C00175976 /* OldABI.swift */; }; 13 | 9EF3204F29D4CE0700175976 /* patchfind.h in Headers */ = {isa = PBXBuildFile; fileRef = 9EF3204D29D4CE0700175976 /* patchfind.h */; }; 14 | 9EF3205029D4CE0700175976 /* patchfind.m in Sources */ = {isa = PBXBuildFile; fileRef = 9EF3204E29D4CE0700175976 /* patchfind.m */; }; 15 | /* End PBXBuildFile section */ 16 | 17 | /* Begin PBXCopyFilesBuildPhase section */ 18 | 9E5D8B0129DE46080068D078 /* CopyFiles */ = { 19 | isa = PBXCopyFilesBuildPhase; 20 | buildActionMask = 2147483647; 21 | dstPath = /usr/share/man/man1/; 22 | dstSubfolderSpec = 0; 23 | files = ( 24 | ); 25 | runOnlyForDeploymentPostprocessing = 1; 26 | }; 27 | /* End PBXCopyFilesBuildPhase section */ 28 | 29 | /* Begin PBXFileReference section */ 30 | 9E5D8B0329DE46080068D078 /* tests */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = tests; sourceTree = BUILT_PRODUCTS_DIR; }; 31 | 9E5D8B0529DE46080068D078 /* main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = ""; usesTabs = 0; }; 32 | 9EF3204229D4CD8200175976 /* OldABI.dylib */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = OldABI.dylib; sourceTree = BUILT_PRODUCTS_DIR; }; 33 | 9EF3204929D4CD8C00175976 /* OldABI.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OldABI.h; sourceTree = ""; }; 34 | 9EF3204A29D4CD8C00175976 /* OldABI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OldABI.swift; sourceTree = ""; }; 35 | 9EF3204D29D4CE0700175976 /* patchfind.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = patchfind.h; sourceTree = ""; }; 36 | 9EF3204E29D4CE0700175976 /* patchfind.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = patchfind.m; sourceTree = ""; }; 37 | /* End PBXFileReference section */ 38 | 39 | /* Begin PBXFrameworksBuildPhase section */ 40 | 9E5D8B0029DE46080068D078 /* Frameworks */ = { 41 | isa = PBXFrameworksBuildPhase; 42 | buildActionMask = 2147483647; 43 | files = ( 44 | ); 45 | runOnlyForDeploymentPostprocessing = 0; 46 | }; 47 | 9EF3204029D4CD8200175976 /* Frameworks */ = { 48 | isa = PBXFrameworksBuildPhase; 49 | buildActionMask = 2147483647; 50 | files = ( 51 | ); 52 | runOnlyForDeploymentPostprocessing = 0; 53 | }; 54 | /* End PBXFrameworksBuildPhase section */ 55 | 56 | /* Begin PBXGroup section */ 57 | 9E5D8B0429DE46080068D078 /* tests */ = { 58 | isa = PBXGroup; 59 | children = ( 60 | 9E5D8B0529DE46080068D078 /* main.swift */, 61 | ); 62 | path = tests; 63 | sourceTree = ""; 64 | }; 65 | 9EF3203929D4CD8200175976 = { 66 | isa = PBXGroup; 67 | children = ( 68 | 9EF3204929D4CD8C00175976 /* OldABI.h */, 69 | 9EF3204A29D4CD8C00175976 /* OldABI.swift */, 70 | 9EF3204D29D4CE0700175976 /* patchfind.h */, 71 | 9EF3204E29D4CE0700175976 /* patchfind.m */, 72 | 9E5D8B0429DE46080068D078 /* tests */, 73 | 9EF3204329D4CD8200175976 /* Products */, 74 | ); 75 | sourceTree = ""; 76 | }; 77 | 9EF3204329D4CD8200175976 /* Products */ = { 78 | isa = PBXGroup; 79 | children = ( 80 | 9EF3204229D4CD8200175976 /* OldABI.dylib */, 81 | 9E5D8B0329DE46080068D078 /* tests */, 82 | ); 83 | name = Products; 84 | sourceTree = ""; 85 | }; 86 | /* End PBXGroup section */ 87 | 88 | /* Begin PBXHeadersBuildPhase section */ 89 | 9EF3203E29D4CD8200175976 /* Headers */ = { 90 | isa = PBXHeadersBuildPhase; 91 | buildActionMask = 2147483647; 92 | files = ( 93 | 9EF3204F29D4CE0700175976 /* patchfind.h in Headers */, 94 | 9EF3204B29D4CD8C00175976 /* OldABI.h in Headers */, 95 | ); 96 | runOnlyForDeploymentPostprocessing = 0; 97 | }; 98 | /* End PBXHeadersBuildPhase section */ 99 | 100 | /* Begin PBXNativeTarget section */ 101 | 9E5D8B0229DE46080068D078 /* tests */ = { 102 | isa = PBXNativeTarget; 103 | buildConfigurationList = 9E5D8B0929DE46080068D078 /* Build configuration list for PBXNativeTarget "tests" */; 104 | buildPhases = ( 105 | 9E5D8AFF29DE46080068D078 /* Sources */, 106 | 9E5D8B0029DE46080068D078 /* Frameworks */, 107 | 9E5D8B0129DE46080068D078 /* CopyFiles */, 108 | ); 109 | buildRules = ( 110 | ); 111 | dependencies = ( 112 | ); 113 | name = tests; 114 | productName = tests; 115 | productReference = 9E5D8B0329DE46080068D078 /* tests */; 116 | productType = "com.apple.product-type.tool"; 117 | }; 118 | 9EF3204129D4CD8200175976 /* OldABI */ = { 119 | isa = PBXNativeTarget; 120 | buildConfigurationList = 9EF3204629D4CD8200175976 /* Build configuration list for PBXNativeTarget "OldABI" */; 121 | buildPhases = ( 122 | 9EF3203E29D4CD8200175976 /* Headers */, 123 | 9EF3203F29D4CD8200175976 /* Sources */, 124 | 9EF3204029D4CD8200175976 /* Frameworks */, 125 | ); 126 | buildRules = ( 127 | ); 128 | dependencies = ( 129 | ); 130 | name = OldABI; 131 | productName = OldABI; 132 | productReference = 9EF3204229D4CD8200175976 /* OldABI.dylib */; 133 | productType = "com.apple.product-type.library.dynamic"; 134 | }; 135 | /* End PBXNativeTarget section */ 136 | 137 | /* Begin PBXProject section */ 138 | 9EF3203A29D4CD8200175976 /* Project object */ = { 139 | isa = PBXProject; 140 | attributes = { 141 | BuildIndependentTargetsInParallel = 1; 142 | LastSwiftUpdateCheck = 1410; 143 | LastUpgradeCheck = 1410; 144 | TargetAttributes = { 145 | 9E5D8B0229DE46080068D078 = { 146 | CreatedOnToolsVersion = 14.1; 147 | }; 148 | 9EF3204129D4CD8200175976 = { 149 | CreatedOnToolsVersion = 14.1; 150 | }; 151 | }; 152 | }; 153 | buildConfigurationList = 9EF3203D29D4CD8200175976 /* Build configuration list for PBXProject "OldABI" */; 154 | compatibilityVersion = "Xcode 14.0"; 155 | developmentRegion = en; 156 | hasScannedForEncodings = 0; 157 | knownRegions = ( 158 | en, 159 | Base, 160 | ); 161 | mainGroup = 9EF3203929D4CD8200175976; 162 | productRefGroup = 9EF3204329D4CD8200175976 /* Products */; 163 | projectDirPath = ""; 164 | projectRoot = ""; 165 | targets = ( 166 | 9EF3204129D4CD8200175976 /* OldABI */, 167 | 9E5D8B0229DE46080068D078 /* tests */, 168 | ); 169 | }; 170 | /* End PBXProject section */ 171 | 172 | /* Begin PBXSourcesBuildPhase section */ 173 | 9E5D8AFF29DE46080068D078 /* Sources */ = { 174 | isa = PBXSourcesBuildPhase; 175 | buildActionMask = 2147483647; 176 | files = ( 177 | 9E5D8B0629DE46080068D078 /* main.swift in Sources */, 178 | ); 179 | runOnlyForDeploymentPostprocessing = 0; 180 | }; 181 | 9EF3203F29D4CD8200175976 /* Sources */ = { 182 | isa = PBXSourcesBuildPhase; 183 | buildActionMask = 2147483647; 184 | files = ( 185 | 9EF3204C29D4CD8C00175976 /* OldABI.swift in Sources */, 186 | 9EF3205029D4CE0700175976 /* patchfind.m in Sources */, 187 | ); 188 | runOnlyForDeploymentPostprocessing = 0; 189 | }; 190 | /* End PBXSourcesBuildPhase section */ 191 | 192 | /* Begin XCBuildConfiguration section */ 193 | 9E5D8B0729DE46080068D078 /* Debug */ = { 194 | isa = XCBuildConfiguration; 195 | buildSettings = { 196 | CODE_SIGN_STYLE = Automatic; 197 | DEVELOPMENT_TEAM = VF46MYDSGH; 198 | ENABLE_HARDENED_RUNTIME = YES; 199 | PRODUCT_NAME = "$(TARGET_NAME)"; 200 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 201 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 202 | SWIFT_VERSION = 5.0; 203 | }; 204 | name = Debug; 205 | }; 206 | 9E5D8B0829DE46080068D078 /* Release */ = { 207 | isa = XCBuildConfiguration; 208 | buildSettings = { 209 | CODE_SIGN_STYLE = Automatic; 210 | DEVELOPMENT_TEAM = VF46MYDSGH; 211 | ENABLE_HARDENED_RUNTIME = YES; 212 | PRODUCT_NAME = "$(TARGET_NAME)"; 213 | SWIFT_COMPILATION_MODE = wholemodule; 214 | SWIFT_OPTIMIZATION_LEVEL = "-O"; 215 | SWIFT_VERSION = 5.0; 216 | }; 217 | name = Release; 218 | }; 219 | 9EF3204429D4CD8200175976 /* Debug */ = { 220 | isa = XCBuildConfiguration; 221 | buildSettings = { 222 | ALWAYS_SEARCH_USER_PATHS = NO; 223 | CLANG_ANALYZER_NONNULL = YES; 224 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 225 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; 226 | CLANG_ENABLE_MODULES = YES; 227 | CLANG_ENABLE_OBJC_ARC = YES; 228 | CLANG_ENABLE_OBJC_WEAK = YES; 229 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 230 | CLANG_WARN_BOOL_CONVERSION = YES; 231 | CLANG_WARN_COMMA = YES; 232 | CLANG_WARN_CONSTANT_CONVERSION = YES; 233 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 234 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 235 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 236 | CLANG_WARN_EMPTY_BODY = YES; 237 | CLANG_WARN_ENUM_CONVERSION = YES; 238 | CLANG_WARN_INFINITE_RECURSION = YES; 239 | CLANG_WARN_INT_CONVERSION = YES; 240 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 241 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 242 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 243 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 244 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 245 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 246 | CLANG_WARN_STRICT_PROTOTYPES = YES; 247 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 248 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 249 | CLANG_WARN_UNREACHABLE_CODE = YES; 250 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 251 | COPY_PHASE_STRIP = NO; 252 | DEBUG_INFORMATION_FORMAT = dwarf; 253 | ENABLE_STRICT_OBJC_MSGSEND = YES; 254 | ENABLE_TESTABILITY = YES; 255 | GCC_C_LANGUAGE_STANDARD = gnu11; 256 | GCC_DYNAMIC_NO_PIC = NO; 257 | GCC_NO_COMMON_BLOCKS = YES; 258 | GCC_OPTIMIZATION_LEVEL = 0; 259 | GCC_PREPROCESSOR_DEFINITIONS = ( 260 | "DEBUG=1", 261 | "$(inherited)", 262 | ); 263 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 264 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 265 | GCC_WARN_UNDECLARED_SELECTOR = YES; 266 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 267 | GCC_WARN_UNUSED_FUNCTION = YES; 268 | GCC_WARN_UNUSED_VARIABLE = YES; 269 | MACOSX_DEPLOYMENT_TARGET = 13.0; 270 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; 271 | MTL_FAST_MATH = YES; 272 | ONLY_ACTIVE_ARCH = YES; 273 | SDKROOT = macosx; 274 | }; 275 | name = Debug; 276 | }; 277 | 9EF3204529D4CD8200175976 /* Release */ = { 278 | isa = XCBuildConfiguration; 279 | buildSettings = { 280 | ALWAYS_SEARCH_USER_PATHS = NO; 281 | CLANG_ANALYZER_NONNULL = YES; 282 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 283 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; 284 | CLANG_ENABLE_MODULES = YES; 285 | CLANG_ENABLE_OBJC_ARC = YES; 286 | CLANG_ENABLE_OBJC_WEAK = YES; 287 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 288 | CLANG_WARN_BOOL_CONVERSION = YES; 289 | CLANG_WARN_COMMA = YES; 290 | CLANG_WARN_CONSTANT_CONVERSION = YES; 291 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 292 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 293 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 294 | CLANG_WARN_EMPTY_BODY = YES; 295 | CLANG_WARN_ENUM_CONVERSION = YES; 296 | CLANG_WARN_INFINITE_RECURSION = YES; 297 | CLANG_WARN_INT_CONVERSION = YES; 298 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 299 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 300 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 301 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 302 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 303 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 304 | CLANG_WARN_STRICT_PROTOTYPES = YES; 305 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 306 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 307 | CLANG_WARN_UNREACHABLE_CODE = YES; 308 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 309 | COPY_PHASE_STRIP = NO; 310 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 311 | ENABLE_NS_ASSERTIONS = NO; 312 | ENABLE_STRICT_OBJC_MSGSEND = YES; 313 | GCC_C_LANGUAGE_STANDARD = gnu11; 314 | GCC_NO_COMMON_BLOCKS = YES; 315 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 316 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 317 | GCC_WARN_UNDECLARED_SELECTOR = YES; 318 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 319 | GCC_WARN_UNUSED_FUNCTION = YES; 320 | GCC_WARN_UNUSED_VARIABLE = YES; 321 | MACOSX_DEPLOYMENT_TARGET = 13.0; 322 | MTL_ENABLE_DEBUG_INFO = NO; 323 | MTL_FAST_MATH = YES; 324 | SDKROOT = macosx; 325 | }; 326 | name = Release; 327 | }; 328 | 9EF3204729D4CD8200175976 /* Debug */ = { 329 | isa = XCBuildConfiguration; 330 | buildSettings = { 331 | ALLOW_TARGET_PLATFORM_SPECIALIZATION = YES; 332 | ARCHS = arm64e; 333 | CODE_SIGN_STYLE = Automatic; 334 | DEVELOPMENT_TEAM = VF46MYDSGH; 335 | DYLIB_COMPATIBILITY_VERSION = 1; 336 | DYLIB_CURRENT_VERSION = 1; 337 | EXECUTABLE_PREFIX = ""; 338 | IPHONEOS_DEPLOYMENT_TARGET = 15.0; 339 | MACOSX_DEPLOYMENT_TARGET = 11.0; 340 | ONLY_ACTIVE_ARCH = NO; 341 | PRODUCT_NAME = "$(TARGET_NAME)"; 342 | SDKROOT = iphoneos; 343 | SKIP_INSTALL = YES; 344 | SUPPORTED_PLATFORMS = "iphonesimulator iphoneos"; 345 | SUPPORTS_MACCATALYST = YES; 346 | SWIFT_OBJC_BRIDGING_HEADER = OldABI.h; 347 | SWIFT_VERSION = 5.0; 348 | }; 349 | name = Debug; 350 | }; 351 | 9EF3204829D4CD8200175976 /* Release */ = { 352 | isa = XCBuildConfiguration; 353 | buildSettings = { 354 | ALLOW_TARGET_PLATFORM_SPECIALIZATION = YES; 355 | ARCHS = arm64e; 356 | CODE_SIGN_STYLE = Automatic; 357 | DEVELOPMENT_TEAM = VF46MYDSGH; 358 | DYLIB_COMPATIBILITY_VERSION = 1; 359 | DYLIB_CURRENT_VERSION = 1; 360 | EXECUTABLE_PREFIX = ""; 361 | IPHONEOS_DEPLOYMENT_TARGET = 15.0; 362 | MACOSX_DEPLOYMENT_TARGET = 11.0; 363 | ONLY_ACTIVE_ARCH = NO; 364 | PRODUCT_NAME = "$(TARGET_NAME)"; 365 | SDKROOT = iphoneos; 366 | SKIP_INSTALL = YES; 367 | SUPPORTED_PLATFORMS = "iphonesimulator iphoneos"; 368 | SUPPORTS_MACCATALYST = YES; 369 | SWIFT_OBJC_BRIDGING_HEADER = OldABI.h; 370 | SWIFT_VERSION = 5.0; 371 | }; 372 | name = Release; 373 | }; 374 | /* End XCBuildConfiguration section */ 375 | 376 | /* Begin XCConfigurationList section */ 377 | 9E5D8B0929DE46080068D078 /* Build configuration list for PBXNativeTarget "tests" */ = { 378 | isa = XCConfigurationList; 379 | buildConfigurations = ( 380 | 9E5D8B0729DE46080068D078 /* Debug */, 381 | 9E5D8B0829DE46080068D078 /* Release */, 382 | ); 383 | defaultConfigurationIsVisible = 0; 384 | defaultConfigurationName = Release; 385 | }; 386 | 9EF3203D29D4CD8200175976 /* Build configuration list for PBXProject "OldABI" */ = { 387 | isa = XCConfigurationList; 388 | buildConfigurations = ( 389 | 9EF3204429D4CD8200175976 /* Debug */, 390 | 9EF3204529D4CD8200175976 /* Release */, 391 | ); 392 | defaultConfigurationIsVisible = 0; 393 | defaultConfigurationName = Release; 394 | }; 395 | 9EF3204629D4CD8200175976 /* Build configuration list for PBXNativeTarget "OldABI" */ = { 396 | isa = XCConfigurationList; 397 | buildConfigurations = ( 398 | 9EF3204729D4CD8200175976 /* Debug */, 399 | 9EF3204829D4CD8200175976 /* Release */, 400 | ); 401 | defaultConfigurationIsVisible = 0; 402 | defaultConfigurationName = Release; 403 | }; 404 | /* End XCConfigurationList section */ 405 | }; 406 | rootObject = 9EF3203A29D4CD8200175976 /* Project object */; 407 | } 408 | -------------------------------------------------------------------------------- /OldABI.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /OldABI.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /OldABI.xcodeproj/project.xcworkspace/xcuserdata/charlotte.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tealbathingsuit/OldABI/ba6396be715c1f8b591aef198217af17f559e3fe/OldABI.xcodeproj/project.xcworkspace/xcuserdata/charlotte.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /OldABI.xcodeproj/xcuserdata/charlotte.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | OldABI.xcscheme_^#shared#^_ 8 | 9 | orderHint 10 | 0 11 | 12 | tests.xcscheme_^#shared#^_ 13 | 14 | orderHint 15 | 1 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /packaging/control: -------------------------------------------------------------------------------- 1 | Architecture: iphoneos-arm64 2 | Author: Evelyn 3 | Depends: ellekit (>= 0.4), cy+cpu.arm64e, firmware (>= 15.0) 4 | Description: Support for legacy arm64e ABI in iOS 15.0+ 5 | Package: oldabi 6 | Maintainer: Evelyn 7 | Name: Legacy arm64e Support 8 | Version: @DEB_VERSION@ 9 | -------------------------------------------------------------------------------- /patchfind.h: -------------------------------------------------------------------------------- 1 | void *patchfind_seek_back(void *startPtr, uint32_t toInstruction, uint32_t mask, unsigned int maxSearch); 2 | void *patchfind_find(int imageIndex, unsigned char *bytesToSearch, unsigned char *byteMask, size_t byteCount); 3 | -------------------------------------------------------------------------------- /patchfind.m: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | #import 4 | #import 5 | #import 6 | 7 | int memcmp_masked(const void *str1, const void *str2, unsigned char *mask, size_t n) 8 | { 9 | const unsigned char *p = (const unsigned char*)str1; 10 | const unsigned char *q = (const unsigned char*)str2; 11 | 12 | if (p == q) return 0; 13 | 14 | for (int i = 0; i < n; i++) { 15 | unsigned char cMask = mask[i]; 16 | if ((p[i] & cMask) != (q[i] & cMask)) { 17 | // we do not care about 1 / -1 18 | return -1; 19 | } 20 | } 21 | 22 | return 0; 23 | } 24 | 25 | void *_patchfind_in_region(vm_address_t startAddr, vm_offset_t regionLength, unsigned char *bytesToSearch, unsigned char *byteMask, size_t byteCount) 26 | { 27 | if (byteCount < 1) { 28 | return NULL; 29 | } 30 | 31 | unsigned int firstByteIndex = 0; 32 | if (byteMask != NULL) { 33 | for (size_t i = 0; i < byteCount; i++) { 34 | if (byteMask[i] == 0xFF) { 35 | firstByteIndex = i; 36 | break; 37 | } 38 | } 39 | } 40 | 41 | unsigned char firstByte = bytesToSearch[firstByteIndex]; 42 | vm_address_t curAddr = startAddr; 43 | 44 | while(curAddr < startAddr + regionLength) { 45 | size_t searchSize = (startAddr - curAddr) + regionLength; 46 | void *foundPtr = memchr((void*)curAddr,firstByte,searchSize); 47 | 48 | if (foundPtr == NULL) { 49 | break; 50 | } 51 | 52 | vm_address_t foundAddr = (vm_address_t)foundPtr; 53 | 54 | // correct foundPtr in respect of firstByteIndex 55 | foundPtr = (void*)((intptr_t)foundPtr - firstByteIndex); 56 | 57 | size_t remainingBytes = regionLength - (foundAddr - startAddr); 58 | 59 | if (remainingBytes >= byteCount) { 60 | int memcmp_res; 61 | if (byteMask != NULL) { 62 | memcmp_res = memcmp_masked(foundPtr, bytesToSearch, byteMask, byteCount); 63 | } 64 | else { 65 | memcmp_res = memcmp(foundPtr, bytesToSearch, byteCount); 66 | } 67 | 68 | if (memcmp_res == 0) { 69 | return foundPtr; 70 | } 71 | } 72 | else { 73 | break; 74 | } 75 | 76 | curAddr = foundAddr + 1; 77 | } 78 | 79 | return NULL; 80 | } 81 | 82 | void *patchfind_seek_back(void *startPtr, uint32_t toInstruction, uint32_t mask, unsigned int maxSearch) 83 | { 84 | vm_address_t startAddr = (vm_address_t)startPtr; 85 | vm_address_t curAddr = startAddr; 86 | 87 | while((startAddr - curAddr) < maxSearch) { 88 | void *curPtr = (void*)curAddr; 89 | uint32_t curInst = *(uint32_t*)curPtr; 90 | 91 | if ((curInst & mask) == (toInstruction & mask)) { 92 | return curPtr; 93 | } 94 | 95 | curAddr = curAddr - 1; 96 | } 97 | 98 | return NULL; 99 | } 100 | 101 | void *patchfind_find(int imageIndex, unsigned char *bytesToSearch, unsigned char *byteMask, size_t byteCount) 102 | { 103 | intptr_t baseAddr = _dyld_get_image_vmaddr_slide(imageIndex); 104 | struct mach_header_64 *header = (struct mach_header_64*)_dyld_get_image_header(imageIndex); 105 | 106 | const struct segment_command_64 *cmd; 107 | 108 | uintptr_t addr = (uintptr_t)(header + 1); 109 | uintptr_t endAddr = addr + header->sizeofcmds; 110 | 111 | for (int ci = 0; ci < header->ncmds && addr <= endAddr; ci++) { 112 | cmd = (typeof(cmd))addr; 113 | 114 | addr = addr + cmd->cmdsize; 115 | 116 | if (cmd->cmd != LC_SEGMENT_64 || strcmp(cmd->segname, "__TEXT")) { 117 | continue; 118 | } 119 | 120 | return _patchfind_in_region(cmd->vmaddr + baseAddr, cmd->vmsize, bytesToSearch, byteMask, byteCount); 121 | } 122 | 123 | return NULL; 124 | } 125 | 126 | extern void swift_ctor(void); 127 | 128 | __attribute__((constructor)) 129 | static void ctor() { 130 | swift_ctor(); 131 | } 132 | -------------------------------------------------------------------------------- /tests/main.swift: -------------------------------------------------------------------------------- 1 | 2 | import Foundation 3 | import MachO 4 | 5 | let ekhandle = dlopen("/var/jb/usr/lib/libellekit.dylib", RTLD_NOW); 6 | 7 | typealias FileHandleC = UnsafeMutablePointer 8 | extension FileHandleC { 9 | @inline(__always) 10 | func readData(ofLength count: Int) -> UnsafeMutableRawPointer { 11 | let alloc = malloc(count) 12 | fread(alloc, 1, count, self) 13 | return alloc! 14 | } 15 | 16 | @discardableResult @inline(__always) 17 | func seek(toFileOffset offset: UInt64) -> UnsafeMutablePointer { 18 | var pos: fpos_t = .init(offset) 19 | fsetpos(self, &pos) 20 | return self 21 | } 22 | 23 | @inline(__always) 24 | var offsetInFile: UInt64 { 25 | var pos: fpos_t = 0 26 | fgetpos(self, &pos) 27 | return .init(pos) 28 | } 29 | 30 | @inline(__always) 31 | func close() { 32 | fclose(self) 33 | } 34 | } 35 | 36 | let hookMemory = { 37 | unsafeBitCast(dlsym(ekhandle, "MSHookMemory"), to: (@convention (c) (UnsafeRawPointer, UnsafeRawPointer, size_t) -> Void).self) 38 | }() 39 | 40 | let hookFunction = { 41 | unsafeBitCast(dlsym(ekhandle, "MSHookFunction"), to: (@convention (c) (UnsafeRawPointer, UnsafeRawPointer, UnsafeMutablePointer?) -> Void).self) 42 | }() 43 | 44 | func looksLegacy(_ path: UnsafePointer) -> Bool { 45 | guard let handle = fopen(path, "r") else { 46 | print("Failed to open destination file") 47 | return false 48 | } 49 | 50 | defer { handle.close() } 51 | 52 | let machHeaderPointer = handle 53 | .readData(ofLength: MemoryLayout.size) 54 | 55 | defer { machHeaderPointer.deallocate() } 56 | 57 | if machHeaderPointer.assumingMemoryBound(to: mach_header_64.self).pointee.magic == FAT_CIGAM { 58 | // we have a fat binary 59 | // get our current cpu subtype 60 | let nslices = handle 61 | .seek(toFileOffset: 0x4) 62 | .readData(ofLength: MemoryLayout.size) 63 | .assumingMemoryBound(to: UInt32.self) 64 | .pointee.bigEndian 65 | 66 | for i in 0...size) 70 | .assumingMemoryBound(to: fat_arch.self) 71 | 72 | let slice = slice_ptr.pointee 73 | 74 | defer { slice_ptr.deallocate() } 75 | 76 | if slice.cputype.bigEndian == CPU_TYPE_ARM64 { 77 | 78 | let slice_ptr = handle 79 | .seek(toFileOffset: UInt64(8 + (Int(i) * 20))) 80 | .readData(ofLength: MemoryLayout.size) 81 | .assumingMemoryBound(to: fat_arch.self) 82 | 83 | let slice = slice_ptr.pointee 84 | 85 | defer { slice_ptr.deallocate() } 86 | 87 | if slice.cpusubtype == 0x2000080 { // new abi 88 | return false 89 | } 90 | 91 | if slice.cpusubtype == 0x2000000 { // old abi 92 | return true 93 | } 94 | } 95 | } 96 | } 97 | 98 | return false 99 | } 100 | 101 | print("RESULT:", looksLegacy("/Users/charlotte/Downloads/oldABI.dylib") == true) 102 | 103 | print("RESULT:", looksLegacy("/Users/charlotte/Downloads/newABI.dylib") == false) 104 | 105 | print("ATRIA:", looksLegacy("/Users/charlotte/Downloads/me.lau.atria_1.3-1.3_iphoneos-arm64/var/jb/Library/MobileSubstrate/DynamicLibraries/Atria.dylib") == true) 106 | --------------------------------------------------------------------------------