├── .github └── workflows │ └── run_tests.yml ├── .gitignore ├── BH2012_MobileCertificatePinning.pdf ├── LICENSE ├── Makefile ├── README.md ├── SSLKillSwitch.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ └── contents.xcworkspacedata └── xcshareddata │ └── xcschemes │ └── SSLKillSwitch.xcscheme ├── SSLKillSwitch ├── Info.plist ├── SSLKillSwitch.h ├── SSLKillSwitch.m └── fishhook │ ├── LICENSE │ ├── README.md │ ├── fishhook.c │ └── fishhook.h ├── SSLKillSwitch2.plist ├── SSLKillSwitchTests ├── Info.plist └── SSLKillSwitchTests.m ├── charles.png └── layout ├── DEBIAN └── control └── Library └── PreferenceLoader └── Preferences ├── SSLKillSwitch.png └── SSLKillSwitch_prefs.plist /.github/workflows/run_tests.yml: -------------------------------------------------------------------------------- 1 | name: Run Tests 2 | 3 | 4 | on: [push, pull_request] 5 | 6 | jobs: 7 | build: 8 | runs-on: macOS-10.15 9 | 10 | steps: 11 | - uses: actions/checkout@v2 12 | 13 | - name: Build and test 14 | run: xcodebuild -project SSLKillSwitch.xcodeproj -scheme SSLKillSwitch build test 15 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | build/ 4 | *.pbxuser 5 | !default.pbxuser 6 | *.mode1v3 7 | !default.mode1v3 8 | *.mode2v3 9 | !default.mode2v3 10 | *.perspectivev3 11 | !default.perspectivev3 12 | xcuserdata 13 | *.xccheckout 14 | *.moved-aside 15 | DerivedData 16 | *.hmap 17 | *.ipa 18 | *.xcuserstate 19 | 20 | # CocoaPods 21 | # 22 | # We recommend against adding the Pods directory to your .gitignore. However 23 | # you should judge for yourself, the pros and cons are mentioned at: 24 | # http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control 25 | # 26 | # Pods/ 27 | 28 | # Appledoc 29 | html/ 30 | 31 | # Facebook Infer 32 | infer-out/ 33 | 34 | # Theos builds 35 | /theos 36 | /obj 37 | /_ 38 | *.deb 39 | .theos 40 | 41 | -------------------------------------------------------------------------------- /BH2012_MobileCertificatePinning.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nabla-c0d3/ssl-kill-switch2/4e69eb4d009b9d4b75c42ba030bbe973b5327a4f/BH2012_MobileCertificatePinning.pdf -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | This is the MIT license: http://www.opensource.org/licenses/mit-license.php 2 | 3 | Copyright 2015 Alban Diquet and contributors 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this 6 | software and associated documentation files (the "Software"), to deal in the Software 7 | without restriction, including without limitation the rights to use, copy, modify, merge, 8 | publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons 9 | to whom the Software is furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all copies or 12 | substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 15 | INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 16 | PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE 17 | FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 18 | OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 19 | DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | ARCHS := arm64 arm64e 2 | 3 | include theos/makefiles/common.mk 4 | 5 | TWEAK_NAME = SSLKillSwitch2 6 | SSLKillSwitch2_FILES = SSLKillSwitch/SSLKillSwitch.m 7 | 8 | SSLKillSwitch2_FRAMEWORKS = Security 9 | 10 | # Build as a Substrate Tweak 11 | SSLKillSwitch2_CFLAGS=-DSUBSTRATE_BUILD 12 | 13 | include $(THEOS_MAKE_PATH)/tweak.mk 14 | include $(THEOS_MAKE_PATH)/aggregate.mk 15 | 16 | 17 | after-install:: 18 | # Respring the device 19 | install.exec "killall -9 SpringBoard" 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | SSL Kill Switch 2 2 | ================= 3 | 4 | Blackbox tool to disable SSL/TLS certificate validation - including certificate 5 | pinning - within iOS and macOS applications. Second iteration of 6 | https://github.com/iSECPartners/ios-ssl-kill-switch . 7 | 8 | Description 9 | ----------- 10 | 11 | Once loaded into an iOS or macOS application, SSL Kill Switch 2 will patch 12 | low-level functions responsible for handling SSL/TLS connections in order to 13 | override and disable the system's default certificate validation, as well as any 14 | kind of custom certificate validation (such as certificate pinning). 15 | 16 | It was successfully tested against various applications implementing certificate 17 | pinning including the Apple App Store. The first version of SSL Kill Switch 18 | was released at Black Hat Vegas 2012. 19 | 20 | The most recent version iOS that is known to be supported is 14.2. 21 | 22 | iOS Instructions 23 | ---------------- 24 | 25 | On iOS, SSL Kill Switch 2 can be installed as a Cydia Subtrate tweak on a 26 | jailbroken device. 27 | 28 | ### WARNING: THIS TWEAK WILL MAKE YOUR DEVICE INSECURE 29 | 30 | Installing SSL Kill Switch 2 allows anyone on the same network as the device to 31 | easily perform man-in-the-middle attacks against *any* SSL or HTTPS connection. 32 | This means that it is trivial to get access to emails, websites viewed in Safari 33 | and any other data downloaded by any App running on the device. 34 | 35 | ### Installation 36 | 37 | The following dependencies should be installed using Cydia: 38 | 39 | * Debian Packager 40 | * Cydia Substrate 41 | * PreferenceLoader 42 | 43 | Then, download the latest pre-compiled package available in the release tab of 44 | the SSL Kill Switch 2's GitHub page. Copy it to the device, install it and 45 | respring the device: 46 | 47 | dpkg -i .deb 48 | killall -HUP SpringBoard 49 | 50 | There should be a new menu in the device's Settings where you can 51 | enable the extension. Finally, kill and restart the App you want to test. 52 | 53 | The tweak can later be uninstalled using: 54 | 55 | dpkg -r com.nablac0d3.SSLKillSwitch2 56 | 57 | ### Intercepting the App Store's traffic 58 | 59 | Lots of people have asked about how to intercept the App Store's traffic using 60 | SSL Kill Switch 2. I wrote down some instructions here but there are now outdated: 61 | http://nabla-c0d3.github.io/blog/2013/08/20/intercepting-the-app-stores-traffic-on-ios/ 62 | 63 | ### Intercepting with Charles Proxy 64 | 65 | By default, SSL Kill Switch will disrupt the Charles Proxy iOS app and you will not be 66 | able to proxy any network traffic with it. To fix this, add the Charles Proxy app 67 | (com.xk72.Charles) to the list of excluded bundle IDs in the SSL Kill Switch config: 68 | 69 | ![Charles proxy](charles.png) 70 | 71 | ### Build 72 | 73 | The build requires the Theos suite to be installed available at 74 | http://www.iphonedevwiki.net/index.php/Theos/Getting_Started . 75 | 76 | Then, within SSL Kill Switch 2's root foler, create a symlink to your theos 77 | installation: 78 | 79 | ln -s / theos 80 | 81 | Make sure dpkg is installed. If you have Homebrew, use: 82 | 83 | brew install dpkg 84 | 85 | Then, the SSL Kill Switch 2 Debian package can be built using: 86 | 87 | make package 88 | 89 | macOS Instructions 90 | ----------------- 91 | 92 | SSL Kill Switch 2 can be used in macOS applications as a dynamic library to be injected into 93 | processes. 94 | 95 | ### WARNING: THIS HAS NOT BEEN TESTED ON RECENT VERSIONS OF MACOS 96 | 97 | ### Usage 98 | 99 | On macOS, the SSLKillSwitch library needs to be manually injected into the process where 100 | SSL pinning needs to be disabled. Once injected, it will automatically override and disable 101 | SSL validation. 102 | 103 | There are several ways to do this including: 104 | 105 | * Starting the process with LLDB or in Xcode Debug->Attach to process then pause, and load SSLKillSwitch using `dlopen()`: 106 | 107 | (lldb) expr (void*)dlopen("/path/to/build/SSLKillSwitch.framework/Versions/A/SSLKillSwitch", 1) 108 | 109 | Expected result is a non-zero pointer: 110 | 111 | (void *) $1 = 0x00007f92e74d10c0 112 | 113 | If you receive a zero pointer then you may need to enable code-signing and build for profiling then use the binary in the release folder, and even may have to copy the binary to the app's resources folder. In which case you would have seen a sandbox read violation output to console. To test a new version of the binary you need to kill the app and load it in again. 114 | 115 | * Using DYLD\_INSERT\_LIBRARIES to inject SSLKillSwitch and start the process. 116 | 117 | ### Restricted Apps 118 | 119 | TBD 120 | 121 | ### Build 122 | 123 | Use the Xcode project to build SSL Kill Switch 2 for macOS. The compiled library will then be 124 | available in _Products/SSLKillSwitch.framework/Versions/A/SSLKillSwitch_. This is the binary 125 | that you need to inject in the process where you want to disable SSL pinning. 126 | 127 | Changelog 128 | --------- 129 | 130 | * v0.14: Added support for iOS 13. 131 | * v0.13: Added support for iOS 12. 132 | * v0.12: Added support for iOS 11. 133 | * v0.11: Added support for iOS 10. 134 | * v0.10: Added support for proxy-ing [CocoaSPDY](https://github.com/twitter/CocoaSPDY) Apps (ie. Twitter iOS). 135 | * v0.9: Extended the MobileLoader filter to simplify the proxy-ing of the Apple App Store application. 136 | * V0.8: Added support for iOS 9. 137 | * v0.7: Renamed tool to SSL Kill Switch 2; added support for macOS applications and TrustKit. 138 | * v0.6: Added support for iOS 7. 139 | * v0.5: Complete rewrite in order to add support for proxy-ing Apple's App Store application. 140 | * v0.4: Added hooks for SecTrustEvaluate(). 141 | * v0.3: Bug fixes and support for iOS 6. 142 | * v0.2: Initial release. 143 | 144 | License 145 | ------- 146 | 147 | MIT - See ./LICENSE. 148 | 149 | Author 150 | ------ 151 | 152 | Alban Diquet - @nabla_c0d3 153 | -------------------------------------------------------------------------------- /SSLKillSwitch.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 8C2312151B50DB7B0057C459 /* SSLKillSwitch.h in Headers */ = {isa = PBXBuildFile; fileRef = 8C2312141B50DB7B0057C459 /* SSLKillSwitch.h */; settings = {ATTRIBUTES = (Public, ); }; }; 11 | 8C23121B1B50DB7B0057C459 /* SSLKillSwitch.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8C23120F1B50DB7B0057C459 /* SSLKillSwitch.framework */; }; 12 | 8C2312221B50DB7B0057C459 /* SSLKillSwitchTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 8C2312211B50DB7B0057C459 /* SSLKillSwitchTests.m */; }; 13 | 8C23122C1B50DC670057C459 /* SSLKillSwitch.m in Sources */ = {isa = PBXBuildFile; fileRef = 8C23122B1B50DC670057C459 /* SSLKillSwitch.m */; }; 14 | 8C2312341B50EB030057C459 /* fishhook.c in Sources */ = {isa = PBXBuildFile; fileRef = 8C2312321B50EB030057C459 /* fishhook.c */; }; 15 | 8C2312351B50EB030057C459 /* fishhook.h in Headers */ = {isa = PBXBuildFile; fileRef = 8C2312331B50EB030057C459 /* fishhook.h */; }; 16 | /* End PBXBuildFile section */ 17 | 18 | /* Begin PBXContainerItemProxy section */ 19 | 8C23121C1B50DB7B0057C459 /* PBXContainerItemProxy */ = { 20 | isa = PBXContainerItemProxy; 21 | containerPortal = 8C2312061B50DB7A0057C459 /* Project object */; 22 | proxyType = 1; 23 | remoteGlobalIDString = 8C23120E1B50DB7B0057C459; 24 | remoteInfo = SSLKillSwitch; 25 | }; 26 | /* End PBXContainerItemProxy section */ 27 | 28 | /* Begin PBXFileReference section */ 29 | 8C23120F1B50DB7B0057C459 /* SSLKillSwitch.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SSLKillSwitch.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 30 | 8C2312131B50DB7B0057C459 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 31 | 8C2312141B50DB7B0057C459 /* SSLKillSwitch.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SSLKillSwitch.h; sourceTree = ""; }; 32 | 8C23121A1B50DB7B0057C459 /* SSLKillSwitchTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SSLKillSwitchTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 33 | 8C2312201B50DB7B0057C459 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 34 | 8C2312211B50DB7B0057C459 /* SSLKillSwitchTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SSLKillSwitchTests.m; sourceTree = ""; }; 35 | 8C23122B1B50DC670057C459 /* SSLKillSwitch.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SSLKillSwitch.m; sourceTree = ""; }; 36 | 8C2312321B50EB030057C459 /* fishhook.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = fishhook.c; path = fishhook/fishhook.c; sourceTree = ""; }; 37 | 8C2312331B50EB030057C459 /* fishhook.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = fishhook.h; path = fishhook/fishhook.h; sourceTree = ""; }; 38 | /* End PBXFileReference section */ 39 | 40 | /* Begin PBXFrameworksBuildPhase section */ 41 | 8C23120B1B50DB7B0057C459 /* Frameworks */ = { 42 | isa = PBXFrameworksBuildPhase; 43 | buildActionMask = 2147483647; 44 | files = ( 45 | ); 46 | runOnlyForDeploymentPostprocessing = 0; 47 | }; 48 | 8C2312171B50DB7B0057C459 /* Frameworks */ = { 49 | isa = PBXFrameworksBuildPhase; 50 | buildActionMask = 2147483647; 51 | files = ( 52 | 8C23121B1B50DB7B0057C459 /* SSLKillSwitch.framework in Frameworks */, 53 | ); 54 | runOnlyForDeploymentPostprocessing = 0; 55 | }; 56 | /* End PBXFrameworksBuildPhase section */ 57 | 58 | /* Begin PBXGroup section */ 59 | 8C2312051B50DB7A0057C459 = { 60 | isa = PBXGroup; 61 | children = ( 62 | 8C2312111B50DB7B0057C459 /* SSLKillSwitch */, 63 | 8C23121E1B50DB7B0057C459 /* SSLKillSwitchTests */, 64 | 8C2312101B50DB7B0057C459 /* Products */, 65 | ); 66 | sourceTree = ""; 67 | }; 68 | 8C2312101B50DB7B0057C459 /* Products */ = { 69 | isa = PBXGroup; 70 | children = ( 71 | 8C23120F1B50DB7B0057C459 /* SSLKillSwitch.framework */, 72 | 8C23121A1B50DB7B0057C459 /* SSLKillSwitchTests.xctest */, 73 | ); 74 | name = Products; 75 | sourceTree = ""; 76 | }; 77 | 8C2312111B50DB7B0057C459 /* SSLKillSwitch */ = { 78 | isa = PBXGroup; 79 | children = ( 80 | 8C2312311B50EAEE0057C459 /* fishhook */, 81 | 8C2312141B50DB7B0057C459 /* SSLKillSwitch.h */, 82 | 8C2312121B50DB7B0057C459 /* Supporting Files */, 83 | 8C23122B1B50DC670057C459 /* SSLKillSwitch.m */, 84 | ); 85 | path = SSLKillSwitch; 86 | sourceTree = ""; 87 | }; 88 | 8C2312121B50DB7B0057C459 /* Supporting Files */ = { 89 | isa = PBXGroup; 90 | children = ( 91 | 8C2312131B50DB7B0057C459 /* Info.plist */, 92 | ); 93 | name = "Supporting Files"; 94 | sourceTree = ""; 95 | }; 96 | 8C23121E1B50DB7B0057C459 /* SSLKillSwitchTests */ = { 97 | isa = PBXGroup; 98 | children = ( 99 | 8C2312211B50DB7B0057C459 /* SSLKillSwitchTests.m */, 100 | 8C23121F1B50DB7B0057C459 /* Supporting Files */, 101 | ); 102 | path = SSLKillSwitchTests; 103 | sourceTree = ""; 104 | }; 105 | 8C23121F1B50DB7B0057C459 /* Supporting Files */ = { 106 | isa = PBXGroup; 107 | children = ( 108 | 8C2312201B50DB7B0057C459 /* Info.plist */, 109 | ); 110 | name = "Supporting Files"; 111 | sourceTree = ""; 112 | }; 113 | 8C2312311B50EAEE0057C459 /* fishhook */ = { 114 | isa = PBXGroup; 115 | children = ( 116 | 8C2312321B50EB030057C459 /* fishhook.c */, 117 | 8C2312331B50EB030057C459 /* fishhook.h */, 118 | ); 119 | name = fishhook; 120 | sourceTree = ""; 121 | }; 122 | /* End PBXGroup section */ 123 | 124 | /* Begin PBXHeadersBuildPhase section */ 125 | 8C23120C1B50DB7B0057C459 /* Headers */ = { 126 | isa = PBXHeadersBuildPhase; 127 | buildActionMask = 2147483647; 128 | files = ( 129 | 8C2312151B50DB7B0057C459 /* SSLKillSwitch.h in Headers */, 130 | 8C2312351B50EB030057C459 /* fishhook.h in Headers */, 131 | ); 132 | runOnlyForDeploymentPostprocessing = 0; 133 | }; 134 | /* End PBXHeadersBuildPhase section */ 135 | 136 | /* Begin PBXNativeTarget section */ 137 | 8C23120E1B50DB7B0057C459 /* SSLKillSwitch */ = { 138 | isa = PBXNativeTarget; 139 | buildConfigurationList = 8C2312251B50DB7B0057C459 /* Build configuration list for PBXNativeTarget "SSLKillSwitch" */; 140 | buildPhases = ( 141 | 8C23120A1B50DB7B0057C459 /* Sources */, 142 | 8C23120B1B50DB7B0057C459 /* Frameworks */, 143 | 8C23120C1B50DB7B0057C459 /* Headers */, 144 | 8C23120D1B50DB7B0057C459 /* Resources */, 145 | ); 146 | buildRules = ( 147 | ); 148 | dependencies = ( 149 | ); 150 | name = SSLKillSwitch; 151 | productName = SSLKillSwitch; 152 | productReference = 8C23120F1B50DB7B0057C459 /* SSLKillSwitch.framework */; 153 | productType = "com.apple.product-type.framework"; 154 | }; 155 | 8C2312191B50DB7B0057C459 /* SSLKillSwitchTests */ = { 156 | isa = PBXNativeTarget; 157 | buildConfigurationList = 8C2312281B50DB7B0057C459 /* Build configuration list for PBXNativeTarget "SSLKillSwitchTests" */; 158 | buildPhases = ( 159 | 8C2312161B50DB7B0057C459 /* Sources */, 160 | 8C2312171B50DB7B0057C459 /* Frameworks */, 161 | 8C2312181B50DB7B0057C459 /* Resources */, 162 | ); 163 | buildRules = ( 164 | ); 165 | dependencies = ( 166 | 8C23121D1B50DB7B0057C459 /* PBXTargetDependency */, 167 | ); 168 | name = SSLKillSwitchTests; 169 | productName = SSLKillSwitchTests; 170 | productReference = 8C23121A1B50DB7B0057C459 /* SSLKillSwitchTests.xctest */; 171 | productType = "com.apple.product-type.bundle.unit-test"; 172 | }; 173 | /* End PBXNativeTarget section */ 174 | 175 | /* Begin PBXProject section */ 176 | 8C2312061B50DB7A0057C459 /* Project object */ = { 177 | isa = PBXProject; 178 | attributes = { 179 | LastUpgradeCheck = 1120; 180 | ORGANIZATIONNAME = nablac0d3; 181 | TargetAttributes = { 182 | 8C23120E1B50DB7B0057C459 = { 183 | CreatedOnToolsVersion = 6.4; 184 | }; 185 | 8C2312191B50DB7B0057C459 = { 186 | CreatedOnToolsVersion = 6.4; 187 | }; 188 | }; 189 | }; 190 | buildConfigurationList = 8C2312091B50DB7A0057C459 /* Build configuration list for PBXProject "SSLKillSwitch" */; 191 | compatibilityVersion = "Xcode 3.2"; 192 | developmentRegion = en; 193 | hasScannedForEncodings = 0; 194 | knownRegions = ( 195 | en, 196 | Base, 197 | ); 198 | mainGroup = 8C2312051B50DB7A0057C459; 199 | productRefGroup = 8C2312101B50DB7B0057C459 /* Products */; 200 | projectDirPath = ""; 201 | projectRoot = ""; 202 | targets = ( 203 | 8C23120E1B50DB7B0057C459 /* SSLKillSwitch */, 204 | 8C2312191B50DB7B0057C459 /* SSLKillSwitchTests */, 205 | ); 206 | }; 207 | /* End PBXProject section */ 208 | 209 | /* Begin PBXResourcesBuildPhase section */ 210 | 8C23120D1B50DB7B0057C459 /* Resources */ = { 211 | isa = PBXResourcesBuildPhase; 212 | buildActionMask = 2147483647; 213 | files = ( 214 | ); 215 | runOnlyForDeploymentPostprocessing = 0; 216 | }; 217 | 8C2312181B50DB7B0057C459 /* Resources */ = { 218 | isa = PBXResourcesBuildPhase; 219 | buildActionMask = 2147483647; 220 | files = ( 221 | ); 222 | runOnlyForDeploymentPostprocessing = 0; 223 | }; 224 | /* End PBXResourcesBuildPhase section */ 225 | 226 | /* Begin PBXSourcesBuildPhase section */ 227 | 8C23120A1B50DB7B0057C459 /* Sources */ = { 228 | isa = PBXSourcesBuildPhase; 229 | buildActionMask = 2147483647; 230 | files = ( 231 | 8C2312341B50EB030057C459 /* fishhook.c in Sources */, 232 | 8C23122C1B50DC670057C459 /* SSLKillSwitch.m in Sources */, 233 | ); 234 | runOnlyForDeploymentPostprocessing = 0; 235 | }; 236 | 8C2312161B50DB7B0057C459 /* Sources */ = { 237 | isa = PBXSourcesBuildPhase; 238 | buildActionMask = 2147483647; 239 | files = ( 240 | 8C2312221B50DB7B0057C459 /* SSLKillSwitchTests.m in Sources */, 241 | ); 242 | runOnlyForDeploymentPostprocessing = 0; 243 | }; 244 | /* End PBXSourcesBuildPhase section */ 245 | 246 | /* Begin PBXTargetDependency section */ 247 | 8C23121D1B50DB7B0057C459 /* PBXTargetDependency */ = { 248 | isa = PBXTargetDependency; 249 | target = 8C23120E1B50DB7B0057C459 /* SSLKillSwitch */; 250 | targetProxy = 8C23121C1B50DB7B0057C459 /* PBXContainerItemProxy */; 251 | }; 252 | /* End PBXTargetDependency section */ 253 | 254 | /* Begin XCBuildConfiguration section */ 255 | 8C2312231B50DB7B0057C459 /* Debug */ = { 256 | isa = XCBuildConfiguration; 257 | buildSettings = { 258 | ALWAYS_SEARCH_USER_PATHS = NO; 259 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; 260 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 261 | CLANG_CXX_LIBRARY = "libc++"; 262 | CLANG_ENABLE_MODULES = YES; 263 | CLANG_ENABLE_OBJC_ARC = YES; 264 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 265 | CLANG_WARN_BOOL_CONVERSION = YES; 266 | CLANG_WARN_COMMA = YES; 267 | CLANG_WARN_CONSTANT_CONVERSION = YES; 268 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 269 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 270 | CLANG_WARN_EMPTY_BODY = YES; 271 | CLANG_WARN_ENUM_CONVERSION = YES; 272 | CLANG_WARN_INFINITE_RECURSION = YES; 273 | CLANG_WARN_INT_CONVERSION = YES; 274 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 275 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 276 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 277 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 278 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 279 | CLANG_WARN_STRICT_PROTOTYPES = YES; 280 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 281 | CLANG_WARN_UNREACHABLE_CODE = YES; 282 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 283 | COPY_PHASE_STRIP = NO; 284 | CURRENT_PROJECT_VERSION = 1; 285 | DEBUG_INFORMATION_FORMAT = dwarf; 286 | ENABLE_STRICT_OBJC_MSGSEND = YES; 287 | ENABLE_TESTABILITY = YES; 288 | GCC_C_LANGUAGE_STANDARD = gnu99; 289 | GCC_DYNAMIC_NO_PIC = NO; 290 | GCC_NO_COMMON_BLOCKS = YES; 291 | GCC_OPTIMIZATION_LEVEL = 0; 292 | GCC_PREPROCESSOR_DEFINITIONS = ( 293 | "DEBUG=1", 294 | "$(inherited)", 295 | ); 296 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 297 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 298 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 299 | GCC_WARN_UNDECLARED_SELECTOR = YES; 300 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 301 | GCC_WARN_UNUSED_FUNCTION = YES; 302 | GCC_WARN_UNUSED_VARIABLE = YES; 303 | MACOSX_DEPLOYMENT_TARGET = 10.10; 304 | MTL_ENABLE_DEBUG_INFO = YES; 305 | ONLY_ACTIVE_ARCH = YES; 306 | SDKROOT = macosx; 307 | VERSIONING_SYSTEM = "apple-generic"; 308 | VERSION_INFO_PREFIX = ""; 309 | }; 310 | name = Debug; 311 | }; 312 | 8C2312241B50DB7B0057C459 /* Release */ = { 313 | isa = XCBuildConfiguration; 314 | buildSettings = { 315 | ALWAYS_SEARCH_USER_PATHS = NO; 316 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; 317 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 318 | CLANG_CXX_LIBRARY = "libc++"; 319 | CLANG_ENABLE_MODULES = YES; 320 | CLANG_ENABLE_OBJC_ARC = YES; 321 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 322 | CLANG_WARN_BOOL_CONVERSION = YES; 323 | CLANG_WARN_COMMA = YES; 324 | CLANG_WARN_CONSTANT_CONVERSION = YES; 325 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 326 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 327 | CLANG_WARN_EMPTY_BODY = YES; 328 | CLANG_WARN_ENUM_CONVERSION = YES; 329 | CLANG_WARN_INFINITE_RECURSION = YES; 330 | CLANG_WARN_INT_CONVERSION = YES; 331 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 332 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 333 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 334 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 335 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 336 | CLANG_WARN_STRICT_PROTOTYPES = YES; 337 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 338 | CLANG_WARN_UNREACHABLE_CODE = YES; 339 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 340 | COPY_PHASE_STRIP = NO; 341 | CURRENT_PROJECT_VERSION = 1; 342 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 343 | ENABLE_NS_ASSERTIONS = NO; 344 | ENABLE_STRICT_OBJC_MSGSEND = YES; 345 | GCC_C_LANGUAGE_STANDARD = gnu99; 346 | GCC_NO_COMMON_BLOCKS = YES; 347 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 348 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 349 | GCC_WARN_UNDECLARED_SELECTOR = YES; 350 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 351 | GCC_WARN_UNUSED_FUNCTION = YES; 352 | GCC_WARN_UNUSED_VARIABLE = YES; 353 | MACOSX_DEPLOYMENT_TARGET = 10.10; 354 | MTL_ENABLE_DEBUG_INFO = NO; 355 | SDKROOT = macosx; 356 | VERSIONING_SYSTEM = "apple-generic"; 357 | VERSION_INFO_PREFIX = ""; 358 | }; 359 | name = Release; 360 | }; 361 | 8C2312261B50DB7B0057C459 /* Debug */ = { 362 | isa = XCBuildConfiguration; 363 | buildSettings = { 364 | COMBINE_HIDPI_IMAGES = YES; 365 | DEFINES_MODULE = YES; 366 | DYLIB_COMPATIBILITY_VERSION = 1; 367 | DYLIB_CURRENT_VERSION = 1; 368 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 369 | FRAMEWORK_VERSION = A; 370 | INFOPLIST_FILE = SSLKillSwitch/Info.plist; 371 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 372 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; 373 | PRODUCT_BUNDLE_IDENTIFIER = "com.nablac0d3.$(PRODUCT_NAME:rfc1034identifier)"; 374 | PRODUCT_NAME = "$(TARGET_NAME)"; 375 | SKIP_INSTALL = YES; 376 | }; 377 | name = Debug; 378 | }; 379 | 8C2312271B50DB7B0057C459 /* Release */ = { 380 | isa = XCBuildConfiguration; 381 | buildSettings = { 382 | COMBINE_HIDPI_IMAGES = YES; 383 | DEFINES_MODULE = YES; 384 | DYLIB_COMPATIBILITY_VERSION = 1; 385 | DYLIB_CURRENT_VERSION = 1; 386 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 387 | FRAMEWORK_VERSION = A; 388 | INFOPLIST_FILE = SSLKillSwitch/Info.plist; 389 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 390 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; 391 | PRODUCT_BUNDLE_IDENTIFIER = "com.nablac0d3.$(PRODUCT_NAME:rfc1034identifier)"; 392 | PRODUCT_NAME = "$(TARGET_NAME)"; 393 | SKIP_INSTALL = YES; 394 | }; 395 | name = Release; 396 | }; 397 | 8C2312291B50DB7B0057C459 /* Debug */ = { 398 | isa = XCBuildConfiguration; 399 | buildSettings = { 400 | COMBINE_HIDPI_IMAGES = YES; 401 | FRAMEWORK_SEARCH_PATHS = ( 402 | "$(DEVELOPER_FRAMEWORKS_DIR)", 403 | "$(inherited)", 404 | ); 405 | GCC_PREPROCESSOR_DEFINITIONS = ( 406 | "DEBUG=1", 407 | "$(inherited)", 408 | ); 409 | INFOPLIST_FILE = SSLKillSwitchTests/Info.plist; 410 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; 411 | PRODUCT_BUNDLE_IDENTIFIER = "com.nablac0d3.$(PRODUCT_NAME:rfc1034identifier)"; 412 | PRODUCT_NAME = "$(TARGET_NAME)"; 413 | }; 414 | name = Debug; 415 | }; 416 | 8C23122A1B50DB7B0057C459 /* Release */ = { 417 | isa = XCBuildConfiguration; 418 | buildSettings = { 419 | COMBINE_HIDPI_IMAGES = YES; 420 | FRAMEWORK_SEARCH_PATHS = ( 421 | "$(DEVELOPER_FRAMEWORKS_DIR)", 422 | "$(inherited)", 423 | ); 424 | INFOPLIST_FILE = SSLKillSwitchTests/Info.plist; 425 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; 426 | PRODUCT_BUNDLE_IDENTIFIER = "com.nablac0d3.$(PRODUCT_NAME:rfc1034identifier)"; 427 | PRODUCT_NAME = "$(TARGET_NAME)"; 428 | }; 429 | name = Release; 430 | }; 431 | /* End XCBuildConfiguration section */ 432 | 433 | /* Begin XCConfigurationList section */ 434 | 8C2312091B50DB7A0057C459 /* Build configuration list for PBXProject "SSLKillSwitch" */ = { 435 | isa = XCConfigurationList; 436 | buildConfigurations = ( 437 | 8C2312231B50DB7B0057C459 /* Debug */, 438 | 8C2312241B50DB7B0057C459 /* Release */, 439 | ); 440 | defaultConfigurationIsVisible = 0; 441 | defaultConfigurationName = Release; 442 | }; 443 | 8C2312251B50DB7B0057C459 /* Build configuration list for PBXNativeTarget "SSLKillSwitch" */ = { 444 | isa = XCConfigurationList; 445 | buildConfigurations = ( 446 | 8C2312261B50DB7B0057C459 /* Debug */, 447 | 8C2312271B50DB7B0057C459 /* Release */, 448 | ); 449 | defaultConfigurationIsVisible = 0; 450 | defaultConfigurationName = Release; 451 | }; 452 | 8C2312281B50DB7B0057C459 /* Build configuration list for PBXNativeTarget "SSLKillSwitchTests" */ = { 453 | isa = XCConfigurationList; 454 | buildConfigurations = ( 455 | 8C2312291B50DB7B0057C459 /* Debug */, 456 | 8C23122A1B50DB7B0057C459 /* Release */, 457 | ); 458 | defaultConfigurationIsVisible = 0; 459 | defaultConfigurationName = Release; 460 | }; 461 | /* End XCConfigurationList section */ 462 | }; 463 | rootObject = 8C2312061B50DB7A0057C459 /* Project object */; 464 | } 465 | -------------------------------------------------------------------------------- /SSLKillSwitch.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /SSLKillSwitch.xcodeproj/xcshareddata/xcschemes/SSLKillSwitch.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 29 | 35 | 36 | 37 | 38 | 39 | 44 | 45 | 51 | 52 | 53 | 54 | 56 | 62 | 63 | 64 | 65 | 66 | 76 | 77 | 83 | 84 | 85 | 86 | 92 | 93 | 99 | 100 | 101 | 102 | 104 | 105 | 108 | 109 | 110 | -------------------------------------------------------------------------------- /SSLKillSwitch/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(CURRENT_PROJECT_VERSION) 23 | NSHumanReadableCopyright 24 | Copyright © 2015 nablac0d3. All rights reserved. 25 | NSPrincipalClass 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /SSLKillSwitch/SSLKillSwitch.h: -------------------------------------------------------------------------------- 1 | // 2 | // SSLKillSwitch.h 3 | // SSLKillSwitch 4 | // 5 | // Created by Alban Diquet on 7/10/15. 6 | // Copyright (c) 2015 Alban Diquet. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | //! Project version number for SSLKillSwitch. 12 | FOUNDATION_EXPORT double SSLKillSwitchVersionNumber; 13 | 14 | //! Project version string for SSLKillSwitch. 15 | FOUNDATION_EXPORT const unsigned char SSLKillSwitchVersionString[]; 16 | 17 | // In this header, you should import all the public headers of your framework using statements like #import 18 | 19 | 20 | -------------------------------------------------------------------------------- /SSLKillSwitch/SSLKillSwitch.m: -------------------------------------------------------------------------------- 1 | // 2 | // SSLKillSwitch.m 3 | // SSLKillSwitch 4 | // 5 | // Created by Alban Diquet on 7/10/15. 6 | // Copyright (c) 2015 Alban Diquet. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | #if SUBSTRATE_BUILD 13 | #import "substrate.h" 14 | 15 | #define PREFERENCE_FILE @"/private/var/mobile/Library/Preferences/com.nablac0d3.SSLKillSwitchSettings.plist" 16 | #define PREFERENCE_KEY @"shouldDisableCertificateValidation" 17 | 18 | #else 19 | 20 | #import "fishhook.h" 21 | #import 22 | 23 | #endif 24 | 25 | 26 | #pragma mark Utility Functions 27 | 28 | static void SSKLog(NSString *format, ...) 29 | { 30 | NSString *newFormat = [[NSString alloc] initWithFormat:@"=== SSL Kill Switch 2: %@", format]; 31 | va_list args; 32 | va_start(args, format); 33 | NSLogv(newFormat, args); 34 | va_end(args); 35 | } 36 | 37 | 38 | #if SUBSTRATE_BUILD 39 | // Utility function to read the Tweak's preferences 40 | static BOOL shouldHookFromPreference(NSString *preferenceSetting) 41 | { 42 | BOOL shouldHook = NO; 43 | NSMutableDictionary* plist = [[NSMutableDictionary alloc] initWithContentsOfFile:PREFERENCE_FILE]; 44 | 45 | if (!plist) 46 | { 47 | SSKLog(@"Preference file not found."); 48 | } 49 | else 50 | { 51 | shouldHook = [[plist objectForKey:preferenceSetting] boolValue]; 52 | SSKLog(@"Preference set to %d.", shouldHook); 53 | 54 | // Checking if BundleId has been excluded by user 55 | NSString *bundleId = [[NSBundle mainBundle] bundleIdentifier]; 56 | bundleId = [bundleId stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]; 57 | 58 | NSString *excludedBundleIdsString = [plist objectForKey:@"excludedBundleIds"]; 59 | excludedBundleIdsString = [excludedBundleIdsString stringByReplacingOccurrencesOfString:@" " withString:@""]; 60 | 61 | NSArray *excludedBundleIds = [excludedBundleIdsString componentsSeparatedByString:@","]; 62 | 63 | if ([excludedBundleIds containsObject:bundleId]) 64 | { 65 | SSKLog(@"Not hooking excluded bundle: %@", bundleId); 66 | shouldHook = NO; 67 | } 68 | } 69 | return shouldHook; 70 | } 71 | #endif 72 | 73 | 74 | #pragma mark SecureTransport hooks - iOS 9 and below 75 | // Explanation here: https://nabla-c0d3.github.io/blog/2013/08/20/ios-ssl-kill-switch-v0-dot-5-released/ 76 | 77 | static OSStatus (*original_SSLSetSessionOption)(SSLContextRef context, 78 | SSLSessionOption option, 79 | Boolean value); 80 | 81 | static OSStatus replaced_SSLSetSessionOption(SSLContextRef context, 82 | SSLSessionOption option, 83 | Boolean value) 84 | { 85 | // Remove the ability to modify the value of the kSSLSessionOptionBreakOnServerAuth option 86 | if (option == kSSLSessionOptionBreakOnServerAuth) 87 | { 88 | return noErr; 89 | } 90 | return original_SSLSetSessionOption(context, option, value); 91 | } 92 | 93 | 94 | static SSLContextRef (*original_SSLCreateContext)(CFAllocatorRef alloc, 95 | SSLProtocolSide protocolSide, 96 | SSLConnectionType connectionType); 97 | 98 | static SSLContextRef replaced_SSLCreateContext(CFAllocatorRef alloc, 99 | SSLProtocolSide protocolSide, 100 | SSLConnectionType connectionType) 101 | { 102 | SSLContextRef sslContext = original_SSLCreateContext(alloc, protocolSide, connectionType); 103 | 104 | // Immediately set the kSSLSessionOptionBreakOnServerAuth option in order to disable cert validation 105 | original_SSLSetSessionOption(sslContext, kSSLSessionOptionBreakOnServerAuth, true); 106 | return sslContext; 107 | } 108 | 109 | 110 | static OSStatus (*original_SSLHandshake)(SSLContextRef context); 111 | 112 | static OSStatus replaced_SSLHandshake(SSLContextRef context) 113 | { 114 | 115 | OSStatus result = original_SSLHandshake(context); 116 | 117 | // Hijack the flow when breaking on server authentication 118 | if (result == errSSLServerAuthCompleted) 119 | { 120 | // Do not check the cert and call SSLHandshake() again 121 | return original_SSLHandshake(context); 122 | } 123 | 124 | return result; 125 | } 126 | 127 | 128 | #pragma mark libsystem_coretls.dylib hooks - iOS 10 129 | // Explanation here: https://nabla-c0d3.github.io/blog/2017/02/05/ios10-ssl-kill-switch/ 130 | 131 | static OSStatus (*original_tls_helper_create_peer_trust)(void *hdsk, bool server, SecTrustRef *trustRef); 132 | 133 | static OSStatus replaced_tls_helper_create_peer_trust(void *hdsk, bool server, SecTrustRef *trustRef) 134 | { 135 | // Do not actually set the trustRef 136 | return errSecSuccess; 137 | } 138 | 139 | 140 | #pragma mark BoringSSL hooks - iOS 12 141 | // Explanation here: https://nabla-c0d3.github.io/blog/2019/05/18/ssl-kill-switch-for-ios12/ 142 | 143 | // Everyone's favorite OpenSSL constant 144 | #define SSL_VERIFY_NONE 0 145 | 146 | // Constant defined in BoringSSL 147 | enum ssl_verify_result_t { 148 | ssl_verify_ok = 0, 149 | ssl_verify_invalid, 150 | ssl_verify_retry, 151 | }; 152 | 153 | 154 | char *replaced_SSL_get_psk_identity(void *ssl) 155 | { 156 | return "notarealPSKidentity"; 157 | } 158 | 159 | 160 | static int custom_verify_callback_that_does_not_validate(void *ssl, uint8_t *out_alert) 161 | { 162 | // Yes this certificate is 100% valid... 163 | return ssl_verify_ok; 164 | } 165 | 166 | 167 | static void (*original_SSL_CTX_set_custom_verify)(void *ctx, int mode, int (*callback)(void *ssl, uint8_t *out_alert)); 168 | static void replaced_SSL_CTX_set_custom_verify(void *ctx, int mode, int (*callback)(void *ssl, uint8_t *out_alert)) 169 | { 170 | SSKLog(@"Entering replaced_SSL_CTX_set_custom_verify()"); 171 | original_SSL_CTX_set_custom_verify(ctx, SSL_VERIFY_NONE, custom_verify_callback_that_does_not_validate); 172 | return; 173 | } 174 | 175 | 176 | static void (*original_SSL_set_custom_verify)(void *ssl, int mode, int (*callback)(void *ssl, uint8_t *out_alert)); 177 | static void replaced_SSL_set_custom_verify(void *ssl, int mode, int (*callback)(void *ssl, uint8_t *out_alert)) 178 | { 179 | SSKLog(@"Entering replaced_SSL_set_custom_verify()"); 180 | original_SSL_set_custom_verify(ssl, SSL_VERIFY_NONE, custom_verify_callback_that_does_not_validate); 181 | return; 182 | } 183 | 184 | 185 | #pragma mark CocoaSPDY hook 186 | #if SUBSTRATE_BUILD 187 | 188 | static void (*oldSetTLSTrustEvaluator)(id self, SEL _cmd, id evaluator); 189 | 190 | static void newSetTLSTrustEvaluator(id self, SEL _cmd, id evaluator) 191 | { 192 | // Set a nil evaluator to disable SSL validation 193 | oldSetTLSTrustEvaluator(self, _cmd, nil); 194 | } 195 | 196 | static void (*oldSetprotocolClasses)(id self, SEL _cmd, NSArray *protocolClasses); 197 | 198 | static void newSetprotocolClasses(id self, SEL _cmd, NSArray *protocolClasses) 199 | { 200 | // Do not register protocol classes which is how CocoaSPDY works 201 | // This should force the App to downgrade from SPDY to HTTPS 202 | } 203 | 204 | static void (*oldRegisterOrigin)(id self, SEL _cmd, NSString *origin); 205 | 206 | static void newRegisterOrigin(id self, SEL _cmd, NSString *origin) 207 | { 208 | // Do not register protocol classes which is how CocoaSPDY works 209 | // This should force the App to downgrade from SPDY to HTTPS 210 | } 211 | #endif 212 | 213 | 214 | #pragma mark Dylib Constructor 215 | 216 | __attribute__((constructor)) static void init(int argc, const char **argv) 217 | { 218 | #if SUBSTRATE_BUILD 219 | // Substrate-based hooking; only hook if the preference file says so 220 | if (shouldHookFromPreference(PREFERENCE_KEY)) 221 | { 222 | SSKLog(@"Substrate hook enabled."); 223 | 224 | NSProcessInfo *processInfo = [NSProcessInfo processInfo]; 225 | if ([processInfo isOperatingSystemAtLeastVersion:(NSOperatingSystemVersion){12, 0, 0}]) 226 | { 227 | // Support for iOS 12 and 13 228 | void* boringssl_handle = dlopen("/usr/lib/libboringssl.dylib", RTLD_NOW); 229 | 230 | if ([processInfo isOperatingSystemAtLeastVersion:(NSOperatingSystemVersion){13, 0, 0}]) 231 | { 232 | SSKLog(@"iOS 13+ detected"); 233 | // iOS 13 uses SSL_set_custom_verify() which was recently added to BoringSSL 234 | void *SSL_set_custom_verify = dlsym(boringssl_handle, "SSL_set_custom_verify"); 235 | if (SSL_set_custom_verify) 236 | { 237 | SSKLog(@"Hooking SSL_set_custom_verify()..."); 238 | MSHookFunction((void *) SSL_set_custom_verify, (void *) replaced_SSL_set_custom_verify, (void **) &original_SSL_set_custom_verify); 239 | } 240 | } 241 | else 242 | { 243 | SSKLog(@"iOS 12 detected"); 244 | // iOS 12 uses the older SSL_CTX_set_custom_verify() 245 | void *SSL_CTX_set_custom_verify = dlsym(boringssl_handle, "SSL_CTX_set_custom_verify"); 246 | if (SSL_CTX_set_custom_verify) 247 | { 248 | SSKLog(@"Hooking SSL_CTX_set_custom_verify()..."); 249 | MSHookFunction((void *) SSL_CTX_set_custom_verify, (void *) replaced_SSL_CTX_set_custom_verify, (void **) &original_SSL_CTX_set_custom_verify); 250 | } 251 | } 252 | 253 | // Hook SSL_get_psk_identity() on both iOS 12 and 13 254 | void *SSL_get_psk_identity = dlsym(boringssl_handle, "SSL_get_psk_identity"); 255 | if (SSL_get_psk_identity) 256 | { 257 | SSKLog(@"Hooking SSL_get_psk_identity()..."); 258 | MSHookFunction((void *) SSL_get_psk_identity, (void *) replaced_SSL_get_psk_identity, (void **) NULL); 259 | } 260 | } 261 | else if ([processInfo isOperatingSystemAtLeastVersion:(NSOperatingSystemVersion){11, 0, 0}]) 262 | { 263 | // Support for iOS 11 264 | SSKLog(@"iOS 11 detected; hooking nw_tls_create_peer_trust()..."); 265 | void* handle = dlopen("/usr/lib/libnetwork.dylib", RTLD_NOW); 266 | void *nw_tls_create_peer_trust = dlsym(handle, "nw_tls_create_peer_trust"); 267 | if (nw_tls_create_peer_trust) 268 | { 269 | MSHookFunction((void *) nw_tls_create_peer_trust, (void *) replaced_tls_helper_create_peer_trust, (void **) &original_tls_helper_create_peer_trust); 270 | } 271 | } 272 | else if ([processInfo isOperatingSystemAtLeastVersion:(NSOperatingSystemVersion){10, 0, 0}]) 273 | { 274 | // Support for iOS 10 275 | SSKLog(@"iOS 10 detected; hooking tls_helper_create_peer_trust()..."); 276 | void *tls_helper_create_peer_trust = dlsym(RTLD_DEFAULT, "tls_helper_create_peer_trust"); 277 | MSHookFunction((void *) tls_helper_create_peer_trust, (void *) replaced_tls_helper_create_peer_trust, (void **) &original_tls_helper_create_peer_trust); 278 | } 279 | else if ([processInfo isOperatingSystemAtLeastVersion:(NSOperatingSystemVersion){8, 0, 0}]) 280 | { 281 | // SecureTransport hooks - works up to iOS 9 282 | SSKLog(@"iOS 8 or 9 detected; hooking SecureTransport..."); 283 | MSHookFunction((void *) SSLHandshake,(void *) replaced_SSLHandshake, (void **) &original_SSLHandshake); 284 | MSHookFunction((void *) SSLSetSessionOption,(void *) replaced_SSLSetSessionOption, (void **) &original_SSLSetSessionOption); 285 | MSHookFunction((void *) SSLCreateContext,(void *) replaced_SSLCreateContext, (void **) &original_SSLCreateContext); 286 | } 287 | 288 | // CocoaSPDY hooks - https://github.com/twitter/CocoaSPDY 289 | // TODO: Enable these hooks for the fishhook-based hooking so it works on OS X too 290 | Class spdyProtocolClass = NSClassFromString(@"SPDYProtocol"); 291 | if (spdyProtocolClass) 292 | { 293 | SSKLog(@"CocoaSPDY detected; hooking it..."); 294 | // Disable trust evaluation 295 | MSHookMessageEx(object_getClass(spdyProtocolClass), NSSelectorFromString(@"setTLSTrustEvaluator:"), (IMP) &newSetTLSTrustEvaluator, (IMP *)&oldSetTLSTrustEvaluator); 296 | 297 | // CocoaSPDY works by getting registered as a NSURLProtocol; block that so the Apps switches back to HTTP as SPDY is tricky to proxy 298 | Class spdyUrlConnectionProtocolClass = NSClassFromString(@"SPDYURLConnectionProtocol"); 299 | MSHookMessageEx(object_getClass(spdyUrlConnectionProtocolClass), NSSelectorFromString(@"registerOrigin:"), (IMP) &newRegisterOrigin, (IMP *)&oldRegisterOrigin); 300 | 301 | MSHookMessageEx(NSClassFromString(@"NSURLSessionConfiguration"), NSSelectorFromString(@"setprotocolClasses:"), (IMP) &newSetprotocolClasses, (IMP *)&oldSetprotocolClasses); 302 | } 303 | } 304 | else 305 | { 306 | SSKLog(@"Substrate hook disabled."); 307 | } 308 | 309 | #else 310 | // Fishhook-based hooking, for OS X builds; always hook 311 | SSKLog(@"Fishhook hook enabled."); 312 | original_SSLHandshake = dlsym(RTLD_DEFAULT, "SSLHandshake"); 313 | if ((rebind_symbols((struct rebinding[1]){{(char *)"SSLHandshake", (void *)replaced_SSLHandshake}}, 1) < 0)) 314 | { 315 | SSKLog(@"Hooking failed."); 316 | } 317 | 318 | original_SSLSetSessionOption = dlsym(RTLD_DEFAULT, "SSLSetSessionOption"); 319 | if ((rebind_symbols((struct rebinding[1]){{(char *)"SSLSetSessionOption", (void *)replaced_SSLSetSessionOption}}, 1) < 0)) 320 | { 321 | SSKLog(@"Hooking failed."); 322 | } 323 | 324 | original_SSLCreateContext = dlsym(RTLD_DEFAULT, "SSLCreateContext"); 325 | if ((rebind_symbols((struct rebinding[1]){{(char *)"SSLCreateContext", (void *)replaced_SSLCreateContext}}, 1) < 0)) 326 | { 327 | SSKLog(@"Hooking failed."); 328 | } 329 | 330 | original_tls_helper_create_peer_trust = dlsym(RTLD_DEFAULT, "tls_helper_create_peer_trust"); 331 | if ((rebind_symbols((struct rebinding[1]){{(char *)"tls_helper_create_peer_trust", (void *)replaced_tls_helper_create_peer_trust}}, 1) < 0)) 332 | { 333 | SSKLog(@"Hooking failed."); 334 | } 335 | #endif 336 | } 337 | -------------------------------------------------------------------------------- /SSLKillSwitch/fishhook/LICENSE: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2013, Facebook, Inc. 2 | // All rights reserved. 3 | // Redistribution and use in source and binary forms, with or without 4 | // modification, are permitted provided that the following conditions are met: 5 | // * Redistributions of source code must retain the above copyright notice, 6 | // this list of conditions and the following disclaimer. 7 | // * Redistributions in binary form must reproduce the above copyright notice, 8 | // this list of conditions and the following disclaimer in the documentation 9 | // and/or other materials provided with the distribution. 10 | // * Neither the name Facebook nor the names of its contributors may be used to 11 | // endorse or promote products derived from this software without specific 12 | // prior written permission. 13 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 14 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 16 | // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 17 | // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18 | // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 19 | // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 20 | // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 21 | // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 22 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /SSLKillSwitch/fishhook/README.md: -------------------------------------------------------------------------------- 1 | # fishhook 2 | 3 | __fishhook__ is a very simple library that enables dynamically rebinding symbols in Mach-O binaries running on iOS in the simulator and on device. This provides functionality that is similar to using [`DYLD_INTERPOSE`][interpose] on OS X. At Facebook, we've found it useful as a way to hook calls in libSystem for debugging/tracing purposes (for example, auditing for double-close issues with file descriptors). 4 | 5 | [interpose]: http://opensource.apple.com/source/dyld/dyld-210.2.3/include/mach-o/dyld-interposing.h "" 6 | 7 | ## Usage 8 | 9 | Once you add `fishhook.h`/`fishhook.c` to your project, you can rebind symbols as follows: 10 | ```Objective-C 11 | #import 12 | 13 | #import 14 | 15 | #import "AppDelegate.h" 16 | #import "fishhook.h" 17 | 18 | static int (*orig_close)(int); 19 | static int (*orig_open)(const char *, int, ...); 20 | 21 | int my_close(int fd) { 22 | printf("Calling real close(%d)\n", fd); 23 | return orig_close(fd); 24 | } 25 | 26 | int my_open(const char *path, int oflag, ...) { 27 | va_list ap = {0}; 28 | mode_t mode = 0; 29 | 30 | if ((oflag & O_CREAT) != 0) { 31 | // mode only applies to O_CREAT 32 | va_start(ap, oflag); 33 | mode = va_arg(ap, int); 34 | va_end(ap); 35 | printf("Calling real open('%s', %d, %d)\n", path, oflag, mode); 36 | return orig_open(path, oflag, mode); 37 | } else { 38 | printf("Calling real open('%s', %d)\n", path, oflag); 39 | return orig_open(path, oflag, mode); 40 | } 41 | } 42 | 43 | int main(int argc, char * argv[]) 44 | { 45 | @autoreleasepool { 46 | rebind_symbols((struct rebinding[2]){{"close", my_close, (void *)&orig_close}, {"open", my_open, (void *)&orig_open}}, 2); 47 | 48 | // Open our own binary and print out first 4 bytes (which is the same 49 | // for all Mach-O binaries on a given architecture) 50 | int fd = open(argv[0], O_RDONLY); 51 | uint32_t magic_number = 0; 52 | read(fd, &magic_number, 4); 53 | printf("Mach-O Magic Number: %x \n", magic_number); 54 | close(fd); 55 | 56 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 57 | } 58 | } 59 | ``` 60 | ### Sample output 61 | ``` 62 | Calling real open('/var/mobile/Applications/161DA598-5B83-41F5-8A44-675491AF6A2C/Test.app/Test', 0) 63 | Mach-O Magic Number: feedface 64 | Calling real close(3) 65 | ... 66 | ``` 67 | 68 | ## How it works 69 | 70 | `dyld` binds lazy and non-lazy symbols by updating pointers in particular sections of the `__DATA` segment of a Mach-O binary. __fishhook__ re-binds these symbols by determining the locations to update for each of the symbol names passed to `rebind_symbols` and then writing out the corresponding replacements. 71 | 72 | For a given image, the `__DATA` segment may contain two sections that are relevant for dynamic symbol bindings: `__nl_symbol_ptr` and `__la_symbol_ptr`. `__nl_symbol_ptr` is an array of pointers to non-lazily bound data (these are bound at the time a library is loaded) and `__la_symbol_ptr` is an array of pointers to imported functions that is generally filled by a routine called `dyld_stub_binder` during the first call to that symbol (it's also possible to tell `dyld` to bind these at launch). In order to find the name of the symbol that corresponds to a particular location in one of these sections, we have to jump through several layers of indirection. For the two relevant sections, the section headers (`struct section`s from ``) provide an offset (in the `reserved1` field) into what is known as the indirect symbol table. The indirect symbol table, which is located in the `__LINKEDIT` segment of the binary, is just an array of indexes into the symbol table (also in `__LINKEDIT`) whose order is identical to that of the pointers in the non-lazy and lazy symbol sections. So, given `struct section nl_symbol_ptr`, the corresponding index in the symbol table of the first address in that section is `indirect_symbol_table[nl_symbol_ptr->reserved1]`. The symbol table itself is an array of `struct nlist`s (see ``), and each `nlist` contains an index into the string table in `__LINKEDIT` which where the actual symbol names are stored. So, for each pointer `__nl_symbol_ptr` and `__la_symbol_ptr`, we are able to find the corresponding symbol and then the corresponding string to compare against the requested symbol names, and if there is a match, we replace the pointer in the section with the replacement. 73 | 74 | The process of looking up the name of a given entry in the lazy or non-lazy pointer tables looks like this: 75 | ![Visual explanation](http://i.imgur.com/HVXqHCz.png) -------------------------------------------------------------------------------- /SSLKillSwitch/fishhook/fishhook.c: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2013, Facebook, Inc. 2 | // All rights reserved. 3 | // Redistribution and use in source and binary forms, with or without 4 | // modification, are permitted provided that the following conditions are met: 5 | // * Redistributions of source code must retain the above copyright notice, 6 | // this list of conditions and the following disclaimer. 7 | // * Redistributions in binary form must reproduce the above copyright notice, 8 | // this list of conditions and the following disclaimer in the documentation 9 | // and/or other materials provided with the distribution. 10 | // * Neither the name Facebook nor the names of its contributors may be used to 11 | // endorse or promote products derived from this software without specific 12 | // prior written permission. 13 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 14 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 16 | // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 17 | // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18 | // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 19 | // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 20 | // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 21 | // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 22 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 | 24 | #include "fishhook.h" 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | 34 | #ifdef __LP64__ 35 | typedef struct mach_header_64 mach_header_t; 36 | typedef struct segment_command_64 segment_command_t; 37 | typedef struct section_64 section_t; 38 | typedef struct nlist_64 nlist_t; 39 | #define LC_SEGMENT_ARCH_DEPENDENT LC_SEGMENT_64 40 | #else 41 | typedef struct mach_header mach_header_t; 42 | typedef struct segment_command segment_command_t; 43 | typedef struct section section_t; 44 | typedef struct nlist nlist_t; 45 | #define LC_SEGMENT_ARCH_DEPENDENT LC_SEGMENT 46 | #endif 47 | 48 | #ifndef SEG_DATA_CONST 49 | #define SEG_DATA_CONST "__DATA_CONST" 50 | #endif 51 | 52 | struct rebindings_entry { 53 | struct rebinding *rebindings; 54 | size_t rebindings_nel; 55 | struct rebindings_entry *next; 56 | }; 57 | 58 | static struct rebindings_entry *_rebindings_head; 59 | 60 | static int prepend_rebindings(struct rebindings_entry **rebindings_head, 61 | struct rebinding rebindings[], 62 | size_t nel) { 63 | struct rebindings_entry *new_entry = (struct rebindings_entry *) malloc(sizeof(struct rebindings_entry)); 64 | if (!new_entry) { 65 | return -1; 66 | } 67 | new_entry->rebindings = (struct rebinding *) malloc(sizeof(struct rebinding) * nel); 68 | if (!new_entry->rebindings) { 69 | free(new_entry); 70 | return -1; 71 | } 72 | memcpy(new_entry->rebindings, rebindings, sizeof(struct rebinding) * nel); 73 | new_entry->rebindings_nel = nel; 74 | new_entry->next = *rebindings_head; 75 | *rebindings_head = new_entry; 76 | return 0; 77 | } 78 | 79 | static void perform_rebinding_with_section(struct rebindings_entry *rebindings, 80 | section_t *section, 81 | intptr_t slide, 82 | nlist_t *symtab, 83 | char *strtab, 84 | uint32_t *indirect_symtab) { 85 | uint32_t *indirect_symbol_indices = indirect_symtab + section->reserved1; 86 | void **indirect_symbol_bindings = (void **)((uintptr_t)slide + section->addr); 87 | for (uint i = 0; i < section->size / sizeof(void *); i++) { 88 | uint32_t symtab_index = indirect_symbol_indices[i]; 89 | if (symtab_index == INDIRECT_SYMBOL_ABS || symtab_index == INDIRECT_SYMBOL_LOCAL || 90 | symtab_index == (INDIRECT_SYMBOL_LOCAL | INDIRECT_SYMBOL_ABS)) { 91 | continue; 92 | } 93 | uint32_t strtab_offset = symtab[symtab_index].n_un.n_strx; 94 | char *symbol_name = strtab + strtab_offset; 95 | bool symbol_name_longer_than_1 = symbol_name[0] && symbol_name[1]; 96 | struct rebindings_entry *cur = rebindings; 97 | while (cur) { 98 | for (uint j = 0; j < cur->rebindings_nel; j++) { 99 | if (symbol_name_longer_than_1 && 100 | strcmp(&symbol_name[1], cur->rebindings[j].name) == 0) { 101 | if (cur->rebindings[j].replaced != NULL && 102 | indirect_symbol_bindings[i] != cur->rebindings[j].replacement) { 103 | *(cur->rebindings[j].replaced) = indirect_symbol_bindings[i]; 104 | } 105 | indirect_symbol_bindings[i] = cur->rebindings[j].replacement; 106 | goto symbol_loop; 107 | } 108 | } 109 | cur = cur->next; 110 | } 111 | symbol_loop:; 112 | } 113 | } 114 | 115 | static void rebind_symbols_for_image(struct rebindings_entry *rebindings, 116 | const struct mach_header *header, 117 | intptr_t slide) { 118 | Dl_info info; 119 | if (dladdr(header, &info) == 0) { 120 | return; 121 | } 122 | 123 | segment_command_t *cur_seg_cmd; 124 | segment_command_t *linkedit_segment = NULL; 125 | struct symtab_command* symtab_cmd = NULL; 126 | struct dysymtab_command* dysymtab_cmd = NULL; 127 | 128 | uintptr_t cur = (uintptr_t)header + sizeof(mach_header_t); 129 | for (uint i = 0; i < header->ncmds; i++, cur += cur_seg_cmd->cmdsize) { 130 | cur_seg_cmd = (segment_command_t *)cur; 131 | if (cur_seg_cmd->cmd == LC_SEGMENT_ARCH_DEPENDENT) { 132 | if (strcmp(cur_seg_cmd->segname, SEG_LINKEDIT) == 0) { 133 | linkedit_segment = cur_seg_cmd; 134 | } 135 | } else if (cur_seg_cmd->cmd == LC_SYMTAB) { 136 | symtab_cmd = (struct symtab_command*)cur_seg_cmd; 137 | } else if (cur_seg_cmd->cmd == LC_DYSYMTAB) { 138 | dysymtab_cmd = (struct dysymtab_command*)cur_seg_cmd; 139 | } 140 | } 141 | 142 | if (!symtab_cmd || !dysymtab_cmd || !linkedit_segment || 143 | !dysymtab_cmd->nindirectsyms) { 144 | return; 145 | } 146 | 147 | // Find base symbol/string table addresses 148 | uintptr_t linkedit_base = (uintptr_t)slide + linkedit_segment->vmaddr - linkedit_segment->fileoff; 149 | nlist_t *symtab = (nlist_t *)(linkedit_base + symtab_cmd->symoff); 150 | char *strtab = (char *)(linkedit_base + symtab_cmd->stroff); 151 | 152 | // Get indirect symbol table (array of uint32_t indices into symbol table) 153 | uint32_t *indirect_symtab = (uint32_t *)(linkedit_base + dysymtab_cmd->indirectsymoff); 154 | 155 | cur = (uintptr_t)header + sizeof(mach_header_t); 156 | for (uint i = 0; i < header->ncmds; i++, cur += cur_seg_cmd->cmdsize) { 157 | cur_seg_cmd = (segment_command_t *)cur; 158 | if (cur_seg_cmd->cmd == LC_SEGMENT_ARCH_DEPENDENT) { 159 | if (strcmp(cur_seg_cmd->segname, SEG_DATA) != 0 && 160 | strcmp(cur_seg_cmd->segname, SEG_DATA_CONST) != 0) { 161 | continue; 162 | } 163 | for (uint j = 0; j < cur_seg_cmd->nsects; j++) { 164 | section_t *sect = 165 | (section_t *)(cur + sizeof(segment_command_t)) + j; 166 | if ((sect->flags & SECTION_TYPE) == S_LAZY_SYMBOL_POINTERS) { 167 | perform_rebinding_with_section(rebindings, sect, slide, symtab, strtab, indirect_symtab); 168 | } 169 | if ((sect->flags & SECTION_TYPE) == S_NON_LAZY_SYMBOL_POINTERS) { 170 | perform_rebinding_with_section(rebindings, sect, slide, symtab, strtab, indirect_symtab); 171 | } 172 | } 173 | } 174 | } 175 | } 176 | 177 | static void _rebind_symbols_for_image(const struct mach_header *header, 178 | intptr_t slide) { 179 | rebind_symbols_for_image(_rebindings_head, header, slide); 180 | } 181 | 182 | int rebind_symbols_image(void *header, 183 | intptr_t slide, 184 | struct rebinding rebindings[], 185 | size_t rebindings_nel) { 186 | struct rebindings_entry *rebindings_head = NULL; 187 | int retval = prepend_rebindings(&rebindings_head, rebindings, rebindings_nel); 188 | rebind_symbols_for_image(rebindings_head, (const struct mach_header *) header, slide); 189 | if (rebindings_head) { 190 | free(rebindings_head->rebindings); 191 | } 192 | free(rebindings_head); 193 | return retval; 194 | } 195 | 196 | int rebind_symbols(struct rebinding rebindings[], size_t rebindings_nel) { 197 | int retval = prepend_rebindings(&_rebindings_head, rebindings, rebindings_nel); 198 | if (retval < 0) { 199 | return retval; 200 | } 201 | // If this was the first call, register callback for image additions (which is also invoked for 202 | // existing images, otherwise, just run on existing images 203 | if (!_rebindings_head->next) { 204 | _dyld_register_func_for_add_image(_rebind_symbols_for_image); 205 | } else { 206 | uint32_t c = _dyld_image_count(); 207 | for (uint32_t i = 0; i < c; i++) { 208 | _rebind_symbols_for_image(_dyld_get_image_header(i), _dyld_get_image_vmaddr_slide(i)); 209 | } 210 | } 211 | return retval; 212 | } 213 | -------------------------------------------------------------------------------- /SSLKillSwitch/fishhook/fishhook.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2013, Facebook, Inc. 2 | // All rights reserved. 3 | // Redistribution and use in source and binary forms, with or without 4 | // modification, are permitted provided that the following conditions are met: 5 | // * Redistributions of source code must retain the above copyright notice, 6 | // this list of conditions and the following disclaimer. 7 | // * Redistributions in binary form must reproduce the above copyright notice, 8 | // this list of conditions and the following disclaimer in the documentation 9 | // and/or other materials provided with the distribution. 10 | // * Neither the name Facebook nor the names of its contributors may be used to 11 | // endorse or promote products derived from this software without specific 12 | // prior written permission. 13 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 14 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 16 | // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 17 | // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18 | // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 19 | // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 20 | // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 21 | // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 22 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 | 24 | #ifndef fishhook_h 25 | #define fishhook_h 26 | 27 | #include 28 | #include 29 | 30 | #if !defined(FISHHOOK_EXPORT) 31 | #define FISHHOOK_VISIBILITY __attribute__((visibility("hidden"))) 32 | #else 33 | #define FISHHOOK_VISIBILITY __attribute__((visibility("default"))) 34 | #endif 35 | 36 | #ifdef __cplusplus 37 | extern "C" { 38 | #endif //__cplusplus 39 | 40 | /* 41 | * A structure representing a particular intended rebinding from a symbol 42 | * name to its replacement 43 | */ 44 | struct rebinding { 45 | const char *name; 46 | void *replacement; 47 | void **replaced; 48 | }; 49 | 50 | /* 51 | * For each rebinding in rebindings, rebinds references to external, indirect 52 | * symbols with the specified name to instead point at replacement for each 53 | * image in the calling process as well as for all future images that are loaded 54 | * by the process. If rebind_functions is called more than once, the symbols to 55 | * rebind are added to the existing list of rebindings, and if a given symbol 56 | * is rebound more than once, the later rebinding will take precedence. 57 | */ 58 | FISHHOOK_VISIBILITY 59 | int rebind_symbols(struct rebinding rebindings[], size_t rebindings_nel); 60 | 61 | /* 62 | * Rebinds as above, but only in the specified image. The header should point 63 | * to the mach-o header, the slide should be the slide offset. Others as above. 64 | */ 65 | FISHHOOK_VISIBILITY 66 | int rebind_symbols_image(void *header, 67 | intptr_t slide, 68 | struct rebinding rebindings[], 69 | size_t rebindings_nel); 70 | 71 | #ifdef __cplusplus 72 | } 73 | #endif //__cplusplus 74 | 75 | #endif //fishhook_h 76 | 77 | -------------------------------------------------------------------------------- /SSLKillSwitch2.plist: -------------------------------------------------------------------------------- 1 | { 2 | Filter = { 3 | Bundles = ( 4 | "com.apple.AuthKit", 5 | "com.apple.UIKit", 6 | "com.apple.itunesstored", 7 | ); 8 | }; 9 | } -------------------------------------------------------------------------------- /SSLKillSwitchTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /SSLKillSwitchTests/SSLKillSwitchTests.m: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | #import 4 | 5 | // Heavily inspired by TrustKit's test suite 6 | #pragma mark Test NSURLSession delegate 7 | 8 | @interface TestNSURLSessionDelegate : NSObject 9 | { 10 | XCTestExpectation *testExpectation; 11 | } 12 | @property NSError *lastError; 13 | @property NSURLResponse *lastResponse; 14 | 15 | @property BOOL wasAuthHandlerCalled; // Used to validate that the delegate's auth handler was called 16 | 17 | 18 | - (instancetype)initWithExpectation:(XCTestExpectation *)expectation; 19 | 20 | - (void)URLSession:(NSURLSession * _Nonnull)session 21 | task:(NSURLSessionTask * _Nonnull)task 22 | didCompleteWithError:(NSError * _Nullable)error; 23 | 24 | - (void)URLSession:(NSURLSession * _Nonnull)session 25 | dataTask:(NSURLSessionDataTask * _Nonnull)dataTask 26 | didReceiveResponse:(NSURLResponse * _Nonnull)response 27 | completionHandler:(void (^ _Nonnull)(NSURLSessionResponseDisposition disposition))completionHandler; 28 | 29 | - (void)URLSession:(NSURLSession * _Nonnull)session 30 | task:(NSURLSessionTask * _Nonnull)task 31 | didReceiveChallenge:(NSURLAuthenticationChallenge * _Nonnull)challenge 32 | completionHandler:(void (^ _Nonnull)(NSURLSessionAuthChallengeDisposition disposition, 33 | NSURLCredential * _Nullable credential))completionHandler; 34 | 35 | @end 36 | 37 | 38 | @implementation TestNSURLSessionDelegate 39 | 40 | - (instancetype)initWithExpectation:(XCTestExpectation *)expectation 41 | { 42 | self = [super init]; 43 | if (self) 44 | { 45 | testExpectation = expectation; 46 | } 47 | return self; 48 | } 49 | 50 | - (void)URLSession:(NSURLSession * _Nonnull)session 51 | task:(NSURLSessionTask * _Nonnull)task 52 | didCompleteWithError:(NSError * _Nullable)error 53 | { 54 | NSLog(@"Received error, %@", error); 55 | _lastError = error; 56 | [testExpectation fulfill]; 57 | } 58 | 59 | - (void)URLSession:(NSURLSession * _Nonnull)session 60 | dataTask:(NSURLSessionDataTask * _Nonnull)dataTask 61 | didReceiveResponse:(NSURLResponse * _Nonnull)response 62 | completionHandler:(void (^ _Nonnull)(NSURLSessionResponseDisposition disposition))completionHandler 63 | { 64 | _lastResponse = response; 65 | [testExpectation fulfill]; 66 | } 67 | 68 | - (void)URLSession:(NSURLSession * _Nonnull)session 69 | task:(NSURLSessionTask * _Nonnull)task 70 | didReceiveChallenge:(NSURLAuthenticationChallenge * _Nonnull)challenge 71 | completionHandler:(void (^ _Nonnull)(NSURLSessionAuthChallengeDisposition disposition, 72 | NSURLCredential * _Nullable credential))completionHandler 73 | { 74 | // Reject all certificates; this replicates what would happen when pinning validation would fail due to traffic interception 75 | completionHandler(NSURLSessionAuthChallengeCancelAuthenticationChallenge, nil); 76 | } 77 | 78 | 79 | @end 80 | 81 | 82 | #pragma mark Test suite 83 | @interface SKSEndToEndNSURLSessionTests : XCTestCase 84 | 85 | @end 86 | 87 | @implementation SKSEndToEndNSURLSessionTests 88 | 89 | - (void)setUp { 90 | [super setUp]; 91 | [[NSURLCache sharedURLCache] removeAllCachedResponses]; 92 | } 93 | 94 | - (void)tearDown { 95 | [super tearDown]; 96 | } 97 | 98 | - (void)test 99 | { 100 | XCTestExpectation *expectation = [self expectationWithDescription:@"TestNSURLSessionTaskDelegate"]; 101 | TestNSURLSessionDelegate* delegate = [[TestNSURLSessionDelegate alloc] initWithExpectation:expectation]; 102 | 103 | NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration ephemeralSessionConfiguration] 104 | delegate:delegate 105 | delegateQueue:nil]; 106 | 107 | NSURLSessionDataTask *task = [session dataTaskWithURL:[NSURL URLWithString:@"https://www.google.com/"]]; 108 | [task resume]; 109 | 110 | // Wait for the connection to succeed 111 | [self waitForExpectationsWithTimeout:5.0 handler:^(NSError *error) 112 | { 113 | if (error) 114 | { 115 | NSLog(@"Timeout Error: %@", error); 116 | } 117 | }]; 118 | XCTAssertNotNil(delegate.lastResponse, @"TLS certificate was rejected although all TLS validation was disabled"); 119 | XCTAssertNil(delegate.lastError, @"TLS certificate was rejected although all TLS validation was disabled"); 120 | } 121 | 122 | @end 123 | -------------------------------------------------------------------------------- /charles.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nabla-c0d3/ssl-kill-switch2/4e69eb4d009b9d4b75c42ba030bbe973b5327a4f/charles.png -------------------------------------------------------------------------------- /layout/DEBIAN/control: -------------------------------------------------------------------------------- 1 | Package: com.nablac0d3.sslkillswitch2 2 | Name: SSL Kill Switch 2 3 | Depends: mobilesubstrate, preferenceloader 4 | Version: 0.14 5 | Architecture: iphoneos-arm 6 | Description: Blackbox tool to disable SSL certificate validation - including certificate pinning - within iOS and OS X Apps. 7 | Maintainer: Alban Diquet 8 | Author: Alban Diquet 9 | Section: Tweaks 10 | -------------------------------------------------------------------------------- /layout/Library/PreferenceLoader/Preferences/SSLKillSwitch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nabla-c0d3/ssl-kill-switch2/4e69eb4d009b9d4b75c42ba030bbe973b5327a4f/layout/Library/PreferenceLoader/Preferences/SSLKillSwitch.png -------------------------------------------------------------------------------- /layout/Library/PreferenceLoader/Preferences/SSLKillSwitch_prefs.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | entry 6 | 7 | cell 8 | PSLinkCell 9 | icon 10 | SSLKillSwitch.png 11 | label 12 | SSL Kill Switch 2 13 | 14 | items 15 | 16 | 17 | cell 18 | PSGroupCell 19 | label 20 | 21 | footerText 22 | SSL Kill Switch 2 23 | 24 | 25 | cell 26 | PSSwitchCell 27 | default 28 | 29 | defaults 30 | com.nablac0d3.SSLKillSwitchSettings 31 | key 32 | shouldDisableCertificateValidation 33 | label 34 | Disable Certificate Validation 35 | 36 | 37 | cell 38 | PSEditTextCell 39 | label 40 | Excluded BundleIDs: 41 | key 42 | excludedBundleIds 43 | default 44 | 45 | defaults 46 | com.nablac0d3.SSLKillSwitchSettings 47 | keyboard 48 | 49 | noAutoCorrect 50 | 51 | 52 | 53 | title 54 | SSL Kill Switch 2 55 | 56 | 57 | --------------------------------------------------------------------------------