├── .gitignore ├── LICENSE.txt ├── README.md ├── bxdiff50.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist ├── xcshareddata │ └── xcschemes │ │ └── BXDIFF50-Swift.xcscheme └── xcuserdata │ └── Salman.xcuserdatad │ ├── xcdebugger │ └── Breakpoints_v2.xcbkptlist │ └── xcschemes │ └── xcschememanagement.plist ├── bxdiff50 ├── Control.swift ├── PBZX.swift ├── Patch.swift ├── PatchSession.swift ├── Utils.swift └── main.swift └── sharingd_test ├── 7664ff8e1b0f6254b57bb78103158d825654b322_sharingd_target ├── ef28d87c911f1ab1b1bc68b436346a7eb91d8d6e_sharingd_source └── patch /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Created by https://www.gitignore.io/api/xcode,swift,macos 3 | # Edit at https://www.gitignore.io/?templates=xcode,swift,macos 4 | 5 | ### macOS ### 6 | # General 7 | .DS_Store 8 | .AppleDouble 9 | .LSOverride 10 | 11 | # Icon must end with two \r 12 | Icon 13 | 14 | # Thumbnails 15 | ._* 16 | 17 | # Files that might appear in the root of a volume 18 | .DocumentRevisions-V100 19 | .fseventsd 20 | .Spotlight-V100 21 | .TemporaryItems 22 | .Trashes 23 | .VolumeIcon.icns 24 | .com.apple.timemachine.donotpresent 25 | 26 | # Directories potentially created on remote AFP share 27 | .AppleDB 28 | .AppleDesktop 29 | Network Trash Folder 30 | Temporary Items 31 | .apdisk 32 | 33 | ### Swift ### 34 | # Xcode 35 | # 36 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 37 | 38 | ## Build generated 39 | build/ 40 | DerivedData/ 41 | 42 | ## Various settings 43 | *.pbxuser 44 | !default.pbxuser 45 | *.mode1v3 46 | !default.mode1v3 47 | *.mode2v3 48 | !default.mode2v3 49 | *.perspectivev3 50 | !default.perspectivev3 51 | xcuserdata/ 52 | 53 | ## Other 54 | *.moved-aside 55 | *.xccheckout 56 | *.xcscmblueprint 57 | 58 | ## Obj-C/Swift specific 59 | *.hmap 60 | *.ipa 61 | *.dSYM.zip 62 | *.dSYM 63 | 64 | ## Playgrounds 65 | timeline.xctimeline 66 | playground.xcworkspace 67 | 68 | # Swift Package Manager 69 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. 70 | # Packages/ 71 | # Package.pins 72 | # Package.resolved 73 | .build/ 74 | 75 | # CocoaPods 76 | # We recommend against adding the Pods directory to your .gitignore. However 77 | # you should judge for yourself, the pros and cons are mentioned at: 78 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 79 | # Pods/ 80 | # Add this line if you want to avoid checking in source code from the Xcode workspace 81 | # *.xcworkspace 82 | 83 | # Carthage 84 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 85 | # Carthage/Checkouts 86 | 87 | Carthage/Build 88 | 89 | # Accio dependency management 90 | Dependencies/ 91 | .accio/ 92 | 93 | # fastlane 94 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 95 | # screenshots whenever they are needed. 96 | # For more information about the recommended setup visit: 97 | # https://docs.fastlane.tools/best-practices/source-control/#source-control 98 | 99 | fastlane/report.xml 100 | fastlane/Preview.html 101 | fastlane/screenshots/**/*.png 102 | fastlane/test_output 103 | 104 | # Code Injection 105 | # After new code Injection tools there's a generated folder /iOSInjectionProject 106 | # https://github.com/johnno1962/injectionforxcode 107 | 108 | iOSInjectionProject/ 109 | 110 | ### Xcode ### 111 | # Xcode 112 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 113 | 114 | ## User settings 115 | 116 | ## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9) 117 | 118 | ## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4) 119 | 120 | ## Xcode Patch 121 | *.xcodeproj/* 122 | !*.xcodeproj/project.pbxproj 123 | !*.xcodeproj/xcshareddata/ 124 | !*.xcworkspace/contents.xcworkspacedata 125 | /*.gcno 126 | 127 | ### Xcode Patch ### 128 | **/xcshareddata/WorkspaceSettings.xcsettings 129 | 130 | # End of https://www.gitignore.io/api/xcode,swift,macos 131 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright © 2021 2 | 3 | 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: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | 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. 8 | 9 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## BXDIFF50 Patcher 2 | 3 | BXDIFF50 is a propritary Apple binary format used for patching system components during an OTA upgrade. 4 | 5 | ### Usage 6 | 7 | `./bxdiff50 ` 8 | 9 | ### Compiling 10 | 11 | Building on macOS is very simple as this project uses exclusively standard library resources. Simply open the Xcode probject and build. 12 | 13 | If you're using Swift on Linux, your runtime must have the `CommonCrypto` and `Compression` modules availble in some functional form. This is an unsupported configuration so really you're on your own. 14 | 15 | ### Patching example output 16 | 17 | Below is the output of patching the `shargind` binary from iOS build 16F5156a (12.3 beta) on the iPhone X to build 16G5027i (12.4 beta) using the [c1cc5c87b52523ccc1d226306ec39ed389bde607.zip](https://ipsw.me/api/ios/v4/ota/download/iPhone10,6/16G5027i?prerequisite=16F5156a) OTA. To verify your build, these binaries have been included in the repo as well under /sharingd_test 18 | 19 | ``` 20 | allison@Allisons-MacBook-Pro sharingd_test % ./bxdiff50 patch ef28d87c911f1ab1b1bc68b436346a7eb91d8d6e_sharingd_source output_test 21 | [INFO] Beginning to patch binary... 22 | [DEBUG] Found section @28 with 408 decompressed bytes 23 | [DEBUG] No more sections to decode. 24 | [DEBUG] Found section @28 with 32456 decompressed bytes 25 | [DEBUG] Found section @32500 with 15520 decompressed bytes 26 | [DEBUG] Found section @48036 with 8276 decompressed bytes 27 | [DEBUG] Found section @56328 with 11144 decompressed bytes 28 | [DEBUG] Found section @67488 with 220 decompressed bytes 29 | [DEBUG] No more sections to decode. 30 | [DEBUG] Found section @28 with 40788 decompressed bytes 31 | [DEBUG] No more sections to decode. 32 | [INFO] SHA1 from patch confirms that this input is valid 33 | 0/73 34 | [DEBUG] Applying: BXDIFF50_Control {mixlen: 10926, copylen: 0, seeklen: 80} 35 | [DEBUG] Applying: BXDIFF50_Control {mixlen: 89998, copylen: 0, seeklen: 32} 36 | [DEBUG] Applying: BXDIFF50_Control {mixlen: 144, copylen: 0, seeklen: 20} 37 | [DEBUG] Applying: BXDIFF50_Control {mixlen: 22, copylen: 0, seeklen: 32} 38 | [DEBUG] Applying: BXDIFF50_Control {mixlen: 30, copylen: 0, seeklen: -52} 39 | [DEBUG] Applying: BXDIFF50_Control {mixlen: 27, copylen: 0, seeklen: 396} 40 | [DEBUG] Applying: BXDIFF50_Control {mixlen: 12, copylen: 0, seeklen: -656} 41 | [DEBUG] Applying: BXDIFF50_Control {mixlen: 0, copylen: 0, seeklen: 228} 42 | [DEBUG] Applying: BXDIFF50_Control {mixlen: 252653, copylen: 0, seeklen: 72} 43 | [DEBUG] Applying: BXDIFF50_Control {mixlen: 170, copylen: 0, seeklen: -36} 44 | 10/73 45 | [DEBUG] Applying: BXDIFF50_Control {mixlen: 0, copylen: 0, seeklen: -36} 46 | [DEBUG] Applying: BXDIFF50_Control {mixlen: 125634, copylen: 0, seeklen: 64} 47 | [DEBUG] Applying: BXDIFF50_Control {mixlen: 171, copylen: 0, seeklen: -16} 48 | [DEBUG] Applying: BXDIFF50_Control {mixlen: 21, copylen: 0, seeklen: 20} 49 | [DEBUG] Applying: BXDIFF50_Control {mixlen: 22, copylen: 0, seeklen: 212} 50 | [DEBUG] Applying: BXDIFF50_Control {mixlen: 43, copylen: 0, seeklen: -156} 51 | [DEBUG] Applying: BXDIFF50_Control {mixlen: 9, copylen: 0, seeklen: -92} 52 | [DEBUG] Applying: BXDIFF50_Control {mixlen: 58, copylen: 0, seeklen: -96} 53 | [DEBUG] Applying: BXDIFF50_Control {mixlen: 36, copylen: 24, seeklen: 208} 54 | [DEBUG] Applying: BXDIFF50_Control {mixlen: 6, copylen: 0, seeklen: -120} 55 | 20/73 56 | [DEBUG] Applying: BXDIFF50_Control {mixlen: 381642, copylen: 0, seeklen: 32} 57 | [DEBUG] Applying: BXDIFF50_Control {mixlen: 192, copylen: 0, seeklen: 20} 58 | [DEBUG] Applying: BXDIFF50_Control {mixlen: 22, copylen: 0, seeklen: -52} 59 | [DEBUG] Applying: BXDIFF50_Control {mixlen: 11496, copylen: 0, seeklen: 368} 60 | [DEBUG] Applying: BXDIFF50_Control {mixlen: 62, copylen: 2, seeklen: 182} 61 | [DEBUG] Applying: BXDIFF50_Control {mixlen: 14, copylen: 0, seeklen: -596} 62 | [DEBUG] Applying: BXDIFF50_Control {mixlen: 287388, copylen: 0, seeklen: 24} 63 | [DEBUG] Applying: BXDIFF50_Control {mixlen: 152, copylen: 4, seeklen: 12} 64 | [DEBUG] Applying: BXDIFF50_Control {mixlen: 18, copylen: 0, seeklen: -32} 65 | [DEBUG] Applying: BXDIFF50_Control {mixlen: 141718, copylen: 0, seeklen: 64} 66 | 30/73 67 | [DEBUG] Applying: BXDIFF50_Control {mixlen: 374, copylen: 0, seeklen: -32} 68 | [DEBUG] Applying: BXDIFF50_Control {mixlen: 0, copylen: 0, seeklen: -32} 69 | [DEBUG] Applying: BXDIFF50_Control {mixlen: 674, copylen: 0, seeklen: 64} 70 | [DEBUG] Applying: BXDIFF50_Control {mixlen: 310, copylen: 0, seeklen: -32} 71 | [DEBUG] Applying: BXDIFF50_Control {mixlen: 0, copylen: 0, seeklen: -32} 72 | [DEBUG] Applying: BXDIFF50_Control {mixlen: 1270310, copylen: 0, seeklen: -96} 73 | [DEBUG] Applying: BXDIFF50_Control {mixlen: 13398, copylen: 0, seeklen: 96} 74 | [DEBUG] Applying: BXDIFF50_Control {mixlen: 55458, copylen: 6, seeklen: 4} 75 | [DEBUG] Applying: BXDIFF50_Control {mixlen: 328, copylen: 6, seeklen: 4} 76 | [DEBUG] Applying: BXDIFF50_Control {mixlen: 43202, copylen: 6, seeklen: 4} 77 | 40/73 78 | [DEBUG] Applying: BXDIFF50_Control {mixlen: 8176, copylen: 6, seeklen: 4} 79 | [DEBUG] Applying: BXDIFF50_Control {mixlen: 3902, copylen: 6, seeklen: 4} 80 | [DEBUG] Applying: BXDIFF50_Control {mixlen: 11578, copylen: 6, seeklen: 4} 81 | [DEBUG] Applying: BXDIFF50_Control {mixlen: 13051, copylen: 6, seeklen: 4} 82 | [DEBUG] Applying: BXDIFF50_Control {mixlen: 54724, copylen: 0, seeklen: -2} 83 | [DEBUG] Applying: BXDIFF50_Control {mixlen: 1342, copylen: 6, seeklen: 4} 84 | [DEBUG] Applying: BXDIFF50_Control {mixlen: 43, copylen: 0, seeklen: 407786} 85 | [DEBUG] Applying: BXDIFF50_Control {mixlen: 12, copylen: 0, seeklen: -407800} 86 | [DEBUG] Applying: BXDIFF50_Control {mixlen: 3011, copylen: 6, seeklen: 4} 87 | [DEBUG] Applying: BXDIFF50_Control {mixlen: 43, copylen: 0, seeklen: 2} 88 | 50/73 89 | [DEBUG] Applying: BXDIFF50_Control {mixlen: 5439, copylen: 6, seeklen: 4} 90 | [DEBUG] Applying: BXDIFF50_Control {mixlen: 30, copylen: 0, seeklen: 2} 91 | [DEBUG] Applying: BXDIFF50_Control {mixlen: 11420, copylen: 6, seeklen: 4} 92 | [DEBUG] Applying: BXDIFF50_Control {mixlen: 35, copylen: 0, seeklen: 2} 93 | [DEBUG] Applying: BXDIFF50_Control {mixlen: 332320, copylen: 5, seeklen: -537} 94 | [DEBUG] Applying: BXDIFF50_Control {mixlen: 1, copylen: 0, seeklen: 540} 95 | [DEBUG] Applying: BXDIFF50_Control {mixlen: 138, copylen: 5, seeklen: -679} 96 | [DEBUG] Applying: BXDIFF50_Control {mixlen: 1, copylen: 0, seeklen: 682} 97 | [DEBUG] Applying: BXDIFF50_Control {mixlen: 280, copylen: 5, seeklen: 1698017} 98 | [DEBUG] Applying: BXDIFF50_Control {mixlen: 1, copylen: 0, seeklen: -1698013} 99 | 60/73 100 | [DEBUG] Applying: BXDIFF50_Control {mixlen: 364, copylen: 0, seeklen: 1} 101 | [DEBUG] Applying: BXDIFF50_Control {mixlen: 24526, copylen: 0, seeklen: 1940} 102 | [DEBUG] Applying: BXDIFF50_Control {mixlen: 0, copylen: 0, seeklen: -1936} 103 | [DEBUG] Applying: BXDIFF50_Control {mixlen: 45307, copylen: 0, seeklen: -480} 104 | [DEBUG] Applying: BXDIFF50_Control {mixlen: 274, copylen: 0, seeklen: 80} 105 | [DEBUG] Applying: BXDIFF50_Control {mixlen: 40, copylen: 0, seeklen: 80} 106 | [DEBUG] Applying: BXDIFF50_Control {mixlen: 0, copylen: 0, seeklen: 320} 107 | [DEBUG] Applying: BXDIFF50_Control {mixlen: 512038, copylen: 0, seeklen: -8} 108 | [DEBUG] Applying: BXDIFF50_Control {mixlen: 46910, copylen: 0, seeklen: 8} 109 | [DEBUG] Applying: BXDIFF50_Control {mixlen: 101094, copylen: 0, seeklen: 14} 110 | 70/73 111 | [DEBUG] Applying: BXDIFF50_Control {mixlen: 49, copylen: 0, seeklen: 18} 112 | [DEBUG] Applying: BXDIFF50_Control {mixlen: 10, copylen: 0, seeklen: -32} 113 | [DEBUG] Applying: BXDIFF50_Control {mixlen: 918469, copylen: 52121, seeklen: 34432} 114 | [INFO] SHA1 from patch confirms that we've patched OK 115 | [INFO] Patch complete! 116 | 117 | ``` 118 | 119 | and when comparing the SHA1 of the synthetic `output_test` to `7664ff8e1b0f6254b57bb78103158d825654b322_sharingd_target` (shargind extracted from a full upgrade/non-patch install of 16G5027i) we find that they are equal, indictating that the patch verification scheme is correct and the patch was completetly successful: 120 | 121 | ``` 122 | allison@Allisons-MacBook-Pro sharingd_test % shasum output_test 7664ff8e1b0f6254b57bb78103158d825654b322_sharingd_target 123 | 39f32b1d9dd5f9f270c492120b15107c8d0398ae output_test 124 | 39f32b1d9dd5f9f270c492120b15107c8d0398ae 7664ff8e1b0f6254b57bb78103158d825654b322_sharingd_target 125 | ``` -------------------------------------------------------------------------------- /bxdiff50.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 50; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 228297A422FC99F3004495A5 /* Utils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 228297A322FC99F3004495A5 /* Utils.swift */; }; 11 | 228297A622FC9A0F004495A5 /* PBZX.swift in Sources */ = {isa = PBXBuildFile; fileRef = 228297A522FC9A0F004495A5 /* PBZX.swift */; }; 12 | 22C4B7E722FA948F00108CAB /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = 22C4B7E622FA948F00108CAB /* main.swift */; }; 13 | 22DA90B422FBD8AC000A86CB /* Patch.swift in Sources */ = {isa = PBXBuildFile; fileRef = 22DA90B322FBD8AC000A86CB /* Patch.swift */; }; 14 | 22DA90B622FBD8E0000A86CB /* Control.swift in Sources */ = {isa = PBXBuildFile; fileRef = 22DA90B522FBD8E0000A86CB /* Control.swift */; }; 15 | 22DA90B822FBD8F5000A86CB /* PatchSession.swift in Sources */ = {isa = PBXBuildFile; fileRef = 22DA90B722FBD8F5000A86CB /* PatchSession.swift */; }; 16 | /* End PBXBuildFile section */ 17 | 18 | /* Begin PBXCopyFilesBuildPhase section */ 19 | 22C4B7E122FA948F00108CAB /* CopyFiles */ = { 20 | isa = PBXCopyFilesBuildPhase; 21 | buildActionMask = 2147483647; 22 | dstPath = /usr/share/man/man1/; 23 | dstSubfolderSpec = 0; 24 | files = ( 25 | ); 26 | runOnlyForDeploymentPostprocessing = 1; 27 | }; 28 | /* End PBXCopyFilesBuildPhase section */ 29 | 30 | /* Begin PBXFileReference section */ 31 | 228297A322FC99F3004495A5 /* Utils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = Utils.swift; path = ../../../../../System/Volumes/Data/Users/allison/Downloads/bxdiff50/bxdiff50/Utils.swift; sourceTree = ""; }; 32 | 228297A522FC9A0F004495A5 /* PBZX.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = PBZX.swift; path = ../../../../../System/Volumes/Data/Users/allison/Downloads/bxdiff50/bxdiff50/PBZX.swift; sourceTree = ""; }; 33 | 22C4B7E322FA948F00108CAB /* bxdiff50 */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = bxdiff50; sourceTree = BUILT_PRODUCTS_DIR; }; 34 | 22C4B7E622FA948F00108CAB /* main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = ""; }; 35 | 22DA90B322FBD8AC000A86CB /* Patch.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Patch.swift; sourceTree = ""; }; 36 | 22DA90B522FBD8E0000A86CB /* Control.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Control.swift; sourceTree = ""; }; 37 | 22DA90B722FBD8F5000A86CB /* PatchSession.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PatchSession.swift; sourceTree = ""; }; 38 | /* End PBXFileReference section */ 39 | 40 | /* Begin PBXFrameworksBuildPhase section */ 41 | 22C4B7E022FA948F00108CAB /* Frameworks */ = { 42 | isa = PBXFrameworksBuildPhase; 43 | buildActionMask = 2147483647; 44 | files = ( 45 | ); 46 | runOnlyForDeploymentPostprocessing = 0; 47 | }; 48 | /* End PBXFrameworksBuildPhase section */ 49 | 50 | /* Begin PBXGroup section */ 51 | 22C4B7DA22FA948F00108CAB = { 52 | isa = PBXGroup; 53 | children = ( 54 | 22C4B7E522FA948F00108CAB /* bxdiff50 */, 55 | 22C4B7E422FA948F00108CAB /* Products */, 56 | ); 57 | sourceTree = ""; 58 | }; 59 | 22C4B7E422FA948F00108CAB /* Products */ = { 60 | isa = PBXGroup; 61 | children = ( 62 | 22C4B7E322FA948F00108CAB /* bxdiff50 */, 63 | ); 64 | name = Products; 65 | sourceTree = ""; 66 | }; 67 | 22C4B7E522FA948F00108CAB /* bxdiff50 */ = { 68 | isa = PBXGroup; 69 | children = ( 70 | 22C4B7E622FA948F00108CAB /* main.swift */, 71 | 22DA90B322FBD8AC000A86CB /* Patch.swift */, 72 | 22DA90B522FBD8E0000A86CB /* Control.swift */, 73 | 22DA90B722FBD8F5000A86CB /* PatchSession.swift */, 74 | 228297A322FC99F3004495A5 /* Utils.swift */, 75 | 228297A522FC9A0F004495A5 /* PBZX.swift */, 76 | ); 77 | path = bxdiff50; 78 | sourceTree = ""; 79 | }; 80 | /* End PBXGroup section */ 81 | 82 | /* Begin PBXNativeTarget section */ 83 | 22C4B7E222FA948F00108CAB /* bxdiff50 */ = { 84 | isa = PBXNativeTarget; 85 | buildConfigurationList = 22C4B7EA22FA948F00108CAB /* Build configuration list for PBXNativeTarget "bxdiff50" */; 86 | buildPhases = ( 87 | 22C4B7DF22FA948F00108CAB /* Sources */, 88 | 22C4B7E022FA948F00108CAB /* Frameworks */, 89 | 22C4B7E122FA948F00108CAB /* CopyFiles */, 90 | ); 91 | buildRules = ( 92 | ); 93 | dependencies = ( 94 | ); 95 | name = bxdiff50; 96 | productName = "BXDIFF50-Swift"; 97 | productReference = 22C4B7E322FA948F00108CAB /* bxdiff50 */; 98 | productType = "com.apple.product-type.tool"; 99 | }; 100 | /* End PBXNativeTarget section */ 101 | 102 | /* Begin PBXProject section */ 103 | 22C4B7DB22FA948F00108CAB /* Project object */ = { 104 | isa = PBXProject; 105 | attributes = { 106 | LastSwiftUpdateCheck = 1100; 107 | LastUpgradeCheck = 1100; 108 | ORGANIZATIONNAME = "Allison Husain"; 109 | TargetAttributes = { 110 | 22C4B7E222FA948F00108CAB = { 111 | CreatedOnToolsVersion = 11.0; 112 | }; 113 | }; 114 | }; 115 | buildConfigurationList = 22C4B7DE22FA948F00108CAB /* Build configuration list for PBXProject "bxdiff50" */; 116 | compatibilityVersion = "Xcode 9.3"; 117 | developmentRegion = en; 118 | hasScannedForEncodings = 0; 119 | knownRegions = ( 120 | en, 121 | Base, 122 | ); 123 | mainGroup = 22C4B7DA22FA948F00108CAB; 124 | productRefGroup = 22C4B7E422FA948F00108CAB /* Products */; 125 | projectDirPath = ""; 126 | projectRoot = ""; 127 | targets = ( 128 | 22C4B7E222FA948F00108CAB /* bxdiff50 */, 129 | ); 130 | }; 131 | /* End PBXProject section */ 132 | 133 | /* Begin PBXSourcesBuildPhase section */ 134 | 22C4B7DF22FA948F00108CAB /* Sources */ = { 135 | isa = PBXSourcesBuildPhase; 136 | buildActionMask = 2147483647; 137 | files = ( 138 | 228297A422FC99F3004495A5 /* Utils.swift in Sources */, 139 | 22DA90B622FBD8E0000A86CB /* Control.swift in Sources */, 140 | 22DA90B422FBD8AC000A86CB /* Patch.swift in Sources */, 141 | 228297A622FC9A0F004495A5 /* PBZX.swift in Sources */, 142 | 22DA90B822FBD8F5000A86CB /* PatchSession.swift in Sources */, 143 | 22C4B7E722FA948F00108CAB /* main.swift in Sources */, 144 | ); 145 | runOnlyForDeploymentPostprocessing = 0; 146 | }; 147 | /* End PBXSourcesBuildPhase section */ 148 | 149 | /* Begin XCBuildConfiguration section */ 150 | 22C4B7E822FA948F00108CAB /* Debug */ = { 151 | isa = XCBuildConfiguration; 152 | buildSettings = { 153 | ALWAYS_SEARCH_USER_PATHS = NO; 154 | CLANG_ANALYZER_NONNULL = YES; 155 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 156 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 157 | CLANG_CXX_LIBRARY = "libc++"; 158 | CLANG_ENABLE_MODULES = YES; 159 | CLANG_ENABLE_OBJC_ARC = YES; 160 | CLANG_ENABLE_OBJC_WEAK = YES; 161 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 162 | CLANG_WARN_BOOL_CONVERSION = YES; 163 | CLANG_WARN_COMMA = YES; 164 | CLANG_WARN_CONSTANT_CONVERSION = YES; 165 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 166 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 167 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 168 | CLANG_WARN_EMPTY_BODY = YES; 169 | CLANG_WARN_ENUM_CONVERSION = YES; 170 | CLANG_WARN_INFINITE_RECURSION = YES; 171 | CLANG_WARN_INT_CONVERSION = YES; 172 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 173 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 174 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 175 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 176 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 177 | CLANG_WARN_STRICT_PROTOTYPES = YES; 178 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 179 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 180 | CLANG_WARN_UNREACHABLE_CODE = YES; 181 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 182 | COPY_PHASE_STRIP = NO; 183 | DEBUG_INFORMATION_FORMAT = dwarf; 184 | ENABLE_STRICT_OBJC_MSGSEND = YES; 185 | ENABLE_TESTABILITY = YES; 186 | GCC_C_LANGUAGE_STANDARD = gnu11; 187 | GCC_DYNAMIC_NO_PIC = NO; 188 | GCC_NO_COMMON_BLOCKS = YES; 189 | GCC_OPTIMIZATION_LEVEL = 0; 190 | GCC_PREPROCESSOR_DEFINITIONS = ( 191 | "DEBUG=1", 192 | "$(inherited)", 193 | ); 194 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 195 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 196 | GCC_WARN_UNDECLARED_SELECTOR = YES; 197 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 198 | GCC_WARN_UNUSED_FUNCTION = YES; 199 | GCC_WARN_UNUSED_VARIABLE = YES; 200 | MACOSX_DEPLOYMENT_TARGET = 10.14; 201 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; 202 | MTL_FAST_MATH = YES; 203 | ONLY_ACTIVE_ARCH = YES; 204 | SDKROOT = macosx; 205 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 206 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 207 | }; 208 | name = Debug; 209 | }; 210 | 22C4B7E922FA948F00108CAB /* Release */ = { 211 | isa = XCBuildConfiguration; 212 | buildSettings = { 213 | ALWAYS_SEARCH_USER_PATHS = NO; 214 | CLANG_ANALYZER_NONNULL = YES; 215 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 216 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 217 | CLANG_CXX_LIBRARY = "libc++"; 218 | CLANG_ENABLE_MODULES = YES; 219 | CLANG_ENABLE_OBJC_ARC = YES; 220 | CLANG_ENABLE_OBJC_WEAK = YES; 221 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 222 | CLANG_WARN_BOOL_CONVERSION = YES; 223 | CLANG_WARN_COMMA = YES; 224 | CLANG_WARN_CONSTANT_CONVERSION = YES; 225 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 226 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 227 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 228 | CLANG_WARN_EMPTY_BODY = YES; 229 | CLANG_WARN_ENUM_CONVERSION = YES; 230 | CLANG_WARN_INFINITE_RECURSION = YES; 231 | CLANG_WARN_INT_CONVERSION = YES; 232 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 233 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 234 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 235 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 236 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 237 | CLANG_WARN_STRICT_PROTOTYPES = YES; 238 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 239 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 240 | CLANG_WARN_UNREACHABLE_CODE = YES; 241 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 242 | COPY_PHASE_STRIP = NO; 243 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 244 | ENABLE_NS_ASSERTIONS = NO; 245 | ENABLE_STRICT_OBJC_MSGSEND = YES; 246 | GCC_C_LANGUAGE_STANDARD = gnu11; 247 | GCC_NO_COMMON_BLOCKS = YES; 248 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 249 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 250 | GCC_WARN_UNDECLARED_SELECTOR = YES; 251 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 252 | GCC_WARN_UNUSED_FUNCTION = YES; 253 | GCC_WARN_UNUSED_VARIABLE = YES; 254 | MACOSX_DEPLOYMENT_TARGET = 10.14; 255 | MTL_ENABLE_DEBUG_INFO = NO; 256 | MTL_FAST_MATH = YES; 257 | SDKROOT = macosx; 258 | SWIFT_COMPILATION_MODE = wholemodule; 259 | SWIFT_OPTIMIZATION_LEVEL = "-O"; 260 | }; 261 | name = Release; 262 | }; 263 | 22C4B7EB22FA948F00108CAB /* Debug */ = { 264 | isa = XCBuildConfiguration; 265 | buildSettings = { 266 | CODE_SIGN_STYLE = Automatic; 267 | DEVELOPMENT_TEAM = XBKLZPN8YT; 268 | ENABLE_HARDENED_RUNTIME = YES; 269 | MACOSX_DEPLOYMENT_TARGET = 10.12; 270 | PRODUCT_NAME = "$(TARGET_NAME)"; 271 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 272 | SWIFT_VERSION = 5.0; 273 | }; 274 | name = Debug; 275 | }; 276 | 22C4B7EC22FA948F00108CAB /* Release */ = { 277 | isa = XCBuildConfiguration; 278 | buildSettings = { 279 | CODE_SIGN_STYLE = Automatic; 280 | DEVELOPMENT_TEAM = XBKLZPN8YT; 281 | ENABLE_HARDENED_RUNTIME = YES; 282 | MACOSX_DEPLOYMENT_TARGET = 10.12; 283 | PRODUCT_NAME = "$(TARGET_NAME)"; 284 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 285 | SWIFT_VERSION = 5.0; 286 | }; 287 | name = Release; 288 | }; 289 | /* End XCBuildConfiguration section */ 290 | 291 | /* Begin XCConfigurationList section */ 292 | 22C4B7DE22FA948F00108CAB /* Build configuration list for PBXProject "bxdiff50" */ = { 293 | isa = XCConfigurationList; 294 | buildConfigurations = ( 295 | 22C4B7E822FA948F00108CAB /* Debug */, 296 | 22C4B7E922FA948F00108CAB /* Release */, 297 | ); 298 | defaultConfigurationIsVisible = 0; 299 | defaultConfigurationName = Release; 300 | }; 301 | 22C4B7EA22FA948F00108CAB /* Build configuration list for PBXNativeTarget "bxdiff50" */ = { 302 | isa = XCConfigurationList; 303 | buildConfigurations = ( 304 | 22C4B7EB22FA948F00108CAB /* Debug */, 305 | 22C4B7EC22FA948F00108CAB /* Release */, 306 | ); 307 | defaultConfigurationIsVisible = 0; 308 | defaultConfigurationName = Release; 309 | }; 310 | /* End XCConfigurationList section */ 311 | }; 312 | rootObject = 22C4B7DB22FA948F00108CAB /* Project object */; 313 | } 314 | -------------------------------------------------------------------------------- /bxdiff50.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /bxdiff50.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /bxdiff50.xcodeproj/xcshareddata/xcschemes/BXDIFF50-Swift.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 43 | 45 | 51 | 52 | 53 | 54 | 60 | 62 | 68 | 69 | 70 | 71 | 73 | 74 | 77 | 78 | 79 | -------------------------------------------------------------------------------- /bxdiff50.xcodeproj/xcuserdata/Salman.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | -------------------------------------------------------------------------------- /bxdiff50.xcodeproj/xcuserdata/Salman.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | BXDIFF50-Swift.xcscheme_^#shared#^_ 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | 22C4B7E222FA948F00108CAB 16 | 17 | primary 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /bxdiff50/Control.swift: -------------------------------------------------------------------------------- 1 | // 2 | // BXDIFF_Control.swift 3 | // BXDIFF50-Swift 4 | // 5 | // Created by Allison Husain on 8/7/19. 6 | // Copyright © 2019 Allison Husain. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | /// A class which interprets a BXDIFF50 control command at a given offset in the control section of a patch 12 | class Control:CustomStringConvertible { 13 | /// How many bytes a control element is in the decompressed buffer 14 | public static let controlSize:Int = 24 // 3 * 8 bytes 15 | 16 | /// How many bytes to "mix" (add from the current patch offset to the current input offset, mod 256) 17 | let mixlen:off_t 18 | 19 | /// How many bytes should be copied off the "extra" section 20 | let copylen:off_t 21 | 22 | /// How many bytes to advance (or reverse) the input pointer 23 | let seeklen:off_t 24 | 25 | 26 | /// Attempt to parse a new control command from the decompressed control buffer 27 | /// - Parameter data: The decompressed control buffer 28 | /// - Parameter number: The index to decompress 29 | init?(data:Data, number:Int) { 30 | let selfOffset = Int(Control.controlSize * number) 31 | 32 | mixlen = Control.read_off_t(data: data, offset: 0 + selfOffset) 33 | copylen = Control.read_off_t(data: data, offset: 8 + selfOffset) 34 | seeklen = Control.read_off_t(data: data, offset: 16 + selfOffset) 35 | } 36 | 37 | 38 | /// Convert a uint64 represented value in to an off_t 39 | /// - Parameter data: The backing buffer 40 | /// - Parameter offset: the offset at which to read (8 bytes) 41 | private static func read_off_t(data:Data,offset:Int) -> off_t { 42 | let b = Data.init(data[offset..<(offset + 8)]) 43 | 44 | var y:off_t = off_t(b[7]) & 0x7f 45 | for i in (0...6).reversed() { 46 | y <<= 8 47 | y += off_t(b[i]) 48 | } 49 | if b[7] & 0x80 != 0 { 50 | y = -y 51 | } 52 | return y 53 | } 54 | 55 | var description: String { 56 | return "BXDIFF50_Control {mixlen: \(mixlen), copylen: \(copylen), seeklen: \(seeklen)}" 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /bxdiff50/PBZX.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PBZX.swift 3 | // bxdiff50 4 | // 5 | // Created by Allison Husain on 8/8/19. 6 | // Copyright © 2019 Allison Husain. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import Compression 11 | 12 | /// PBZX decomperssion utilities 13 | class PBZX { 14 | /// Verify that a buffer is a PBZX buffer using magic bytes 15 | public static func verifyPBZXBuffer(buffer:Data) -> Bool { 16 | if buffer.count < 34 { 17 | return false 18 | } 19 | 20 | return buffer[0..<4] == Data.init([0x70,0x62,0x7a,0x78]) 21 | } 22 | 23 | /// Attempt to extract all XZ archives contained within a PBZX buffer. 24 | /// If there are multiple XZ archives, their contents will be appended 25 | public static func extractPBZX(buffer:Data) -> Data? { 26 | var outputBuffer:Data? = nil 27 | if buffer[0..<4] != Data.init([0x70,0x62,0x7a,0x78]) { 28 | print("[!!!] Cannot extract buffer because it is not a pbzx buffer") 29 | return nil 30 | } 31 | 32 | var searchRange = Range.init(NSRange.init(location: 0, length: buffer.count)) 33 | 34 | while true { 35 | guard let xzStartMagicRange = buffer.range(of: Data.init([0xfd,0x37,0x7a,0x58,0x5a]), options: [], in: searchRange) else { 36 | print("[DEBUG] No more sections to decode.") 37 | break 38 | } 39 | searchRange = (xzStartMagicRange.upperBound)...allocate(capacity: 1) 71 | defer { 72 | streamPointer.deallocate() 73 | } 74 | 75 | var stream = streamPointer.pointee 76 | var status = compression_stream_init(&stream, COMPRESSION_STREAM_DECODE, COMPRESSION_LZMA) 77 | guard status != COMPRESSION_STATUS_ERROR else { 78 | print("[!!!] Unable to initilize the decompression runtime") 79 | abort() 80 | } 81 | defer { 82 | compression_stream_destroy(&stream) 83 | } 84 | 85 | let dstSize = 1024*1024 86 | let dstPointer = UnsafeMutablePointer.allocate(capacity: dstSize) 87 | defer { 88 | dstPointer.deallocate() 89 | } 90 | 91 | let optionalDecompressedData = _7zXZData.withUnsafeBytes { (srcPointer:UnsafePointer) -> Data? in 92 | var output = Data() 93 | 94 | stream.src_ptr = srcPointer 95 | stream.src_size = _7zXZData.count 96 | stream.dst_ptr = dstPointer 97 | stream.dst_size = dstSize 98 | 99 | while status == COMPRESSION_STATUS_OK { 100 | // process the stream 101 | status = compression_stream_process(&stream, 0x00) 102 | 103 | // collect bytes from the stream and reset 104 | switch status { 105 | case COMPRESSION_STATUS_OK: 106 | output.append(dstPointer, count: dstSize) 107 | stream.dst_ptr = dstPointer 108 | stream.dst_size = dstSize 109 | case COMPRESSION_STATUS_ERROR: 110 | return nil 111 | case COMPRESSION_STATUS_END: 112 | output.append(dstPointer, count: stream.dst_ptr - dstPointer) 113 | default: 114 | fatalError() 115 | } 116 | } 117 | return output 118 | } 119 | 120 | 121 | guard let decompressedData = optionalDecompressedData else { 122 | print("[!!!] Unable to decompress") 123 | continue 124 | } 125 | 126 | if outputBuffer == nil { 127 | outputBuffer = decompressedData 128 | }else { 129 | outputBuffer?.append(decompressedData) 130 | } 131 | } 132 | 133 | return outputBuffer 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /bxdiff50/Patch.swift: -------------------------------------------------------------------------------- 1 | // 2 | // BXDIFF50_Patch.swift 3 | // BXDIFF50-Swift 4 | // 5 | // Created by Allison Husain on 8/7/19. 6 | // Copyright © 2019 Allison Husain. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | /// A class which parses a BXDIFF50 style diff patch. Provides information on the patch as well as decompresses the various patch buffers 12 | class Patch { 13 | /// The number of bytes the resulting file should be after patching 14 | public let patchedFileSize:uint64 15 | 16 | /// The number of compressed bytes used by the control section 17 | public let controlSize:uint64 18 | 19 | /// The number of compressed bytes used by the diff section 20 | public let diffSize:uint64 21 | 22 | /// The number of compressed bytes used by the extra section 23 | public let extraSize:uint64 24 | 25 | /// The SHA1 hash bytes of the desired binary *after* a successful patch 26 | public let resultSHA1:[uint8] 27 | 28 | /// The SHA1 hash bytes of the binary which this patch was composed for 29 | public let targetSHA1:[uint8] 30 | 31 | /// A decompressed section of data built from three byte chunks which describes how to patch the binary 32 | public let controlData:Data 33 | 34 | /// The raw data used for storing changes to the binary 35 | public let diffData:Data 36 | 37 | /// Raw bytes which are inserted at various points 38 | public let extraData:Data 39 | 40 | 41 | /// Parse and decompress the patch 42 | /// - Parameter data: The BXDIFF50 patch bytes 43 | init?(data:Data) { 44 | let uint64_size:uint64 = 8 45 | var position:uint64 = 0 46 | 47 | if data.count < 88 { 48 | print("[!!!] Invalid patch, too short") 49 | return nil 50 | } 51 | 52 | //Verify magic 53 | let magicBytes = data[0...7] 54 | position += 8 55 | if magicBytes != Data.init([0x42,0x58,0x44,0x49,0x46,0x46,0x35,0x30]) {//BXDIFF50 56 | print("[!!!] Non-BXDIFF50 input!") 57 | return nil 58 | } 59 | 60 | //skip unknown 8 byte 61 | position += uint64_size 62 | 63 | patchedFileSize = Utils.readUINT64(from: data, offset: position, bigEndian: false) 64 | position += uint64_size 65 | 66 | controlSize = Utils.readUINT64(from: data, offset: position, bigEndian: false) 67 | position += uint64_size 68 | 69 | extraSize = Utils.readUINT64(from: data, offset: position, bigEndian: false) 70 | position += uint64_size 71 | 72 | resultSHA1 = Utils.readUINT8Array(from: data, count: 20, offset: position) 73 | position += 20 74 | 75 | diffSize = Utils.readUINT64(from: data, offset: position, bigEndian: false) 76 | position += uint64_size 77 | 78 | targetSHA1 = Utils.readUINT8Array(from: data, count: 20, offset: position) 79 | position += 20 80 | 81 | //Validate the header size reports against the actuall file size 82 | //88 is the size of the header 83 | if controlSize + diffSize + extraSize + 88 != data.count { 84 | print("[!!!] Patch header sizes and actual size do not match. Cannot process.") 85 | return nil 86 | } 87 | 88 | let controlDataCompressed = Data.init(data[position..<(position + controlSize)]) 89 | position += controlSize 90 | if !PBZX.verifyPBZXBuffer(buffer: controlDataCompressed) { 91 | print("[!!!] Bad control data in patch") 92 | return nil 93 | } 94 | guard let controlData = PBZX.extractPBZX(buffer: controlDataCompressed) else { 95 | print("[!!!] Unable to decompress control data") 96 | return nil 97 | } 98 | self.controlData = controlData 99 | 100 | 101 | let diffDataCompressed = Data.init(data[position..<(position + diffSize)]) 102 | position += diffSize 103 | if !PBZX.verifyPBZXBuffer(buffer: diffDataCompressed) { 104 | print("[!!!] Bad control data in patch") 105 | return nil 106 | } 107 | guard let diffData = PBZX.extractPBZX(buffer: diffDataCompressed) else { 108 | print("[!!!] Unable to decompress diff data") 109 | return nil 110 | } 111 | self.diffData = diffData 112 | 113 | 114 | let extraDataCompressed = Data.init(data[position..<(position + extraSize)]) 115 | position += extraSize 116 | if !PBZX.verifyPBZXBuffer(buffer: extraDataCompressed) { 117 | print("[!!!] Bad extra data in patch") 118 | return nil 119 | } 120 | guard let extraData = PBZX.extractPBZX(buffer: extraDataCompressed) else { 121 | print("[!!!] Unable to decompress extra data") 122 | return nil 123 | } 124 | self.extraData = extraData 125 | } 126 | } 127 | 128 | -------------------------------------------------------------------------------- /bxdiff50/PatchSession.swift: -------------------------------------------------------------------------------- 1 | // 2 | // BXPatchAgent.swift 3 | // BXDIFF50-Swift 4 | // 5 | // Created by Allison Husain on 8/7/19. 6 | // Copyright © 2019 Allison Husain. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import CommonCrypto 11 | 12 | /// An object which facilitates patching 13 | class PatchSession { 14 | 15 | /// The source binary to be patched 16 | private let input:Data 17 | 18 | /// The binary data after being patched 19 | private var output:Data 20 | 21 | /// The patch used for patching 22 | private let patch:Patch 23 | 24 | // various positions used for tracking the read locaiton in the differnt source buffers 25 | private var diffSeekPosition:Int = 0 26 | private var extraSeekPosition:Int = 0 27 | private var inputSeekPosition:Int = 0 28 | 29 | 30 | /// Attempt to create a new patch session 31 | /// This method verifies the SHA1 of the input against the patch's input to ensure that patch is valid for the binary 32 | /// - Parameter input: The bytes to patch 33 | /// - Parameter patch: The patch to apply to the input 34 | init?(input:Data, patch:Patch) { 35 | if PatchSession.verifyHash(data: input, sha1Target: patch.targetSHA1) == false { 36 | print("[!!!] The input file does not match the provided patch") 37 | }else { 38 | print("[INFO] SHA1 from patch confirms that this input is valid") 39 | } 40 | self.patch = patch 41 | self.input = input 42 | 43 | output = Data.init() 44 | } 45 | 46 | /// Compute the SHA1 of the data, and return true if it matches the target 47 | private static func verifyHash(data:Data,sha1Target:[UInt8]) -> Bool { 48 | if sha1Target.count != Int(CC_SHA1_DIGEST_LENGTH) { 49 | return false 50 | } 51 | 52 | var digest = UnsafeMutablePointer.allocate(capacity: Int(CC_SHA1_DIGEST_LENGTH)) 53 | defer { 54 | digest.deallocate() 55 | } 56 | 57 | return data.withUnsafeBytes { (dPointer:UnsafePointer) -> Bool in 58 | CC_SHA1(dPointer, UInt32(data.count), digest) 59 | for i in 0.. Data? { 95 | if output.count != 0 { 96 | print("[!!!] Cannot reuse session, output buffer is dirty") 97 | return nil 98 | } 99 | 100 | let expectedControlSectionCount = patch.controlData.count / Control.controlSize 101 | 102 | for i in 0.. uint64 { 14 | let n = bigEndian ? Data.init(data[offset.. uint64 in 16 | return buffer.bindMemory(to: uint64.self).baseAddress!.pointee 17 | } 18 | } 19 | 20 | /// Attempt to read out an array of bytes from the buffer at a given offset 21 | public static func readUINT8Array(from data:Data,count:Int,offset:uint64) -> [uint8] { 22 | var results = [uint8].init(repeating: 0x0, count: count) 23 | for i in 0.. Data? { 32 | return try? Data.init(contentsOf: URL.init(fileURLWithPath: path)) 33 | } 34 | 35 | /// Write data to a path, overwriting if it exists 36 | public static func write(data:Data, path:String) -> Bool { 37 | do { 38 | try data.write(to: URL.init(fileURLWithPath: path)) 39 | return true 40 | }catch { 41 | return false 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /bxdiff50/main.swift: -------------------------------------------------------------------------------- 1 | // 2 | // main.swift 3 | // BXDIFF50-Swift 4 | // 5 | // Created by Allison Husain on 8/6/19. 6 | // Copyright © 2019 Allison Husain. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | 12 | if CommandLine.arguments.count != 4 { 13 | print(""" 14 | usage: 15 | 16 | bxdiff50 17 | """) 18 | exit(1) 19 | } 20 | 21 | let patchPath = CommandLine.arguments[1] 22 | let inputFilePath = CommandLine.arguments[2] 23 | let outputFilePath = CommandLine.arguments[3] 24 | 25 | print("[INFO] Beginning to patch binary...") 26 | guard let patchData = Utils.load(path: patchPath) else { 27 | print("[!!!] Unable to load patch") 28 | abort() 29 | } 30 | 31 | guard let patch = Patch.init(data: patchData) else { 32 | print("[!!!] Failed to parse patch. Abort.") 33 | abort() 34 | } 35 | 36 | guard let patchTargetData = Utils.load(path: inputFilePath) else { 37 | print("[!!!] Unable to load patch target") 38 | abort() 39 | } 40 | 41 | guard let patcher = PatchSession.init(input: patchTargetData, patch: patch) else { 42 | print("[!!!] Unable to create patcher") 43 | abort() 44 | } 45 | guard let output = patcher.applyAllPatches() else { 46 | print("[!!!] Patch failure") 47 | abort() 48 | } 49 | 50 | if !Utils.write(data: output, path: outputFilePath) { 51 | print("[!!!] Unable to write out patched binary") 52 | abort() 53 | } 54 | 55 | print("[INFO] Patch complete!") 56 | -------------------------------------------------------------------------------- /sharingd_test/7664ff8e1b0f6254b57bb78103158d825654b322_sharingd_target: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ezhes/bxdiff50/ec19e047fddc0cf286cd613a0f7896e2429bc022/sharingd_test/7664ff8e1b0f6254b57bb78103158d825654b322_sharingd_target -------------------------------------------------------------------------------- /sharingd_test/ef28d87c911f1ab1b1bc68b436346a7eb91d8d6e_sharingd_source: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ezhes/bxdiff50/ec19e047fddc0cf286cd613a0f7896e2429bc022/sharingd_test/ef28d87c911f1ab1b1bc68b436346a7eb91d8d6e_sharingd_source -------------------------------------------------------------------------------- /sharingd_test/patch: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ezhes/bxdiff50/ec19e047fddc0cf286cd613a0f7896e2429bc022/sharingd_test/patch --------------------------------------------------------------------------------