├── charles.png
├── BH2012_MobileCertificatePinning.pdf
├── SSLKillSwitch2.plist
├── layout
├── Library
│ └── PreferenceLoader
│ │ └── Preferences
│ │ ├── SSLKillSwitch.png
│ │ └── SSLKillSwitch_prefs.plist
└── DEBIAN
│ └── control
├── SSLKillSwitch.xcodeproj
├── project.xcworkspace
│ └── contents.xcworkspacedata
├── xcshareddata
│ └── xcschemes
│ │ └── SSLKillSwitch.xcscheme
└── project.pbxproj
├── .github
└── workflows
│ └── run_tests.yml
├── Makefile
├── SSLKillSwitch
├── SSLKillSwitch.h
├── Info.plist
├── fishhook
│ ├── LICENSE
│ ├── fishhook.h
│ ├── README.md
│ └── fishhook.c
└── SSLKillSwitch.m
├── .gitignore
├── SSLKillSwitchTests
├── Info.plist
└── SSLKillSwitchTests.m
├── LICENSE
└── README.md
/charles.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nabla-c0d3/ssl-kill-switch2/HEAD/charles.png
--------------------------------------------------------------------------------
/BH2012_MobileCertificatePinning.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nabla-c0d3/ssl-kill-switch2/HEAD/BH2012_MobileCertificatePinning.pdf
--------------------------------------------------------------------------------
/SSLKillSwitch2.plist:
--------------------------------------------------------------------------------
1 | {
2 | Filter = {
3 | Bundles = (
4 | "com.apple.AuthKit",
5 | "com.apple.UIKit",
6 | "com.apple.itunesstored",
7 | );
8 | };
9 | }
--------------------------------------------------------------------------------
/layout/Library/PreferenceLoader/Preferences/SSLKillSwitch.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nabla-c0d3/ssl-kill-switch2/HEAD/layout/Library/PreferenceLoader/Preferences/SSLKillSwitch.png
--------------------------------------------------------------------------------
/SSLKillSwitch.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/.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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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.
--------------------------------------------------------------------------------
/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.
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 | 
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 | 
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/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/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.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 |
--------------------------------------------------------------------------------