├── README.md ├── Gatekeerper ├── Info.plist ├── configuration.h ├── utils.h ├── functions_clone.h ├── trustedbsd_hooks.h ├── logging.h ├── utils.c ├── Gatekeerper.c ├── kernel_symbols.h ├── functions_clone.c ├── cloned_functions.s ├── trustedbsd_hooks.c └── kernel_symbols.c └── Gatekeerper.xcodeproj └── project.pbxproj /README.md: -------------------------------------------------------------------------------- 1 | Gatekeerper 2 | 3 | A kernel extension to mitigate Gatekeeper bypasses 4 | 5 | Doesn't let linked (frameworks, libraries, bundles) unsigned code run if main binary is signed 6 | 7 | Untested with latest Gatekeeper bypass by Patrick Wardle (https://www.virusbtn.com/pdf/conference_slides/2015/Wardle-VB2015.pdf). 8 | 9 | I'm too lazy to create a PoC of that bypass. So I'm just guessing it will work but I'm pretty confident anyway :-) 10 | 11 | Copyright (c) fG!, 2015. All rights reserved. 12 | 13 | reverser@put.as - https://reverse.put.as 14 | 15 | -------------------------------------------------------------------------------- /Gatekeerper/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 | KEXT 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | NSHumanReadableCopyright 24 | Copyright © 2015 Put.as. All rights reserved. 25 | OSBundleLibraries 26 | 27 | com.apple.kpi.mach 28 | 10.0.0 29 | com.apple.kpi.libkern 30 | 10.0.0 31 | com.apple.kpi.bsd 32 | 10.0.0 33 | com.apple.kpi.dsep 34 | 10.0.0 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /Gatekeerper/configuration.h: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * ('-. .-') _ ('-. .-. .-') ('-. ('-. _ .-') _ (`-. ('-. _ .-') 4 | * ( OO ).-.( OO) ) _( OO) \ ( OO ) _( OO) _( OO)( \( -O ) ( (OO ) _( OO)( \( -O ) 5 | * ,----. / . --. // '._(,------.,--. ,--. (,------.(,------.,------. _.` \(,------.,------. 6 | * ' .-./-') | \-. \ |'--...__)| .---'| .' / | .---' | .---'| /`. '(__...--'' | .---'| /`. ' 7 | * | |_( O- ).-'-' | |'--. .--'| | | /, | | | | | / | | | / | | | | | / | | 8 | * | | .--, \ \| |_.' | | | (| '--. | ' _)(| '--. (| '--. | |_.' | | |_.' |(| '--. | |_.' | 9 | * (| | '. (_/ | .-. | | | | .--' | . \ | .--' | .--' | . '.' | .___.' | .--' | . '.' 10 | * | '--' | | | | | | | | `---.| |\ \ | `---. | `---.| |\ \ | | | `---.| |\ \ 11 | * `------' `--' `--' `--' `------'`--' '--' `------' `------'`--' '--' `--' `------'`--' '--' 12 | * 13 | * Gatekeerper 14 | * A kernel extension to mitigate Gatekeeper bypasses 15 | * Doesn't let linked (frameworks, libraries, bundles) unsigned code run if main binary is signed 16 | * 17 | * Untested with latest Gatekeeper bypass, too lazy to create a PoC of that 18 | * So I'm just guessing it will work, I'm pretty confident anyway :P 19 | * 20 | * Not guaranteed to be secure code! It might even destroy your computer but that is your problem! 21 | * 22 | * Created by reverser on 01/10/15. 23 | * Copyright (c) fG!, 2015. All rights reserved. 24 | * reverser@put.as - https://reverse.put.as 25 | * 26 | * config.h 27 | * 28 | * Redistribution and use in source and binary forms, with or without 29 | * modification, are permitted provided that the following conditions 30 | * are met: 31 | * 1. Redistributions of source code must retain the above copyright 32 | * notice, this list of conditions and the following disclaimer. 33 | * 2. Redistributions in binary form must reproduce the above copyright 34 | * notice, this list of conditions and the following disclaimer in the 35 | * documentation and/or other materials provided with the distribution. 36 | * 3. The name of the author may not be used to endorse or promote products 37 | * derived from this software without specific prior written permission. 38 | * 39 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 40 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 41 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 42 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 43 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 44 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 45 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 46 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 47 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 48 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 49 | * 50 | */ 51 | 52 | #ifndef gatekeerper_config_h 53 | #define gatekeerper_config_h 54 | 55 | #endif 56 | -------------------------------------------------------------------------------- /Gatekeerper/utils.h: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * ('-. .-') _ ('-. .-. .-') ('-. ('-. _ .-') _ (`-. ('-. _ .-') 4 | * ( OO ).-.( OO) ) _( OO) \ ( OO ) _( OO) _( OO)( \( -O ) ( (OO ) _( OO)( \( -O ) 5 | * ,----. / . --. // '._(,------.,--. ,--. (,------.(,------.,------. _.` \(,------.,------. 6 | * ' .-./-') | \-. \ |'--...__)| .---'| .' / | .---' | .---'| /`. '(__...--'' | .---'| /`. ' 7 | * | |_( O- ).-'-' | |'--. .--'| | | /, | | | | | / | | | / | | | | | / | | 8 | * | | .--, \ \| |_.' | | | (| '--. | ' _)(| '--. (| '--. | |_.' | | |_.' |(| '--. | |_.' | 9 | * (| | '. (_/ | .-. | | | | .--' | . \ | .--' | .--' | . '.' | .___.' | .--' | . '.' 10 | * | '--' | | | | | | | | `---.| |\ \ | `---. | `---.| |\ \ | | | `---.| |\ \ 11 | * `------' `--' `--' `--' `------'`--' '--' `------' `------'`--' '--' `--' `------'`--' '--' 12 | * 13 | * Gatekeerper 14 | * A kernel extension to mitigate Gatekeeper bypasses 15 | * Doesn't let linked (frameworks, libraries, bundles) unsigned code run if main binary is signed 16 | * 17 | * Untested with latest Gatekeeper bypass, too lazy to create a PoC of that 18 | * So I'm just guessing it will work, I'm pretty confident anyway :P 19 | * 20 | * Not guaranteed to be secure code! It might even destroy your computer but that is your problem! 21 | * 22 | * Created by reverser on 09/11/15. 23 | * Copyright (c) fG!, 2015. All rights reserved. 24 | * reverser@put.as - https://reverse.put.as 25 | * 26 | * utils.h 27 | * 28 | * Misc auxiliary kernel functions 29 | * 30 | * Redistribution and use in source and binary forms, with or without 31 | * modification, are permitted provided that the following conditions 32 | * are met: 33 | * 1. Redistributions of source code must retain the above copyright 34 | * notice, this list of conditions and the following disclaimer. 35 | * 2. Redistributions in binary form must reproduce the above copyright 36 | * notice, this list of conditions and the following disclaimer in the 37 | * documentation and/or other materials provided with the distribution. 38 | * 3. The name of the author may not be used to endorse or promote products 39 | * derived from this software without specific prior written permission. 40 | * 41 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 42 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 43 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 44 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 45 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 46 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 47 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 48 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 49 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 50 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 51 | * 52 | */ 53 | 54 | #ifndef gatekeerper_utils_h 55 | #define gatekeerper_utils_h 56 | 57 | #include 58 | 59 | uint8_t disable_wp(void); 60 | uint8_t enable_wp(void); 61 | 62 | #define enable_interrupts() __asm__ volatile("sti"); 63 | #define disable_interrupts() __asm__ volatile("cli"); 64 | 65 | #endif 66 | -------------------------------------------------------------------------------- /Gatekeerper/functions_clone.h: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * ('-. .-') _ ('-. .-. .-') ('-. ('-. _ .-') _ (`-. ('-. _ .-') 4 | * ( OO ).-.( OO) ) _( OO) \ ( OO ) _( OO) _( OO)( \( -O ) ( (OO ) _( OO)( \( -O ) 5 | * ,----. / . --. // '._(,------.,--. ,--. (,------.(,------.,------. _.` \(,------.,------. 6 | * ' .-./-') | \-. \ |'--...__)| .---'| .' / | .---' | .---'| /`. '(__...--'' | .---'| /`. ' 7 | * | |_( O- ).-'-' | |'--. .--'| | | /, | | | | | / | | | / | | | | | / | | 8 | * | | .--, \ \| |_.' | | | (| '--. | ' _)(| '--. (| '--. | |_.' | | |_.' |(| '--. | |_.' | 9 | * (| | '. (_/ | .-. | | | | .--' | . \ | .--' | .--' | . '.' | .___.' | .--' | . '.' 10 | * | '--' | | | | | | | | `---.| |\ \ | `---. | `---.| |\ \ | | | `---.| |\ \ 11 | * `------' `--' `--' `--' `------'`--' '--' `------' `------'`--' '--' `--' `------'`--' '--' 12 | * 13 | * Gatekeerper 14 | * A kernel extension to mitigate Gatekeeper bypasses 15 | * Doesn't let linked (frameworks, libraries, bundles) unsigned code run if main binary is signed 16 | * 17 | * Untested with latest Gatekeeper bypass, too lazy to create a PoC of that 18 | * So I'm just guessing it will work, I'm pretty confident anyway :P 19 | * 20 | * Not guaranteed to be secure code! It might even destroy your computer but that is your problem! 21 | * 22 | * Created by reverser on 01/10/15. 23 | * Copyright (c) fG!, 2015. All rights reserved. 24 | * reverser@put.as - https://reverse.put.as 25 | * 26 | * functions_clone.h 27 | * 28 | * Functions to clone and fix kernel functions 29 | * XXX: TODO! 30 | * 31 | * Redistribution and use in source and binary forms, with or without 32 | * modification, are permitted provided that the following conditions 33 | * are met: 34 | * 1. Redistributions of source code must retain the above copyright 35 | * notice, this list of conditions and the following disclaimer. 36 | * 2. Redistributions in binary form must reproduce the above copyright 37 | * notice, this list of conditions and the following disclaimer in the 38 | * documentation and/or other materials provided with the distribution. 39 | * 3. The name of the author may not be used to endorse or promote products 40 | * derived from this software without specific prior written permission. 41 | * 42 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 43 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 44 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 45 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 46 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 47 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 48 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 49 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 50 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 51 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 52 | * 53 | */ 54 | 55 | #ifndef gatekeerper_functions_clone_h 56 | #define gatekeerper_functions_clone_h 57 | 58 | #include 59 | 60 | kern_return_t clone_csfg_get_platform_binary(void); 61 | kern_return_t clone_csproc_get_teamid(void); 62 | 63 | #endif /* gatekeerper_functions_clone_h */ 64 | -------------------------------------------------------------------------------- /Gatekeerper/trustedbsd_hooks.h: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * ('-. .-') _ ('-. .-. .-') ('-. ('-. _ .-') _ (`-. ('-. _ .-') 4 | * ( OO ).-.( OO) ) _( OO) \ ( OO ) _( OO) _( OO)( \( -O ) ( (OO ) _( OO)( \( -O ) 5 | * ,----. / . --. // '._(,------.,--. ,--. (,------.(,------.,------. _.` \(,------.,------. 6 | * ' .-./-') | \-. \ |'--...__)| .---'| .' / | .---' | .---'| /`. '(__...--'' | .---'| /`. ' 7 | * | |_( O- ).-'-' | |'--. .--'| | | /, | | | | | / | | | / | | | | | / | | 8 | * | | .--, \ \| |_.' | | | (| '--. | ' _)(| '--. (| '--. | |_.' | | |_.' |(| '--. | |_.' | 9 | * (| | '. (_/ | .-. | | | | .--' | . \ | .--' | .--' | . '.' | .___.' | .--' | . '.' 10 | * | '--' | | | | | | | | `---.| |\ \ | `---. | `---.| |\ \ | | | `---.| |\ \ 11 | * `------' `--' `--' `--' `------'`--' '--' `------' `------'`--' '--' `--' `------'`--' '--' 12 | * 13 | * Gatekeerper 14 | * A kernel extension to mitigate Gatekeeper bypasses 15 | * Doesn't let linked (frameworks, libraries, bundles) unsigned code run if main binary is signed 16 | * 17 | * Untested with latest Gatekeeper bypass, too lazy to create a PoC of that 18 | * So I'm just guessing it will work, I'm pretty confident anyway :P 19 | * 20 | * Not guaranteed to be secure code! It might even destroy your computer but that is your problem! 21 | * 22 | * Created by reverser on 01/10/15. 23 | * Copyright (c) fG!, 2015. All rights reserved. 24 | * reverser@put.as - https://reverse.put.as 25 | * 26 | * trustedbsd_hooks.h 27 | * 28 | * Functions to replace AMFI hooks and control unsigned code 29 | * Where all the magic happens! 30 | * 31 | * Redistribution and use in source and binary forms, with or without 32 | * modification, are permitted provided that the following conditions 33 | * are met: 34 | * 1. Redistributions of source code must retain the above copyright 35 | * notice, this list of conditions and the following disclaimer. 36 | * 2. Redistributions in binary form must reproduce the above copyright 37 | * notice, this list of conditions and the following disclaimer in the 38 | * documentation and/or other materials provided with the distribution. 39 | * 3. The name of the author may not be used to endorse or promote products 40 | * derived from this software without specific prior written permission. 41 | * 42 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 43 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 44 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 45 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 46 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 47 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 48 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 49 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 50 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 51 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 52 | * 53 | */ 54 | 55 | #ifndef gatekeerper_trustedbsd_hooks_h 56 | #define gatekeerper_trustedbsd_hooks_h 57 | 58 | #include 59 | 60 | kern_return_t start_trustedbsd_hooks(void *d); 61 | kern_return_t stop_trustedbsd_hooks(void); 62 | 63 | #endif /* gatekeerper_trustedbsd_hooks_h */ 64 | -------------------------------------------------------------------------------- /Gatekeerper/logging.h: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * ('-. .-') _ ('-. .-. .-') ('-. ('-. _ .-') _ (`-. ('-. _ .-') 4 | * ( OO ).-.( OO) ) _( OO) \ ( OO ) _( OO) _( OO)( \( -O ) ( (OO ) _( OO)( \( -O ) 5 | * ,----. / . --. // '._(,------.,--. ,--. (,------.(,------.,------. _.` \(,------.,------. 6 | * ' .-./-') | \-. \ |'--...__)| .---'| .' / | .---' | .---'| /`. '(__...--'' | .---'| /`. ' 7 | * | |_( O- ).-'-' | |'--. .--'| | | /, | | | | | / | | | / | | | | | / | | 8 | * | | .--, \ \| |_.' | | | (| '--. | ' _)(| '--. (| '--. | |_.' | | |_.' |(| '--. | |_.' | 9 | * (| | '. (_/ | .-. | | | | .--' | . \ | .--' | .--' | . '.' | .___.' | .--' | . '.' 10 | * | '--' | | | | | | | | `---.| |\ \ | `---. | `---.| |\ \ | | | `---.| |\ \ 11 | * `------' `--' `--' `--' `------'`--' '--' `------' `------'`--' '--' `--' `------'`--' '--' 12 | * 13 | * Gatekeerper 14 | * A kernel extension to mitigate Gatekeeper bypasses 15 | * Doesn't let linked (frameworks, libraries, bundles) unsigned code run if main binary is signed 16 | * 17 | * Untested with latest Gatekeeper bypass, too lazy to create a PoC of that 18 | * So I'm just guessing it will work, I'm pretty confident anyway :P 19 | * 20 | * Not guaranteed to be secure code! It might even destroy your computer but that is your problem! 21 | * 22 | * Created by reverser on 01/10/15. 23 | * Copyright (c) fG!, 2015. All rights reserved. 24 | * reverser@put.as - https://reverse.put.as 25 | * 26 | * logging.h 27 | * 28 | * Redistribution and use in source and binary forms, with or without 29 | * modification, are permitted provided that the following conditions 30 | * are met: 31 | * 1. Redistributions of source code must retain the above copyright 32 | * notice, this list of conditions and the following disclaimer. 33 | * 2. Redistributions in binary form must reproduce the above copyright 34 | * notice, this list of conditions and the following disclaimer in the 35 | * documentation and/or other materials provided with the distribution. 36 | * 3. The name of the author may not be used to endorse or promote products 37 | * derived from this software without specific prior written permission. 38 | * 39 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 40 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 41 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 42 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 43 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 44 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 45 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 46 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 47 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 48 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 49 | * 50 | */ 51 | 52 | #ifndef gatekeerper_logging_h 53 | #define gatekeerper_logging_h 54 | 55 | #include 56 | 57 | #if DEBUG == NO 58 | 59 | #define DEBUG_MSG(fmt, ...) do {} while (0) 60 | #define ERROR_MSG(fmt, ...) printf("[ERROR] " fmt "\n", ## __VA_ARGS__) 61 | 62 | #else /* DEBUG == YES */ 63 | 64 | #define DEBUG_MSG(fmt, ...) printf("[DEBUG] " fmt "\n", ## __VA_ARGS__) 65 | #define ERROR_MSG(fmt, ...) printf("[ERROR] " fmt " (%s, %d)\n", ## __VA_ARGS__, __func__, __LINE__) 66 | 67 | #endif /* DEBUG */ 68 | 69 | /* kernel symbols */ 70 | #define SOLVE_KERNEL_SYMBOL(string, pointer) if (solve_kernel_symbol((string), (void**)&(pointer))) { ERROR_MSG("Can't solve kernel symbol %s", (string)); return KERN_FAILURE;} 71 | #define SOLVE_KERNEL_VARIABLE(string, output) if (solve_kernel_variable((string), &(output))) { ERROR_MSG("Can't solve kernel variable %s", (string)); return KERN_FAILURE;} 72 | 73 | #endif 74 | -------------------------------------------------------------------------------- /Gatekeerper/utils.c: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * ('-. .-') _ ('-. .-. .-') ('-. ('-. _ .-') _ (`-. ('-. _ .-') 4 | * ( OO ).-.( OO) ) _( OO) \ ( OO ) _( OO) _( OO)( \( -O ) ( (OO ) _( OO)( \( -O ) 5 | * ,----. / . --. // '._(,------.,--. ,--. (,------.(,------.,------. _.` \(,------.,------. 6 | * ' .-./-') | \-. \ |'--...__)| .---'| .' / | .---' | .---'| /`. '(__...--'' | .---'| /`. ' 7 | * | |_( O- ).-'-' | |'--. .--'| | | /, | | | | | / | | | / | | | | | / | | 8 | * | | .--, \ \| |_.' | | | (| '--. | ' _)(| '--. (| '--. | |_.' | | |_.' |(| '--. | |_.' | 9 | * (| | '. (_/ | .-. | | | | .--' | . \ | .--' | .--' | . '.' | .___.' | .--' | . '.' 10 | * | '--' | | | | | | | | `---.| |\ \ | `---. | `---.| |\ \ | | | `---.| |\ \ 11 | * `------' `--' `--' `--' `------'`--' '--' `------' `------'`--' '--' `--' `------'`--' '--' 12 | * 13 | * Gatekeerper 14 | * A kernel extension to mitigate Gatekeeper bypasses 15 | * Doesn't let linked (frameworks, libraries, bundles) unsigned code run if main binary is signed 16 | * 17 | * Untested with latest Gatekeeper bypass, too lazy to create a PoC of that 18 | * So I'm just guessing it will work, I'm pretty confident anyway :P 19 | * 20 | * Not guaranteed to be secure code! It might even destroy your computer but that is your problem! 21 | * 22 | * Created by reverser on 09/11/15. 23 | * Copyright (c) fG!, 2015. All rights reserved. 24 | * reverser@put.as - https://reverse.put.as 25 | * 26 | * utils.c 27 | * 28 | * Misc auxiliary kernel functions 29 | * 30 | * Redistribution and use in source and binary forms, with or without 31 | * modification, are permitted provided that the following conditions 32 | * are met: 33 | * 1. Redistributions of source code must retain the above copyright 34 | * notice, this list of conditions and the following disclaimer. 35 | * 2. Redistributions in binary form must reproduce the above copyright 36 | * notice, this list of conditions and the following disclaimer in the 37 | * documentation and/or other materials provided with the distribution. 38 | * 3. The name of the author may not be used to endorse or promote products 39 | * derived from this software without specific prior written permission. 40 | * 41 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 42 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 43 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 44 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 45 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 46 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 47 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 48 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 49 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 50 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 51 | * 52 | */ 53 | 54 | #include "utils.h" 55 | 56 | #include "logging.h" 57 | #include "configuration.h" 58 | #include 59 | 60 | /* 61 | * disable the Write Protection bit in CR0 register so we can modify kernel code 62 | */ 63 | uint8_t 64 | disable_wp(void) 65 | { 66 | uintptr_t cr0; 67 | // retrieve current value 68 | cr0 = get_cr0(); 69 | // remove the WP bit 70 | cr0 = cr0 & ~CR0_WP; 71 | // and write it back 72 | set_cr0(cr0); 73 | // verify if we were successful 74 | if ((get_cr0() & CR0_WP) == 0) return 0; 75 | else return 1; 76 | } 77 | 78 | /* 79 | * enable the Write Protection bit in CR0 register 80 | */ 81 | uint8_t 82 | enable_wp(void) 83 | { 84 | uintptr_t cr0; 85 | // retrieve current value 86 | cr0 = get_cr0(); 87 | // add the WP bit 88 | cr0 = cr0 | CR0_WP; 89 | // and write it back 90 | set_cr0(cr0); 91 | // verify if we were successful 92 | if ((get_cr0() & CR0_WP) != 0) return 0; 93 | else return 1; 94 | } 95 | -------------------------------------------------------------------------------- /Gatekeerper/Gatekeerper.c: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * ('-. .-') _ ('-. .-. .-') ('-. ('-. _ .-') _ (`-. ('-. _ .-') 4 | * ( OO ).-.( OO) ) _( OO) \ ( OO ) _( OO) _( OO)( \( -O ) ( (OO ) _( OO)( \( -O ) 5 | * ,----. / . --. // '._(,------.,--. ,--. (,------.(,------.,------. _.` \(,------.,------. 6 | * ' .-./-') | \-. \ |'--...__)| .---'| .' / | .---' | .---'| /`. '(__...--'' | .---'| /`. ' 7 | * | |_( O- ).-'-' | |'--. .--'| | | /, | | | | | / | | | / | | | | | / | | 8 | * | | .--, \ \| |_.' | | | (| '--. | ' _)(| '--. (| '--. | |_.' | | |_.' |(| '--. | |_.' | 9 | * (| | '. (_/ | .-. | | | | .--' | . \ | .--' | .--' | . '.' | .___.' | .--' | . '.' 10 | * | '--' | | | | | | | | `---.| |\ \ | `---. | `---.| |\ \ | | | `---.| |\ \ 11 | * `------' `--' `--' `--' `------'`--' '--' `------' `------'`--' '--' `--' `------'`--' '--' 12 | * 13 | * Gatekeerper 14 | * A kernel extension to mitigate Gatekeeper bypasses 15 | * Doesn't let linked (frameworks, libraries, bundles) unsigned code run if main binary is signed 16 | * 17 | * Untested with latest Gatekeeper bypass, too lazy to create a PoC of that 18 | * So I'm just guessing it will work, I'm pretty confident anyway :P 19 | * 20 | * Not guaranteed to be secure code! It might even destroy your computer but that is your problem! 21 | * 22 | * TESTED ONLY WITH YOSEMITE 10.10.5 - EVERYTHING ELSE = KERNEL PANIC! 23 | * 24 | * Created by reverser on 01/10/15. 25 | * Copyright (c) fG!, 2015. All rights reserved. 26 | * reverser@put.as - https://reverse.put.as 27 | * 28 | * Gatekeerper.c 29 | * 30 | * Redistribution and use in source and binary forms, with or without 31 | * modification, are permitted provided that the following conditions 32 | * are met: 33 | * 1. Redistributions of source code must retain the above copyright 34 | * notice, this list of conditions and the following disclaimer. 35 | * 2. Redistributions in binary form must reproduce the above copyright 36 | * notice, this list of conditions and the following disclaimer in the 37 | * documentation and/or other materials provided with the distribution. 38 | * 3. The name of the author may not be used to endorse or promote products 39 | * derived from this software without specific prior written permission. 40 | * 41 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 42 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 43 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 44 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 45 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 46 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 47 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 48 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 49 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 50 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 51 | * 52 | */ 53 | 54 | #include 55 | #include "logging.h" 56 | #include "configuration.h" 57 | #include "kernel_symbols.h" 58 | #include "trustedbsd_hooks.h" 59 | #include 60 | 61 | /* global variables */ 62 | /* structure to hold kernel headers info we use to solve symbols */ 63 | struct kernel_info g_kinfo; 64 | 65 | extern const int version_major; 66 | extern const int version_minor; 67 | extern const int version_revision; 68 | 69 | kern_return_t Gatekeerper_start(kmod_info_t * ki, void *d); 70 | kern_return_t Gatekeerper_stop(kmod_info_t *ki, void *d); 71 | 72 | kern_return_t Gatekeerper_start(kmod_info_t * ki, void *d) 73 | { 74 | /* TESTED ONLY WITH YOSEMITE 10.10.5 - EVERYTHING ELSE = KERNEL PANIC! */ 75 | if (version_major != 14 && version_minor != 5 && version_revision != 0) 76 | { 77 | ERROR_MSG("This kext only supports Yosemite 10.10.5."); 78 | return KERN_NOT_SUPPORTED; 79 | } 80 | 81 | /* initialize structure with kernel information to solve symbols */ 82 | if (init_kernel_info() != KERN_SUCCESS) 83 | { 84 | /* in case of failure buffers are freed inside */ 85 | ERROR_MSG("Failed to init kernel info structure!"); 86 | return KERN_FAILURE; 87 | } 88 | 89 | /* solve kernel symbols we need */ 90 | SOLVE_KERNEL_SYMBOL("_csfg_get_path", _csfg_get_path) 91 | SOLVE_KERNEL_SYMBOL("_csfg_get_teamid", _csfg_get_teamid) 92 | SOLVE_KERNEL_SYMBOL("_csfg_get_platform_binary", _csfg_get_platform_binary) 93 | SOLVE_KERNEL_SYMBOL("_csproc_get_teamid", _csproc_get_teamid) 94 | SOLVE_KERNEL_SYMBOL("_ubc_cs_blob_get", _ubc_cs_blob_get) 95 | 96 | start_trustedbsd_hooks(d); 97 | 98 | return KERN_SUCCESS; 99 | } 100 | 101 | kern_return_t Gatekeerper_stop(kmod_info_t *ki, void *d) 102 | { 103 | stop_trustedbsd_hooks(); 104 | return KERN_SUCCESS; 105 | } 106 | -------------------------------------------------------------------------------- /Gatekeerper/kernel_symbols.h: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * ('-. .-') _ ('-. .-. .-') ('-. ('-. _ .-') _ (`-. ('-. _ .-') 4 | * ( OO ).-.( OO) ) _( OO) \ ( OO ) _( OO) _( OO)( \( -O ) ( (OO ) _( OO)( \( -O ) 5 | * ,----. / . --. // '._(,------.,--. ,--. (,------.(,------.,------. _.` \(,------.,------. 6 | * ' .-./-') | \-. \ |'--...__)| .---'| .' / | .---' | .---'| /`. '(__...--'' | .---'| /`. ' 7 | * | |_( O- ).-'-' | |'--. .--'| | | /, | | | | | / | | | / | | | | | / | | 8 | * | | .--, \ \| |_.' | | | (| '--. | ' _)(| '--. (| '--. | |_.' | | |_.' |(| '--. | |_.' | 9 | * (| | '. (_/ | .-. | | | | .--' | . \ | .--' | .--' | . '.' | .___.' | .--' | . '.' 10 | * | '--' | | | | | | | | `---.| |\ \ | `---. | `---.| |\ \ | | | `---.| |\ \ 11 | * `------' `--' `--' `--' `------'`--' '--' `------' `------'`--' '--' `--' `------'`--' '--' 12 | * 13 | * Gatekeerper 14 | * A kernel extension to mitigate Gatekeeper bypasses 15 | * Doesn't let linked (frameworks, libraries, bundles) unsigned code run if main binary is signed 16 | * 17 | * Untested with latest Gatekeeper bypass, too lazy to create a PoC of that 18 | * So I'm just guessing it will work, I'm pretty confident anyway :P 19 | * 20 | * Not guaranteed to be secure code! It might even destroy your computer but that is your problem! 21 | * 22 | * Created by reverser on 01/10/15. 23 | * Copyright (c) fG!, 2015. All rights reserved. 24 | * reverser@put.as - https://reverse.put.as 25 | * 26 | * kernel_symbols.h 27 | * 28 | * Functions to solve kernel symbols 29 | * 30 | * Redistribution and use in source and binary forms, with or without 31 | * modification, are permitted provided that the following conditions 32 | * are met: 33 | * 1. Redistributions of source code must retain the above copyright 34 | * notice, this list of conditions and the following disclaimer. 35 | * 2. Redistributions in binary form must reproduce the above copyright 36 | * notice, this list of conditions and the following disclaimer in the 37 | * documentation and/or other materials provided with the distribution. 38 | * 3. The name of the author may not be used to endorse or promote products 39 | * derived from this software without specific prior written permission. 40 | * 41 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 42 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 43 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 44 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 45 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 46 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 47 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 48 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 49 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 50 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 51 | * 52 | */ 53 | 54 | #ifndef gatekeerper_kernel_symbols_h 55 | #define gatekeerper_kernel_symbols_h 56 | 57 | #include 58 | #include 59 | #include 60 | #include 61 | 62 | struct fileglob; 63 | struct cs_blob; 64 | 65 | /* exported data structures */ 66 | struct kernel_info 67 | { 68 | mach_vm_address_t memory_text_addr; // the address of __TEXT segment in kernel memory 69 | mach_vm_address_t disk_text_addr; // the same address at /mach_kernel in filesystem 70 | mach_vm_address_t kaslr_slide; // the kernel aslr slide, computed as the difference between above's addresses 71 | mach_vm_address_t disk_DATA_addr; /* the address of __DATA segment in mach-o header */ 72 | void *linkedit_buf; // pointer to __LINKEDIT buffer containing symbols to solve 73 | uint64_t linkedit_fileoff; // __LINKEDIT file offset so we can read 74 | // WARNING: does not contain the fat offset value in case it's a FAT kernel 75 | uint64_t linkedit_size; 76 | uint32_t symboltable_fileoff; // file offset to symbol table - used to position inside the __LINKEDIT buffer 77 | uint32_t symboltable_nr_symbols; 78 | uint32_t stringtable_fileoff; // file offset to string table 79 | uint32_t stringtable_size; 80 | // other info from the header we might need 81 | uint64_t text_size; // size of __text section to disassemble 82 | uint64_t DATA_size; /* the VM size of __DATA segment */ 83 | }; 84 | 85 | /* exported functions */ 86 | kern_return_t init_kernel_info(void); 87 | kern_return_t cleanup_kernel_info(void); 88 | kern_return_t solve_kernel_symbol(char *symbol_to_solve, void **symbol_ptr); 89 | kern_return_t solve_kernel_variable(char *symbol_to_solve, mach_vm_address_t *output); 90 | 91 | /* kernel symbols we will manually solve */ 92 | extern int (*_csfg_get_path)(struct fileglob *fg, char *path, int *len); 93 | extern const char * (*_csfg_get_teamid)(struct fileglob *fg); 94 | extern int (*_csfg_get_platform_binary)(struct fileglob *fg); 95 | extern struct cs_blob * (*_csproc_get_blob)(struct proc *p); 96 | extern const char * (*_csproc_get_teamid)(struct proc *p); 97 | extern struct cs_blob * (*_ubc_cs_blob_get)(struct vnode *vp, cpu_type_t cputype, off_t offset); 98 | 99 | #endif 100 | -------------------------------------------------------------------------------- /Gatekeerper/functions_clone.c: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * ('-. .-') _ ('-. .-. .-') ('-. ('-. _ .-') _ (`-. ('-. _ .-') 4 | * ( OO ).-.( OO) ) _( OO) \ ( OO ) _( OO) _( OO)( \( -O ) ( (OO ) _( OO)( \( -O ) 5 | * ,----. / . --. // '._(,------.,--. ,--. (,------.(,------.,------. _.` \(,------.,------. 6 | * ' .-./-') | \-. \ |'--...__)| .---'| .' / | .---' | .---'| /`. '(__...--'' | .---'| /`. ' 7 | * | |_( O- ).-'-' | |'--. .--'| | | /, | | | | | / | | | / | | | | | / | | 8 | * | | .--, \ \| |_.' | | | (| '--. | ' _)(| '--. (| '--. | |_.' | | |_.' |(| '--. | |_.' | 9 | * (| | '. (_/ | .-. | | | | .--' | . \ | .--' | .--' | . '.' | .___.' | .--' | . '.' 10 | * | '--' | | | | | | | | `---.| |\ \ | `---. | `---.| |\ \ | | | `---.| |\ \ 11 | * `------' `--' `--' `--' `------'`--' '--' `------' `------'`--' '--' `--' `------'`--' '--' 12 | * 13 | * Gatekeerper 14 | * A kernel extension to mitigate Gatekeeper bypasses 15 | * Doesn't let linked (frameworks, libraries, bundles) unsigned code run if main binary is signed 16 | * 17 | * Untested with latest Gatekeeper bypass, too lazy to create a PoC of that 18 | * So I'm just guessing it will work, I'm pretty confident anyway :P 19 | * 20 | * Not guaranteed to be secure code! It might even destroy your computer but that is your problem! 21 | * 22 | * Created by reverser on 01/10/15. 23 | * Copyright (c) fG!, 2015. All rights reserved. 24 | * reverser@put.as - https://reverse.put.as 25 | * 26 | * functions_clone.c 27 | * 28 | * Functions to clone and fix kernel functions 29 | * 30 | * Redistribution and use in source and binary forms, with or without 31 | * modification, are permitted provided that the following conditions 32 | * are met: 33 | * 1. Redistributions of source code must retain the above copyright 34 | * notice, this list of conditions and the following disclaimer. 35 | * 2. Redistributions in binary form must reproduce the above copyright 36 | * notice, this list of conditions and the following disclaimer in the 37 | * documentation and/or other materials provided with the distribution. 38 | * 3. The name of the author may not be used to endorse or promote products 39 | * derived from this software without specific prior written permission. 40 | * 41 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 42 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 43 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 44 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 45 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 46 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 47 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 48 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 49 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 50 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 51 | * 52 | */ 53 | 54 | #include "functions_clone.h" 55 | 56 | #include 57 | #include 58 | #include 59 | #include 60 | #include 61 | #include 62 | #include 63 | 64 | #include "logging.h" 65 | #include "configuration.h" 66 | #include "kernel_symbols.h" 67 | #include "utils.h" 68 | 69 | /* the island space */ 70 | extern char cloned_csfg_get_platform_binary[], cloned_csproc_get_teamid[], jump_island1[], jump_island2[], jump_island3[]; 71 | 72 | /* 73 | * clone csfg_get_platform_binary, fix relocations, and patch it the way we need 74 | * 75 | * HARDCODED OFFSETS - Only valid for latest Yosemite 10.10.5 76 | * 77 | * This can be obviously improved using a disassembler but this is just a PoC 78 | * and things are stable enough to be ok this way 79 | * 80 | */ 81 | kern_return_t 82 | clone_csfg_get_platform_binary(void) 83 | { 84 | DEBUG_MSG("Address of cloned_space is %p", (void*)cloned_csfg_get_platform_binary); 85 | DEBUG_MSG("Address of csfg_get_platform_binary is %p", (void*)_csfg_get_platform_binary); 86 | DEBUG_MSG("Jump island 1 address %p", (void*)jump_island1); 87 | DEBUG_MSG("Jump island 2 address %p", (void*)jump_island2); 88 | 89 | void *_lck_mtx_lock = NULL; 90 | void *_lck_mtx_unlock = NULL; 91 | SOLVE_KERNEL_SYMBOL("_lck_mtx_lock", _lck_mtx_lock) 92 | SOLVE_KERNEL_SYMBOL("_lck_mtx_unlock", _lck_mtx_unlock) 93 | 94 | DEBUG_MSG("Locks %p and %p", _lck_mtx_lock, _lck_mtx_unlock); 95 | 96 | /* copy the function we want to clone into our cloned space */ 97 | /* we need to disable kernel write protection to modify kext code - easier than calling mach_vm_protect */ 98 | disable_interrupts(); 99 | disable_wp(); 100 | memcpy(cloned_csfg_get_platform_binary, (void*)_csfg_get_platform_binary, 100); // XXX: hardcoded size 101 | 102 | /* update first island - lck_mtx_lock */ 103 | *(uint64_t*)(jump_island1 + 2) = (uint64_t)_lck_mtx_lock; 104 | /* update second island - lck_mtx_unlock */ 105 | *(uint64_t*)(jump_island2 + 2) = (uint64_t)_lck_mtx_unlock; 106 | 107 | /* update calls to the islands in cloned function */ 108 | *(int32_t*)(cloned_csfg_get_platform_binary + 0x1F) = (int32_t)(jump_island1 - (cloned_csfg_get_platform_binary + 0x1E + 5)); 109 | *(int32_t*)(cloned_csfg_get_platform_binary + 0x48) = (int32_t)((jump_island2) - (cloned_csfg_get_platform_binary + 0x47 + 5)); 110 | 111 | /* the original function returns csb_platform_binary 112 | * we patch it to return if uip->cs_blobs is NULL or not 113 | * meaning that it's code signed or not 114 | */ 115 | *(int16_t*)(cloned_csfg_get_platform_binary + 0x41) = 0xC3FF; // inc ebx 116 | *(int8_t*)(cloned_csfg_get_platform_binary + 0x43) = 0x90; // ebx is then moved to eax and default is NULL 117 | 118 | /* and we are ready to continue */ 119 | enable_wp(); 120 | enable_interrupts(); 121 | return KERN_SUCCESS; 122 | } 123 | 124 | /* 125 | * clone csproc_get_teamid, fix relocations, and patch it the way we need 126 | * 127 | * HARDCODED OFFSETS - Only valid for latest Yosemite 10.10.5 128 | * 129 | * This can be obviously improved using a disassembler but this is just a PoC 130 | * and things are stable enough to be ok this way 131 | * 132 | */ 133 | kern_return_t 134 | clone_csproc_get_teamid(void) 135 | { 136 | DEBUG_MSG("Address of cloned_space is %p", (void*)cloned_csproc_get_teamid); 137 | DEBUG_MSG("Address of csproc_get_teamid is %p", (void*)_csproc_get_teamid); 138 | DEBUG_MSG("Jump island 3 address %p", (void*)jump_island3); 139 | 140 | /* copy the function we want to clone into our cloned space */ 141 | /* we need to disable kernel write protection to modify kext code - easier than calling mach_vm_protect */ 142 | disable_interrupts(); 143 | disable_wp(); 144 | 145 | /* clone _csproc_get_teamid and fix it with our patch */ 146 | memcpy(cloned_csproc_get_teamid, (void*)_csproc_get_teamid, 100); // XXX: hardcoded size 147 | 148 | /* update _csproc_get_teamid island */ 149 | *(uint64_t*)(jump_island3 + 2) = (uint64_t)_ubc_cs_blob_get; 150 | /* update calls to the islands in cloned function */ 151 | *(int32_t*)(cloned_csproc_get_teamid + 0x29) = (int32_t)(jump_island3 - (cloned_csproc_get_teamid + 0x28 + 5)); 152 | 153 | /* the original function returns a pointer 154 | * we modify it to return an int 155 | * 0 there's no code signing blob in current_proc() aka main binary not signed 156 | * 1 main binary is signed 157 | */ 158 | *(uint32_t*)(cloned_csproc_get_teamid + 0x37) = 0x9090C0FF; // inc eax 159 | 160 | /* and we are ready to continue */ 161 | enable_wp(); 162 | enable_interrupts(); 163 | return KERN_SUCCESS; 164 | } 165 | -------------------------------------------------------------------------------- /Gatekeerper/cloned_functions.s: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * ('-. .-') _ ('-. .-. .-') ('-. ('-. _ .-') _ (`-. ('-. _ .-') 4 | * ( OO ).-.( OO) ) _( OO) \ ( OO ) _( OO) _( OO)( \( -O ) ( (OO ) _( OO)( \( -O ) 5 | * ,----. / . --. // '._(,------.,--. ,--. (,------.(,------.,------. _.` \(,------.,------. 6 | * ' .-./-') | \-. \ |'--...__)| .---'| .' / | .---' | .---'| /`. '(__...--'' | .---'| /`. ' 7 | * | |_( O- ).-'-' | |'--. .--'| | | /, | | | | | / | | | / | | | | | / | | 8 | * | | .--, \ \| |_.' | | | (| '--. | ' _)(| '--. (| '--. | |_.' | | |_.' |(| '--. | |_.' | 9 | * (| | '. (_/ | .-. | | | | .--' | . \ | .--' | .--' | . '.' | .___.' | .--' | . '.' 10 | * | '--' | | | | | | | | `---.| |\ \ | `---. | `---.| |\ \ | | | `---.| |\ \ 11 | * `------' `--' `--' `--' `------'`--' '--' `------' `------'`--' '--' `--' `------'`--' '--' 12 | * 13 | * Gatekeerper 14 | * A kernel extension to mitigate Gatekeeper bypasses 15 | * Doesn't let linked (frameworks, libraries, bundles) unsigned code run if main binary is signed 16 | * 17 | * Untested with latest Gatekeeper bypass, too lazy to create a PoC of that 18 | * So I'm just guessing it will work, I'm pretty confident anyway :P 19 | * 20 | * Not guaranteed to be secure code! It might even destroy your computer but that is your problem! 21 | * 22 | * Created by reverser on 01/10/15. 23 | * Copyright (c) fG!, 2015. All rights reserved. 24 | * reverser@put.as - https://reverse.put.as 25 | * 26 | * cloned_functions.s 27 | * 28 | * Some lazy NOP space that can be used to copy cloned functions into 29 | * and jump islands for easily fixing the relocations 30 | * Easier and faster to do it this way than allocating memory, making it executable, and so on... 31 | * 32 | * Redistribution and use in source and binary forms, with or without 33 | * modification, are permitted provided that the following conditions 34 | * are met: 35 | * 1. Redistributions of source code must retain the above copyright 36 | * notice, this list of conditions and the following disclaimer. 37 | * 2. Redistributions in binary form must reproduce the above copyright 38 | * notice, this list of conditions and the following disclaimer in the 39 | * documentation and/or other materials provided with the distribution. 40 | * 3. The name of the author may not be used to endorse or promote products 41 | * derived from this software without specific prior written permission. 42 | * 43 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 44 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 45 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 46 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 47 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 48 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 49 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 50 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 51 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 52 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 53 | * 54 | */ 55 | 56 | .globl _cloned_csfg_get_platform_binary, _cloned_csproc_get_teamid, _jump_island1, _jump_island2, _jump_island3 57 | 58 | /* 1024 bytes space */ 59 | /* 64 bytes each line */ 60 | _cloned_csfg_get_platform_binary: 61 | .quad 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090 62 | .quad 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090 63 | .quad 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090 64 | .quad 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090 65 | .quad 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090 66 | .quad 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090 67 | .quad 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090 68 | .quad 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090 69 | .quad 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090 70 | .quad 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090 71 | .quad 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090 72 | .quad 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090 73 | .quad 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090 74 | .quad 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090 75 | .quad 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090 76 | .quad 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090 77 | /* unreachable */ 78 | int3 79 | 80 | _cloned_csproc_get_teamid: 81 | .quad 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090 82 | .quad 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090 83 | .quad 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090 84 | .quad 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090 85 | .quad 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090 86 | .quad 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090 87 | .quad 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090 88 | .quad 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090 89 | .quad 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090 90 | .quad 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090 91 | .quad 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090 92 | .quad 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090 93 | .quad 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090 94 | .quad 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090 95 | .quad 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090 96 | .quad 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090, 0x9090909090909090 97 | /* unreachable */ 98 | int3 99 | 100 | _jump_island1: 101 | movabsq $0, %rax 102 | jmp *%rax 103 | /* unreachable */ 104 | int3 105 | 106 | _jump_island2: 107 | movabsq $0, %rax 108 | jmp *%rax 109 | /* unreachable */ 110 | int3 111 | 112 | _jump_island3: 113 | movabsq $0, %rax 114 | jmp *%rax 115 | /* unreachable */ 116 | int3 117 | -------------------------------------------------------------------------------- /Gatekeerper/trustedbsd_hooks.c: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * ('-. .-') _ ('-. .-. .-') ('-. ('-. _ .-') _ (`-. ('-. _ .-') 4 | * ( OO ).-.( OO) ) _( OO) \ ( OO ) _( OO) _( OO)( \( -O ) ( (OO ) _( OO)( \( -O ) 5 | * ,----. / . --. // '._(,------.,--. ,--. (,------.(,------.,------. _.` \(,------.,------. 6 | * ' .-./-') | \-. \ |'--...__)| .---'| .' / | .---' | .---'| /`. '(__...--'' | .---'| /`. ' 7 | * | |_( O- ).-'-' | |'--. .--'| | | /, | | | | | / | | | / | | | | | / | | 8 | * | | .--, \ \| |_.' | | | (| '--. | ' _)(| '--. (| '--. | |_.' | | |_.' |(| '--. | |_.' | 9 | * (| | '. (_/ | .-. | | | | .--' | . \ | .--' | .--' | . '.' | .___.' | .--' | . '.' 10 | * | '--' | | | | | | | | `---.| |\ \ | `---. | `---.| |\ \ | | | `---.| |\ \ 11 | * `------' `--' `--' `--' `------'`--' '--' `------' `------'`--' '--' `--' `------'`--' '--' 12 | * 13 | * Gatekeerper 14 | * A kernel extension to mitigate Gatekeeper bypasses 15 | * Doesn't let linked (frameworks, libraries, bundles) unsigned code run if main binary is signed 16 | * 17 | * Untested with latest Gatekeeper bypass, too lazy to create a PoC of that 18 | * So I'm just guessing it will work, I'm pretty confident anyway :P 19 | * 20 | * Not guaranteed to be secure code! It might even destroy your computer but that is your problem! 21 | * 22 | * Created by reverser on 01/10/15. 23 | * Copyright (c) fG!, 2015. All rights reserved. 24 | * reverser@put.as - https://reverse.put.as 25 | * 26 | * trustedbsd_hooks.c 27 | * 28 | * Functions to replace AMFI hooks and control unsigned code 29 | * Where all the magic happens! 30 | * 31 | * Redistribution and use in source and binary forms, with or without 32 | * modification, are permitted provided that the following conditions 33 | * are met: 34 | * 1. Redistributions of source code must retain the above copyright 35 | * notice, this list of conditions and the following disclaimer. 36 | * 2. Redistributions in binary form must reproduce the above copyright 37 | * notice, this list of conditions and the following disclaimer in the 38 | * documentation and/or other materials provided with the distribution. 39 | * 3. The name of the author may not be used to endorse or promote products 40 | * derived from this software without specific prior written permission. 41 | * 42 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 43 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 44 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 45 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 46 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 47 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 48 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 49 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 50 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 51 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 52 | * 53 | */ 54 | 55 | #include "trustedbsd_hooks.h" 56 | 57 | #include 58 | #include 59 | #include 60 | #include 61 | #include 62 | #include 63 | #include 64 | #define CONFIG_MACF 1 65 | #include 66 | #include 67 | #include 68 | #include 69 | 70 | #include "logging.h" 71 | #include "configuration.h" 72 | #include "kernel_symbols.h" 73 | #include "utils.h" 74 | #include "functions_clone.h" 75 | 76 | extern const int version_major; 77 | extern const int version_minor; 78 | extern char cloned_csfg_get_platform_binary[], cloned_csproc_get_teamid[]; 79 | 80 | static void *original_amfi_hook = NULL; 81 | static int amfi_driver_position = -1; 82 | 83 | /* structures and definitions */ 84 | 85 | /* NOTE: these structures are internal to TrustedBSD and not exposed in public includes */ 86 | /* they are stable since the initial implementation but we still have some risk in defining them here */ 87 | struct mac_policy_list_element { 88 | struct mac_policy_conf *mpc; 89 | }; 90 | 91 | struct mac_policy_list { 92 | u_int numloaded; 93 | u_int max; 94 | u_int maxindex; 95 | u_int staticmax; 96 | u_int chunks; 97 | u_int freehint; 98 | struct mac_policy_list_element *entries; 99 | }; 100 | 101 | typedef struct mac_policy_list mac_policy_list_t; 102 | 103 | mach_vm_address_t g_mac_policy_list; /* address of mac_policy_list kernel variable */ 104 | 105 | /* the hook definition changed between Yosemite and El Capitan */ 106 | typedef int mpo_file_check_mmap_14_t( 107 | kauth_cred_t cred, 108 | struct fileglob *fg, 109 | struct label *label, 110 | int prot, 111 | int flags, 112 | int *maxprot 113 | ); 114 | 115 | mpo_file_check_mmap_14_t gatekeerper_hook_file_check_mmap_14; 116 | 117 | /* these are our modified prototypes for our modified cloned functions */ 118 | typedef int csfg_get_platform_binary_t(struct fileglob *fg); 119 | typedef int csproc_get_teamid_t(struct proc *p); 120 | 121 | #pragma mark - 122 | #pragma mark Start and stop functions 123 | 124 | /* 125 | * replace Yosemite AMFI check_file_mmap hook with our own to control the mmap hook 126 | * 127 | */ 128 | kern_return_t 129 | start_trustedbsd_hooks(void *d) 130 | { 131 | /* only support for Yosemite at the moment! */ 132 | if (version_major != 14) 133 | { 134 | ERROR_MSG("Unsupported OS X version!"); 135 | return KERN_FAILURE; 136 | } 137 | 138 | /* find where AMFI hooks are */ 139 | /* Only relevant for Yosemite, El Capitan, and maybe higher */ 140 | if (version_major == 14) // Yosemite 141 | { 142 | DEBUG_MSG("Replacing AMFI hook..."); 143 | 144 | /* clone the functions we need inside our modified hook */ 145 | if (clone_csfg_get_platform_binary() != KERN_SUCCESS) 146 | { 147 | ERROR_MSG("Can't clone csfg_get_platform_binary."); 148 | return KERN_FAILURE; 149 | } 150 | if (clone_csproc_get_teamid() != KERN_SUCCESS) 151 | { 152 | ERROR_MSG("Can't clone csproc_get_teamid."); 153 | return KERN_FAILURE; 154 | } 155 | 156 | /* we have the cloned functions ready 157 | * so next step is to exchange the AMFI hook with our version 158 | * that will use our cloned functions 159 | * and then return to the original AMFI hook 160 | */ 161 | 162 | /* retrieve location of TrustedBSD base structure */ 163 | SOLVE_KERNEL_VARIABLE("_mac_policy_list", g_mac_policy_list) 164 | /* find where AMFI is loaded */ 165 | struct mac_policy_list policy_list = *(struct mac_policy_list*)g_mac_policy_list; 166 | for (int i = 0; i < policy_list.numloaded; i++) 167 | { 168 | struct mac_policy_conf *mpc = policy_list.entries[i].mpc; 169 | if (mpc != NULL) 170 | { 171 | if (strcmp(mpc->mpc_name, "AMFI") == 0) 172 | { 173 | DEBUG_MSG("Found AMFI driver %d.", i); 174 | amfi_driver_position = i; 175 | break; 176 | } 177 | } 178 | } 179 | /* if we don't know where AMFI is we can't do anything */ 180 | if (amfi_driver_position == -1) 181 | { 182 | ERROR_MSG("No idea where AMFI position is. Can't proceed!"); 183 | return KERN_FAILURE; 184 | } 185 | 186 | /* exchange hook inside AMFI driver */ 187 | /* hook prototype changed between Yosemite and El Capitan */ 188 | DEBUG_MSG("Ready to exchange AMFI hooks..."); 189 | disable_interrupts(); 190 | struct mac_policy_conf *temp = policy_list.entries[amfi_driver_position].mpc; 191 | struct mac_policy_ops *ops = temp->mpc_ops; 192 | switch (version_major) { 193 | case 14: 194 | { 195 | original_amfi_hook = (void*)ops->mpo_file_check_mmap; 196 | ops->mpo_file_check_mmap = (void*)gatekeerper_hook_file_check_mmap_14; 197 | break; 198 | } 199 | default: 200 | { 201 | ERROR_MSG("Unsupported OS X version."); 202 | enable_interrupts(); 203 | return KERN_FAILURE; 204 | } 205 | } 206 | enable_interrupts(); 207 | DEBUG_MSG("Replaced AMFI hook, Gatekeerper is now active."); 208 | return KERN_SUCCESS; 209 | } 210 | 211 | return KERN_FAILURE; 212 | } 213 | 214 | /* restore original AMFI hook */ 215 | kern_return_t 216 | stop_trustedbsd_hooks(void) 217 | { 218 | if (version_major >= 14 && amfi_driver_position != -1) 219 | { 220 | disable_interrupts(); 221 | struct mac_policy_list policy_list = *(struct mac_policy_list*)g_mac_policy_list; 222 | struct mac_policy_conf *temp = policy_list.entries[amfi_driver_position].mpc; 223 | struct mac_policy_ops *ops = temp->mpc_ops; 224 | switch (version_major) { 225 | case 14: 226 | { 227 | ops->mpo_file_check_mmap = (void*)original_amfi_hook; 228 | break; 229 | } 230 | default: 231 | { 232 | ERROR_MSG("Unsupported OS X version."); 233 | enable_interrupts(); 234 | return KERN_FAILURE; 235 | } 236 | } 237 | enable_interrupts(); 238 | DEBUG_MSG("AMFI original hook restored."); 239 | } 240 | return KERN_SUCCESS; 241 | } 242 | 243 | #pragma mark - 244 | #pragma mark The Hooks 245 | 246 | /* Our Yosemite AMFI hook*/ 247 | int 248 | gatekeerper_hook_file_check_mmap_14( 249 | kauth_cred_t cred, 250 | struct fileglob *fg, 251 | struct label *label, 252 | int prot, 253 | int flags, 254 | int *maxprot 255 | ) 256 | { 257 | char binary_path[MAXPATHLEN] = {0}; 258 | int pathbuff_len = sizeof(binary_path); 259 | 260 | int result = 0; 261 | 262 | /* try to get some info about what is being mmap'ed */ 263 | result = _csfg_get_path(fg, binary_path, &pathbuff_len); 264 | /* we only want to mess around with executable stuff */ 265 | if (result == 0 && (prot & 0x4)) 266 | { 267 | /* the platform binary field is not good enough for our purpose 268 | * so we need to use our cloned and patched functions 269 | * to understand if the mmap'ed binary is code signed 270 | * and if the main proc is also code signed 271 | * 272 | * not pretty but there's no full support in XNU to gather useful info from 273 | * code signing 274 | * It has improved in El Capitan but far from useful to external devs and hackers ;-) 275 | */ 276 | 277 | /* first, get the status of the main proc */ 278 | proc_t p = current_proc(); 279 | if (p == (struct proc *)0) 280 | { 281 | ERROR_MSG("Can't retrieve current proc."); 282 | /* XXX: deny access */ 283 | return 1; 284 | } 285 | 286 | /* verify is main process is signed or not 287 | * this could also be used to deny running any unsigned process 288 | */ 289 | int is_main_signed = ((csproc_get_teamid_t*)(void*)(cloned_csproc_get_teamid))(p); 290 | /* just some debug code, can be removed */ 291 | if (is_main_signed == 0) 292 | { 293 | DEBUG_MSG("current_proc is not signed"); 294 | } 295 | 296 | /* verify if the binary code trying to be mapped is signed or not 297 | * we don't let unsigned code run if the main binary is signed 298 | */ 299 | int is_mapped_signed = ((csfg_get_platform_binary_t*)cloned_csfg_get_platform_binary)(fg); 300 | if (is_mapped_signed == 0 && is_main_signed == 1) 301 | { 302 | ERROR_MSG("mmap'ed executable %s is not code signed for a signed main proc", binary_path); 303 | /* XXX: this will make the process crash because it can't load the linked external code */ 304 | /* shouldn't we just kill it? we have current_proc() anyway */ 305 | return 1; 306 | } 307 | } 308 | /* we can't get info about what is being mapped 309 | * what is the decision here? deny access? 310 | * for now just log the error and pass control to original AMFI hook 311 | */ 312 | else if (result != 0) 313 | { 314 | ERROR_MSG("Failed to get path: %d", result); 315 | } 316 | 317 | /* pass control back to AMFI */ 318 | return ((mpo_file_check_mmap_14_t*)original_amfi_hook)(cred, fg, label, prot, flags, maxprot); 319 | } 320 | -------------------------------------------------------------------------------- /Gatekeerper.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 7B94C3F11BBDB0550084BCCE /* Gatekeerper.c in Sources */ = {isa = PBXBuildFile; fileRef = 7B94C3F01BBDB0550084BCCE /* Gatekeerper.c */; }; 11 | 7B94C4271BBDB0A90084BCCE /* configuration.h in Headers */ = {isa = PBXBuildFile; fileRef = 7B94C41D1BBDB0A90084BCCE /* configuration.h */; }; 12 | 7B94C42B1BBDB0A90084BCCE /* kernel_symbols.c in Sources */ = {isa = PBXBuildFile; fileRef = 7B94C4211BBDB0A90084BCCE /* kernel_symbols.c */; }; 13 | 7B94C42C1BBDB0A90084BCCE /* kernel_symbols.h in Headers */ = {isa = PBXBuildFile; fileRef = 7B94C4221BBDB0A90084BCCE /* kernel_symbols.h */; }; 14 | 7B94C42D1BBDB0A90084BCCE /* logging.h in Headers */ = {isa = PBXBuildFile; fileRef = 7B94C4231BBDB0A90084BCCE /* logging.h */; }; 15 | 7B94C42F1BBDB0A90084BCCE /* trustedbsd_hooks.c in Sources */ = {isa = PBXBuildFile; fileRef = 7B94C4251BBDB0A90084BCCE /* trustedbsd_hooks.c */; }; 16 | 7B94C4301BBDB0A90084BCCE /* trustedbsd_hooks.h in Headers */ = {isa = PBXBuildFile; fileRef = 7B94C4261BBDB0A90084BCCE /* trustedbsd_hooks.h */; }; 17 | 7BAEA31D1BF0BB050002C5AC /* utils.c in Sources */ = {isa = PBXBuildFile; fileRef = 7BAEA31B1BF0BB050002C5AC /* utils.c */; }; 18 | 7BAEA31E1BF0BB050002C5AC /* utils.h in Headers */ = {isa = PBXBuildFile; fileRef = 7BAEA31C1BF0BB050002C5AC /* utils.h */; }; 19 | 7BF2AE151BC24FA400FD6D8B /* functions_clone.c in Sources */ = {isa = PBXBuildFile; fileRef = 7BF2AE131BC24FA400FD6D8B /* functions_clone.c */; }; 20 | 7BF2AE161BC24FA500FD6D8B /* functions_clone.h in Headers */ = {isa = PBXBuildFile; fileRef = 7BF2AE141BC24FA400FD6D8B /* functions_clone.h */; }; 21 | 7BF2AE181BC252DF00FD6D8B /* cloned_functions.s in Sources */ = {isa = PBXBuildFile; fileRef = 7BF2AE171BC252DF00FD6D8B /* cloned_functions.s */; }; 22 | /* End PBXBuildFile section */ 23 | 24 | /* Begin PBXFileReference section */ 25 | 7B94C3ED1BBDB0550084BCCE /* Gatekeerper.kext */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Gatekeerper.kext; sourceTree = BUILT_PRODUCTS_DIR; }; 26 | 7B94C3F01BBDB0550084BCCE /* Gatekeerper.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = Gatekeerper.c; sourceTree = ""; }; 27 | 7B94C3F21BBDB0550084BCCE /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 28 | 7B94C41D1BBDB0A90084BCCE /* configuration.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = configuration.h; sourceTree = ""; }; 29 | 7B94C4211BBDB0A90084BCCE /* kernel_symbols.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = kernel_symbols.c; sourceTree = ""; }; 30 | 7B94C4221BBDB0A90084BCCE /* kernel_symbols.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = kernel_symbols.h; sourceTree = ""; }; 31 | 7B94C4231BBDB0A90084BCCE /* logging.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = logging.h; sourceTree = ""; }; 32 | 7B94C4251BBDB0A90084BCCE /* trustedbsd_hooks.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = trustedbsd_hooks.c; sourceTree = ""; }; 33 | 7B94C4261BBDB0A90084BCCE /* trustedbsd_hooks.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = trustedbsd_hooks.h; sourceTree = ""; }; 34 | 7BAEA31B1BF0BB050002C5AC /* utils.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = utils.c; sourceTree = ""; }; 35 | 7BAEA31C1BF0BB050002C5AC /* utils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = utils.h; sourceTree = ""; }; 36 | 7BF2AE131BC24FA400FD6D8B /* functions_clone.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = functions_clone.c; sourceTree = ""; }; 37 | 7BF2AE141BC24FA400FD6D8B /* functions_clone.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = functions_clone.h; sourceTree = ""; }; 38 | 7BF2AE171BC252DF00FD6D8B /* cloned_functions.s */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; path = cloned_functions.s; sourceTree = ""; }; 39 | /* End PBXFileReference section */ 40 | 41 | /* Begin PBXFrameworksBuildPhase section */ 42 | 7B94C3E91BBDB0550084BCCE /* Frameworks */ = { 43 | isa = PBXFrameworksBuildPhase; 44 | buildActionMask = 2147483647; 45 | files = ( 46 | ); 47 | runOnlyForDeploymentPostprocessing = 0; 48 | }; 49 | /* End PBXFrameworksBuildPhase section */ 50 | 51 | /* Begin PBXGroup section */ 52 | 7B94C3E31BBDB0550084BCCE = { 53 | isa = PBXGroup; 54 | children = ( 55 | 7B94C3EF1BBDB0550084BCCE /* Gatekeerper */, 56 | 7B94C3EE1BBDB0550084BCCE /* Products */, 57 | ); 58 | sourceTree = ""; 59 | }; 60 | 7B94C3EE1BBDB0550084BCCE /* Products */ = { 61 | isa = PBXGroup; 62 | children = ( 63 | 7B94C3ED1BBDB0550084BCCE /* Gatekeerper.kext */, 64 | ); 65 | name = Products; 66 | sourceTree = ""; 67 | }; 68 | 7B94C3EF1BBDB0550084BCCE /* Gatekeerper */ = { 69 | isa = PBXGroup; 70 | children = ( 71 | 7B94C3F01BBDB0550084BCCE /* Gatekeerper.c */, 72 | 7B94C41D1BBDB0A90084BCCE /* configuration.h */, 73 | 7B94C4231BBDB0A90084BCCE /* logging.h */, 74 | 7B94C4211BBDB0A90084BCCE /* kernel_symbols.c */, 75 | 7B94C4221BBDB0A90084BCCE /* kernel_symbols.h */, 76 | 7B94C4251BBDB0A90084BCCE /* trustedbsd_hooks.c */, 77 | 7B94C4261BBDB0A90084BCCE /* trustedbsd_hooks.h */, 78 | 7BF2AE131BC24FA400FD6D8B /* functions_clone.c */, 79 | 7BF2AE141BC24FA400FD6D8B /* functions_clone.h */, 80 | 7BAEA31B1BF0BB050002C5AC /* utils.c */, 81 | 7BAEA31C1BF0BB050002C5AC /* utils.h */, 82 | 7BF2AE171BC252DF00FD6D8B /* cloned_functions.s */, 83 | 7B94C3F21BBDB0550084BCCE /* Info.plist */, 84 | ); 85 | path = Gatekeerper; 86 | sourceTree = ""; 87 | }; 88 | /* End PBXGroup section */ 89 | 90 | /* Begin PBXHeadersBuildPhase section */ 91 | 7B94C3EA1BBDB0550084BCCE /* Headers */ = { 92 | isa = PBXHeadersBuildPhase; 93 | buildActionMask = 2147483647; 94 | files = ( 95 | 7BAEA31E1BF0BB050002C5AC /* utils.h in Headers */, 96 | 7B94C42D1BBDB0A90084BCCE /* logging.h in Headers */, 97 | 7BF2AE161BC24FA500FD6D8B /* functions_clone.h in Headers */, 98 | 7B94C42C1BBDB0A90084BCCE /* kernel_symbols.h in Headers */, 99 | 7B94C4271BBDB0A90084BCCE /* configuration.h in Headers */, 100 | 7B94C4301BBDB0A90084BCCE /* trustedbsd_hooks.h in Headers */, 101 | ); 102 | runOnlyForDeploymentPostprocessing = 0; 103 | }; 104 | /* End PBXHeadersBuildPhase section */ 105 | 106 | /* Begin PBXNativeTarget section */ 107 | 7B94C3EC1BBDB0550084BCCE /* Gatekeerper */ = { 108 | isa = PBXNativeTarget; 109 | buildConfigurationList = 7B94C3F51BBDB0550084BCCE /* Build configuration list for PBXNativeTarget "Gatekeerper" */; 110 | buildPhases = ( 111 | 7B94C3E81BBDB0550084BCCE /* Sources */, 112 | 7B94C3E91BBDB0550084BCCE /* Frameworks */, 113 | 7B94C3EA1BBDB0550084BCCE /* Headers */, 114 | 7B94C3EB1BBDB0550084BCCE /* Resources */, 115 | ); 116 | buildRules = ( 117 | ); 118 | dependencies = ( 119 | ); 120 | name = Gatekeerper; 121 | productName = Gatekeerper; 122 | productReference = 7B94C3ED1BBDB0550084BCCE /* Gatekeerper.kext */; 123 | productType = "com.apple.product-type.kernel-extension"; 124 | }; 125 | /* End PBXNativeTarget section */ 126 | 127 | /* Begin PBXProject section */ 128 | 7B94C3E41BBDB0550084BCCE /* Project object */ = { 129 | isa = PBXProject; 130 | attributes = { 131 | LastUpgradeCheck = 0700; 132 | ORGANIZATIONNAME = Put.as; 133 | TargetAttributes = { 134 | 7B94C3EC1BBDB0550084BCCE = { 135 | CreatedOnToolsVersion = 7.0.1; 136 | }; 137 | }; 138 | }; 139 | buildConfigurationList = 7B94C3E71BBDB0550084BCCE /* Build configuration list for PBXProject "Gatekeerper" */; 140 | compatibilityVersion = "Xcode 3.2"; 141 | developmentRegion = English; 142 | hasScannedForEncodings = 0; 143 | knownRegions = ( 144 | en, 145 | ); 146 | mainGroup = 7B94C3E31BBDB0550084BCCE; 147 | productRefGroup = 7B94C3EE1BBDB0550084BCCE /* Products */; 148 | projectDirPath = ""; 149 | projectRoot = ""; 150 | targets = ( 151 | 7B94C3EC1BBDB0550084BCCE /* Gatekeerper */, 152 | ); 153 | }; 154 | /* End PBXProject section */ 155 | 156 | /* Begin PBXResourcesBuildPhase section */ 157 | 7B94C3EB1BBDB0550084BCCE /* Resources */ = { 158 | isa = PBXResourcesBuildPhase; 159 | buildActionMask = 2147483647; 160 | files = ( 161 | ); 162 | runOnlyForDeploymentPostprocessing = 0; 163 | }; 164 | /* End PBXResourcesBuildPhase section */ 165 | 166 | /* Begin PBXSourcesBuildPhase section */ 167 | 7B94C3E81BBDB0550084BCCE /* Sources */ = { 168 | isa = PBXSourcesBuildPhase; 169 | buildActionMask = 2147483647; 170 | files = ( 171 | 7B94C42F1BBDB0A90084BCCE /* trustedbsd_hooks.c in Sources */, 172 | 7B94C42B1BBDB0A90084BCCE /* kernel_symbols.c in Sources */, 173 | 7BF2AE181BC252DF00FD6D8B /* cloned_functions.s in Sources */, 174 | 7BAEA31D1BF0BB050002C5AC /* utils.c in Sources */, 175 | 7B94C3F11BBDB0550084BCCE /* Gatekeerper.c in Sources */, 176 | 7BF2AE151BC24FA400FD6D8B /* functions_clone.c in Sources */, 177 | ); 178 | runOnlyForDeploymentPostprocessing = 0; 179 | }; 180 | /* End PBXSourcesBuildPhase section */ 181 | 182 | /* Begin XCBuildConfiguration section */ 183 | 7B94C3F31BBDB0550084BCCE /* Debug */ = { 184 | isa = XCBuildConfiguration; 185 | buildSettings = { 186 | ALWAYS_SEARCH_USER_PATHS = NO; 187 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 188 | CLANG_CXX_LIBRARY = "libc++"; 189 | CLANG_ENABLE_MODULES = YES; 190 | CLANG_ENABLE_OBJC_ARC = YES; 191 | CLANG_WARN_BOOL_CONVERSION = YES; 192 | CLANG_WARN_CONSTANT_CONVERSION = YES; 193 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 194 | CLANG_WARN_EMPTY_BODY = YES; 195 | CLANG_WARN_ENUM_CONVERSION = YES; 196 | CLANG_WARN_INT_CONVERSION = YES; 197 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 198 | CLANG_WARN_UNREACHABLE_CODE = YES; 199 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 200 | COPY_PHASE_STRIP = NO; 201 | DEBUG_INFORMATION_FORMAT = dwarf; 202 | ENABLE_STRICT_OBJC_MSGSEND = YES; 203 | ENABLE_TESTABILITY = YES; 204 | GCC_C_LANGUAGE_STANDARD = gnu99; 205 | GCC_DYNAMIC_NO_PIC = NO; 206 | GCC_NO_COMMON_BLOCKS = YES; 207 | GCC_OPTIMIZATION_LEVEL = 0; 208 | GCC_PREPROCESSOR_DEFINITIONS = ( 209 | "DEBUG=1", 210 | "$(inherited)", 211 | ); 212 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 213 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 214 | GCC_WARN_UNDECLARED_SELECTOR = YES; 215 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 216 | GCC_WARN_UNUSED_FUNCTION = YES; 217 | GCC_WARN_UNUSED_VARIABLE = YES; 218 | MACOSX_DEPLOYMENT_TARGET = 10.10; 219 | MTL_ENABLE_DEBUG_INFO = YES; 220 | ONLY_ACTIVE_ARCH = YES; 221 | SDKROOT = macosx; 222 | }; 223 | name = Debug; 224 | }; 225 | 7B94C3F41BBDB0550084BCCE /* Release */ = { 226 | isa = XCBuildConfiguration; 227 | buildSettings = { 228 | ALWAYS_SEARCH_USER_PATHS = NO; 229 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 230 | CLANG_CXX_LIBRARY = "libc++"; 231 | CLANG_ENABLE_MODULES = YES; 232 | CLANG_ENABLE_OBJC_ARC = YES; 233 | CLANG_WARN_BOOL_CONVERSION = YES; 234 | CLANG_WARN_CONSTANT_CONVERSION = YES; 235 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 236 | CLANG_WARN_EMPTY_BODY = YES; 237 | CLANG_WARN_ENUM_CONVERSION = YES; 238 | CLANG_WARN_INT_CONVERSION = YES; 239 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 240 | CLANG_WARN_UNREACHABLE_CODE = YES; 241 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 242 | COPY_PHASE_STRIP = NO; 243 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 244 | ENABLE_NS_ASSERTIONS = NO; 245 | ENABLE_STRICT_OBJC_MSGSEND = YES; 246 | GCC_C_LANGUAGE_STANDARD = gnu99; 247 | GCC_NO_COMMON_BLOCKS = YES; 248 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 249 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 250 | GCC_WARN_UNDECLARED_SELECTOR = YES; 251 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 252 | GCC_WARN_UNUSED_FUNCTION = YES; 253 | GCC_WARN_UNUSED_VARIABLE = YES; 254 | MACOSX_DEPLOYMENT_TARGET = 10.10; 255 | MTL_ENABLE_DEBUG_INFO = NO; 256 | SDKROOT = macosx; 257 | }; 258 | name = Release; 259 | }; 260 | 7B94C3F61BBDB0550084BCCE /* Debug */ = { 261 | isa = XCBuildConfiguration; 262 | buildSettings = { 263 | CODE_SIGN_IDENTITY = "Mac Developer"; 264 | INFOPLIST_FILE = Gatekeerper/Info.plist; 265 | MODULE_NAME = com.put.as.Gatekeerper; 266 | MODULE_START = Gatekeerper_start; 267 | MODULE_STOP = Gatekeerper_stop; 268 | MODULE_VERSION = 1.0.0d1; 269 | PRODUCT_BUNDLE_IDENTIFIER = com.put.as.Gatekeerper; 270 | PRODUCT_NAME = "$(TARGET_NAME)"; 271 | WRAPPER_EXTENSION = kext; 272 | }; 273 | name = Debug; 274 | }; 275 | 7B94C3F71BBDB0550084BCCE /* Release */ = { 276 | isa = XCBuildConfiguration; 277 | buildSettings = { 278 | CODE_SIGN_IDENTITY = "Mac Developer"; 279 | INFOPLIST_FILE = Gatekeerper/Info.plist; 280 | MODULE_NAME = com.put.as.Gatekeerper; 281 | MODULE_START = Gatekeerper_start; 282 | MODULE_STOP = Gatekeerper_stop; 283 | MODULE_VERSION = 1.0.0d1; 284 | PRODUCT_BUNDLE_IDENTIFIER = com.put.as.Gatekeerper; 285 | PRODUCT_NAME = "$(TARGET_NAME)"; 286 | WRAPPER_EXTENSION = kext; 287 | }; 288 | name = Release; 289 | }; 290 | /* End XCBuildConfiguration section */ 291 | 292 | /* Begin XCConfigurationList section */ 293 | 7B94C3E71BBDB0550084BCCE /* Build configuration list for PBXProject "Gatekeerper" */ = { 294 | isa = XCConfigurationList; 295 | buildConfigurations = ( 296 | 7B94C3F31BBDB0550084BCCE /* Debug */, 297 | 7B94C3F41BBDB0550084BCCE /* Release */, 298 | ); 299 | defaultConfigurationIsVisible = 0; 300 | defaultConfigurationName = Release; 301 | }; 302 | 7B94C3F51BBDB0550084BCCE /* Build configuration list for PBXNativeTarget "Gatekeerper" */ = { 303 | isa = XCConfigurationList; 304 | buildConfigurations = ( 305 | 7B94C3F61BBDB0550084BCCE /* Debug */, 306 | 7B94C3F71BBDB0550084BCCE /* Release */, 307 | ); 308 | defaultConfigurationIsVisible = 0; 309 | defaultConfigurationName = Release; 310 | }; 311 | /* End XCConfigurationList section */ 312 | }; 313 | rootObject = 7B94C3E41BBDB0550084BCCE /* Project object */; 314 | } 315 | -------------------------------------------------------------------------------- /Gatekeerper/kernel_symbols.c: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * ('-. .-') _ ('-. .-. .-') ('-. ('-. _ .-') _ (`-. ('-. _ .-') 4 | * ( OO ).-.( OO) ) _( OO) \ ( OO ) _( OO) _( OO)( \( -O ) ( (OO ) _( OO)( \( -O ) 5 | * ,----. / . --. // '._(,------.,--. ,--. (,------.(,------.,------. _.` \(,------.,------. 6 | * ' .-./-') | \-. \ |'--...__)| .---'| .' / | .---' | .---'| /`. '(__...--'' | .---'| /`. ' 7 | * | |_( O- ).-'-' | |'--. .--'| | | /, | | | | | / | | | / | | | | | / | | 8 | * | | .--, \ \| |_.' | | | (| '--. | ' _)(| '--. (| '--. | |_.' | | |_.' |(| '--. | |_.' | 9 | * (| | '. (_/ | .-. | | | | .--' | . \ | .--' | .--' | . '.' | .___.' | .--' | . '.' 10 | * | '--' | | | | | | | | `---.| |\ \ | `---. | `---.| |\ \ | | | `---.| |\ \ 11 | * `------' `--' `--' `--' `------'`--' '--' `------' `------'`--' '--' `--' `------'`--' '--' 12 | * 13 | * Gatekeerper 14 | * A kernel extension to mitigate Gatekeeper bypasses 15 | * Doesn't let linked (frameworks, libraries, bundles) unsigned code run if main binary is signed 16 | * 17 | * Untested with latest Gatekeeper bypass, too lazy to create a PoC of that 18 | * So I'm just guessing it will work, I'm pretty confident anyway :P 19 | * 20 | * Not guaranteed to be secure code! It might even destroy your computer but that is your problem! 21 | * 22 | * Created by reverser on 01/10/15. 23 | * Copyright (c) fG!, 2015. All rights reserved. 24 | * reverser@put.as - https://reverse.put.as 25 | * 26 | * kernel_symbols.c 27 | * 28 | * Functions to solve kernel symbols 29 | * 30 | * Redistribution and use in source and binary forms, with or without 31 | * modification, are permitted provided that the following conditions 32 | * are met: 33 | * 1. Redistributions of source code must retain the above copyright 34 | * notice, this list of conditions and the following disclaimer. 35 | * 2. Redistributions in binary form must reproduce the above copyright 36 | * notice, this list of conditions and the following disclaimer in the 37 | * documentation and/or other materials provided with the distribution. 38 | * 3. The name of the author may not be used to endorse or promote products 39 | * derived from this software without specific prior written permission. 40 | * 41 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 42 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 43 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 44 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 45 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 46 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 47 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 48 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 49 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 50 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 51 | * 52 | */ 53 | 54 | #include "kernel_symbols.h" 55 | 56 | #include 57 | #include 58 | #include 59 | #include 60 | #include 61 | #include 62 | #include 63 | #include 64 | #include 65 | 66 | #include "logging.h" 67 | 68 | /* location of kernel in filesystem */ 69 | #define MACH_KERNEL "/System/Library/Kernels/kernel" 70 | 71 | /* structures and definitions */ 72 | /* 16 bytes IDT descriptor, used for 32 and 64 bits kernels (64 bit capable cpus!) */ 73 | struct descriptor_idt 74 | { 75 | uint16_t offset_low; 76 | uint16_t seg_selector; 77 | uint8_t reserved; 78 | uint8_t flag; 79 | uint16_t offset_middle; 80 | uint32_t offset_high; 81 | uint32_t reserved2; 82 | }; 83 | 84 | /* global variables */ 85 | /* kernel symbols to be manually solved */ 86 | int (*_csfg_get_path)(struct fileglob *fg, char *path, int *len); 87 | const char * (*_csfg_get_teamid)(struct fileglob *fg); 88 | int (*_csfg_get_platform_binary)(struct fileglob *fg); 89 | struct cs_blob * (*_csproc_get_blob)(struct proc *p); 90 | const char * (*_csproc_get_teamid)(struct proc *p); 91 | struct cs_blob * (*_ubc_cs_blob_get)(struct vnode *vp, cpu_type_t cputype, off_t offset); 92 | 93 | /* external global variables */ 94 | extern struct kernel_info g_kinfo; 95 | 96 | /* local functions */ 97 | static kern_return_t get_kernel_mach_header(void *buffer, vnode_t kernel_vnode); 98 | static kern_return_t process_kernel_mach_header(void *kernel_header, struct kernel_info *kinfo); 99 | static kern_return_t get_kernel_linkedit(vnode_t kernel_vnode, struct kernel_info *kinfo); 100 | static mach_vm_address_t calculate_int80address(const mach_vm_address_t idt_address); 101 | static kern_return_t get_running_text_address(struct kernel_info *kinfo); 102 | static mach_vm_address_t find_kernel_base(const mach_vm_address_t int80_address); 103 | static void get_addr_idt (mach_vm_address_t* idt); 104 | 105 | # pragma mark Exported functions 106 | 107 | /* 108 | * entrypoint function to read necessary information from running kernel and kernel at disk 109 | * such as kaslr slide, linkedit location 110 | * the reads from disk are implemented using the available KPI VFS functions 111 | */ 112 | kern_return_t 113 | init_kernel_info(void) 114 | { 115 | struct kernel_info *kinfo = &g_kinfo; 116 | /* lookup vnode for /mach_kernel - remember to free reference count if successful */ 117 | vnode_t kernel_vnode = NULLVP; 118 | /* 119 | * if we want to put the driver booting very early we need to create our own context 120 | * instead of passing NULL as usual 121 | * the reference count increases so we must release it later 122 | * the vfs_context_create() call is valid because it's made in a process context 123 | */ 124 | vfs_context_t myvfs_context = vfs_context_create(NULL); 125 | if (myvfs_context == NULL) 126 | { 127 | ERROR_MSG("Failed to create context."); 128 | return KERN_FAILURE; 129 | } 130 | /* try to locate the kernel in one of the two valid locations */ 131 | kern_return_t kr = 0; 132 | kr = vnode_lookup(MACH_KERNEL, 0, &kernel_vnode, myvfs_context); 133 | if (kr != KERN_SUCCESS) 134 | { 135 | ERROR_MSG("Kernel vnode lookup failed!"); 136 | vfs_context_rele(myvfs_context); 137 | return KERN_FAILURE; 138 | } 139 | 140 | /* from this point failure is handled by goto failure; */ 141 | 142 | /* 143 | * the first thing we do is to read 4k of the kernel header so we can extract 144 | * a bunch of information and __LINKEDIT location 145 | */ 146 | void *kernel_header = _MALLOC(PAGE_SIZE_64, M_TEMP, M_WAITOK | M_ZERO); 147 | if (kernel_header == NULL) 148 | { 149 | ERROR_MSG("Can't allocate memory for initial kernel mach-o header."); 150 | goto failure; 151 | } 152 | 153 | if (get_kernel_mach_header(kernel_header, kernel_vnode) != KERN_SUCCESS) 154 | { 155 | ERROR_MSG("Failed to get initial kernel mach-o header!"); 156 | goto failure; 157 | } 158 | if (process_kernel_mach_header(kernel_header, kinfo) != KERN_SUCCESS) 159 | { 160 | ERROR_MSG("Failed to process kernel mach-o header!"); 161 | goto failure; 162 | } 163 | 164 | /* compute kaslr slide - difference between __TEXT in memory and disk*/ 165 | if (get_running_text_address(kinfo) != KERN_SUCCESS) 166 | { 167 | ERROR_MSG("Can't find kernel's running text address!"); 168 | goto failure; 169 | } 170 | kinfo->kaslr_slide = kinfo->memory_text_addr - kinfo->disk_text_addr; 171 | if (kinfo->kaslr_slide > kinfo->memory_text_addr) 172 | { 173 | ERROR_MSG("overflow?"); 174 | goto failure; 175 | } 176 | 177 | DEBUG_MSG("Kernel ASLR slide: 0x%llx", kinfo->kaslr_slide); 178 | /* 179 | * we know the location of linkedit and offsets into symbols and their strings 180 | * now we need to read linkedit into a buffer so we can process it later 181 | * __LINKEDIT total size is around 1MB 182 | * we should free this buffer later when we don't need anymore to solve symbols 183 | */ 184 | kinfo->linkedit_buf = _MALLOC(kinfo->linkedit_size, M_TEMP, M_WAITOK | M_ZERO); 185 | if (kinfo->linkedit_buf == NULL) 186 | { 187 | ERROR_MSG("Could not allocate enough memory for __LINKEDIT segment"); 188 | goto failure; 189 | } 190 | if (get_kernel_linkedit(kernel_vnode, kinfo) != KERN_SUCCESS) 191 | { 192 | ERROR_MSG("Failed to get kernel linkedit info!"); 193 | goto failure; 194 | } 195 | 196 | success: 197 | /* kinfo->linkedit_buf should be freed by the caller */ 198 | _FREE(kernel_header, M_TEMP); 199 | /* 200 | * drop the iocount due to vnode_lookup() 201 | * we must do this else machine will block on shutdown/reboot 202 | */ 203 | vnode_put(kernel_vnode); 204 | vfs_context_rele(myvfs_context); 205 | return KERN_SUCCESS; 206 | 207 | failure: 208 | if (kinfo->linkedit_buf) 209 | { 210 | _FREE(kinfo->linkedit_buf, M_TEMP); 211 | } 212 | if (kernel_header) 213 | { 214 | _FREE(kernel_header, M_TEMP); 215 | } 216 | vnode_put(kernel_vnode); 217 | vfs_context_rele(myvfs_context); 218 | return KERN_FAILURE; 219 | } 220 | 221 | /* 222 | * cleanup the kernel info buffer to avoid memory leak. 223 | * there's nothing else to cleanup here, for now 224 | */ 225 | kern_return_t 226 | cleanup_kernel_info(void) 227 | { 228 | DEBUG_MSG("Cleaning up kernel info..."); 229 | if (g_kinfo.linkedit_buf) 230 | { 231 | _FREE(g_kinfo.linkedit_buf, M_TEMP); 232 | } 233 | DEBUG_MSG("All done cleaning up kernel info."); 234 | return KERN_SUCCESS; 235 | } 236 | 237 | /* 238 | * function to solve a kernel symbol, 64 bits kernels support ONLY! 239 | */ 240 | kern_return_t 241 | solve_kernel_symbol(char *symbol_to_solve, void **symbol_ptr) 242 | { 243 | if (symbol_to_solve == NULL || symbol_ptr == NULL) 244 | { 245 | ERROR_MSG("Bad parameters!"); 246 | return KERN_FAILURE; 247 | } 248 | 249 | struct kernel_info *kinfo = &g_kinfo; 250 | struct nlist_64 *nlist = NULL; 251 | 252 | if (kinfo == NULL || kinfo->linkedit_buf == NULL) 253 | { 254 | ERROR_MSG("g_kernel_info is null or no kernel __LINKEDIT buffer available!"); 255 | return KERN_FAILURE; 256 | } 257 | // symbols and strings offsets into LINKEDIT 258 | // we just read the __LINKEDIT but fileoff values are relative to the full /mach_kernel 259 | // subtract the base of LINKEDIT to fix the value into our buffer 260 | mach_vm_address_t symbol_off = kinfo->symboltable_fileoff - kinfo->linkedit_fileoff; 261 | mach_vm_address_t string_off = kinfo->stringtable_fileoff - kinfo->linkedit_fileoff; 262 | if (symbol_off > kinfo->symboltable_fileoff || string_off > kinfo->stringtable_fileoff) 263 | { 264 | ERROR_MSG("overflow?"); 265 | return KERN_FAILURE; 266 | 267 | } 268 | // search for the symbol and get its location if found 269 | for (uint32_t i = 0; i < kinfo->symboltable_nr_symbols; i++) 270 | { 271 | // get the pointer to the symbol entry and extract its symbol string 272 | nlist = (struct nlist_64*)((char*)kinfo->linkedit_buf + symbol_off + i * sizeof(struct nlist_64)); 273 | char *symbol_string = ((char*)kinfo->linkedit_buf + string_off + nlist->n_un.n_strx); 274 | // find if symbol matches 275 | if (strncmp(symbol_to_solve, symbol_string, strlen(symbol_to_solve)) == 0) 276 | { 277 | /* the symbols values are without kernel ASLR so we need to add it */ 278 | mach_vm_address_t solved_addr = nlist->n_value + kinfo->kaslr_slide; 279 | /* verify if symbol is in the kernel __text section */ 280 | mach_vm_address_t floor = kinfo->memory_text_addr; 281 | mach_vm_address_t cap = kinfo->memory_text_addr + kinfo->text_size; 282 | if (solved_addr < floor || solved_addr > cap) 283 | { 284 | ERROR_MSG("Solved symbol address doesn't belong to running __text section. Something is wrong!"); 285 | return KERN_FAILURE; 286 | } 287 | *symbol_ptr = (void*)solved_addr; 288 | return KERN_SUCCESS; 289 | } 290 | } 291 | /* failure */ 292 | ERROR_MSG("Failed to solve symbol %s", symbol_to_solve); 293 | return KERN_FAILURE; 294 | } 295 | 296 | /* 297 | * function to solve a kernel variable symbol, 64 bits kernels support ONLY! 298 | */ 299 | kern_return_t 300 | solve_kernel_variable(char *symbol_to_solve, mach_vm_address_t *output) 301 | { 302 | if (symbol_to_solve == NULL || output == NULL) 303 | { 304 | ERROR_MSG("Bad parameters!"); 305 | return KERN_FAILURE; 306 | } 307 | 308 | struct kernel_info *kinfo = &g_kinfo; 309 | struct nlist_64 *nlist = NULL; 310 | 311 | if (kinfo == NULL || kinfo->linkedit_buf == NULL) 312 | { 313 | ERROR_MSG("g_kernel_info is null or no kernel __LINKEDIT buffer available!"); 314 | return KERN_FAILURE; 315 | } 316 | /* symbols and strings offsets into LINKEDIT 317 | * we just read the __LINKEDIT but fileoff values are relative to the full /mach_kernel 318 | * subtract the base of LINKEDIT to fix the value into our buffer 319 | */ 320 | mach_vm_address_t symbol_off = kinfo->symboltable_fileoff - kinfo->linkedit_fileoff; 321 | mach_vm_address_t string_off = kinfo->stringtable_fileoff - kinfo->linkedit_fileoff; 322 | if (symbol_off > kinfo->symboltable_fileoff || string_off > kinfo->stringtable_fileoff) 323 | { 324 | ERROR_MSG("overflow?"); 325 | return KERN_FAILURE; 326 | 327 | } 328 | /* search for the symbol and get its location if found */ 329 | for (uint32_t i = 0; i < kinfo->symboltable_nr_symbols; i++) 330 | { 331 | /* get the pointer to the symbol entry and extract its symbol string */ 332 | nlist = (struct nlist_64*)((char*)kinfo->linkedit_buf + symbol_off + i * sizeof(struct nlist_64)); 333 | char *symbol_string = ((char*)kinfo->linkedit_buf + string_off + nlist->n_un.n_strx); 334 | /* find if symbol matches */ 335 | if (strncmp(symbol_to_solve, symbol_string, strlen(symbol_to_solve)) == 0) 336 | { 337 | /* the symbols values are without kernel ASLR so we need to add it */ 338 | mach_vm_address_t solved_addr = nlist->n_value + kinfo->kaslr_slide; 339 | /* verify if symbol is in the kernel __DATA segment */ 340 | /* we are less precise than in solve_kernel_symbol() */ 341 | mach_vm_address_t floor = kinfo->disk_DATA_addr + kinfo->kaslr_slide; 342 | mach_vm_address_t cap = floor + kinfo->DATA_size; 343 | if (solved_addr < floor || solved_addr > cap) 344 | { 345 | ERROR_MSG("Solved symbol address doesn't belong to running __DATA segment. Something is wrong!"); 346 | return KERN_FAILURE; 347 | } 348 | *output = solved_addr; 349 | return KERN_SUCCESS; 350 | } 351 | } 352 | /* failure */ 353 | ERROR_MSG("Failed to solve variable symbol %s", symbol_to_solve); 354 | return KERN_FAILURE; 355 | } 356 | 357 | #pragma mark Internal helper functions 358 | 359 | /* 360 | * retrieve the first page of kernel binary at disk into a buffer 361 | * version that uses KPI VFS functions and a ripped uio_createwithbuffer() from XNU 362 | * if it's a FAT kernel we locate the 64 bits kernel offset and reread to the same buffer 363 | * so the buffer always end with a 64 bits kernel or error 364 | */ 365 | static kern_return_t 366 | get_kernel_mach_header(void *buffer, vnode_t kernel_vnode) 367 | { 368 | if (buffer == NULL || kernel_vnode == NULL) 369 | { 370 | ERROR_MSG("Bad parameters!"); 371 | return KERN_FAILURE; 372 | } 373 | 374 | int error = 0; 375 | 376 | uio_t uio = NULL; 377 | uio = uio_create(1, 0, UIO_SYSSPACE, UIO_READ); 378 | if (uio == NULL) 379 | { 380 | ERROR_MSG("uio_create returned null!"); 381 | return KERN_FAILURE; 382 | } 383 | // imitate the kernel and read a single page from the header 384 | if ( (error = uio_addiov(uio, CAST_USER_ADDR_T(buffer), PAGE_SIZE_64)) ) 385 | { 386 | ERROR_MSG("uio_addiov returned error %d!", error); 387 | return KERN_FAILURE; 388 | } 389 | /* create a context - OS X 10.10 finally removed the "feature" to pass NULL */ 390 | vfs_context_t context = vfs_context_create(NULL); 391 | if (context == NULL) 392 | { 393 | ERROR_MSG("Can't create context."); 394 | return KERN_FAILURE; 395 | } 396 | // read kernel vnode into the buffer 397 | if ( (error = VNOP_READ(kernel_vnode, uio, 0, context)) ) 398 | { 399 | ERROR_MSG("VNOP_READ failed %d!", error); 400 | vfs_context_rele(context); 401 | return KERN_FAILURE; 402 | } 403 | else if (uio_resid(uio)) 404 | { 405 | ERROR_MSG("uio_resid!"); 406 | vfs_context_rele(context); 407 | return KERN_FAILURE; 408 | } 409 | 410 | vfs_context_rele(context); 411 | return KERN_SUCCESS; 412 | } 413 | 414 | /* 415 | * retrieve the whole linkedit segment into target buffer from kernel binary at disk 416 | * we keep this buffer until we don't need to solve symbols anymore 417 | */ 418 | static kern_return_t 419 | get_kernel_linkedit(vnode_t kernel_vnode, struct kernel_info *kinfo) 420 | { 421 | if (kernel_vnode == NULL || kinfo == NULL) 422 | { 423 | ERROR_MSG("Bad parameters!"); 424 | return KERN_FAILURE; 425 | } 426 | 427 | int error = 0; 428 | uio_t uio = NULL; 429 | uio = uio_create(1, kinfo->linkedit_fileoff, UIO_SYSSPACE, UIO_READ); 430 | if (uio == NULL) 431 | { 432 | ERROR_MSG("uio_create returned null!"); 433 | return KERN_FAILURE; 434 | } 435 | if ( (error = uio_addiov(uio, CAST_USER_ADDR_T(kinfo->linkedit_buf), kinfo->linkedit_size)) ) 436 | { 437 | ERROR_MSG("uio_addiov returned error %d!", error); 438 | return KERN_FAILURE; 439 | } 440 | /* create a context - OS X 10.10 finally removed the "feature" to pass NULL */ 441 | vfs_context_t context = vfs_context_create(NULL); 442 | if (context == NULL) 443 | { 444 | ERROR_MSG("Can't create context."); 445 | return KERN_FAILURE; 446 | } 447 | if ( (error = VNOP_READ(kernel_vnode, uio, 0, context)) ) 448 | { 449 | ERROR_MSG("VNOP_READ failed %d!", error); 450 | vfs_context_rele(context); 451 | return KERN_FAILURE; 452 | } 453 | else if (uio_resid(uio)) 454 | { 455 | ERROR_MSG("uio_resid!"); 456 | vfs_context_rele(context); 457 | return KERN_FAILURE; 458 | } 459 | vfs_context_rele(context); 460 | return KERN_SUCCESS; 461 | } 462 | 463 | /* 464 | * retrieve necessary mach-o header information from the kernel buffer 465 | * stored at our kernel_info structure 466 | * NOTE: we only process 64 bits kernels 467 | */ 468 | static kern_return_t 469 | process_kernel_mach_header(void *kernel_header, struct kernel_info *kinfo) 470 | { 471 | if (kernel_header == NULL || kinfo == NULL) 472 | { 473 | ERROR_MSG("Bad parameters!"); 474 | return KERN_FAILURE; 475 | } 476 | 477 | struct mach_header_64 *mh = (struct mach_header_64*)kernel_header; 478 | if (mh->magic != MH_MAGIC_64) 479 | { 480 | ERROR_MSG("Kernel is not 64bits!"); 481 | return KERN_FAILURE; 482 | } 483 | if (mh->ncmds == 0 || mh->sizeofcmds == 0) 484 | { 485 | ERROR_MSG("Invalid kernel file"); 486 | return KERN_FAILURE; 487 | } 488 | 489 | struct load_command *load_cmd = NULL; 490 | /* point to the first load command */ 491 | char *load_cmd_addr = (char*)kernel_header + sizeof(struct mach_header_64); 492 | /* iterate over all load cmds and retrieve required info to solve symbols */ 493 | /* __LINKEDIT location and symbol/string table location */ 494 | for (uint32_t i = 0; i < mh->ncmds; i++) 495 | { 496 | load_cmd = (struct load_command*)load_cmd_addr; 497 | if (load_cmd->cmd == LC_SEGMENT_64) 498 | { 499 | struct segment_command_64 *seg_cmd = (struct segment_command_64*)load_cmd; 500 | /* use this one to retrieve the original vm address of __TEXT so we can compute kernel aslr slide */ 501 | if (strncmp(seg_cmd->segname, "__TEXT", sizeof(seg_cmd->segname)) == 0) 502 | { 503 | kinfo->disk_text_addr = seg_cmd->vmaddr; 504 | kinfo->text_size = seg_cmd->vmsize; 505 | } 506 | else if (strncmp(seg_cmd->segname, "__DATA", sizeof(seg_cmd->segname)) == 0) 507 | { 508 | kinfo->disk_DATA_addr = seg_cmd->vmaddr; 509 | kinfo->DATA_size = seg_cmd->vmsize; 510 | } 511 | else if (strncmp(seg_cmd->segname, "__LINKEDIT", sizeof(seg_cmd->segname)) == 0) 512 | { 513 | kinfo->linkedit_fileoff = seg_cmd->fileoff; 514 | kinfo->linkedit_size = seg_cmd->filesize; 515 | } 516 | } 517 | /* table information available at LC_SYMTAB command */ 518 | else if (load_cmd->cmd == LC_SYMTAB) 519 | { 520 | struct symtab_command *symtab_cmd = (struct symtab_command*)load_cmd; 521 | kinfo->symboltable_fileoff = symtab_cmd->symoff; 522 | kinfo->symboltable_nr_symbols = symtab_cmd->nsyms; 523 | kinfo->stringtable_fileoff = symtab_cmd->stroff; 524 | kinfo->stringtable_size = symtab_cmd->strsize; 525 | } 526 | load_cmd_addr += load_cmd->cmdsize; 527 | } 528 | return KERN_SUCCESS; 529 | } 530 | 531 | /* 532 | * retrieve the __TEXT address of current loaded kernel so we can compute the KASLR slide 533 | * also the size of __text 534 | * NOTE: only processing 64 bits kernels! 535 | */ 536 | static kern_return_t 537 | get_running_text_address(struct kernel_info *kinfo) 538 | { 539 | if (kinfo == NULL) 540 | { 541 | ERROR_MSG("Bad parameters!"); 542 | return KERN_FAILURE; 543 | } 544 | 545 | /* retrieves the address of the IDT */ 546 | mach_vm_address_t idt_address = 0; 547 | get_addr_idt(&idt_address); 548 | /* calculate the address of the int80 handler */ 549 | mach_vm_address_t int80_address = calculate_int80address(idt_address); 550 | /* search backwards for the kernel base address (mach-o header) */ 551 | mach_vm_address_t kernel_base = find_kernel_base(int80_address); 552 | if (kernel_base != 0) 553 | { 554 | /* get the vm address of __TEXT segment */ 555 | struct mach_header_64 *mh = (struct mach_header_64*)kernel_base; 556 | struct load_command *load_cmd = NULL; 557 | char *load_cmd_addr = (char*)kernel_base + sizeof(struct mach_header_64); 558 | for (uint32_t i = 0; i < mh->ncmds; i++) 559 | { 560 | load_cmd = (struct load_command*)load_cmd_addr; 561 | if (load_cmd->cmd == LC_SEGMENT_64) 562 | { 563 | struct segment_command_64 *seg_cmd = (struct segment_command_64*)load_cmd; 564 | if (strncmp(seg_cmd->segname, "__TEXT", sizeof(seg_cmd->segname)) == 0) 565 | { 566 | kinfo->memory_text_addr = seg_cmd->vmaddr; 567 | return KERN_SUCCESS; 568 | } 569 | } 570 | load_cmd_addr += load_cmd->cmdsize; 571 | } 572 | } 573 | return KERN_FAILURE; 574 | } 575 | 576 | /* calculate the address of the kernel int80 handler using the IDT array */ 577 | static mach_vm_address_t 578 | calculate_int80address(const mach_vm_address_t idt_address) 579 | { 580 | if (idt_address == 0) 581 | { 582 | ERROR_MSG("Bogus idt address paramenter!"); 583 | return 0; 584 | } 585 | /* find the address of interrupt 0x80 - EXCEP64_SPC_USR(0x80,hi64_unix_scall) @ osfmk/i386/idt64.s */ 586 | struct descriptor_idt *int80_descriptor = NULL; 587 | mach_vm_address_t int80_address = 0; 588 | // we need to compute the address, it's not direct 589 | // extract the stub address 590 | // retrieve the descriptor for interrupt 0x80 591 | // the IDT is an array of descriptors 592 | int80_descriptor = (struct descriptor_idt*)(idt_address + sizeof(struct descriptor_idt)*0x80); 593 | uint64_t high = (unsigned long)int80_descriptor->offset_high << 32; 594 | uint32_t middle = (unsigned int)int80_descriptor->offset_middle << 16; 595 | int80_address = (mach_vm_address_t)(high + middle + int80_descriptor->offset_low); 596 | return int80_address; 597 | } 598 | 599 | /* 600 | * find the kernel base address (mach-o header) 601 | * by searching backwards using the int80 handler as starting point 602 | */ 603 | static mach_vm_address_t 604 | find_kernel_base(const mach_vm_address_t int80_address) 605 | { 606 | if (int80_address == 0) 607 | { 608 | ERROR_MSG("Bogus int80 address!"); 609 | return 0; 610 | } 611 | mach_vm_address_t temp_address = int80_address; 612 | struct segment_command_64 *segment_command = NULL; 613 | struct mach_header_64 *mh = NULL; 614 | while (temp_address > 0) 615 | { 616 | mh = (struct mach_header_64*)temp_address; 617 | if (mh->magic == MH_MAGIC_64 && mh->filetype == MH_EXECUTE && mh->ncmds > 0 && mh->sizeofcmds > 0) 618 | { 619 | /* make sure it's the header and not some reference to the MAGIC number */ 620 | segment_command = (struct segment_command_64*)(temp_address + sizeof(struct mach_header_64)); 621 | if (strncmp(segment_command->segname, "__TEXT", sizeof(segment_command->segname)) == 0) 622 | { 623 | return temp_address; 624 | } 625 | } 626 | /* check for int overflow */ 627 | if (temp_address - 1 > temp_address) 628 | { 629 | break; 630 | } 631 | temp_address--; 632 | } 633 | return 0; 634 | } 635 | 636 | /* retrieve the address of the IDT */ 637 | static void 638 | get_addr_idt(mach_vm_address_t *idt) 639 | { 640 | if (idt == NULL) 641 | { 642 | ERROR_MSG("Bad parameters!"); 643 | return; 644 | } 645 | 646 | uint8_t idtr[10] = {0}; 647 | __asm__ volatile ("sidt %0": "=m" (idtr)); 648 | *idt = *(mach_vm_address_t *)(idtr+2); 649 | } 650 | --------------------------------------------------------------------------------