├── README ├── hydra-userland ├── hydra-userland.xcodeproj │ └── project.pbxproj └── hydra-userland │ └── main.c └── hydra ├── hydra.xcodeproj └── project.pbxproj └── hydra ├── cpu_protections.c ├── cpu_protections.h ├── en.lproj └── InfoPlist.strings ├── hydra-Info.plist ├── hydra-Prefix.pch ├── hydra.c ├── idt.c ├── idt.h ├── kernel_control.c ├── kernel_control.h ├── kernel_info.c ├── kernel_info.h ├── my_data_definitions.h ├── proc.h ├── shared_data.h ├── suspend_proc.c ├── suspend_proc.h └── uthash.h /README: -------------------------------------------------------------------------------- 1 | 2 | ____ ____ _____ _____ _____ _____ ____ 3 | | | | ||\ \ / /| ___|\ \ ___|\ \ ____|\ \ 4 | | | | || \ \ / / || |\ \ | |\ \ / /\ \ 5 | | |_| || \____\/ / /| | | || | | || | | | 6 | | .-. | \ | / / / | | | || |/____/ | |__| | 7 | | | | | \|___/ / / | | | || |\ \ | .--. | 8 | | | | | / / / | | | || | | || | | | 9 | |____| |____| /____/ / |____|/____/||____| |____||____| |____| 10 | | | | | |` | / | / | || | | || | | | 11 | |____| |____| |_____|/ |____|____|/ |____| |____||____| |____| 12 | \( )/ )/ \( )/ \( )/ \( )/ 13 | ' ' ' ' ' ' ' ' ' 14 | Hydra 15 | 16 | Copyright (c) fG!, 2012,2013 - reverser@put.as - http://reverse.put.as 17 | All rights reserved. 18 | 19 | Welcome, 20 | 21 | Hydra is sample code of a kernel extension that will intercept process creation, suspend, and 22 | communicate it to a userland daemon that will be in charge of patching the application. 23 | 24 | Its goal is to demonstrate a process hijacking technique from the kernel and also how to use 25 | kernel control API. Technically all the patching could be done from the kernel extension. 26 | 27 | It can be used to crack codesign applications without touching the disk image or resigning 28 | the code. This is due to the fact that patching is done after code signature is verified. 29 | The only exception is if there are any code checksum features, either using internal functions 30 | or the ones from Apple code signing (not even sure if there's an API available for this). 31 | 32 | The kernel extension should be feature complete but the userland daemon implements a very 33 | basic example of adding a target and patching it. To be complete it needs an interface to 34 | add targets at request, save a configuration file with targets and patching information. 35 | 36 | The userland daemon requires task_for_pid() privileges. You will need to run it as root 37 | or sign it to run with debugging privileges (as gdb does). Follow this lldb document 38 | https://llvm.org/svn/llvm-project/lldb/trunk/docs/code-signing.txt to sign it. 39 | 40 | The only supported target for now is Mountain Lion. It's rather easy to support all OS X 41 | versions. In fact if the target is Lion and/or Mountain Lion, there's no need to read 42 | the kernel image from disk to solve symbols. They are available in memory! This applies 43 | if you want to make it work with Snow Leopard and below. Anyway, this code is also an 44 | example about how to read/write files from a kernel extension. 45 | 46 | As usual, this is only sample code. Any usage you make out of it is your own responsibility. 47 | 48 | Have fun, 49 | fG! 50 | 51 | 52 | -------------------------------------------------------------------------------- /hydra-userland/hydra-userland.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 7B90F213166EE86B00DD5FC6 /* main.c in Sources */ = {isa = PBXBuildFile; fileRef = 7B90F212166EE86B00DD5FC6 /* main.c */; }; 11 | 7B90F215166EE86B00DD5FC6 /* hydra_userland.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = 7B90F214166EE86B00DD5FC6 /* hydra_userland.1 */; }; 12 | /* End PBXBuildFile section */ 13 | 14 | /* Begin PBXCopyFilesBuildPhase section */ 15 | 7B90F20C166EE86B00DD5FC6 /* CopyFiles */ = { 16 | isa = PBXCopyFilesBuildPhase; 17 | buildActionMask = 2147483647; 18 | dstPath = /usr/share/man/man1/; 19 | dstSubfolderSpec = 0; 20 | files = ( 21 | 7B90F215166EE86B00DD5FC6 /* hydra_userland.1 in CopyFiles */, 22 | ); 23 | runOnlyForDeploymentPostprocessing = 1; 24 | }; 25 | /* End PBXCopyFilesBuildPhase section */ 26 | 27 | /* Begin PBXFileReference section */ 28 | 7B4E00F9168CA9DF0014D6A3 /* shared_data.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = shared_data.h; path = ../../hydra/hydra/shared_data.h; sourceTree = ""; }; 29 | 7B90F20E166EE86B00DD5FC6 /* hydra-userland */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = "hydra-userland"; sourceTree = BUILT_PRODUCTS_DIR; }; 30 | 7B90F212166EE86B00DD5FC6 /* main.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = main.c; sourceTree = ""; }; 31 | 7B90F214166EE86B00DD5FC6 /* hydra_userland.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = hydra_userland.1; sourceTree = ""; }; 32 | /* End PBXFileReference section */ 33 | 34 | /* Begin PBXFrameworksBuildPhase section */ 35 | 7B90F20B166EE86B00DD5FC6 /* Frameworks */ = { 36 | isa = PBXFrameworksBuildPhase; 37 | buildActionMask = 2147483647; 38 | files = ( 39 | ); 40 | runOnlyForDeploymentPostprocessing = 0; 41 | }; 42 | /* End PBXFrameworksBuildPhase section */ 43 | 44 | /* Begin PBXGroup section */ 45 | 7B90F203166EE86B00DD5FC6 = { 46 | isa = PBXGroup; 47 | children = ( 48 | 7B90F211166EE86B00DD5FC6 /* hydra-userland */, 49 | 7B90F20F166EE86B00DD5FC6 /* Products */, 50 | ); 51 | sourceTree = ""; 52 | }; 53 | 7B90F20F166EE86B00DD5FC6 /* Products */ = { 54 | isa = PBXGroup; 55 | children = ( 56 | 7B90F20E166EE86B00DD5FC6 /* hydra-userland */, 57 | ); 58 | name = Products; 59 | sourceTree = ""; 60 | }; 61 | 7B90F211166EE86B00DD5FC6 /* hydra-userland */ = { 62 | isa = PBXGroup; 63 | children = ( 64 | 7B90F212166EE86B00DD5FC6 /* main.c */, 65 | 7B4E00F9168CA9DF0014D6A3 /* shared_data.h */, 66 | 7B90F214166EE86B00DD5FC6 /* hydra_userland.1 */, 67 | ); 68 | path = "hydra-userland"; 69 | sourceTree = ""; 70 | }; 71 | /* End PBXGroup section */ 72 | 73 | /* Begin PBXNativeTarget section */ 74 | 7B90F20D166EE86B00DD5FC6 /* hydra-userland */ = { 75 | isa = PBXNativeTarget; 76 | buildConfigurationList = 7B90F218166EE86B00DD5FC6 /* Build configuration list for PBXNativeTarget "hydra-userland" */; 77 | buildPhases = ( 78 | 7B90F20A166EE86B00DD5FC6 /* Sources */, 79 | 7B90F20B166EE86B00DD5FC6 /* Frameworks */, 80 | 7B90F20C166EE86B00DD5FC6 /* CopyFiles */, 81 | ); 82 | buildRules = ( 83 | ); 84 | dependencies = ( 85 | ); 86 | name = "hydra-userland"; 87 | productName = "hydra-userland"; 88 | productReference = 7B90F20E166EE86B00DD5FC6 /* hydra-userland */; 89 | productType = "com.apple.product-type.tool"; 90 | }; 91 | /* End PBXNativeTarget section */ 92 | 93 | /* Begin PBXProject section */ 94 | 7B90F205166EE86B00DD5FC6 /* Project object */ = { 95 | isa = PBXProject; 96 | attributes = { 97 | LastUpgradeCheck = 0450; 98 | ORGANIZATIONNAME = Put.as; 99 | }; 100 | buildConfigurationList = 7B90F208166EE86B00DD5FC6 /* Build configuration list for PBXProject "hydra-userland" */; 101 | compatibilityVersion = "Xcode 3.2"; 102 | developmentRegion = English; 103 | hasScannedForEncodings = 0; 104 | knownRegions = ( 105 | en, 106 | ); 107 | mainGroup = 7B90F203166EE86B00DD5FC6; 108 | productRefGroup = 7B90F20F166EE86B00DD5FC6 /* Products */; 109 | projectDirPath = ""; 110 | projectRoot = ""; 111 | targets = ( 112 | 7B90F20D166EE86B00DD5FC6 /* hydra-userland */, 113 | ); 114 | }; 115 | /* End PBXProject section */ 116 | 117 | /* Begin PBXSourcesBuildPhase section */ 118 | 7B90F20A166EE86B00DD5FC6 /* Sources */ = { 119 | isa = PBXSourcesBuildPhase; 120 | buildActionMask = 2147483647; 121 | files = ( 122 | 7B90F213166EE86B00DD5FC6 /* main.c in Sources */, 123 | ); 124 | runOnlyForDeploymentPostprocessing = 0; 125 | }; 126 | /* End PBXSourcesBuildPhase section */ 127 | 128 | /* Begin XCBuildConfiguration section */ 129 | 7B90F216166EE86B00DD5FC6 /* Debug */ = { 130 | isa = XCBuildConfiguration; 131 | buildSettings = { 132 | ALWAYS_SEARCH_USER_PATHS = NO; 133 | ARCHS = "$(ARCHS_STANDARD_64_BIT)"; 134 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 135 | CLANG_CXX_LIBRARY = "libc++"; 136 | CLANG_WARN_EMPTY_BODY = YES; 137 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 138 | COPY_PHASE_STRIP = NO; 139 | GCC_C_LANGUAGE_STANDARD = gnu99; 140 | GCC_DYNAMIC_NO_PIC = NO; 141 | GCC_ENABLE_OBJC_EXCEPTIONS = YES; 142 | GCC_OPTIMIZATION_LEVEL = 0; 143 | GCC_PREPROCESSOR_DEFINITIONS = ( 144 | "DEBUG=1", 145 | "$(inherited)", 146 | ); 147 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 148 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 149 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 150 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 151 | GCC_WARN_UNUSED_VARIABLE = YES; 152 | MACOSX_DEPLOYMENT_TARGET = 10.8; 153 | ONLY_ACTIVE_ARCH = YES; 154 | SDKROOT = macosx; 155 | }; 156 | name = Debug; 157 | }; 158 | 7B90F217166EE86B00DD5FC6 /* Release */ = { 159 | isa = XCBuildConfiguration; 160 | buildSettings = { 161 | ALWAYS_SEARCH_USER_PATHS = NO; 162 | ARCHS = "$(ARCHS_STANDARD_64_BIT)"; 163 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 164 | CLANG_CXX_LIBRARY = "libc++"; 165 | CLANG_WARN_EMPTY_BODY = YES; 166 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 167 | COPY_PHASE_STRIP = YES; 168 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 169 | GCC_C_LANGUAGE_STANDARD = gnu99; 170 | GCC_ENABLE_OBJC_EXCEPTIONS = YES; 171 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 172 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 173 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 174 | GCC_WARN_UNUSED_VARIABLE = YES; 175 | MACOSX_DEPLOYMENT_TARGET = 10.8; 176 | SDKROOT = macosx; 177 | }; 178 | name = Release; 179 | }; 180 | 7B90F219166EE86B00DD5FC6 /* Debug */ = { 181 | isa = XCBuildConfiguration; 182 | buildSettings = { 183 | PRODUCT_NAME = "$(TARGET_NAME)"; 184 | }; 185 | name = Debug; 186 | }; 187 | 7B90F21A166EE86B00DD5FC6 /* Release */ = { 188 | isa = XCBuildConfiguration; 189 | buildSettings = { 190 | PRODUCT_NAME = "$(TARGET_NAME)"; 191 | }; 192 | name = Release; 193 | }; 194 | /* End XCBuildConfiguration section */ 195 | 196 | /* Begin XCConfigurationList section */ 197 | 7B90F208166EE86B00DD5FC6 /* Build configuration list for PBXProject "hydra-userland" */ = { 198 | isa = XCConfigurationList; 199 | buildConfigurations = ( 200 | 7B90F216166EE86B00DD5FC6 /* Debug */, 201 | 7B90F217166EE86B00DD5FC6 /* Release */, 202 | ); 203 | defaultConfigurationIsVisible = 0; 204 | defaultConfigurationName = Release; 205 | }; 206 | 7B90F218166EE86B00DD5FC6 /* Build configuration list for PBXNativeTarget "hydra-userland" */ = { 207 | isa = XCConfigurationList; 208 | buildConfigurations = ( 209 | 7B90F219166EE86B00DD5FC6 /* Debug */, 210 | 7B90F21A166EE86B00DD5FC6 /* Release */, 211 | ); 212 | defaultConfigurationIsVisible = 0; 213 | defaultConfigurationName = Release; 214 | }; 215 | /* End XCConfigurationList section */ 216 | }; 217 | rootObject = 7B90F205166EE86B00DD5FC6 /* Project object */; 218 | } 219 | -------------------------------------------------------------------------------- /hydra-userland/hydra-userland/main.c: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * dddddddd 4 | * HHHHHHHHH HHHHHHHHH d::::::d 5 | * H:::::::H H:::::::H d::::::d 6 | * H:::::::H H:::::::H d::::::d 7 | * HH::::::H H::::::HH d:::::d 8 | * H:::::H H:::::Hyyyyyyy yyyyyyy ddddddddd:::::drrrrr rrrrrrrrr aaaaaaaaaaaaa 9 | * H:::::H H:::::H y:::::y y:::::ydd::::::::::::::dr::::rrr:::::::::r a::::::::::::a 10 | * H::::::HHHHH::::::H y:::::y y:::::yd::::::::::::::::dr:::::::::::::::::r aaaaaaaaa:::::a 11 | * H:::::::::::::::::H y:::::y y:::::yd:::::::ddddd:::::drr::::::rrrrr::::::r a::::a 12 | * H:::::::::::::::::H y:::::y y:::::y d::::::d d:::::d r:::::r r:::::r aaaaaaa:::::a 13 | * H::::::HHHHH::::::H y:::::y y:::::y d:::::d d:::::d r:::::r rrrrrrraa::::::::::::a 14 | * H:::::H H:::::H y:::::y:::::y d:::::d d:::::d r:::::r a::::aaaa::::::a 15 | * H:::::H H:::::H y:::::::::y d:::::d d:::::d r:::::r a::::a a:::::a 16 | * HH::::::H H::::::HH y:::::::y d::::::ddddd::::::ddr:::::r a::::a a:::::a 17 | * H:::::::H H:::::::H y:::::y d:::::::::::::::::dr:::::r a:::::aaaa::::::a 18 | * H:::::::H H:::::::H y:::::y d:::::::::ddd::::dr:::::r a::::::::::aa:::a 19 | * HHHHHHHHH HHHHHHHHH y:::::y ddddddddd dddddrrrrrrr aaaaaaaaaa aaaa 20 | * y:::::y 21 | * y:::::y 22 | * y:::::y 23 | * y:::::y 24 | * yyyyyyy 25 | * 26 | * The userland daemon to talk to the kernel and process the target apps 27 | * 28 | * Copyright (c) 2012,2013 fG!. All rights reserved. 29 | * reverser@put.as - http://reverse.put.as 30 | * 31 | * main.c 32 | * 33 | * Redistribution and use in source and binary forms, with or without 34 | * modification, are permitted provided that the following conditions 35 | * are met: 36 | * 1. Redistributions of source code must retain the above copyright 37 | * notice, this list of conditions and the following disclaimer. 38 | * 2. Redistributions in binary form must reproduce the above copyright 39 | * notice, this list of conditions and the following disclaimer in the 40 | * documentation and/or other materials provided with the distribution. 41 | * 3. The name of the author may not be used to endorse or promote products 42 | * derived from this software without specific prior written permission. 43 | * 44 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 45 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 46 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 47 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 48 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 49 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 50 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 51 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 52 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 53 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 54 | * 55 | */ 56 | 57 | #include 58 | #include 59 | #include 60 | #include 61 | #include 62 | #include 63 | #include 64 | #include 65 | #include 66 | #include 67 | #include 68 | #include 69 | #include 70 | #include 71 | 72 | #include 73 | #include 74 | #include 75 | #include 76 | 77 | #include "shared_data.h" 78 | 79 | static int g_socket = -1; 80 | 81 | int main(int argc, const char * argv[]) 82 | { 83 | struct sockaddr_ctl sc = { 0 }; 84 | struct ctl_info ctl_info = { 0 }; 85 | int ret = 0; 86 | 87 | g_socket = socket(PF_SYSTEM, SOCK_DGRAM, SYSPROTO_CONTROL); 88 | if (g_socket < 0) 89 | { 90 | perror("creating socket"); 91 | exit(1); 92 | } 93 | // the control ID is dynamically generated so we must obtain sc_id using ioctl 94 | memset(&ctl_info, 0, sizeof(ctl_info)); 95 | strncpy(ctl_info.ctl_name, BUNDLE_ID, MAX_KCTL_NAME); 96 | ctl_info.ctl_name[MAX_KCTL_NAME-1] = '\0'; 97 | if (ioctl(g_socket, CTLIOCGINFO, &ctl_info) == -1) 98 | { 99 | perror("ioctl CTLIOCGINFO"); 100 | exit(1); 101 | } 102 | else 103 | printf("ctl_id: 0x%x for ctl_name: %s\n", ctl_info.ctl_id, ctl_info.ctl_name); 104 | 105 | bzero(&sc, sizeof(struct sockaddr_ctl)); 106 | sc.sc_len = sizeof(struct sockaddr_ctl); 107 | sc.sc_family = AF_SYSTEM; 108 | sc.ss_sysaddr = AF_SYS_CONTROL; 109 | sc.sc_id = ctl_info.ctl_id; 110 | sc.sc_unit = 0; 111 | 112 | ret = connect(g_socket, (struct sockaddr*)&sc, sizeof(sc)); 113 | if (ret) 114 | { 115 | perror("connect"); 116 | exit(1); 117 | } 118 | 119 | // add a target to the kernel list 120 | if (!ret) 121 | { 122 | char *target = "Dash"; 123 | ret = setsockopt(g_socket, SYSPROTO_CONTROL, ADD_APP, (void*)target, (socklen_t)strlen(target)+1); 124 | if (ret) 125 | printf("socket send failed!\n"); 126 | } 127 | pid_t pid; 128 | ssize_t n; 129 | // loop and get target processes from kernel 130 | while ((n = recv(g_socket, &pid, sizeof(pid_t), 0))) 131 | { 132 | printf("[INFO] Received pid for target process is %d\n", pid); 133 | mach_port_t task; 134 | kern_return_t ret = 0; 135 | ret = task_for_pid(mach_task_self(), pid, &task); 136 | if (ret) 137 | { 138 | printf("task for pid failed!\n"); 139 | continue; 140 | } 141 | 142 | // do whatever processing and patching we need to the target 143 | uint16_t patch1 = 0x9090; 144 | mach_msg_type_number_t len = 2; 145 | #define TARGET_ADDRESS 0 146 | // change memory protection to writable 147 | mach_vm_protect(task, (mach_vm_address_t)TARGET_ADDRESS, len, FALSE, VM_PROT_READ | VM_PROT_WRITE | VM_PROT_COPY); 148 | // patch the process 149 | ret = mach_vm_write(task, (mach_vm_address_t)TARGET_ADDRESS, (vm_offset_t)&patch1, len); 150 | if (ret) 151 | { 152 | printf("mach vm write failed! %d\n", ret); 153 | } 154 | // restore original protection 155 | mach_vm_protect(task, (mach_vm_address_t)TARGET_ADDRESS, len, FALSE, VM_PROT_READ | VM_PROT_EXECUTE); 156 | // not sure why I added this small pause, maybe some test? 157 | sleep(2); 158 | // resume process 159 | kill(pid, SIGCONT); 160 | } 161 | printf("[INFO] My work is done, see you later!\n"); 162 | return 0; 163 | } 164 | 165 | -------------------------------------------------------------------------------- /hydra/hydra.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 7B4E00E2168C9D5F0014D6A3 /* uthash.h in Headers */ = {isa = PBXBuildFile; fileRef = 7B4E00E1168C9D5F0014D6A3 /* uthash.h */; }; 11 | 7B88C8C7168BBF37000D6573 /* proc.h in Headers */ = {isa = PBXBuildFile; fileRef = 7B88C8C4168BBF37000D6573 /* proc.h */; }; 12 | 7B88C8CD168BC316000D6573 /* kernel_info.c in Sources */ = {isa = PBXBuildFile; fileRef = 7B88C8CB168BC316000D6573 /* kernel_info.c */; }; 13 | 7B88C8CE168BC316000D6573 /* kernel_info.h in Headers */ = {isa = PBXBuildFile; fileRef = 7B88C8CC168BC316000D6573 /* kernel_info.h */; }; 14 | 7B88C8D9168BCCBA000D6573 /* cpu_protections.c in Sources */ = {isa = PBXBuildFile; fileRef = 7B88C8D3168BCCBA000D6573 /* cpu_protections.c */; }; 15 | 7B88C8DA168BCCBA000D6573 /* cpu_protections.h in Headers */ = {isa = PBXBuildFile; fileRef = 7B88C8D4168BCCBA000D6573 /* cpu_protections.h */; }; 16 | 7B88C8DB168BCCBA000D6573 /* idt.c in Sources */ = {isa = PBXBuildFile; fileRef = 7B88C8D5168BCCBA000D6573 /* idt.c */; }; 17 | 7B88C8DC168BCCBA000D6573 /* idt.h in Headers */ = {isa = PBXBuildFile; fileRef = 7B88C8D6168BCCBA000D6573 /* idt.h */; }; 18 | 7B88C8E1168BD887000D6573 /* suspend_proc.c in Sources */ = {isa = PBXBuildFile; fileRef = 7B88C8DF168BD887000D6573 /* suspend_proc.c */; }; 19 | 7B88C8E2168BD887000D6573 /* suspend_proc.h in Headers */ = {isa = PBXBuildFile; fileRef = 7B88C8E0168BD887000D6573 /* suspend_proc.h */; }; 20 | 7B88C8E5168BF216000D6573 /* kernel_control.c in Sources */ = {isa = PBXBuildFile; fileRef = 7B88C8E3168BF216000D6573 /* kernel_control.c */; }; 21 | 7B88C8E6168BF216000D6573 /* kernel_control.h in Headers */ = {isa = PBXBuildFile; fileRef = 7B88C8E4168BF216000D6573 /* kernel_control.h */; }; 22 | 7B90F1F0166ECD4E00DD5FC6 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 7B90F1EE166ECD4E00DD5FC6 /* InfoPlist.strings */; }; 23 | 7B90F1F2166ECD4E00DD5FC6 /* hydra.c in Sources */ = {isa = PBXBuildFile; fileRef = 7B90F1F1166ECD4E00DD5FC6 /* hydra.c */; }; 24 | /* End PBXBuildFile section */ 25 | 26 | /* Begin PBXFileReference section */ 27 | 7B4E00E0168C9AFE0014D6A3 /* shared_data.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = shared_data.h; sourceTree = ""; }; 28 | 7B4E00E1168C9D5F0014D6A3 /* uthash.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = uthash.h; sourceTree = ""; }; 29 | 7B88C8C4168BBF37000D6573 /* proc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = proc.h; sourceTree = ""; }; 30 | 7B88C8CA168BC1D1000D6573 /* my_data_definitions.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = my_data_definitions.h; sourceTree = ""; }; 31 | 7B88C8CB168BC316000D6573 /* kernel_info.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = kernel_info.c; sourceTree = ""; }; 32 | 7B88C8CC168BC316000D6573 /* kernel_info.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = kernel_info.h; sourceTree = ""; }; 33 | 7B88C8D3168BCCBA000D6573 /* cpu_protections.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = cpu_protections.c; sourceTree = ""; }; 34 | 7B88C8D4168BCCBA000D6573 /* cpu_protections.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cpu_protections.h; sourceTree = ""; }; 35 | 7B88C8D5168BCCBA000D6573 /* idt.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = idt.c; sourceTree = ""; }; 36 | 7B88C8D6168BCCBA000D6573 /* idt.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = idt.h; sourceTree = ""; }; 37 | 7B88C8DF168BD887000D6573 /* suspend_proc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = suspend_proc.c; sourceTree = ""; }; 38 | 7B88C8E0168BD887000D6573 /* suspend_proc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = suspend_proc.h; sourceTree = ""; }; 39 | 7B88C8E3168BF216000D6573 /* kernel_control.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = kernel_control.c; sourceTree = ""; }; 40 | 7B88C8E4168BF216000D6573 /* kernel_control.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = kernel_control.h; sourceTree = ""; }; 41 | 7B90F1E6166ECD4E00DD5FC6 /* hydra.kext */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = hydra.kext; sourceTree = BUILT_PRODUCTS_DIR; }; 42 | 7B90F1EA166ECD4E00DD5FC6 /* Kernel.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Kernel.framework; path = System/Library/Frameworks/Kernel.framework; sourceTree = SDKROOT; }; 43 | 7B90F1ED166ECD4E00DD5FC6 /* hydra-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "hydra-Info.plist"; sourceTree = ""; }; 44 | 7B90F1EF166ECD4E00DD5FC6 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 45 | 7B90F1F1166ECD4E00DD5FC6 /* hydra.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = hydra.c; sourceTree = ""; }; 46 | 7B90F1F3166ECD4E00DD5FC6 /* hydra-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "hydra-Prefix.pch"; sourceTree = ""; }; 47 | /* End PBXFileReference section */ 48 | 49 | /* Begin PBXFrameworksBuildPhase section */ 50 | 7B90F1E1166ECD4E00DD5FC6 /* Frameworks */ = { 51 | isa = PBXFrameworksBuildPhase; 52 | buildActionMask = 2147483647; 53 | files = ( 54 | ); 55 | runOnlyForDeploymentPostprocessing = 0; 56 | }; 57 | /* End PBXFrameworksBuildPhase section */ 58 | 59 | /* Begin PBXGroup section */ 60 | 7B88C8C2168BBF12000D6573 /* kernel_includes */ = { 61 | isa = PBXGroup; 62 | children = ( 63 | 7B88C8C4168BBF37000D6573 /* proc.h */, 64 | ); 65 | name = kernel_includes; 66 | sourceTree = ""; 67 | }; 68 | 7B90F1D9166ECD4E00DD5FC6 = { 69 | isa = PBXGroup; 70 | children = ( 71 | 7B90F1EB166ECD4E00DD5FC6 /* hydra */, 72 | 7B90F1E8166ECD4E00DD5FC6 /* Frameworks */, 73 | 7B90F1E7166ECD4E00DD5FC6 /* Products */, 74 | ); 75 | sourceTree = ""; 76 | }; 77 | 7B90F1E7166ECD4E00DD5FC6 /* Products */ = { 78 | isa = PBXGroup; 79 | children = ( 80 | 7B90F1E6166ECD4E00DD5FC6 /* hydra.kext */, 81 | ); 82 | name = Products; 83 | sourceTree = ""; 84 | }; 85 | 7B90F1E8166ECD4E00DD5FC6 /* Frameworks */ = { 86 | isa = PBXGroup; 87 | children = ( 88 | 7B90F1E9166ECD4E00DD5FC6 /* Other Frameworks */, 89 | ); 90 | name = Frameworks; 91 | sourceTree = ""; 92 | }; 93 | 7B90F1E9166ECD4E00DD5FC6 /* Other Frameworks */ = { 94 | isa = PBXGroup; 95 | children = ( 96 | 7B90F1EA166ECD4E00DD5FC6 /* Kernel.framework */, 97 | ); 98 | name = "Other Frameworks"; 99 | sourceTree = ""; 100 | }; 101 | 7B90F1EB166ECD4E00DD5FC6 /* hydra */ = { 102 | isa = PBXGroup; 103 | children = ( 104 | 7B90F1F1166ECD4E00DD5FC6 /* hydra.c */, 105 | 7B88C8DF168BD887000D6573 /* suspend_proc.c */, 106 | 7B88C8E0168BD887000D6573 /* suspend_proc.h */, 107 | 7B88C8CB168BC316000D6573 /* kernel_info.c */, 108 | 7B88C8CC168BC316000D6573 /* kernel_info.h */, 109 | 7B88C8E3168BF216000D6573 /* kernel_control.c */, 110 | 7B88C8E4168BF216000D6573 /* kernel_control.h */, 111 | 7B88C8D3168BCCBA000D6573 /* cpu_protections.c */, 112 | 7B88C8D4168BCCBA000D6573 /* cpu_protections.h */, 113 | 7B88C8D5168BCCBA000D6573 /* idt.c */, 114 | 7B88C8D6168BCCBA000D6573 /* idt.h */, 115 | 7B88C8CA168BC1D1000D6573 /* my_data_definitions.h */, 116 | 7B4E00E0168C9AFE0014D6A3 /* shared_data.h */, 117 | 7B4E00E1168C9D5F0014D6A3 /* uthash.h */, 118 | 7B88C8C2168BBF12000D6573 /* kernel_includes */, 119 | 7B90F1EC166ECD4E00DD5FC6 /* Supporting Files */, 120 | ); 121 | path = hydra; 122 | sourceTree = ""; 123 | }; 124 | 7B90F1EC166ECD4E00DD5FC6 /* Supporting Files */ = { 125 | isa = PBXGroup; 126 | children = ( 127 | 7B90F1ED166ECD4E00DD5FC6 /* hydra-Info.plist */, 128 | 7B90F1EE166ECD4E00DD5FC6 /* InfoPlist.strings */, 129 | 7B90F1F3166ECD4E00DD5FC6 /* hydra-Prefix.pch */, 130 | ); 131 | name = "Supporting Files"; 132 | sourceTree = ""; 133 | }; 134 | /* End PBXGroup section */ 135 | 136 | /* Begin PBXHeadersBuildPhase section */ 137 | 7B90F1E2166ECD4E00DD5FC6 /* Headers */ = { 138 | isa = PBXHeadersBuildPhase; 139 | buildActionMask = 2147483647; 140 | files = ( 141 | 7B88C8C7168BBF37000D6573 /* proc.h in Headers */, 142 | 7B88C8CE168BC316000D6573 /* kernel_info.h in Headers */, 143 | 7B88C8DA168BCCBA000D6573 /* cpu_protections.h in Headers */, 144 | 7B88C8DC168BCCBA000D6573 /* idt.h in Headers */, 145 | 7B88C8E2168BD887000D6573 /* suspend_proc.h in Headers */, 146 | 7B88C8E6168BF216000D6573 /* kernel_control.h in Headers */, 147 | 7B4E00E2168C9D5F0014D6A3 /* uthash.h in Headers */, 148 | ); 149 | runOnlyForDeploymentPostprocessing = 0; 150 | }; 151 | /* End PBXHeadersBuildPhase section */ 152 | 153 | /* Begin PBXNativeTarget section */ 154 | 7B90F1E5166ECD4E00DD5FC6 /* hydra */ = { 155 | isa = PBXNativeTarget; 156 | buildConfigurationList = 7B90F1F6166ECD4E00DD5FC6 /* Build configuration list for PBXNativeTarget "hydra" */; 157 | buildPhases = ( 158 | 7B90F1E0166ECD4E00DD5FC6 /* Sources */, 159 | 7B90F1E1166ECD4E00DD5FC6 /* Frameworks */, 160 | 7B90F1E2166ECD4E00DD5FC6 /* Headers */, 161 | 7B90F1E3166ECD4E00DD5FC6 /* Resources */, 162 | 7B90F1E4166ECD4E00DD5FC6 /* Rez */, 163 | ); 164 | buildRules = ( 165 | ); 166 | dependencies = ( 167 | ); 168 | name = hydra; 169 | productName = hydra; 170 | productReference = 7B90F1E6166ECD4E00DD5FC6 /* hydra.kext */; 171 | productType = "com.apple.product-type.kernel-extension"; 172 | }; 173 | /* End PBXNativeTarget section */ 174 | 175 | /* Begin PBXProject section */ 176 | 7B90F1DB166ECD4E00DD5FC6 /* Project object */ = { 177 | isa = PBXProject; 178 | attributes = { 179 | LastUpgradeCheck = 0450; 180 | ORGANIZATIONNAME = Put.as; 181 | }; 182 | buildConfigurationList = 7B90F1DE166ECD4E00DD5FC6 /* Build configuration list for PBXProject "hydra" */; 183 | compatibilityVersion = "Xcode 3.2"; 184 | developmentRegion = English; 185 | hasScannedForEncodings = 0; 186 | knownRegions = ( 187 | en, 188 | ); 189 | mainGroup = 7B90F1D9166ECD4E00DD5FC6; 190 | productRefGroup = 7B90F1E7166ECD4E00DD5FC6 /* Products */; 191 | projectDirPath = ""; 192 | projectRoot = ""; 193 | targets = ( 194 | 7B90F1E5166ECD4E00DD5FC6 /* hydra */, 195 | ); 196 | }; 197 | /* End PBXProject section */ 198 | 199 | /* Begin PBXResourcesBuildPhase section */ 200 | 7B90F1E3166ECD4E00DD5FC6 /* Resources */ = { 201 | isa = PBXResourcesBuildPhase; 202 | buildActionMask = 2147483647; 203 | files = ( 204 | 7B90F1F0166ECD4E00DD5FC6 /* InfoPlist.strings in Resources */, 205 | ); 206 | runOnlyForDeploymentPostprocessing = 0; 207 | }; 208 | /* End PBXResourcesBuildPhase section */ 209 | 210 | /* Begin PBXRezBuildPhase section */ 211 | 7B90F1E4166ECD4E00DD5FC6 /* Rez */ = { 212 | isa = PBXRezBuildPhase; 213 | buildActionMask = 2147483647; 214 | files = ( 215 | ); 216 | runOnlyForDeploymentPostprocessing = 0; 217 | }; 218 | /* End PBXRezBuildPhase section */ 219 | 220 | /* Begin PBXSourcesBuildPhase section */ 221 | 7B90F1E0166ECD4E00DD5FC6 /* Sources */ = { 222 | isa = PBXSourcesBuildPhase; 223 | buildActionMask = 2147483647; 224 | files = ( 225 | 7B90F1F2166ECD4E00DD5FC6 /* hydra.c in Sources */, 226 | 7B88C8CD168BC316000D6573 /* kernel_info.c in Sources */, 227 | 7B88C8D9168BCCBA000D6573 /* cpu_protections.c in Sources */, 228 | 7B88C8DB168BCCBA000D6573 /* idt.c in Sources */, 229 | 7B88C8E1168BD887000D6573 /* suspend_proc.c in Sources */, 230 | 7B88C8E5168BF216000D6573 /* kernel_control.c in Sources */, 231 | ); 232 | runOnlyForDeploymentPostprocessing = 0; 233 | }; 234 | /* End PBXSourcesBuildPhase section */ 235 | 236 | /* Begin PBXVariantGroup section */ 237 | 7B90F1EE166ECD4E00DD5FC6 /* InfoPlist.strings */ = { 238 | isa = PBXVariantGroup; 239 | children = ( 240 | 7B90F1EF166ECD4E00DD5FC6 /* en */, 241 | ); 242 | name = InfoPlist.strings; 243 | sourceTree = ""; 244 | }; 245 | /* End PBXVariantGroup section */ 246 | 247 | /* Begin XCBuildConfiguration section */ 248 | 7B90F1F4166ECD4E00DD5FC6 /* Debug */ = { 249 | isa = XCBuildConfiguration; 250 | buildSettings = { 251 | ALWAYS_SEARCH_USER_PATHS = NO; 252 | ARCHS = "$(ARCHS_STANDARD_64_BIT)"; 253 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 254 | CLANG_CXX_LIBRARY = "libc++"; 255 | CLANG_WARN_EMPTY_BODY = YES; 256 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 257 | COPY_PHASE_STRIP = NO; 258 | GCC_C_LANGUAGE_STANDARD = gnu99; 259 | GCC_DYNAMIC_NO_PIC = NO; 260 | GCC_ENABLE_OBJC_EXCEPTIONS = YES; 261 | GCC_OPTIMIZATION_LEVEL = 0; 262 | GCC_PREPROCESSOR_DEFINITIONS = ( 263 | "DEBUG=1", 264 | "$(inherited)", 265 | ); 266 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 267 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 268 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 269 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 270 | GCC_WARN_UNUSED_VARIABLE = YES; 271 | MACOSX_DEPLOYMENT_TARGET = 10.8; 272 | ONLY_ACTIVE_ARCH = YES; 273 | SDKROOT = macosx; 274 | }; 275 | name = Debug; 276 | }; 277 | 7B90F1F5166ECD4E00DD5FC6 /* Release */ = { 278 | isa = XCBuildConfiguration; 279 | buildSettings = { 280 | ALWAYS_SEARCH_USER_PATHS = NO; 281 | ARCHS = "$(ARCHS_STANDARD_64_BIT)"; 282 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 283 | CLANG_CXX_LIBRARY = "libc++"; 284 | CLANG_WARN_EMPTY_BODY = YES; 285 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 286 | COPY_PHASE_STRIP = YES; 287 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 288 | GCC_C_LANGUAGE_STANDARD = gnu99; 289 | GCC_ENABLE_OBJC_EXCEPTIONS = YES; 290 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 291 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 292 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 293 | GCC_WARN_UNUSED_VARIABLE = YES; 294 | MACOSX_DEPLOYMENT_TARGET = 10.8; 295 | SDKROOT = macosx; 296 | }; 297 | name = Release; 298 | }; 299 | 7B90F1F7166ECD4E00DD5FC6 /* Debug */ = { 300 | isa = XCBuildConfiguration; 301 | buildSettings = { 302 | COMBINE_HIDPI_IMAGES = YES; 303 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 304 | GCC_PREFIX_HEADER = "hydra/hydra-Prefix.pch"; 305 | GCC_VERSION = com.apple.compilers.llvmgcc42; 306 | INFOPLIST_FILE = "hydra/hydra-Info.plist"; 307 | INSTALL_PATH = "$(SYSTEM_LIBRARY_DIR)/Extensions"; 308 | MODULE_NAME = put.as.hydra; 309 | MODULE_START = hydra_start; 310 | MODULE_STOP = hydra_stop; 311 | MODULE_VERSION = 1.0.0d1; 312 | PRODUCT_NAME = "$(TARGET_NAME)"; 313 | WRAPPER_EXTENSION = kext; 314 | }; 315 | name = Debug; 316 | }; 317 | 7B90F1F8166ECD4E00DD5FC6 /* Release */ = { 318 | isa = XCBuildConfiguration; 319 | buildSettings = { 320 | COMBINE_HIDPI_IMAGES = YES; 321 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 322 | GCC_PREFIX_HEADER = "hydra/hydra-Prefix.pch"; 323 | GCC_VERSION = com.apple.compilers.llvmgcc42; 324 | INFOPLIST_FILE = "hydra/hydra-Info.plist"; 325 | INSTALL_PATH = "$(SYSTEM_LIBRARY_DIR)/Extensions"; 326 | MODULE_NAME = put.as.hydra; 327 | MODULE_START = hydra_start; 328 | MODULE_STOP = hydra_stop; 329 | MODULE_VERSION = 1.0.0d1; 330 | PRODUCT_NAME = "$(TARGET_NAME)"; 331 | WRAPPER_EXTENSION = kext; 332 | }; 333 | name = Release; 334 | }; 335 | /* End XCBuildConfiguration section */ 336 | 337 | /* Begin XCConfigurationList section */ 338 | 7B90F1DE166ECD4E00DD5FC6 /* Build configuration list for PBXProject "hydra" */ = { 339 | isa = XCConfigurationList; 340 | buildConfigurations = ( 341 | 7B90F1F4166ECD4E00DD5FC6 /* Debug */, 342 | 7B90F1F5166ECD4E00DD5FC6 /* Release */, 343 | ); 344 | defaultConfigurationIsVisible = 0; 345 | defaultConfigurationName = Release; 346 | }; 347 | 7B90F1F6166ECD4E00DD5FC6 /* Build configuration list for PBXNativeTarget "hydra" */ = { 348 | isa = XCConfigurationList; 349 | buildConfigurations = ( 350 | 7B90F1F7166ECD4E00DD5FC6 /* Debug */, 351 | 7B90F1F8166ECD4E00DD5FC6 /* Release */, 352 | ); 353 | defaultConfigurationIsVisible = 0; 354 | defaultConfigurationName = Release; 355 | }; 356 | /* End XCConfigurationList section */ 357 | }; 358 | rootObject = 7B90F1DB166ECD4E00DD5FC6 /* Project object */; 359 | } 360 | -------------------------------------------------------------------------------- /hydra/hydra/cpu_protections.c: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * dddddddd 4 | * HHHHHHHHH HHHHHHHHH d::::::d 5 | * H:::::::H H:::::::H d::::::d 6 | * H:::::::H H:::::::H d::::::d 7 | * HH::::::H H::::::HH d:::::d 8 | * H:::::H H:::::Hyyyyyyy yyyyyyy ddddddddd:::::drrrrr rrrrrrrrr aaaaaaaaaaaaa 9 | * H:::::H H:::::H y:::::y y:::::ydd::::::::::::::dr::::rrr:::::::::r a::::::::::::a 10 | * H::::::HHHHH::::::H y:::::y y:::::yd::::::::::::::::dr:::::::::::::::::r aaaaaaaaa:::::a 11 | * H:::::::::::::::::H y:::::y y:::::yd:::::::ddddd:::::drr::::::rrrrr::::::r a::::a 12 | * H:::::::::::::::::H y:::::y y:::::y d::::::d d:::::d r:::::r r:::::r aaaaaaa:::::a 13 | * H::::::HHHHH::::::H y:::::y y:::::y d:::::d d:::::d r:::::r rrrrrrraa::::::::::::a 14 | * H:::::H H:::::H y:::::y:::::y d:::::d d:::::d r:::::r a::::aaaa::::::a 15 | * H:::::H H:::::H y:::::::::y d:::::d d:::::d r:::::r a::::a a:::::a 16 | * HH::::::H H::::::HH y:::::::y d::::::ddddd::::::ddr:::::r a::::a a:::::a 17 | * H:::::::H H:::::::H y:::::y d:::::::::::::::::dr:::::r a:::::aaaa::::::a 18 | * H:::::::H H:::::::H y:::::y d:::::::::ddd::::dr:::::r a::::::::::aa:::a 19 | * HHHHHHHHH HHHHHHHHH y:::::y ddddddddd dddddrrrrrrr aaaaaaaaaa aaaa 20 | * y:::::y 21 | * y:::::y 22 | * y:::::y 23 | * y:::::y 24 | * yyyyyyy 25 | * 26 | * A kernel extension to suspend applications and notify a userland daemon 27 | * 28 | * Copyright (c) 2012,2013 fG!. All rights reserved. 29 | * reverser@put.as - http://reverse.put.as 30 | * 31 | * cpu_protections.c 32 | * 33 | * Functions to deal with cpu/kernel protections against writing memory and so on 34 | * 35 | * Redistribution and use in source and binary forms, with or without 36 | * modification, are permitted provided that the following conditions 37 | * are met: 38 | * 1. Redistributions of source code must retain the above copyright 39 | * notice, this list of conditions and the following disclaimer. 40 | * 2. Redistributions in binary form must reproduce the above copyright 41 | * notice, this list of conditions and the following disclaimer in the 42 | * documentation and/or other materials provided with the distribution. 43 | * 3. The name of the author may not be used to endorse or promote products 44 | * derived from this software without specific prior written permission. 45 | * 46 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 47 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 48 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 49 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 50 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 51 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 52 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 53 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 54 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 55 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 56 | * 57 | */ 58 | 59 | #include "cpu_protections.h" 60 | 61 | // disable the Write Protection bit in CR0 register 62 | // so we can modify kernel code 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) 75 | return(0); 76 | else 77 | return(1); 78 | } 79 | 80 | // enable the Write Protection bit in CR0 register 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) 93 | return(0); 94 | else 95 | return(1); 96 | } 97 | 98 | // check if WP is set or not 99 | // 0 - it's set 100 | // 1 - not set 101 | uint8_t 102 | verify_wp(void) 103 | { 104 | uintptr_t cr0; 105 | cr0 = get_cr0(); 106 | if (cr0 & CR0_WP) 107 | return(0); 108 | else 109 | return(1); 110 | } 111 | 112 | void enable_interrupts(void) 113 | { 114 | __asm__ volatile("sti"); 115 | } 116 | 117 | void disable_interrupts(void) 118 | { 119 | __asm__ volatile("cli"); 120 | } 121 | 122 | -------------------------------------------------------------------------------- /hydra/hydra/cpu_protections.h: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * dddddddd 4 | * HHHHHHHHH HHHHHHHHH d::::::d 5 | * H:::::::H H:::::::H d::::::d 6 | * H:::::::H H:::::::H d::::::d 7 | * HH::::::H H::::::HH d:::::d 8 | * H:::::H H:::::Hyyyyyyy yyyyyyy ddddddddd:::::drrrrr rrrrrrrrr aaaaaaaaaaaaa 9 | * H:::::H H:::::H y:::::y y:::::ydd::::::::::::::dr::::rrr:::::::::r a::::::::::::a 10 | * H::::::HHHHH::::::H y:::::y y:::::yd::::::::::::::::dr:::::::::::::::::r aaaaaaaaa:::::a 11 | * H:::::::::::::::::H y:::::y y:::::yd:::::::ddddd:::::drr::::::rrrrr::::::r a::::a 12 | * H:::::::::::::::::H y:::::y y:::::y d::::::d d:::::d r:::::r r:::::r aaaaaaa:::::a 13 | * H::::::HHHHH::::::H y:::::y y:::::y d:::::d d:::::d r:::::r rrrrrrraa::::::::::::a 14 | * H:::::H H:::::H y:::::y:::::y d:::::d d:::::d r:::::r a::::aaaa::::::a 15 | * H:::::H H:::::H y:::::::::y d:::::d d:::::d r:::::r a::::a a:::::a 16 | * HH::::::H H::::::HH y:::::::y d::::::ddddd::::::ddr:::::r a::::a a:::::a 17 | * H:::::::H H:::::::H y:::::y d:::::::::::::::::dr:::::r a:::::aaaa::::::a 18 | * H:::::::H H:::::::H y:::::y d:::::::::ddd::::dr:::::r a::::::::::aa:::a 19 | * HHHHHHHHH HHHHHHHHH y:::::y ddddddddd dddddrrrrrrr aaaaaaaaaa aaaa 20 | * y:::::y 21 | * y:::::y 22 | * y:::::y 23 | * y:::::y 24 | * yyyyyyy 25 | * 26 | * A kernel extension to suspend applications and notify a userland daemon 27 | * 28 | * Copyright (c) 2012,2013 fG!. All rights reserved. 29 | * reverser@put.as - http://reverse.put.as 30 | * 31 | * cpu_protections.h 32 | * 33 | * Functions to deal with cpu/kernel protections against writing memory and so on 34 | * 35 | * Redistribution and use in source and binary forms, with or without 36 | * modification, are permitted provided that the following conditions 37 | * are met: 38 | * 1. Redistributions of source code must retain the above copyright 39 | * notice, this list of conditions and the following disclaimer. 40 | * 2. Redistributions in binary form must reproduce the above copyright 41 | * notice, this list of conditions and the following disclaimer in the 42 | * documentation and/or other materials provided with the distribution. 43 | * 3. The name of the author may not be used to endorse or promote products 44 | * derived from this software without specific prior written permission. 45 | * 46 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 47 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 48 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 49 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 50 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 51 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 52 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 53 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 54 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 55 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 56 | * 57 | */ 58 | 59 | #ifndef hydra_cpu_protections_h 60 | #define hydra_cpu_protections_h 61 | 62 | #include 63 | 64 | uint8_t disable_wp(void); 65 | uint8_t enable_wp(void); 66 | uint8_t verify_wp(void); 67 | 68 | void enable_interrupts(void); 69 | void disable_interrupts(void); 70 | 71 | #endif 72 | -------------------------------------------------------------------------------- /hydra/hydra/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /hydra/hydra/hydra-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | English 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIconFile 10 | 11 | CFBundleIdentifier 12 | put.as.${PRODUCT_NAME:rfc1034identifier} 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | ${PRODUCT_NAME} 17 | CFBundlePackageType 18 | KEXT 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1 25 | NSHumanReadableCopyright 26 | Copyright © 2012,2013 fG!. All rights reserved. 27 | OSBundleLibraries 28 | 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 | com.apple.kpi.mach 36 | 10.0.0 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /hydra/hydra/hydra-Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header for all source files of the 'hydra' target in the 'hydra' project 3 | // 4 | 5 | -------------------------------------------------------------------------------- /hydra/hydra/hydra.c: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * dddddddd 4 | * HHHHHHHHH HHHHHHHHH d::::::d 5 | * H:::::::H H:::::::H d::::::d 6 | * H:::::::H H:::::::H d::::::d 7 | * HH::::::H H::::::HH d:::::d 8 | * H:::::H H:::::Hyyyyyyy yyyyyyy ddddddddd:::::drrrrr rrrrrrrrr aaaaaaaaaaaaa 9 | * H:::::H H:::::H y:::::y y:::::ydd::::::::::::::dr::::rrr:::::::::r a::::::::::::a 10 | * H::::::HHHHH::::::H y:::::y y:::::yd::::::::::::::::dr:::::::::::::::::r aaaaaaaaa:::::a 11 | * H:::::::::::::::::H y:::::y y:::::yd:::::::ddddd:::::drr::::::rrrrr::::::r a::::a 12 | * H:::::::::::::::::H y:::::y y:::::y d::::::d d:::::d r:::::r r:::::r aaaaaaa:::::a 13 | * H::::::HHHHH::::::H y:::::y y:::::y d:::::d d:::::d r:::::r rrrrrrraa::::::::::::a 14 | * H:::::H H:::::H y:::::y:::::y d:::::d d:::::d r:::::r a::::aaaa::::::a 15 | * H:::::H H:::::H y:::::::::y d:::::d d:::::d r:::::r a::::a a:::::a 16 | * HH::::::H H::::::HH y:::::::y d::::::ddddd::::::ddr:::::r a::::a a:::::a 17 | * H:::::::H H:::::::H y:::::y d:::::::::::::::::dr:::::r a:::::aaaa::::::a 18 | * H:::::::H H:::::::H y:::::y d:::::::::ddd::::dr:::::r a::::::::::aa:::a 19 | * HHHHHHHHH HHHHHHHHH y:::::y ddddddddd dddddrrrrrrr aaaaaaaaaa aaaa 20 | * y:::::y 21 | * y:::::y 22 | * y:::::y 23 | * y:::::y 24 | * yyyyyyy 25 | * 26 | * A kernel extension to suspend applications and notify a userland daemon 27 | * 28 | * Copyright (c) 2012,2013 fG!. All rights reserved. 29 | * reverser@put.as - http://reverse.put.as 30 | * 31 | * hydra.c 32 | * 33 | * Redistribution and use in source and binary forms, with or without 34 | * modification, are permitted provided that the following conditions 35 | * are met: 36 | * 1. Redistributions of source code must retain the above copyright 37 | * notice, this list of conditions and the following disclaimer. 38 | * 2. Redistributions in binary form must reproduce the above copyright 39 | * notice, this list of conditions and the following disclaimer in the 40 | * documentation and/or other materials provided with the distribution. 41 | * 3. The name of the author may not be used to endorse or promote products 42 | * derived from this software without specific prior written permission. 43 | * 44 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 45 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 46 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 47 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 48 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 49 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 50 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 51 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 52 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 53 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 54 | * 55 | */ 56 | 57 | #include 58 | #include 59 | #include 60 | #include 61 | #include 62 | #include 63 | #include 64 | #include 65 | #include 66 | #include 67 | #include 68 | #include 69 | 70 | #include "my_data_definitions.h" 71 | #include "kernel_info.h" 72 | #include "cpu_protections.h" 73 | #include "suspend_proc.h" 74 | #include "kernel_control.h" 75 | 76 | kern_return_t hydra_start(kmod_info_t * ki, void *d); 77 | kern_return_t hydra_stop(kmod_info_t *ki, void *d); 78 | 79 | // global vars to hold original bytes, targets, and info to solve symbols 80 | char g_original_bytes[12]; 81 | targets_t g_targets_list = NULL; 82 | struct kernel_info g_kernel_info; 83 | mach_vm_address_t g_hook_symbol; 84 | 85 | /* 86 | * where the fun begins 87 | */ 88 | kern_return_t 89 | hydra_start(kmod_info_t * ki, void *d) 90 | { 91 | /* 92 | * first step: retrieve necessary kernel information so we can solve the symbols 93 | * we need: 94 | * - find kernel aslr 95 | * - patch kernel function to suspend processes 96 | * - solve symbols 97 | */ 98 | if (init_kernel_info(&g_kernel_info) != KERN_SUCCESS) 99 | { 100 | return KERN_FAILURE; 101 | } 102 | g_hook_symbol = solve_kernel_symbol(&g_kernel_info, "_proc_resetregister"); 103 | if (g_hook_symbol == 0) 104 | { 105 | LOG_MSG("[ERROR] Failure to solve proc_resetregister() symbol...\n"); 106 | return KERN_FAILURE; 107 | } 108 | // first we need to store the original bytes 109 | memcpy(g_original_bytes, (void*)g_hook_symbol, 12); 110 | // now we can overwrite with the jump to our function 111 | disable_wp(); 112 | disable_interrupts(); 113 | char trampoline[12] = "\x48\xB8\x00\x00\x00\x00\x00\x00\x00\x00" // mov rax, address 114 | "\xFF\xE0"; // jmp rax 115 | mach_vm_address_t patch_address = (mach_vm_address_t)myproc_resetregister; 116 | #if DEBUG 117 | LOG_MSG("[DEBUG] address of my proc: %llx\n", (uint64_t)myproc_resetregister); 118 | #endif 119 | // add the address of our proc_resetregister function to the trampoline 120 | memcpy(trampoline+2, &patch_address, 8); 121 | // and finally patch the kernel code 122 | memcpy((void*)g_hook_symbol, trampoline, 12); 123 | enable_wp(); 124 | enable_interrupts(); 125 | // implement the communication channel with userland 126 | start_kern_control(); 127 | // startup work is done, userland daemon is in charge 128 | return KERN_SUCCESS; 129 | } 130 | 131 | /* 132 | * no more fun :-( 133 | */ 134 | kern_return_t 135 | hydra_stop(kmod_info_t *ki, void *d) 136 | { 137 | // restore original bytes of proc_resetregister 138 | disable_wp(); 139 | disable_interrupts(); 140 | memcpy((void*)g_hook_symbol, g_original_bytes, 12); 141 | enable_wp(); 142 | enable_interrupts(); 143 | // remove kernel control channel 144 | stop_kern_control(); 145 | // all done, bye bye to hydra! 146 | return KERN_SUCCESS; 147 | } 148 | -------------------------------------------------------------------------------- /hydra/hydra/idt.c: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * dddddddd 4 | * HHHHHHHHH HHHHHHHHH d::::::d 5 | * H:::::::H H:::::::H d::::::d 6 | * H:::::::H H:::::::H d::::::d 7 | * HH::::::H H::::::HH d:::::d 8 | * H:::::H H:::::Hyyyyyyy yyyyyyy ddddddddd:::::drrrrr rrrrrrrrr aaaaaaaaaaaaa 9 | * H:::::H H:::::H y:::::y y:::::ydd::::::::::::::dr::::rrr:::::::::r a::::::::::::a 10 | * H::::::HHHHH::::::H y:::::y y:::::yd::::::::::::::::dr:::::::::::::::::r aaaaaaaaa:::::a 11 | * H:::::::::::::::::H y:::::y y:::::yd:::::::ddddd:::::drr::::::rrrrr::::::r a::::a 12 | * H:::::::::::::::::H y:::::y y:::::y d::::::d d:::::d r:::::r r:::::r aaaaaaa:::::a 13 | * H::::::HHHHH::::::H y:::::y y:::::y d:::::d d:::::d r:::::r rrrrrrraa::::::::::::a 14 | * H:::::H H:::::H y:::::y:::::y d:::::d d:::::d r:::::r a::::aaaa::::::a 15 | * H:::::H H:::::H y:::::::::y d:::::d d:::::d r:::::r a::::a a:::::a 16 | * HH::::::H H::::::HH y:::::::y d::::::ddddd::::::ddr:::::r a::::a a:::::a 17 | * H:::::::H H:::::::H y:::::y d:::::::::::::::::dr:::::r a:::::aaaa::::::a 18 | * H:::::::H H:::::::H y:::::y d:::::::::ddd::::dr:::::r a::::::::::aa:::a 19 | * HHHHHHHHH HHHHHHHHH y:::::y ddddddddd dddddrrrrrrr aaaaaaaaaa aaaa 20 | * y:::::y 21 | * y:::::y 22 | * y:::::y 23 | * y:::::y 24 | * yyyyyyy 25 | * 26 | * A kernel extension to suspend applications and notify a userland daemon 27 | * 28 | * Copyright (c) 2012,2013 fG!. All rights reserved. 29 | * reverser@put.as - http://reverse.put.as 30 | * 31 | * idt.c 32 | * 33 | * Functions to deal with IDT table 34 | * 35 | * Redistribution and use in source and binary forms, with or without 36 | * modification, are permitted provided that the following conditions 37 | * are met: 38 | * 1. Redistributions of source code must retain the above copyright 39 | * notice, this list of conditions and the following disclaimer. 40 | * 2. Redistributions in binary form must reproduce the above copyright 41 | * notice, this list of conditions and the following disclaimer in the 42 | * documentation and/or other materials provided with the distribution. 43 | * 3. The name of the author may not be used to endorse or promote products 44 | * derived from this software without specific prior written permission. 45 | * 46 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 47 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 48 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 49 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 50 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 51 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 52 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 53 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 54 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 55 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 56 | * 57 | */ 58 | 59 | #include "idt.h" 60 | 61 | // retrieve the address of the IDT 62 | void 63 | get_addr_idt(mach_vm_address_t *idt) 64 | { 65 | uint8_t idtr[10]; 66 | __asm__ volatile ("sidt %0": "=m" (idtr)); 67 | *idt = *(mach_vm_address_t *)(idtr+2); 68 | } 69 | 70 | // retrieve the size of the IDT 71 | uint16_t 72 | get_size_idt(void) 73 | { 74 | uint8_t idtr[10]; 75 | uint16_t size = 0; 76 | __asm__ volatile ("sidt %0": "=m" (idtr)); 77 | size = *((uint16_t *) &idtr[0]); 78 | return(size); 79 | } 80 | -------------------------------------------------------------------------------- /hydra/hydra/idt.h: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * dddddddd 4 | * HHHHHHHHH HHHHHHHHH d::::::d 5 | * H:::::::H H:::::::H d::::::d 6 | * H:::::::H H:::::::H d::::::d 7 | * HH::::::H H::::::HH d:::::d 8 | * H:::::H H:::::Hyyyyyyy yyyyyyy ddddddddd:::::drrrrr rrrrrrrrr aaaaaaaaaaaaa 9 | * H:::::H H:::::H y:::::y y:::::ydd::::::::::::::dr::::rrr:::::::::r a::::::::::::a 10 | * H::::::HHHHH::::::H y:::::y y:::::yd::::::::::::::::dr:::::::::::::::::r aaaaaaaaa:::::a 11 | * H:::::::::::::::::H y:::::y y:::::yd:::::::ddddd:::::drr::::::rrrrr::::::r a::::a 12 | * H:::::::::::::::::H y:::::y y:::::y d::::::d d:::::d r:::::r r:::::r aaaaaaa:::::a 13 | * H::::::HHHHH::::::H y:::::y y:::::y d:::::d d:::::d r:::::r rrrrrrraa::::::::::::a 14 | * H:::::H H:::::H y:::::y:::::y d:::::d d:::::d r:::::r a::::aaaa::::::a 15 | * H:::::H H:::::H y:::::::::y d:::::d d:::::d r:::::r a::::a a:::::a 16 | * HH::::::H H::::::HH y:::::::y d::::::ddddd::::::ddr:::::r a::::a a:::::a 17 | * H:::::::H H:::::::H y:::::y d:::::::::::::::::dr:::::r a:::::aaaa::::::a 18 | * H:::::::H H:::::::H y:::::y d:::::::::ddd::::dr:::::r a::::::::::aa:::a 19 | * HHHHHHHHH HHHHHHHHH y:::::y ddddddddd dddddrrrrrrr aaaaaaaaaa aaaa 20 | * y:::::y 21 | * y:::::y 22 | * y:::::y 23 | * y:::::y 24 | * yyyyyyy 25 | * 26 | * A kernel extension to suspend applications and notify a userland daemon 27 | * 28 | * Copyright (c) 2012,2013 fG!. All rights reserved. 29 | * reverser@put.as - http://reverse.put.as 30 | * 31 | * idt.h 32 | * 33 | * Functions to deal with IDT table 34 | * 35 | * Redistribution and use in source and binary forms, with or without 36 | * modification, are permitted provided that the following conditions 37 | * are met: 38 | * 1. Redistributions of source code must retain the above copyright 39 | * notice, this list of conditions and the following disclaimer. 40 | * 2. Redistributions in binary form must reproduce the above copyright 41 | * notice, this list of conditions and the following disclaimer in the 42 | * documentation and/or other materials provided with the distribution. 43 | * 3. The name of the author may not be used to endorse or promote products 44 | * derived from this software without specific prior written permission. 45 | * 46 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 47 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 48 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 49 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 50 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 51 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 52 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 53 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 54 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 55 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 56 | * 57 | */ 58 | 59 | #ifndef hydra_idt_h 60 | #define hydra_idt_h 61 | 62 | #include 63 | #include 64 | 65 | // 16 bytes IDT descriptor, used for 32 and 64 bits kernels (64 bit capable cpus!) 66 | struct descriptor_idt 67 | { 68 | uint16_t offset_low; 69 | uint16_t seg_selector; 70 | uint8_t reserved; 71 | uint8_t flag; 72 | uint16_t offset_middle; 73 | uint32_t offset_high; 74 | uint32_t reserved2; 75 | }; 76 | 77 | uint16_t get_size_idt(void); 78 | void get_addr_idt (mach_vm_address_t* idt); 79 | 80 | #endif -------------------------------------------------------------------------------- /hydra/hydra/kernel_control.c: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * dddddddd 4 | * HHHHHHHHH HHHHHHHHH d::::::d 5 | * H:::::::H H:::::::H d::::::d 6 | * H:::::::H H:::::::H d::::::d 7 | * HH::::::H H::::::HH d:::::d 8 | * H:::::H H:::::Hyyyyyyy yyyyyyy ddddddddd:::::drrrrr rrrrrrrrr aaaaaaaaaaaaa 9 | * H:::::H H:::::H y:::::y y:::::ydd::::::::::::::dr::::rrr:::::::::r a::::::::::::a 10 | * H::::::HHHHH::::::H y:::::y y:::::yd::::::::::::::::dr:::::::::::::::::r aaaaaaaaa:::::a 11 | * H:::::::::::::::::H y:::::y y:::::yd:::::::ddddd:::::drr::::::rrrrr::::::r a::::a 12 | * H:::::::::::::::::H y:::::y y:::::y d::::::d d:::::d r:::::r r:::::r aaaaaaa:::::a 13 | * H::::::HHHHH::::::H y:::::y y:::::y d:::::d d:::::d r:::::r rrrrrrraa::::::::::::a 14 | * H:::::H H:::::H y:::::y:::::y d:::::d d:::::d r:::::r a::::aaaa::::::a 15 | * H:::::H H:::::H y:::::::::y d:::::d d:::::d r:::::r a::::a a:::::a 16 | * HH::::::H H::::::HH y:::::::y d::::::ddddd::::::ddr:::::r a::::a a:::::a 17 | * H:::::::H H:::::::H y:::::y d:::::::::::::::::dr:::::r a:::::aaaa::::::a 18 | * H:::::::H H:::::::H y:::::y d:::::::::ddd::::dr:::::r a::::::::::aa:::a 19 | * HHHHHHHHH HHHHHHHHH y:::::y ddddddddd dddddrrrrrrr aaaaaaaaaa aaaa 20 | * y:::::y 21 | * y:::::y 22 | * y:::::y 23 | * y:::::y 24 | * yyyyyyy 25 | * 26 | * A kernel extension to suspend applications and notify a userland daemon 27 | * 28 | * Copyright (c) 2012,2013 fG!. All rights reserved. 29 | * reverser@put.as - http://reverse.put.as 30 | * 31 | * kernel_control.c 32 | * 33 | * Redistribution and use in source and binary forms, with or without 34 | * modification, are permitted provided that the following conditions 35 | * are met: 36 | * 1. Redistributions of source code must retain the above copyright 37 | * notice, this list of conditions and the following disclaimer. 38 | * 2. Redistributions in binary form must reproduce the above copyright 39 | * notice, this list of conditions and the following disclaimer in the 40 | * documentation and/or other materials provided with the distribution. 41 | * 3. The name of the author may not be used to endorse or promote products 42 | * derived from this software without specific prior written permission. 43 | * 44 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 45 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 46 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 47 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 48 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 49 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 50 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 51 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 52 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 53 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 54 | * 55 | */ 56 | 57 | #include "kernel_control.h" 58 | 59 | #include 60 | #include 61 | #include 62 | #include 63 | #include 64 | #include 65 | #include 66 | #include 67 | 68 | #include "shared_data.h" 69 | #include "my_data_definitions.h" 70 | 71 | // local functions 72 | static int ctl_connect(kern_ctl_ref ctl_ref, struct sockaddr_ctl *sac, void **unitinfo); 73 | static errno_t ctl_disconnect(kern_ctl_ref ctl_ref, u_int32_t unit, void *unitinfo); 74 | static int ctl_get(kern_ctl_ref ctl_ref, u_int32_t unit, void *unitinfo, int opt, void *data, size_t *len); 75 | static int ctl_set(kern_ctl_ref ctl_ref, u_int32_t unit, void *unitinfo, int opt, void *data, size_t len); 76 | 77 | // vars, external and local 78 | extern targets_t g_targets_list; 79 | 80 | static boolean_t gKernCtlRegistered = FALSE; 81 | static int max_clients; 82 | static uint32_t gClientUnit = 0; 83 | static kern_ctl_ref gClientCtlRef = NULL; 84 | static kern_ctl_ref gctl_ref; 85 | 86 | #pragma mark Kernel Control struct and handler functions 87 | 88 | // described at Network Kernel Extensions Programming Guide 89 | static struct kern_ctl_reg gctl_reg = { 90 | BUNDLE_ID, /* use a reverse dns name which includes a name unique to your comany */ 91 | 0, /* set to 0 for dynamically assigned control ID - CTL_FLAG_REG_ID_UNIT not set */ 92 | 0, /* ctl_unit - ignored when CTL_FLAG_REG_ID_UNIT not set */ 93 | CTL_FLAG_PRIVILEGED, /* privileged access required to access this filter */ 94 | 0, /* use default send size buffer */ 95 | 0, /* Override receive buffer size */ 96 | ctl_connect, /* Called when a connection request is accepted */ 97 | ctl_disconnect, /* called when a connection becomes disconnected */ 98 | NULL, /* ctl_send_func - handles data sent from the client to kernel control */ 99 | ctl_set, /* called when the user process makes the setsockopt call */ 100 | ctl_get /* called when the user process makes the getsockopt call */ 101 | }; 102 | 103 | #pragma mark start and stop functions, the only exported ones 104 | 105 | /* 106 | * initialize the kernel control 107 | */ 108 | kern_return_t 109 | start_kern_control(void) 110 | { 111 | errno_t error = 0; 112 | // register the kernel control 113 | error = ctl_register(&gctl_reg, &gctl_ref); 114 | if (error == 0) 115 | { 116 | gKernCtlRegistered = TRUE; 117 | return KERN_SUCCESS; 118 | } 119 | else 120 | { 121 | LOG_MSG("[ERROR] Could not initialize control channel!\n"); 122 | return KERN_FAILURE; 123 | } 124 | } 125 | 126 | /* 127 | * and remove it 128 | */ 129 | kern_return_t 130 | stop_kern_control(void) 131 | { 132 | errno_t error = 0; 133 | // remove kernel control 134 | // XXX: this is useless since we fail if control failed to install 135 | if (gKernCtlRegistered == TRUE) 136 | { 137 | error = ctl_deregister(gctl_ref); 138 | } 139 | return KERN_SUCCESS; 140 | } 141 | 142 | /* 143 | * get data ready for userland to grab 144 | * we only send PID of the suspended process and let the userland daemon do the rest 145 | */ 146 | kern_return_t 147 | queue_userland_data(pid_t pid) 148 | { 149 | errno_t error = 0; 150 | 151 | if (gClientCtlRef == NULL) 152 | { 153 | LOG_MSG("[ERROR] No client reference available, can't proceed...\n"); 154 | return KERN_FAILURE; 155 | } 156 | 157 | error = ctl_enqueuedata(gClientCtlRef, gClientUnit, &pid, sizeof(pid_t), 0); 158 | if (error) 159 | { 160 | LOG_MSG("[ERROR] ctl_enqueuedata failed with error: %d\n", error); 161 | return KERN_FAILURE; 162 | } 163 | 164 | return KERN_SUCCESS; 165 | } 166 | 167 | #pragma mark Kernel Control handler functions 168 | 169 | /* 170 | * called when a client connects to the socket 171 | * we need to store some info to use later 172 | */ 173 | static int 174 | ctl_connect(kern_ctl_ref ctl_ref, struct sockaddr_ctl *sac, void **unitinfo) 175 | { 176 | // we only accept a single client 177 | if (max_clients > 0) 178 | { 179 | LOG_MSG("[ERROR] Maximum number of clients reached!\n"); 180 | return EBUSY; 181 | } 182 | max_clients++; 183 | // store the unit id and ctl_ref of the client that connected 184 | // we will need these to queue data to userland 185 | gClientUnit = sac->sc_unit; 186 | gClientCtlRef = ctl_ref; 187 | return 0; 188 | } 189 | 190 | /* 191 | * and when client disconnects 192 | */ 193 | static errno_t 194 | ctl_disconnect(kern_ctl_ref ctl_ref, u_int32_t unit, void *unitinfo) 195 | { 196 | // reset max clients 197 | max_clients = 0; 198 | gClientUnit = 0; 199 | gClientCtlRef = NULL; 200 | return 0; 201 | } 202 | 203 | /* 204 | * kernel -> userland 205 | */ 206 | static int 207 | ctl_get(kern_ctl_ref ctl_ref, u_int32_t unit, void *unitinfo, int opt, void *data, size_t *len) 208 | { 209 | int error = 0; 210 | size_t valsize = 0; 211 | void *buf = NULL; 212 | switch (opt) 213 | { 214 | case 0: 215 | { 216 | valsize = 0; 217 | break; 218 | } 219 | default: 220 | error = ENOTSUP; 221 | break; 222 | } 223 | if (error == 0) 224 | { 225 | *len = valsize; 226 | if (data != NULL) bcopy(buf, data, valsize); 227 | } 228 | return error; 229 | } 230 | 231 | /* 232 | * userland -> kernel 233 | * this is how userland apps adds and removes apps to be suspended 234 | */ 235 | static int 236 | ctl_set(kern_ctl_ref ctl_ref, u_int32_t unit, void *unitinfo, int opt, void *data, size_t len) 237 | { 238 | int error = 0; 239 | 240 | switch (opt) 241 | { 242 | case ADD_APP: 243 | { 244 | if (len > 0 && data != NULL) 245 | { 246 | targets_t temp; 247 | HASH_FIND_STR(g_targets_list, (char*)data, temp); 248 | if (temp == NULL) 249 | { 250 | temp = _MALLOC(sizeof(struct targets), 1, M_ZERO); 251 | if (temp != NULL) 252 | { 253 | // the process name will be truncated at MAXCOMLEN so there's no need to allocate more than that 254 | if (len >= MAXCOMLEN) 255 | { 256 | temp->name = _MALLOC(MAXCOMLEN+1, 1, M_ZERO); 257 | len = MAXCOMLEN+1; 258 | } 259 | else 260 | { 261 | // the len should include the space for the nul char 262 | // else we will lose last char 263 | temp->name = _MALLOC(len, 1, M_ZERO); 264 | } 265 | strlcpy(temp->name, (const char*)data, len); 266 | // we need to recompute len or substract 1 else hash will not match strings 267 | HASH_ADD_KEYPTR(hh, g_targets_list, temp->name, (int)strlen(temp->name), temp); 268 | } 269 | } 270 | } 271 | break; 272 | } 273 | case REMOVE_APP: 274 | { 275 | if (len > 0 && data != NULL) 276 | { 277 | targets_t temp; 278 | HASH_FIND_STR(g_targets_list, (char*)data, temp); 279 | if (temp) 280 | { 281 | #if DEBUG 282 | LOG_MSG("[DEBUG] Found element in list, removing!\n"); 283 | #endif 284 | // free the name string we alloc'ed before 285 | _FREE(temp->name, M_ZERO); 286 | // remove from the list and free the element 287 | HASH_DEL(g_targets_list, temp); 288 | _FREE(temp, M_ZERO); 289 | } 290 | } 291 | break; 292 | } 293 | case REMOVE_ALL_APPS: 294 | { 295 | targets_t temp; 296 | targets_t target; 297 | HASH_ITER(hh, g_targets_list, target, temp) 298 | { 299 | _FREE(target->name, M_ZERO); 300 | HASH_DEL(g_targets_list, target); 301 | _FREE(target, M_ZERO); 302 | } 303 | 304 | break; 305 | } 306 | default: 307 | error = ENOTSUP; 308 | break; 309 | } 310 | return error; 311 | } 312 | -------------------------------------------------------------------------------- /hydra/hydra/kernel_control.h: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * dddddddd 4 | * HHHHHHHHH HHHHHHHHH d::::::d 5 | * H:::::::H H:::::::H d::::::d 6 | * H:::::::H H:::::::H d::::::d 7 | * HH::::::H H::::::HH d:::::d 8 | * H:::::H H:::::Hyyyyyyy yyyyyyy ddddddddd:::::drrrrr rrrrrrrrr aaaaaaaaaaaaa 9 | * H:::::H H:::::H y:::::y y:::::ydd::::::::::::::dr::::rrr:::::::::r a::::::::::::a 10 | * H::::::HHHHH::::::H y:::::y y:::::yd::::::::::::::::dr:::::::::::::::::r aaaaaaaaa:::::a 11 | * H:::::::::::::::::H y:::::y y:::::yd:::::::ddddd:::::drr::::::rrrrr::::::r a::::a 12 | * H:::::::::::::::::H y:::::y y:::::y d::::::d d:::::d r:::::r r:::::r aaaaaaa:::::a 13 | * H::::::HHHHH::::::H y:::::y y:::::y d:::::d d:::::d r:::::r rrrrrrraa::::::::::::a 14 | * H:::::H H:::::H y:::::y:::::y d:::::d d:::::d r:::::r a::::aaaa::::::a 15 | * H:::::H H:::::H y:::::::::y d:::::d d:::::d r:::::r a::::a a:::::a 16 | * HH::::::H H::::::HH y:::::::y d::::::ddddd::::::ddr:::::r a::::a a:::::a 17 | * H:::::::H H:::::::H y:::::y d:::::::::::::::::dr:::::r a:::::aaaa::::::a 18 | * H:::::::H H:::::::H y:::::y d:::::::::ddd::::dr:::::r a::::::::::aa:::a 19 | * HHHHHHHHH HHHHHHHHH y:::::y ddddddddd dddddrrrrrrr aaaaaaaaaa aaaa 20 | * y:::::y 21 | * y:::::y 22 | * y:::::y 23 | * y:::::y 24 | * yyyyyyy 25 | * 26 | * A kernel extension to suspend applications and notify a userland daemon 27 | * 28 | * Copyright (c) 2012,2013 fG!. All rights reserved. 29 | * reverser@put.as - http://reverse.put.as 30 | * 31 | * kernel_control.h 32 | * 33 | * Redistribution and use in source and binary forms, with or without 34 | * modification, are permitted provided that the following conditions 35 | * are met: 36 | * 1. Redistributions of source code must retain the above copyright 37 | * notice, this list of conditions and the following disclaimer. 38 | * 2. Redistributions in binary form must reproduce the above copyright 39 | * notice, this list of conditions and the following disclaimer in the 40 | * documentation and/or other materials provided with the distribution. 41 | * 3. The name of the author may not be used to endorse or promote products 42 | * derived from this software without specific prior written permission. 43 | * 44 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 45 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 46 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 47 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 48 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 49 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 50 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 51 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 52 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 53 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 54 | * 55 | */ 56 | 57 | #ifndef hydra_kernel_control_h 58 | #define hydra_kernel_control_h 59 | 60 | #include 61 | #include 62 | 63 | kern_return_t start_kern_control(void); 64 | kern_return_t stop_kern_control(void); 65 | kern_return_t queue_userland_data(pid_t pid); 66 | 67 | #endif 68 | -------------------------------------------------------------------------------- /hydra/hydra/kernel_info.c: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * dddddddd 4 | * HHHHHHHHH HHHHHHHHH d::::::d 5 | * H:::::::H H:::::::H d::::::d 6 | * H:::::::H H:::::::H d::::::d 7 | * HH::::::H H::::::HH d:::::d 8 | * H:::::H H:::::Hyyyyyyy yyyyyyy ddddddddd:::::drrrrr rrrrrrrrr aaaaaaaaaaaaa 9 | * H:::::H H:::::H y:::::y y:::::ydd::::::::::::::dr::::rrr:::::::::r a::::::::::::a 10 | * H::::::HHHHH::::::H y:::::y y:::::yd::::::::::::::::dr:::::::::::::::::r aaaaaaaaa:::::a 11 | * H:::::::::::::::::H y:::::y y:::::yd:::::::ddddd:::::drr::::::rrrrr::::::r a::::a 12 | * H:::::::::::::::::H y:::::y y:::::y d::::::d d:::::d r:::::r r:::::r aaaaaaa:::::a 13 | * H::::::HHHHH::::::H y:::::y y:::::y d:::::d d:::::d r:::::r rrrrrrraa::::::::::::a 14 | * H:::::H H:::::H y:::::y:::::y d:::::d d:::::d r:::::r a::::aaaa::::::a 15 | * H:::::H H:::::H y:::::::::y d:::::d d:::::d r:::::r a::::a a:::::a 16 | * HH::::::H H::::::HH y:::::::y d::::::ddddd::::::ddr:::::r a::::a a:::::a 17 | * H:::::::H H:::::::H y:::::y d:::::::::::::::::dr:::::r a:::::aaaa::::::a 18 | * H:::::::H H:::::::H y:::::y d:::::::::ddd::::dr:::::r a::::::::::aa:::a 19 | * HHHHHHHHH HHHHHHHHH y:::::y ddddddddd dddddrrrrrrr aaaaaaaaaa aaaa 20 | * y:::::y 21 | * y:::::y 22 | * y:::::y 23 | * y:::::y 24 | * yyyyyyy 25 | * 26 | * A kernel extension to suspend applications and notify a userland daemon 27 | * 28 | * Copyright (c) 2012,2013 fG!. All rights reserved. 29 | * reverser@put.as - http://reverse.put.as 30 | * 31 | * kernel_info.c 32 | * 33 | * Redistribution and use in source and binary forms, with or without 34 | * modification, are permitted provided that the following conditions 35 | * are met: 36 | * 1. Redistributions of source code must retain the above copyright 37 | * notice, this list of conditions and the following disclaimer. 38 | * 2. Redistributions in binary form must reproduce the above copyright 39 | * notice, this list of conditions and the following disclaimer in the 40 | * documentation and/or other materials provided with the distribution. 41 | * 3. The name of the author may not be used to endorse or promote products 42 | * derived from this software without specific prior written permission. 43 | * 44 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 45 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 46 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 47 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 48 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 49 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 50 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 51 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 52 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 53 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 54 | * 55 | */ 56 | 57 | #include "kernel_info.h" 58 | 59 | #include 60 | #include 61 | #include 62 | #include 63 | #include 64 | #include 65 | #include 66 | #include 67 | 68 | #include "proc.h" 69 | #include "idt.h" 70 | 71 | static int get_kernel_mach_header(void *buffer, vnode_t kernel_vnode); 72 | static int process_mach_header(void *kernel_header, kernel_info_t kernel_info); 73 | static int get_kernel_linkedit(vnode_t kernel_vnode, kernel_info_t kernel_info); 74 | static mach_vm_address_t calculate_int80address(const mach_vm_address_t idt_address); 75 | static mach_vm_address_t get_running_text_address(void); 76 | static mach_vm_address_t find_kernel_base(const mach_vm_address_t int80_address); 77 | 78 | #pragma mark Public functions 79 | 80 | /* 81 | * entrypoint function to read necessary information from running kernel and kernel at disk 82 | * such as kaslr slide, linkedit location 83 | */ 84 | kern_return_t 85 | init_kernel_info(kernel_info_t kernel_info) 86 | { 87 | kern_return_t error = 0; 88 | // lookup vnode for /mach_kernel 89 | vnode_t kernel_vnode = NULLVP; 90 | 91 | error = vnode_lookup("/mach_kernel", 0, &kernel_vnode, NULL); 92 | if (error) 93 | { 94 | LOG_MSG("[ERROR] Kernel vnode lookup failed!\n"); 95 | return KERN_FAILURE; 96 | } 97 | 98 | void *kernel_header = _MALLOC(PAGE_SIZE_64, 1, M_ZERO); 99 | if (kernel_header == NULL) 100 | { 101 | LOG_MSG("[ERROR] Failed to allocate memory for kernel mach-o header!\n"); 102 | goto failure; 103 | } 104 | // read and process kernel header from filesystem 105 | if (get_kernel_mach_header(kernel_header, kernel_vnode) || 106 | process_mach_header(kernel_header, kernel_info)) 107 | { 108 | goto failure; 109 | } 110 | // compute kaslr slide 111 | kernel_info->running_text_addr = get_running_text_address(); 112 | kernel_info->kaslr_slide = kernel_info->running_text_addr - kernel_info->disk_text_addr; 113 | #if DEBUG 114 | LOG_MSG("[DEBUG] kernel aslr slide is %llx\n", kernel_info->kaslr_slide); 115 | #endif 116 | // we know the location of linkedit and offsets into symbols and their strings 117 | // now we need to read linkedit into a buffer so we can process it 118 | // __LINKEDIT total size is around 1MB 119 | kernel_info->linkedit_buf = _MALLOC(kernel_info->linkedit_size, 1, M_ZERO); 120 | if (kernel_info->linkedit_buf == NULL) 121 | { 122 | LOG_MSG("[ERROR] Failed to allocate memory for linkedit buffer!\n"); 123 | goto failure; 124 | } 125 | // read linkedit from filesystem 126 | if (get_kernel_linkedit(kernel_vnode, kernel_info)) 127 | { 128 | goto failure; 129 | } 130 | 131 | success: 132 | _FREE(kernel_header, M_ZERO); 133 | vnode_put(kernel_vnode); 134 | return KERN_SUCCESS; 135 | 136 | failure: 137 | if (kernel_header != NULL) 138 | { 139 | _FREE(kernel_header, M_ZERO); 140 | } 141 | vnode_put(kernel_vnode); 142 | return KERN_FAILURE; 143 | } 144 | 145 | /* 146 | * function to solve a kernel symbol 147 | */ 148 | mach_vm_address_t 149 | solve_kernel_symbol(kernel_info_t kernel_info, char *symbol_to_solve) 150 | { 151 | struct nlist_64 *nlist = NULL; 152 | kernel_info_t ki = kernel_info; 153 | 154 | if (ki == NULL || ki->linkedit_buf == NULL) 155 | { 156 | LOG_MSG("[ERROR] Kernel info struct is NULL or no linkedit buffer available!\n"); 157 | return 0; 158 | } 159 | 160 | mach_vm_address_t symbol_offset = ki->symboltable_fileoffset - ki->linkedit_fileoffset; 161 | mach_vm_address_t string_offset = ki->stringtable_fileoffset - ki->linkedit_fileoffset; 162 | 163 | for (int i = 0; i < ki->symboltable_nr_symbols; i++) 164 | { 165 | nlist = (struct nlist_64*)((char*)ki->linkedit_buf + symbol_offset + i * sizeof(struct nlist_64)); 166 | char *symbol_string = ((char*)ki->linkedit_buf + string_offset + nlist->n_un.n_strx); 167 | // find if symbol matches 168 | if (strncasecmp(symbol_to_solve, symbol_string, strlen(symbol_to_solve)) == 0) 169 | { 170 | #if DEBUG 171 | LOG_MSG("[DEBUG] found kernel symbol %s at %p\n", symbol_to_solve, (void*)nlist->n_value); 172 | #endif 173 | return (nlist->n_value + ki->kaslr_slide); 174 | } 175 | } 176 | return 0; 177 | } 178 | 179 | #pragma Local functions to get data from filesystem /mach_kernel 180 | 181 | /* 182 | * retrieve the first page of kernel binary at disk into input buffer 183 | * XXX: only ready for Mountain Lion since it assumes kernel image is non-fat 184 | * not hard to make it compatible with fat images 185 | */ 186 | static int 187 | get_kernel_mach_header(void *buffer, vnode_t kernel_vnode) 188 | { 189 | int error = KERN_SUCCESS; 190 | uio_t uio = uio_create(1, 0, UIO_SYSSPACE, UIO_READ); 191 | if (uio == NULL) 192 | { 193 | LOG_MSG("[ERROR] uio_create returned null!\n"); 194 | return KERN_FAILURE; 195 | } 196 | error = uio_addiov(uio, CAST_USER_ADDR_T(buffer), PAGE_SIZE_64); 197 | if (error) 198 | { 199 | LOG_MSG("[ERROR] uio_addiov returned error!\n"); 200 | return KERN_FAILURE; 201 | } 202 | // read kernel vnode into the buffer 203 | error = VNOP_READ(kernel_vnode, uio, 0, NULL); 204 | if (error) 205 | { 206 | LOG_MSG("[ERROR] VNOP_READ failed!\n"); 207 | return KERN_FAILURE; 208 | } 209 | else if (uio_resid(uio)) 210 | { 211 | return EINVAL; 212 | } 213 | 214 | return KERN_SUCCESS; 215 | } 216 | 217 | /* 218 | * retrieve the whole linkedit segment into target buffer from kernel binary at disk 219 | */ 220 | static int 221 | get_kernel_linkedit(vnode_t kernel_vnode, kernel_info_t kernel_info) 222 | { 223 | int error = 0; 224 | uio_t uio = uio_create(1, kernel_info->linkedit_fileoffset, UIO_SYSSPACE, UIO_READ); 225 | if (uio == NULL) 226 | { 227 | LOG_MSG("[ERROR] uio_create returned null!\n"); 228 | return KERN_FAILURE; 229 | } 230 | 231 | error = uio_addiov(uio, CAST_USER_ADDR_T(kernel_info->linkedit_buf), kernel_info->linkedit_size); 232 | if (error) 233 | { 234 | LOG_MSG("[ERROR] uio_addiov returned error!\n"); 235 | return KERN_FAILURE; 236 | } 237 | 238 | error = VNOP_READ(kernel_vnode, uio, 0, NULL); 239 | if (error) 240 | { 241 | LOG_MSG("[ERROR] VNOP_READ failed!\n"); 242 | return KERN_FAILURE; 243 | } 244 | else if (uio_resid(uio)) 245 | { 246 | return EINVAL; 247 | } 248 | 249 | return KERN_SUCCESS; 250 | } 251 | 252 | #pragma Local functions to read kernel Mach-O header 253 | 254 | /* 255 | * retrieve necessary information from the kernel at disk 256 | */ 257 | static int 258 | process_mach_header(void *kernel_header, kernel_info_t kernel_info) 259 | { 260 | // now we can iterate over the kernel headers 261 | struct mach_header_64 *mh = (struct mach_header_64*)kernel_header; 262 | struct load_command *load_cmd = NULL; 263 | // point to the first load command 264 | char *load_cmd_addr = (char*)kernel_header + sizeof(struct mach_header_64); 265 | // iterate over all load cmds and retrieve required info to solve symbols 266 | // __LINKEDIT location and symbol table location 267 | for (int i = 0; i < mh->ncmds; i++) 268 | { 269 | load_cmd = (struct load_command*)load_cmd_addr; 270 | if (load_cmd->cmd == LC_SEGMENT_64) 271 | { 272 | struct segment_command_64 *seg_cmd = (struct segment_command_64*)load_cmd; 273 | // use this one to retrieve the original vm address of __TEXT so we can compute aslr slide 274 | if (strncmp(seg_cmd->segname, "__TEXT", 16) == 0) 275 | { 276 | kernel_info->disk_text_addr = seg_cmd->vmaddr; 277 | } 278 | else if (strncmp(seg_cmd->segname, "__LINKEDIT", 16) == 0) 279 | { 280 | kernel_info->linkedit_fileoffset = seg_cmd->fileoff; 281 | kernel_info->linkedit_size = seg_cmd->filesize; 282 | } 283 | } 284 | else if (load_cmd->cmd == LC_SYMTAB) 285 | { 286 | struct symtab_command *symtab_cmd = (struct symtab_command*)load_cmd; 287 | kernel_info->symboltable_fileoffset = symtab_cmd->symoff; 288 | kernel_info->symboltable_nr_symbols = symtab_cmd->nsyms; 289 | kernel_info->stringtable_fileoffset = symtab_cmd->stroff; 290 | kernel_info->stringtable_size = symtab_cmd->strsize; 291 | } 292 | load_cmd_addr += load_cmd->cmdsize; 293 | } 294 | return KERN_SUCCESS; 295 | } 296 | 297 | #pragma Local functions to find address of running kernel and find kernel ASLR slide 298 | 299 | /* 300 | * retrieve the __TEXT address of current loaded kernel so we can compute the KASLR slide 301 | */ 302 | static mach_vm_address_t 303 | get_running_text_address(void) 304 | { 305 | // retrieves the address of the IDT 306 | mach_vm_address_t idt_address = 0; 307 | get_addr_idt(&idt_address); 308 | // calculate the address of the int80 handler 309 | mach_vm_address_t int80_address = calculate_int80address(idt_address); 310 | // search backwards for the kernel base address (mach-o header) 311 | mach_vm_address_t kernel_base = find_kernel_base(int80_address); 312 | // get the vm address of __TEXT segment 313 | if (kernel_base != 0) 314 | { 315 | // get the vm address of __TEXT segment 316 | struct mach_header_64 *mh = (struct mach_header_64*)kernel_base; 317 | struct load_command *load_cmd = NULL; 318 | char *load_cmd_addr = (char*)kernel_base + sizeof(struct mach_header_64); 319 | for (uint32_t i = 0; i < mh->ncmds; i++) 320 | { 321 | load_cmd = (struct load_command*)load_cmd_addr; 322 | if (load_cmd->cmd == LC_SEGMENT_64) 323 | { 324 | struct segment_command_64 *seg_cmd = (struct segment_command_64*)load_cmd; 325 | if (strncmp(seg_cmd->segname, "__TEXT", 16) == 0) 326 | { 327 | return seg_cmd->vmaddr; 328 | } 329 | } 330 | load_cmd_addr += load_cmd->cmdsize; 331 | } 332 | } 333 | // return 0 in case of failure 334 | return 0; 335 | } 336 | 337 | /* 338 | * calculate the address of the kernel int80 handler 339 | * using the IDT array 340 | */ 341 | static mach_vm_address_t 342 | calculate_int80address(const mach_vm_address_t idt_address) 343 | { 344 | // find the address of interrupt 0x80 - EXCEP64_SPC_USR(0x80,hi64_unix_scall) @ osfmk/i386/idt64.s 345 | struct descriptor_idt *int80_descriptor = NULL; 346 | mach_vm_address_t int80_address = 0; 347 | // we need to compute the address, it's not direct 348 | // extract the stub address 349 | // retrieve the descriptor for interrupt 0x80 350 | // the IDT is an array of descriptors 351 | int80_descriptor = (struct descriptor_idt*)(idt_address+sizeof(struct descriptor_idt)*0x80); 352 | uint64_t high = (unsigned long)int80_descriptor->offset_high << 32; 353 | uint32_t middle = (unsigned int)int80_descriptor->offset_middle << 16; 354 | int80_address = (mach_vm_address_t)(high + middle + int80_descriptor->offset_low); 355 | #if DEBUG 356 | LOG_MSG("[DEBUG] Address of interrupt 80 stub is %llx\n", int80_address); 357 | #endif 358 | return int80_address; 359 | } 360 | 361 | /* 362 | * find the kernel base address (mach-o header) 363 | * by searching backwards using the int80 handler as starting point 364 | */ 365 | static mach_vm_address_t 366 | find_kernel_base(const mach_vm_address_t int80_address) 367 | { 368 | mach_vm_address_t temp_address = int80_address; 369 | struct segment_command_64 *segment_command = NULL; 370 | 371 | while (temp_address > 0) 372 | { 373 | if (*(uint32_t*)(temp_address) == MH_MAGIC_64) 374 | { 375 | // make sure it's the header and not some reference to the MAGIC number 376 | segment_command = (struct segment_command_64*)(temp_address+sizeof(struct mach_header_64)); 377 | if (strncmp(segment_command->segname, "__TEXT", 16) == 0) 378 | { 379 | #if DEBUG 380 | LOG_MSG("[DEBUG] Found kernel mach-o header address at %p\n", (void*)(temp_address)); 381 | #endif 382 | return (mach_vm_address_t)temp_address; 383 | } 384 | } 385 | temp_address--; 386 | } 387 | return 0; 388 | } 389 | -------------------------------------------------------------------------------- /hydra/hydra/kernel_info.h: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * dddddddd 4 | * HHHHHHHHH HHHHHHHHH d::::::d 5 | * H:::::::H H:::::::H d::::::d 6 | * H:::::::H H:::::::H d::::::d 7 | * HH::::::H H::::::HH d:::::d 8 | * H:::::H H:::::Hyyyyyyy yyyyyyy ddddddddd:::::drrrrr rrrrrrrrr aaaaaaaaaaaaa 9 | * H:::::H H:::::H y:::::y y:::::ydd::::::::::::::dr::::rrr:::::::::r a::::::::::::a 10 | * H::::::HHHHH::::::H y:::::y y:::::yd::::::::::::::::dr:::::::::::::::::r aaaaaaaaa:::::a 11 | * H:::::::::::::::::H y:::::y y:::::yd:::::::ddddd:::::drr::::::rrrrr::::::r a::::a 12 | * H:::::::::::::::::H y:::::y y:::::y d::::::d d:::::d r:::::r r:::::r aaaaaaa:::::a 13 | * H::::::HHHHH::::::H y:::::y y:::::y d:::::d d:::::d r:::::r rrrrrrraa::::::::::::a 14 | * H:::::H H:::::H y:::::y:::::y d:::::d d:::::d r:::::r a::::aaaa::::::a 15 | * H:::::H H:::::H y:::::::::y d:::::d d:::::d r:::::r a::::a a:::::a 16 | * HH::::::H H::::::HH y:::::::y d::::::ddddd::::::ddr:::::r a::::a a:::::a 17 | * H:::::::H H:::::::H y:::::y d:::::::::::::::::dr:::::r a:::::aaaa::::::a 18 | * H:::::::H H:::::::H y:::::y d:::::::::ddd::::dr:::::r a::::::::::aa:::a 19 | * HHHHHHHHH HHHHHHHHH y:::::y ddddddddd dddddrrrrrrr aaaaaaaaaa aaaa 20 | * y:::::y 21 | * y:::::y 22 | * y:::::y 23 | * y:::::y 24 | * yyyyyyy 25 | * 26 | * A kernel extension to suspend applications and notify a userland daemon 27 | * 28 | * Copyright (c) 2012,2013 fG!. All rights reserved. 29 | * reverser@put.as - http://reverse.put.as 30 | * 31 | * kernel_info.h 32 | * 33 | * Redistribution and use in source and binary forms, with or without 34 | * modification, are permitted provided that the following conditions 35 | * are met: 36 | * 1. Redistributions of source code must retain the above copyright 37 | * notice, this list of conditions and the following disclaimer. 38 | * 2. Redistributions in binary form must reproduce the above copyright 39 | * notice, this list of conditions and the following disclaimer in the 40 | * documentation and/or other materials provided with the distribution. 41 | * 3. The name of the author may not be used to endorse or promote products 42 | * derived from this software without specific prior written permission. 43 | * 44 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 45 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 46 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 47 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 48 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 49 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 50 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 51 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 52 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 53 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 54 | * 55 | */ 56 | 57 | 58 | #ifndef hydra_kernel_info_h 59 | #define hydra_kernel_info_h 60 | 61 | #include "my_data_definitions.h" 62 | 63 | kern_return_t init_kernel_info(struct kernel_info *kernel_info); 64 | mach_vm_address_t solve_kernel_symbol(kernel_info_t kernel_info, char *symbol_to_solve); 65 | 66 | 67 | #endif 68 | -------------------------------------------------------------------------------- /hydra/hydra/my_data_definitions.h: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * dddddddd 4 | * HHHHHHHHH HHHHHHHHH d::::::d 5 | * H:::::::H H:::::::H d::::::d 6 | * H:::::::H H:::::::H d::::::d 7 | * HH::::::H H::::::HH d:::::d 8 | * H:::::H H:::::Hyyyyyyy yyyyyyy ddddddddd:::::drrrrr rrrrrrrrr aaaaaaaaaaaaa 9 | * H:::::H H:::::H y:::::y y:::::ydd::::::::::::::dr::::rrr:::::::::r a::::::::::::a 10 | * H::::::HHHHH::::::H y:::::y y:::::yd::::::::::::::::dr:::::::::::::::::r aaaaaaaaa:::::a 11 | * H:::::::::::::::::H y:::::y y:::::yd:::::::ddddd:::::drr::::::rrrrr::::::r a::::a 12 | * H:::::::::::::::::H y:::::y y:::::y d::::::d d:::::d r:::::r r:::::r aaaaaaa:::::a 13 | * H::::::HHHHH::::::H y:::::y y:::::y d:::::d d:::::d r:::::r rrrrrrraa::::::::::::a 14 | * H:::::H H:::::H y:::::y:::::y d:::::d d:::::d r:::::r a::::aaaa::::::a 15 | * H:::::H H:::::H y:::::::::y d:::::d d:::::d r:::::r a::::a a:::::a 16 | * HH::::::H H::::::HH y:::::::y d::::::ddddd::::::ddr:::::r a::::a a:::::a 17 | * H:::::::H H:::::::H y:::::y d:::::::::::::::::dr:::::r a:::::aaaa::::::a 18 | * H:::::::H H:::::::H y:::::y d:::::::::ddd::::dr:::::r a::::::::::aa:::a 19 | * HHHHHHHHH HHHHHHHHH y:::::y ddddddddd dddddrrrrrrr aaaaaaaaaa aaaa 20 | * y:::::y 21 | * y:::::y 22 | * y:::::y 23 | * y:::::y 24 | * yyyyyyy 25 | * 26 | * A kernel extension to suspend applications and notify a userland daemon 27 | * 28 | * Copyright (c) 2012,2013 fG!. All rights reserved. 29 | * reverser@put.as - http://reverse.put.as 30 | * 31 | * my_data_definitions.h 32 | * 33 | * Redistribution and use in source and binary forms, with or without 34 | * modification, are permitted provided that the following conditions 35 | * are met: 36 | * 1. Redistributions of source code must retain the above copyright 37 | * notice, this list of conditions and the following disclaimer. 38 | * 2. Redistributions in binary form must reproduce the above copyright 39 | * notice, this list of conditions and the following disclaimer in the 40 | * documentation and/or other materials provided with the distribution. 41 | * 3. The name of the author may not be used to endorse or promote products 42 | * derived from this software without specific prior written permission. 43 | * 44 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 45 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 46 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 47 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 48 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 49 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 50 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 51 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 52 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 53 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 54 | * 55 | */ 56 | 57 | #ifndef hydra_my_data_definitions_h 58 | #define hydra_my_data_definitions_h 59 | 60 | #include 61 | #include 62 | #include 63 | #include "uthash.h" 64 | 65 | #define LOG_MSG(...) printf(__VA_ARGS__) 66 | 67 | struct kernel_info 68 | { 69 | mach_vm_address_t running_text_addr; 70 | mach_vm_address_t disk_text_addr; 71 | mach_vm_address_t kaslr_slide; 72 | void *linkedit_buf; 73 | uint64_t linkedit_fileoffset; 74 | uint64_t linkedit_size; 75 | uint32_t symboltable_fileoffset; 76 | uint32_t symboltable_nr_symbols; 77 | uint32_t stringtable_fileoffset; 78 | uint32_t stringtable_size; 79 | }; 80 | 81 | typedef struct kernel_info * kernel_info_t; 82 | 83 | struct targets 84 | { 85 | char *name; 86 | UT_hash_handle hh; 87 | }; 88 | 89 | typedef struct targets * targets_t; 90 | 91 | #endif 92 | -------------------------------------------------------------------------------- /hydra/hydra/proc.h: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * dddddddd 4 | * HHHHHHHHH HHHHHHHHH d::::::d 5 | * H:::::::H H:::::::H d::::::d 6 | * H:::::::H H:::::::H d::::::d 7 | * HH::::::H H::::::HH d:::::d 8 | * H:::::H H:::::Hyyyyyyy yyyyyyy ddddddddd:::::drrrrr rrrrrrrrr aaaaaaaaaaaaa 9 | * H:::::H H:::::H y:::::y y:::::ydd::::::::::::::dr::::rrr:::::::::r a::::::::::::a 10 | * H::::::HHHHH::::::H y:::::y y:::::yd::::::::::::::::dr:::::::::::::::::r aaaaaaaaa:::::a 11 | * H:::::::::::::::::H y:::::y y:::::yd:::::::ddddd:::::drr::::::rrrrr::::::r a::::a 12 | * H:::::::::::::::::H y:::::y y:::::y d::::::d d:::::d r:::::r r:::::r aaaaaaa:::::a 13 | * H::::::HHHHH::::::H y:::::y y:::::y d:::::d d:::::d r:::::r rrrrrrraa::::::::::::a 14 | * H:::::H H:::::H y:::::y:::::y d:::::d d:::::d r:::::r a::::aaaa::::::a 15 | * H:::::H H:::::H y:::::::::y d:::::d d:::::d r:::::r a::::a a:::::a 16 | * HH::::::H H::::::HH y:::::::y d::::::ddddd::::::ddr:::::r a::::a a:::::a 17 | * H:::::::H H:::::::H y:::::y d:::::::::::::::::dr:::::r a:::::aaaa::::::a 18 | * H:::::::H H:::::::H y:::::y d:::::::::ddd::::dr:::::r a::::::::::aa:::a 19 | * HHHHHHHHH HHHHHHHHH y:::::y ddddddddd dddddrrrrrrr aaaaaaaaaa aaaa 20 | * y:::::y 21 | * y:::::y 22 | * y:::::y 23 | * y:::::y 24 | * yyyyyyy 25 | * 26 | * A kernel extension to suspend applications and notify a userland daemon 27 | * 28 | * Copyright (c) 2012,2013 fG!. All rights reserved. 29 | * reverser@put.as - http://reverse.put.as 30 | * 31 | * proc.h 32 | * 33 | * Copy of private proc structures we will need 34 | * 35 | */ 36 | 37 | #define __APPLE_API_UNSTABLE 38 | #define SYSCTL_DEF_ENABLED 39 | #define PROC_DEF_ENABLED 40 | #define MACH_KERNEL_PRIVATE 41 | 42 | #include 43 | #include 44 | #include 45 | #include 46 | #include 47 | #include 48 | #include 49 | 50 | // options that are set in the different MASTER files 51 | 52 | #define CONFIG_MACF 1 53 | #define CONFIG_VFS_FUNNEL 1 54 | //#define CONFIG_TRIGGERS 1 55 | #define TASK_SWAPPER 1 56 | #define CONFIG_COUNTERS 1 57 | #define CONFIG_MACF_MACH 1 58 | 59 | // we need this to complete the proc structure 60 | // osfmk/i386/locks.h 61 | // ML ready 62 | struct __lck_mtx_t__ { 63 | union { 64 | struct { 65 | volatile uintptr_t lck_mtxd_owner; 66 | union { 67 | struct { 68 | volatile uint32_t 69 | lck_mtxd_waiters:16, 70 | lck_mtxd_pri:8, 71 | lck_mtxd_ilocked:1, 72 | lck_mtxd_mlocked:1, 73 | lck_mtxd_promoted:1, 74 | lck_mtxd_spin:1, 75 | lck_mtxd_is_ext:1, 76 | lck_mtxd_pad3:3; 77 | }; 78 | uint32_t lck_mtxd_state; 79 | }; 80 | /* Pad field used as a canary, initialized to ~0 */ 81 | uint32_t lck_mtxd_pad32; 82 | } lck_mtxd; 83 | struct { 84 | struct _lck_mtx_ext_ *lck_mtxi_ptr; 85 | uint32_t lck_mtxi_tag; 86 | uint32_t lck_mtxi_pad32; 87 | } lck_mtxi; 88 | } lck_mtx_sw; 89 | }; 90 | 91 | // osfmk/i386/locks.h 92 | // ML ready 93 | struct lck_spin_t { 94 | volatile uintptr_t interlock; 95 | unsigned long lck_spin_pad[9]; /* XXX - usimple_lock_data_t */ 96 | }; 97 | 98 | 99 | 100 | // ripped from xnu/bsd/sys/proc_internal.h 101 | // Needed so we can access the proc structure passed to the syscall 102 | // I had to comment some fields because other kernel includes would be needed 103 | // This should be valid since we are not doing any copies of this structure (just having it's definition to avoid dereference pointer to incomplete types) 104 | // else things might go wrong (big kabooommm) 105 | // FOR SNOW LEOPARD 106 | // XXX: different from SL to Lion. Lion != ML 107 | // XXX: FIXME 108 | struct proc { 109 | LIST_ENTRY(proc) p_list; /* List of all processes. */ 110 | 111 | pid_t p_pid; /* Process identifier. (static)*/ 112 | void * task; /* corresponding task (static)*/ 113 | struct proc * p_pptr; /* Pointer to parent process.(LL) */ 114 | pid_t p_ppid; /* process's parent pid number */ 115 | pid_t p_pgrpid; /* process group id of the process (LL)*/ 116 | uid_t p_uid; 117 | gid_t p_gid; 118 | uid_t p_ruid; 119 | gid_t p_rgid; 120 | uid_t p_svuid; 121 | gid_t p_svgid; 122 | uint64_t p_uniqueid; /* process uniqe ID */ 123 | 124 | lck_mtx_t p_mlock; /* mutex lock for proc */ 125 | 126 | char p_stat; /* S* process status. (PL)*/ 127 | char p_shutdownstate; 128 | char p_kdebug; /* P_KDEBUG eq (CC)*/ 129 | char p_btrace; /* P_BTRACE eq (CC)*/ 130 | 131 | LIST_ENTRY(proc) p_pglist; /* List of processes in pgrp.(PGL) */ 132 | LIST_ENTRY(proc) p_sibling; /* List of sibling processes. (LL)*/ 133 | LIST_HEAD(, proc) p_children; /* Pointer to list of children. (LL)*/ 134 | TAILQ_HEAD( , uthread) p_uthlist; /* List of uthreads (PL) */ 135 | 136 | LIST_ENTRY(proc) p_hash; /* Hash chain. (LL)*/ 137 | TAILQ_HEAD( ,eventqelt) p_evlist; /* (PL) */ 138 | 139 | lck_mtx_t p_fdmlock; /* proc lock to protect fdesc */ 140 | 141 | /* substructures: */ 142 | kauth_cred_t p_ucred; /* Process owner's identity. (PL) */ 143 | struct filedesc *p_fd; /* Ptr to open files structure. (PFDL) */ 144 | struct pstats *p_stats; /* Accounting/statistics (PL). */ 145 | struct plimit *p_limit; /* Process limits.(PL) */ 146 | 147 | struct sigacts *p_sigacts; /* Signal actions, state (PL) */ 148 | int p_siglist; /* signals captured back from threads */ 149 | struct lck_spin_t p_slock; /* spin lock for itimer/profil protection */ 150 | 151 | #define p_rlimit p_limit->pl_rlimit 152 | 153 | struct plimit *p_olimit; /* old process limits - not inherited by child (PL) */ 154 | unsigned int p_flag; /* P_* flags. (atomic bit ops) */ 155 | unsigned int p_lflag; /* local flags (PL) */ 156 | unsigned int p_listflag; /* list flags (LL) */ 157 | unsigned int p_ladvflag; /* local adv flags (atomic) */ 158 | int p_refcount; /* number of outstanding users(LL) */ 159 | int p_childrencnt; /* children holding ref on parent (LL) */ 160 | int p_parentref; /* children lookup ref on parent (LL) */ 161 | 162 | pid_t p_oppid; /* Save parent pid during ptrace. XXX */ 163 | u_int p_xstat; /* Exit status for wait; also stop signal. */ 164 | 165 | #ifdef _PROC_HAS_SCHEDINFO_ 166 | /* may need cleanup, not used */ 167 | u_int p_estcpu; /* Time averaged value of p_cpticks.(used by aio and proc_comapre) */ 168 | fixpt_t p_pctcpu; /* %cpu for this process during p_swtime (used by aio)*/ 169 | u_int p_slptime; /* used by proc_compare */ 170 | #endif /* _PROC_HAS_SCHEDINFO_ */ 171 | 172 | struct itimerval p_realtimer; /* Alarm timer. (PSL) */ 173 | struct timeval p_rtime; /* Real time.(PSL) */ 174 | struct itimerval p_vtimer_user; /* Virtual timers.(PSL) */ 175 | struct itimerval p_vtimer_prof; /* (PSL) */ 176 | 177 | struct timeval p_rlim_cpu; /* Remaining rlim cpu value.(PSL) */ 178 | int p_debugger; /* NU 1: can exec set-bit programs if suser */ 179 | boolean_t sigwait; /* indication to suspend (PL) */ 180 | void *sigwait_thread; /* 'thread' holding sigwait(PL) */ 181 | void *exit_thread; /* Which thread is exiting(PL) */ 182 | int p_vforkcnt; /* number of outstanding vforks(PL) */ 183 | void * p_vforkact; /* activation running this vfork proc)(static) */ 184 | int p_fpdrainwait; /* (PFDL) */ 185 | pid_t p_contproc; /* last PID to send us a SIGCONT (PL) */ 186 | 187 | /* Following fields are info from SIGCHLD (PL) */ 188 | pid_t si_pid; /* (PL) */ 189 | u_int si_status; /* (PL) */ 190 | u_int si_code; /* (PL) */ 191 | uid_t si_uid; /* (PL) */ 192 | 193 | void * vm_shm; /* (SYSV SHM Lock) for sysV shared memory */ 194 | 195 | #if CONFIG_DTRACE 196 | user_addr_t p_dtrace_argv; /* (write once, read only after that) */ 197 | user_addr_t p_dtrace_envp; /* (write once, read only after that) */ 198 | lck_mtx_t p_dtrace_sprlock; /* sun proc lock emulation */ 199 | int p_dtrace_probes; /* (PL) are there probes for this proc? */ 200 | u_int p_dtrace_count; /* (sprlock) number of DTrace tracepoints */ 201 | uint8_t p_dtrace_stop; /* indicates a DTrace-desired stop */ 202 | struct dtrace_ptss_page* p_dtrace_ptss_pages; /* (sprlock) list of user ptss pages */ 203 | struct dtrace_ptss_page_entry* p_dtrace_ptss_free_list; /* (atomic) list of individual ptss entries */ 204 | struct dtrace_helpers* p_dtrace_helpers; /* (dtrace_lock) DTrace per-proc private */ 205 | struct dof_ioctl_data* p_dtrace_lazy_dofs; /* (sprlock) unloaded dof_helper_t's */ 206 | #endif /* CONFIG_DTRACE */ 207 | 208 | /* XXXXXXXXXXXXX BCOPY'ed on fork XXXXXXXXXXXXXXXX */ 209 | /* The following fields are all copied upon creation in fork. */ 210 | #define p_startcopy p_argslen 211 | 212 | u_int p_argslen; /* Length of process arguments. */ 213 | int p_argc; /* saved argc for sysctl_procargs() */ 214 | user_addr_t user_stack; /* where user stack was allocated */ 215 | struct vnode *p_textvp; /* Vnode of executable. */ 216 | off_t p_textoff; /* offset in executable vnode */ 217 | 218 | sigset_t p_sigmask; /* DEPRECATED */ 219 | sigset_t p_sigignore; /* Signals being ignored. (PL) */ 220 | sigset_t p_sigcatch; /* Signals being caught by user.(PL) */ 221 | 222 | u_char p_priority; /* (NU) Process priority. */ 223 | u_char p_resv0; /* (NU) User-priority based on p_cpu and p_nice. */ 224 | char p_nice; /* Process "nice" value.(PL) */ 225 | u_char p_resv1; /* (NU) User-priority based on p_cpu and p_nice. */ 226 | 227 | #if CONFIG_MACF 228 | int p_mac_enforce; /* MAC policy enforcement control */ 229 | #endif 230 | 231 | char p_comm[MAXCOMLEN+1]; 232 | char p_name[(2*MAXCOMLEN)+1]; /* PL */ 233 | 234 | struct pgrp *p_pgrp; /* Pointer to process group. (LL) */ 235 | uint32_t p_csflags; /* flags for codesign (PL) */ 236 | uint32_t p_pcaction; /* action for process control on starvation */ 237 | uint8_t p_uuid[16]; /* from LC_UUID load command */ 238 | 239 | #if !CONFIG_EMBEDDED 240 | #define PROC_LEGACY_BEHAVIOR_IOTHROTTLE (0x00000001) 241 | uint32_t p_legacy_behavior; 242 | #endif 243 | /* End area that is copied on creation. */ 244 | /* XXXXXXXXXXXXX End of BCOPY'ed on fork (AIOLOCK)XXXXXXXXXXXXXXXX */ 245 | #define p_endcopy p_aio_total_count 246 | int p_aio_total_count; /* all allocated AIO requests for this proc */ 247 | int p_aio_active_count; /* all unfinished AIO requests for this proc */ 248 | TAILQ_HEAD( , aio_workq_entry ) p_aio_activeq; /* active async IO requests */ 249 | TAILQ_HEAD( , aio_workq_entry ) p_aio_doneq; /* completed async IO requests */ 250 | 251 | // struct klist p_klist; /* knote list (PL ?)*/ 252 | 253 | struct rusage *p_ru; /* Exit information. (PL) */ 254 | int p_sigwaitcnt; 255 | thread_t p_signalholder; 256 | thread_t p_transholder; 257 | 258 | /* DEPRECATE following field */ 259 | u_short p_acflag; /* Accounting flags. */ 260 | 261 | struct lctx *p_lctx; /* Pointer to login context. */ 262 | LIST_ENTRY(proc) p_lclist; /* List of processes in lctx. */ 263 | user_addr_t p_threadstart; /* pthread start fn */ 264 | user_addr_t p_wqthread; /* pthread workqueue fn */ 265 | int p_pthsize; /* pthread size */ 266 | user_addr_t p_targconc; /* target concurrency ptr */ 267 | void * p_wqptr; /* workq ptr */ 268 | int p_wqsize; /* allocated size */ 269 | boolean_t p_wqiniting; /* semaphore to serialze wq_open */ 270 | struct lck_spin_t p_wqlock; /* lock to protect work queue */ 271 | struct timeval p_start; /* starting time */ 272 | void * p_rcall; 273 | int p_ractive; 274 | int p_idversion; /* version of process identity */ 275 | void * p_pthhash; /* pthread waitqueue hash */ 276 | #if DIAGNOSTIC 277 | unsigned int p_fdlock_pc[4]; 278 | unsigned int p_fdunlock_pc[4]; 279 | #if SIGNAL_DEBUG 280 | unsigned int lockpc[8]; 281 | unsigned int unlockpc[8]; 282 | #endif /* SIGNAL_DEBUG */ 283 | #endif /* DIAGNOSTIC */ 284 | uint64_t p_dispatchqueue_offset; 285 | #if VM_PRESSURE_EVENTS 286 | struct timeval vm_pressure_last_notify_tstamp; 287 | #endif 288 | int p_dirty; /* dirty state */ 289 | }; 290 | 291 | 292 | // bsd/sys/proc.h 293 | #define P_TRACED 0x00000800 294 | #define P_NOCLDSTOP 0x00000008 /* No SIGCHLD when children stop */ 295 | #define P_LP64 0x00000004 /* Process is LP64 */ 296 | 297 | // bsd/sys/sysctl.h 298 | // ML ready 299 | struct _pcred { 300 | char pc_lock[72]; /* opaque content */ 301 | struct ucred *pc_ucred; /* Current credentials. */ 302 | uid_t p_ruid; /* Real user id. */ 303 | uid_t p_svuid; /* Saved effective user id. */ 304 | gid_t p_rgid; /* Real group id. */ 305 | gid_t p_svgid; /* Saved effective group id. */ 306 | int p_refcnt; /* Number of references. */ 307 | }; 308 | 309 | // bsd/sys/sysctl.h 310 | // ML ready 311 | struct _ucred { 312 | int32_t cr_ref; /* reference count */ 313 | uid_t cr_uid; /* effective user id */ 314 | short cr_ngroups; /* number of groups */ 315 | gid_t cr_groups[NGROUPS]; /* groups */ 316 | }; 317 | 318 | // @ bsd/sys/filedesc.h 319 | // ML ready 320 | struct filedesc { 321 | struct fileproc **fd_ofiles; /* file structures for open files */ 322 | char *fd_ofileflags; /* per-process open file flags */ 323 | struct vnode *fd_cdir; /* current directory */ 324 | struct vnode *fd_rdir; /* root directory */ 325 | int fd_nfiles; /* number of open files allocated */ 326 | int fd_lastfile; /* high-water mark of fd_ofiles */ 327 | int fd_freefile; /* approx. next free file */ 328 | u_short fd_cmask; /* mask for file creation */ 329 | uint32_t fd_refcnt; /* reference count */ 330 | 331 | int fd_knlistsize; /* size of knlist */ 332 | struct klist *fd_knlist; /* list of attached knotes */ 333 | u_long fd_knhashmask; /* size of knhash */ 334 | struct klist *fd_knhash; /* hash table for attached knotes */ 335 | int fd_flags; 336 | }; 337 | 338 | // @ bsd/sys/file_internal.h 339 | // ML ready 340 | struct fileproc { 341 | unsigned int f_flags; 342 | int32_t f_iocount; 343 | struct fileglob * f_fglob; 344 | void * f_waddr; 345 | }; 346 | 347 | // @ bsd/sys/file_internal.h 348 | /* file types */ 349 | typedef enum { 350 | DTYPE_VNODE = 1, /* file */ 351 | DTYPE_SOCKET, /* communications endpoint */ 352 | DTYPE_PSXSHM, /* POSIX Shared memory */ 353 | DTYPE_PSXSEM, /* POSIX Semaphores */ 354 | DTYPE_KQUEUE, /* kqueue */ 355 | DTYPE_PIPE, /* pipe */ 356 | DTYPE_FSEVENTS /* fsevents */ 357 | } file_type_t; 358 | 359 | // @ bsd/sys/file_internal.h 360 | // ML ready 361 | struct fileglob { 362 | LIST_ENTRY(fileglob) f_msglist;/* list of active files */ 363 | int32_t fg_flag; /* see fcntl.h */ 364 | file_type_t fg_type; /* descriptor type */ 365 | int32_t fg_count; /* reference count */ 366 | int32_t fg_msgcount; /* references from message queue */ 367 | kauth_cred_t fg_cred; /* credentials associated with descriptor */ 368 | struct fileops { 369 | int (*fo_read) (struct fileproc *fp, struct uio *uio, 370 | int flags, vfs_context_t ctx); 371 | int (*fo_write) (struct fileproc *fp, struct uio *uio, 372 | int flags, vfs_context_t ctx); 373 | #define FOF_OFFSET 0x00000001 /* offset supplied to vn_write */ 374 | #define FOF_PCRED 0x00000002 /* cred from proc, not current thread */ 375 | int (*fo_ioctl) (struct fileproc *fp, u_long com, 376 | caddr_t data, vfs_context_t ctx); 377 | int (*fo_select) (struct fileproc *fp, int which, 378 | void *wql, vfs_context_t ctx); 379 | int (*fo_close) (struct fileglob *fg, vfs_context_t ctx); 380 | int (*fo_kqfilter) (struct fileproc *fp, struct knote *kn, 381 | vfs_context_t ctx); 382 | int (*fo_drain) (struct fileproc *fp, vfs_context_t ctx); 383 | } *fg_ops; 384 | off_t fg_offset; 385 | void *fg_data; /* vnode or socket or SHM or semaphore */ 386 | lck_mtx_t fg_lock; 387 | int32_t fg_lflags; /* file global flags */ 388 | #if CONFIG_MACF 389 | struct label *fg_label; /* JMM - use the one in the cred? */ 390 | #endif 391 | }; 392 | 393 | #define NULLVP ((struct vnode *)NULL) 394 | 395 | // @ bsd/sys/vnode_internal.h 396 | // XXX 397 | struct vnode { 398 | lck_mtx_t v_lock; /* vnode mutex */ 399 | TAILQ_ENTRY(vnode) v_freelist; /* vnode freelist */ 400 | TAILQ_ENTRY(vnode) v_mntvnodes; /* vnodes for mount point */ 401 | LIST_HEAD(, namecache) v_nclinks; /* name cache entries that name this vnode */ 402 | LIST_HEAD(, namecache) v_ncchildren; /* name cache entries that regard us as there parent */ 403 | vnode_t v_defer_reclaimlist; /* in case we have to defer the reclaim to avoid recursion */ 404 | uint32_t v_listflag; /* flags protected by the vnode_list_lock (see below) */ 405 | uint32_t v_flag; /* vnode flags (see below) */ 406 | uint16_t v_lflag; /* vnode local and named ref flags */ 407 | uint8_t v_iterblkflags; /* buf iterator flags */ 408 | uint8_t v_references; /* number of times io_count has been granted */ 409 | int32_t v_kusecount; /* count of in-kernel refs */ 410 | int32_t v_usecount; /* reference count of users */ 411 | int32_t v_iocount; /* iocounters */ 412 | void * v_owner; /* act that owns the vnode */ 413 | uint16_t v_type; /* vnode type */ 414 | uint16_t v_tag; /* type of underlying data */ 415 | uint32_t v_id; /* identity of vnode contents */ 416 | union { 417 | struct mount *vu_mountedhere;/* ptr to mounted vfs (VDIR) */ 418 | struct socket *vu_socket; /* unix ipc (VSOCK) */ 419 | struct specinfo *vu_specinfo; /* device (VCHR, VBLK) */ 420 | struct fifoinfo *vu_fifoinfo; /* fifo (VFIFO) */ 421 | struct ubc_info *vu_ubcinfo; /* valid for (VREG) */ 422 | } v_un; 423 | // struct buflists v_cleanblkhd; /* clean blocklist head */ 424 | // struct buflists v_dirtyblkhd; /* dirty blocklist head */ 425 | // struct klist v_knotes; /* knotes attached to this vnode */ 426 | int64_t v_cleanblkhd; /* clean blocklist head */ 427 | int64_t v_dirtyblkhd; /* dirty blocklist head */ 428 | int64_t v_knotes; /* knotes attached to this vnode */ 429 | /* 430 | * the following 4 fields are protected 431 | * by the name_cache_lock held in 432 | * excluive mode 433 | */ 434 | kauth_cred_t v_cred; /* last authorized credential */ 435 | int v_authorized_actions; /* current authorized actions for v_cred */ 436 | int v_cred_timestamp; /* determine if entry is stale for MNTK_AUTH_OPAQUE */ 437 | int v_nc_generation; /* changes when nodes are removed from the name cache */ 438 | /* 439 | * back to the vnode lock for protection 440 | */ 441 | int32_t v_numoutput; /* num of writes in progress */ 442 | int32_t v_writecount; /* reference count of writers */ 443 | const char *v_name; /* name component of the vnode */ 444 | vnode_t v_parent; /* pointer to parent vnode */ 445 | struct lockf *v_lockf; /* advisory lock list head */ 446 | #if CONFIG_VFS_FUNNEL 447 | struct unsafe_fsnode *v_unsafefs; /* pointer to struct used to lock */ 448 | #else 449 | int32_t v_reserved1; 450 | #ifdef __LP64__ 451 | int32_t v_reserved2; 452 | #endif 453 | #endif /* CONFIG_VFS_FUNNEL */ 454 | int (**v_op)(void *); /* vnode operations vector */ 455 | mount_t v_mount; /* ptr to vfs we are in */ 456 | void * v_data; /* private data for fs */ 457 | #if CONFIG_MACF 458 | struct label *v_label; /* MAC security label */ 459 | #endif 460 | #if CONFIG_TRIGGERS 461 | vnode_resolve_t v_resolve; /* trigger vnode resolve info (VDIR only) */ 462 | #endif /* CONFIG_TRIGGERS */ 463 | }; 464 | 465 | // @ bsd/sys/user.h 466 | // ML ready 467 | struct vfs_context { 468 | thread_t vc_thread; /* pointer to Mach thread */ 469 | kauth_cred_t vc_ucred; /* per thread credential */ 470 | }; 471 | 472 | // @ osfmk/kern/queue.h 473 | // ML ready 474 | struct queue_entry { 475 | struct queue_entry *next; /* next element */ 476 | struct queue_entry *prev; /* previous element */ 477 | }; 478 | 479 | typedef struct queue_entry *queue_t; 480 | typedef struct queue_entry queue_head_t; 481 | typedef struct queue_entry queue_chain_t; 482 | typedef struct queue_entry *queue_entry_t; 483 | 484 | // @ osfmk/kern/exception.h 485 | // ML ready 486 | struct exception_action { 487 | struct ipc_port *port; /* exception port */ 488 | thread_state_flavor_t flavor; /* state flavor to send */ 489 | exception_behavior_t behavior; /* exception type to raise */ 490 | boolean_t privileged; /* survives ipc_task_reset */ 491 | }; 492 | 493 | 494 | 495 | // @ osfmk/i386/locks.h 496 | // ML ready 497 | #pragma pack(1) /* Make sure the structure stays as we defined it */ 498 | typedef struct _lck_rw_t_internal_ { 499 | volatile uint16_t lck_rw_shared_count; /* No. of accepted readers */ 500 | uint8_t lck_rw_interlock; /* Interlock byte */ 501 | volatile uint8_t 502 | lck_rw_priv_excl:1, /* Writers prioritized if set */ 503 | lck_rw_want_upgrade:1, /* Read-to-write upgrade waiting */ 504 | lck_rw_want_write:1, /* Writer waiting or locked for write */ 505 | lck_r_waiting:1, /* Reader is sleeping on lock */ 506 | lck_w_waiting:1, /* Writer is sleeping on lock */ 507 | lck_rw_can_sleep:1, /* Can attempts to lock go to sleep? */ 508 | lck_rw_padb6:2; /* padding */ 509 | 510 | uint32_t lck_rw_tag; /* This can be obsoleted when stats 511 | * are in 512 | */ 513 | uint32_t lck_rw_pad8; 514 | uint32_t lck_rw_pad12; 515 | } _lck_rw_t; 516 | #pragma pack() 517 | 518 | typedef _lck_rw_t lock_t; 519 | 520 | // @ osfmk/vm/vm_map.h 521 | // ML ready 522 | struct vm_map_links { 523 | struct vm_map_entry *prev; /* previous entry */ 524 | struct vm_map_entry *next; /* next entry */ 525 | vm_map_offset_t start; /* start address */ 526 | vm_map_offset_t end; /* end address */ 527 | }; 528 | 529 | // @ osfmk/vm/vm_map.h 530 | // ML ready 531 | struct vm_map_header { 532 | struct vm_map_links links; /* first, last, min, max */ 533 | int nentries; /* Number of entries */ 534 | boolean_t entries_pageable; 535 | /* are map entries pageable? */ 536 | vm_map_offset_t highest_entry_end_addr; /* The ending address of the highest allocated vm_entry_t */ 537 | #ifdef VM_MAP_STORE_USE_RB 538 | struct rb_head rb_head_store; 539 | #endif 540 | }; 541 | 542 | typedef struct vm_object *vm_object_t; 543 | 544 | // @ osfmk/vm/vm_map.h 545 | // ML ready 546 | typedef union vm_map_object { 547 | vm_object_t vm_object; /* object object */ 548 | vm_map_t sub_map; /* belongs to another map */ 549 | } vm_map_object_t; 550 | 551 | // @ osfmk/vm/vm_map.h 552 | // ML ready 553 | struct vm_map_entry { 554 | struct vm_map_links links; /* links to other entries */ 555 | #define vme_prev links.prev 556 | #define vme_next links.next 557 | #define vme_start links.start 558 | #define vme_end links.end 559 | // XXX: fixme 560 | // struct vm_map_store store; 561 | union vm_map_object object; /* object I point to */ 562 | vm_object_offset_t offset; /* offset into object */ 563 | unsigned int 564 | /* boolean_t */ is_shared:1, /* region is shared */ 565 | /* boolean_t */ is_sub_map:1, /* Is "object" a submap? */ 566 | /* boolean_t */ in_transition:1, /* Entry being changed */ 567 | /* boolean_t */ needs_wakeup:1, /* Waiters on in_transition */ 568 | /* vm_behavior_t */ behavior:2, /* user paging behavior hint */ 569 | /* behavior is not defined for submap type */ 570 | /* boolean_t */ needs_copy:1, /* object need to be copied? */ 571 | /* Only in task maps: */ 572 | /* vm_prot_t */ protection:3, /* protection code */ 573 | /* vm_prot_t */ max_protection:3,/* maximum protection */ 574 | /* vm_inherit_t */ inheritance:2, /* inheritance */ 575 | /* boolean_t */ use_pmap:1, /* nested pmaps */ 576 | /* 577 | * IMPORTANT: 578 | * The "alias" field can be updated while holding the VM map lock 579 | * "shared". It's OK as along as it's the only field that can be 580 | * updated without the VM map "exclusive" lock. 581 | */ 582 | /* unsigned char */ alias:8, /* user alias */ 583 | /* boolean_t */ no_cache:1, /* should new pages be cached? */ 584 | /* boolean_t */ permanent:1, /* mapping can not be removed */ 585 | /* boolean_t */ superpage_size:3,/* use superpages of a certain size */ 586 | /* boolean_t */ zero_wired_pages:1, /* zero out the wired pages of this entry it is being deleted without unwiring them */ 587 | /* boolean_t */ used_for_jit:1, 588 | /* boolean_t */ from_reserved_zone:1; /* Allocated from 589 | * kernel reserved zone */ 590 | unsigned short wired_count; /* can be paged if = 0 */ 591 | unsigned short user_wired_count; /* for vm_wire */ 592 | #if DEBUG 593 | #define MAP_ENTRY_CREATION_DEBUG (1) 594 | #endif 595 | #if MAP_ENTRY_CREATION_DEBUG 596 | uintptr_t vme_bt[16]; 597 | #endif 598 | }; 599 | 600 | 601 | //@osfmk/mach/vm_types.h 602 | typedef struct pmap *pmap_t; 603 | 604 | typedef struct { 605 | unsigned int type; 606 | unsigned int pad4; 607 | vm_offset_t pc; 608 | vm_offset_t thread; 609 | } lck_mtx_deb_t; 610 | 611 | // @ osfmk/i386/locks.h 612 | // ML ready 613 | typedef struct _lck_mtx_ext_ { 614 | lck_mtx_t lck_mtx; 615 | struct _lck_grp_ *lck_mtx_grp; 616 | unsigned int lck_mtx_attr; 617 | #ifdef __x86_64__ 618 | unsigned int lck_mtx_pad1; 619 | #endif 620 | lck_mtx_deb_t lck_mtx_deb; 621 | uint64_t lck_mtx_stat; 622 | #ifdef __x86_64__ 623 | unsigned int lck_mtx_pad2[2]; 624 | #endif 625 | } _lck_mtx_ext_t; 626 | 627 | // @ osfmk/vm/vm_map.h 628 | // ML ready 629 | typedef struct vm_map_entry *vm_map_entry_t; 630 | 631 | struct _vm_map { 632 | lock_t lock; /* uni- and smp-lock */ 633 | struct vm_map_header hdr; /* Map entry header */ 634 | #define min_offset hdr.links.start /* start of range */ 635 | #define max_offset hdr.links.end /* end of range */ 636 | pmap_t pmap; /* Physical map */ 637 | vm_map_size_t size; /* virtual size */ 638 | vm_map_size_t user_wire_limit;/* rlimit on user locked memory */ 639 | vm_map_size_t user_wire_size; /* current size of user locked memory in this map */ 640 | int ref_count; /* Reference count */ 641 | #if TASK_SWAPPER 642 | int res_count; /* Residence count (swap) */ 643 | int sw_state; /* Swap state */ 644 | #endif /* TASK_SWAPPER */ 645 | decl_lck_mtx_data(, s_lock) /* Lock ref, res fields */ 646 | _lck_mtx_ext_t s_lock_ext; 647 | vm_map_entry_t hint; /* hint for quick lookups */ 648 | vm_map_entry_t first_free; /* First free space hint */ 649 | unsigned int 650 | /* boolean_t */ wait_for_space:1, /* Should callers wait for space? */ 651 | /* boolean_t */ wiring_required:1, /* All memory wired? */ 652 | /* boolean_t */ no_zero_fill:1, /*No zero fill absent pages */ 653 | /* boolean_t */ mapped_in_other_pmaps:1, /*has this submap been mapped in maps that use a different pmap */ 654 | /* boolean_t */ switch_protect:1, /* Protect map from write faults while switched */ 655 | /* boolean_t */ disable_vmentry_reuse:1, /* All vm entries should keep using newer and higher addresses in the map */ 656 | /* boolean_t */ map_disallow_data_exec:1, /* Disallow execution from data pages on exec-permissive architectures */ 657 | /* reserved */ pad:25; 658 | unsigned int timestamp; /* Version number */ 659 | unsigned int color_rr; /* next color (not protected by a lock) */ 660 | #if CONFIG_FREEZE 661 | void *default_freezer_handle; 662 | #endif 663 | boolean_t jit_entry_exists; 664 | } ; 665 | 666 | typedef struct _vm_map *_vm_map_t; 667 | 668 | // @ osfmk/kern/zalloc.h 669 | typedef struct zinfo_usage_store_t { 670 | /* These fields may be updated atomically, and so must be 8 byte aligned */ 671 | uint64_t alloc __attribute__((aligned(8))); /* allocation counter */ 672 | uint64_t free __attribute__((aligned(8))); /* free counter */ 673 | } zinfo_usage_store_t; 674 | typedef zinfo_usage_store_t *zinfo_usage_t; 675 | 676 | // @ osfmk/kern/thread_call.h 677 | typedef struct thread_call *thread_call_t; 678 | 679 | // @ osfmk/ipc/ipc_labelh.h 680 | typedef struct ipc_labelh 681 | { 682 | natural_t lh_references; 683 | int lh_type; 684 | struct label lh_label; 685 | ipc_port_t lh_port; 686 | decl_lck_mtx_data(, lh_lock_data) 687 | } *ipc_labelh_t; 688 | 689 | /* task_t */ 690 | // @ osfmk/kern/task.h 691 | typedef struct process_policy { 692 | uint64_t apptype:4, 693 | rfu1:4, 694 | ru_power:4, /* Resource Usage Power */ 695 | ru_net:4, /* Resource Usage Network */ 696 | ru_disk:4, /* Resource Usage Disk */ 697 | ru_cpu:4, /* Resource Usage CPU */ 698 | ru_virtmem:4, /* Resource Usage VM */ 699 | ru_wiredmem:4,/* Resource Usage Wired Memory */ 700 | low_vm:4, /* Low Virtual Memory */ 701 | rfu2:4, 702 | hw_cpu:4, /* HW Access to CPU */ 703 | hw_net:4, /* HW Access to Network */ 704 | hw_gpu:4, /* HW Access to GPU */ 705 | hw_disk:4, /* HW Access to Disk */ 706 | hw_bg:8; /* Darwin Background Policy */ 707 | } process_policy_t; 708 | 709 | struct task { 710 | /* Synchronization/destruction information */ 711 | decl_lck_mtx_data(,lock) /* Task's lock */ 712 | uint32_t ref_count; /* Number of references to me */ 713 | boolean_t active; /* Task has not been terminated */ 714 | boolean_t halting; /* Task is being halted */ 715 | 716 | /* Miscellaneous */ 717 | _vm_map_t map; /* Address space description */ 718 | queue_chain_t tasks; /* global list of tasks */ 719 | void *user_data; /* Arbitrary data settable via IPC */ 720 | 721 | /* Threads in this task */ 722 | queue_head_t threads; 723 | 724 | processor_set_t pset_hint; 725 | struct affinity_space *affinity_space; 726 | 727 | int thread_count; 728 | uint32_t active_thread_count; 729 | int suspend_count; /* Internal scheduling only */ 730 | 731 | /* User-visible scheduling information */ 732 | integer_t user_stop_count; /* outstanding stops */ 733 | 734 | task_role_t role; 735 | 736 | integer_t priority; /* base priority for threads */ 737 | integer_t max_priority; /* maximum priority for threads */ 738 | 739 | /* Task security and audit tokens */ 740 | security_token_t sec_token; 741 | audit_token_t audit_token; 742 | 743 | /* Statistics */ 744 | uint64_t total_user_time; /* terminated threads only */ 745 | uint64_t total_system_time; 746 | 747 | /* Virtual timers */ 748 | uint32_t vtimers; 749 | 750 | /* IPC structures */ 751 | decl_lck_mtx_data(,itk_lock_data) 752 | struct ipc_port *itk_self; /* not a right, doesn't hold ref */ 753 | struct ipc_port *itk_nself; /* not a right, doesn't hold ref */ 754 | struct ipc_port *itk_sself; /* a send right */ 755 | struct exception_action exc_actions[EXC_TYPES_COUNT]; 756 | /* a send right each valid element */ 757 | struct ipc_port *itk_host; /* a send right */ 758 | struct ipc_port *itk_bootstrap; /* a send right */ 759 | struct ipc_port *itk_seatbelt; /* a send right */ 760 | struct ipc_port *itk_gssd; /* yet another send right */ 761 | struct ipc_port *itk_task_access; /* and another send right */ 762 | #define TASK_PORT_REGISTER_MAX 3 763 | struct ipc_port *itk_registered[TASK_PORT_REGISTER_MAX]; 764 | /* all send rights */ 765 | 766 | struct ipc_space *itk_space; 767 | 768 | /* Synchronizer ownership information */ 769 | queue_head_t semaphore_list; /* list of owned semaphores */ 770 | queue_head_t lock_set_list; /* list of owned lock sets */ 771 | int semaphores_owned; /* number of semaphores owned */ 772 | int lock_sets_owned; /* number of lock sets owned */ 773 | 774 | /* Ledgers */ 775 | ledger_t ledger; 776 | 777 | unsigned int priv_flags; /* privilege resource flags */ 778 | #define VM_BACKING_STORE_PRIV 0x1 779 | #define MACHINE_TASK \ 780 | struct user_ldt * i386_ldt; \ 781 | void* task_debug; 782 | 783 | MACHINE_TASK 784 | 785 | integer_t faults; /* faults counter */ 786 | integer_t pageins; /* pageins counter */ 787 | integer_t cow_faults; /* copy on write fault counter */ 788 | integer_t messages_sent; /* messages sent counter */ 789 | integer_t messages_received; /* messages received counter */ 790 | integer_t syscalls_mach; /* mach system call counter */ 791 | integer_t syscalls_unix; /* unix system call counter */ 792 | uint32_t c_switch; /* total context switches */ 793 | uint32_t p_switch; /* total processor switches */ 794 | uint32_t ps_switch; /* total pset switches */ 795 | 796 | zinfo_usage_t tkm_zinfo; /* per-task, per-zone usage statistics */ 797 | 798 | void *bsd_info; 799 | struct vm_shared_region *shared_region; 800 | uint32_t taskFeatures[2]; /* Special feature for this task */ 801 | #define tf64BitAddr 0x80000000 /* Task has 64-bit addressing */ 802 | #define tf64BitData 0x40000000 /* Task has 64-bit data registers */ 803 | #define task_has_64BitAddr(task) \ 804 | (((task)->taskFeatures[0] & tf64BitAddr) != 0) 805 | #define task_set_64BitAddr(task) \ 806 | ((task)->taskFeatures[0] |= tf64BitAddr) 807 | #define task_clear_64BitAddr(task) \ 808 | ((task)->taskFeatures[0] &= ~tf64BitAddr) 809 | 810 | mach_vm_address_t all_image_info_addr; /* dyld __all_image_info */ 811 | mach_vm_size_t all_image_info_size; /* section location and size */ 812 | #if CONFIG_MACF_MACH 813 | ipc_labelh_t label; 814 | #endif 815 | 816 | #if CONFIG_COUNTERS 817 | #define TASK_PMC_FLAG 0x1 /* Bit in "t_chud" signifying PMC interest */ 818 | uint32_t t_chud; /* CHUD flags, used for Shark */ 819 | #endif 820 | boolean_t pidsuspended; /* pid_suspend called; no threads can execute */ 821 | boolean_t frozen; /* frozen; private resident pages committed to swap */ 822 | process_policy_t ext_appliedstate; /* externally applied actions */ 823 | process_policy_t ext_policystate; /* externally defined process policy states*/ 824 | process_policy_t appliedstate; /* self applied acions */ 825 | process_policy_t policystate; /* process wide policy states */ 826 | uint8_t rusage_cpu_flags; 827 | uint8_t rusage_cpu_percentage; /* Task-wide CPU limit percentage */ 828 | uint64_t rusage_cpu_interval; /* Task-wide CPU limit interval */ 829 | uint8_t rusage_cpu_perthr_percentage; /* Per-thread CPU limit percentage */ 830 | uint64_t rusage_cpu_perthr_interval; /* Per-thread CPU limit interval */ 831 | uint64_t rusage_cpu_deadline; 832 | thread_call_t rusage_cpu_callt; 833 | #if CONFIG_EMBEDDED 834 | uint32_t appstate; /* the current appstate */ 835 | queue_head_t task_watchers; /* app state watcher threads */ 836 | int num_taskwatchers; 837 | int watchapplying; 838 | #endif /* CONFIG_EMBEDDED */ 839 | 840 | vm_extmod_statistics_data_t extmod_statistics; 841 | natural_t proc_terminate; /* the process is marked for proc_terminate */ 842 | 843 | 844 | }; 845 | 846 | /* Exported fields for kern sysctls */ 847 | // bsd/sys/proc_internal.h 848 | // FIXME 849 | struct extern_proc { 850 | union { 851 | struct { 852 | struct proc *__p_forw; /* Doubly-linked run/sleep queue. */ 853 | struct proc *__p_back; 854 | } p_st1; 855 | struct timeval __p_starttime; /* process start time */ 856 | } p_un; 857 | #define p_forw p_un.p_st1.__p_forw 858 | #define p_back p_un.p_st1.__p_back 859 | #define p_starttime p_un.__p_starttime 860 | struct vmspace *p_vmspace; /* Address space. */ 861 | // bsd/sys/signalvar.h 862 | struct sigacts *p_sigacts; /* Signal actions, state (PROC ONLY). */ 863 | int p_flag; /* P_* flags. */ 864 | char p_stat; /* S* process status. */ 865 | pid_t p_pid; /* Process identifier. */ 866 | pid_t p_oppid; /* Save parent pid during ptrace. XXX */ 867 | int p_dupfd; /* Sideways return value from fdopen. XXX */ 868 | /* Mach related */ 869 | caddr_t user_stack; /* where user stack was allocated */ 870 | void *exit_thread; /* XXX Which thread is exiting? */ 871 | int p_debugger; /* allow to debug */ 872 | boolean_t sigwait; /* indication to suspend */ 873 | /* scheduling */ 874 | u_int p_estcpu; /* Time averaged value of p_cpticks. */ 875 | int p_cpticks; /* Ticks of cpu time. */ 876 | fixpt_t p_pctcpu; /* %cpu for this process during p_swtime */ 877 | void *p_wchan; /* Sleep address. */ 878 | char *p_wmesg; /* Reason for sleep. */ 879 | u_int p_swtime; /* Time swapped in or out. */ 880 | u_int p_slptime; /* Time since last blocked. */ 881 | struct itimerval p_realtimer; /* Alarm timer. */ 882 | struct timeval p_rtime; /* Real time. */ 883 | u_quad_t p_uticks; /* Statclock hits in user mode. */ 884 | u_quad_t p_sticks; /* Statclock hits in system mode. */ 885 | u_quad_t p_iticks; /* Statclock hits processing intr. */ 886 | int p_traceflag; /* Kernel trace points. */ 887 | struct vnode *p_tracep; /* Trace to vnode. */ 888 | int p_siglist; /* DEPRECATED. */ 889 | struct vnode *p_textvp; /* Vnode of executable. */ 890 | int p_holdcnt; /* If non-zero, don't swap. */ 891 | sigset_t p_sigmask; /* DEPRECATED. */ 892 | sigset_t p_sigignore; /* Signals being ignored. */ 893 | sigset_t p_sigcatch; /* Signals being caught by user. */ 894 | u_char p_priority; /* Process priority. */ 895 | u_char p_usrpri; /* User-priority based on p_cpu and p_nice. */ 896 | char p_nice; /* Process "nice" value. */ 897 | char p_comm[MAXCOMLEN+1]; 898 | struct pgrp *p_pgrp; /* Pointer to process group. */ 899 | struct user *p_addr; /* Kernel virtual addr of u-area (PROC ONLY). */ 900 | u_short p_xstat; /* Exit status for wait; also stop signal. */ 901 | u_short p_acflag; /* Accounting flags. */ 902 | struct rusage *p_ru; /* Exit information. XXX */ 903 | }; 904 | 905 | 906 | // @ bsd/sys/sysctl.h 907 | // ML ready 908 | struct kinfo_proc { 909 | struct extern_proc kp_proc; /* proc structure */ 910 | struct eproc { 911 | struct proc *e_paddr; /* address of proc */ 912 | struct session *e_sess; /* session pointer */ 913 | struct _pcred e_pcred; /* process credentials */ 914 | struct _ucred e_ucred; /* current credentials */ 915 | struct vmspace e_vm; /* address space */ 916 | pid_t e_ppid; /* parent process id */ 917 | pid_t e_pgid; /* process group id */ 918 | short e_jobc; /* job control counter */ 919 | dev_t e_tdev; /* controlling tty dev */ 920 | pid_t e_tpgid; /* tty process group id */ 921 | struct session *e_tsess; /* tty session pointer */ 922 | #define WMESGLEN 7 923 | char e_wmesg[WMESGLEN+1]; /* wchan message */ 924 | segsz_t e_xsize; /* text size */ 925 | short e_xrssize; /* text rss */ 926 | short e_xccount; /* text references */ 927 | short e_xswrss; 928 | int32_t e_flag; 929 | #define EPROC_CTTY 0x01 /* controlling tty vnode active */ 930 | #define EPROC_SLEADER 0x02 /* session leader */ 931 | #define COMAPT_MAXLOGNAME 12 932 | char e_login[COMAPT_MAXLOGNAME]; /* short setlogin() name */ 933 | #if CONFIG_LCTX 934 | pid_t e_lcid; 935 | int32_t e_spare[3]; 936 | #else 937 | int32_t e_spare[4]; 938 | #endif 939 | } kp_eproc; 940 | }; 941 | 942 | 943 | // 64 bits stuff 944 | // FIXME 945 | struct user_vmspace { 946 | int vm_refcnt; /* number of references */ 947 | user_addr_t vm_shm __attribute((aligned(8))); /* SYS5 shared memory private data XXX */ 948 | segsz_t vm_rssize; /* current resident set size in pages */ 949 | segsz_t vm_swrss; /* resident set size before last swap */ 950 | segsz_t vm_tsize; /* text size (pages) XXX */ 951 | segsz_t vm_dsize; /* data size (pages) XXX */ 952 | segsz_t vm_ssize; /* stack size (pages) */ 953 | user_addr_t vm_taddr __attribute((aligned(8))); /* user virtual address of text XXX */ 954 | user_addr_t vm_daddr; /* user virtual address of data XXX */ 955 | user_addr_t vm_maxsaddr; /* user VA at max stack growth */ 956 | }; 957 | 958 | // FIXME 959 | struct user64_pcred { 960 | char pc_lock[72]; /* opaque content */ 961 | user64_addr_t pc_ucred; /* Current credentials. */ 962 | uid_t p_ruid; /* Real user id. */ 963 | uid_t p_svuid; /* Saved effective user id. */ 964 | gid_t p_rgid; /* Real group id. */ 965 | gid_t p_svgid; /* Saved effective group id. */ 966 | int p_refcnt; /* Number of references. */ 967 | }; 968 | 969 | // FIXME 970 | struct user64_extern_proc { 971 | union { 972 | struct { 973 | user_addr_t __p_forw; /* Doubly-linked run/sleep queue. */ 974 | user_addr_t __p_back; 975 | } p_st1; 976 | struct user64_timeval __p_starttime; /* process start time */ 977 | } p_un; 978 | user_addr_t p_vmspace; /* Address space. */ 979 | user_addr_t p_sigacts; /* Signal actions, state (PROC ONLY). */ 980 | int p_flag; /* P_* flags. */ 981 | char p_stat; /* S* process status. */ 982 | pid_t p_pid; /* Process identifier. */ 983 | pid_t p_oppid; /* Save parent pid during ptrace. XXX */ 984 | int p_dupfd; /* Sideways return value from fdopen. XXX */ 985 | /* Mach related */ 986 | user_addr_t user_stack __attribute((aligned(8))); /* where user stack was allocated */ 987 | user_addr_t exit_thread; /* XXX Which thread is exiting? */ 988 | int p_debugger; /* allow to debug */ 989 | boolean_t sigwait; /* indication to suspend */ 990 | /* scheduling */ 991 | u_int p_estcpu; /* Time averaged value of p_cpticks. */ 992 | int p_cpticks; /* Ticks of cpu time. */ 993 | fixpt_t p_pctcpu; /* %cpu for this process during p_swtime */ 994 | user_addr_t p_wchan __attribute((aligned(8))); /* Sleep address. */ 995 | user_addr_t p_wmesg; /* Reason for sleep. */ 996 | u_int p_swtime; /* Time swapped in or out. */ 997 | u_int p_slptime; /* Time since last blocked. */ 998 | struct user64_itimerval p_realtimer; /* Alarm timer. */ 999 | struct user64_timeval p_rtime; /* Real time. */ 1000 | u_quad_t p_uticks; /* Statclock hits in user mode. */ 1001 | u_quad_t p_sticks; /* Statclock hits in system mode. */ 1002 | u_quad_t p_iticks; /* Statclock hits processing intr. */ 1003 | int p_traceflag; /* Kernel trace points. */ 1004 | user_addr_t p_tracep __attribute((aligned(8))); /* Trace to vnode. */ 1005 | int p_siglist; /* DEPRECATED */ 1006 | user_addr_t p_textvp __attribute((aligned(8))); /* Vnode of executable. */ 1007 | int p_holdcnt; /* If non-zero, don't swap. */ 1008 | sigset_t p_sigmask; /* DEPRECATED. */ 1009 | sigset_t p_sigignore; /* Signals being ignored. */ 1010 | sigset_t p_sigcatch; /* Signals being caught by user. */ 1011 | u_char p_priority; /* Process priority. */ 1012 | u_char p_usrpri; /* User-priority based on p_cpu and p_nice. */ 1013 | char p_nice; /* Process "nice" value. */ 1014 | char p_comm[MAXCOMLEN+1]; 1015 | user_addr_t p_pgrp __attribute((aligned(8))); /* Pointer to process group. */ 1016 | user_addr_t p_addr; /* Kernel virtual addr of u-area (PROC ONLY). */ 1017 | u_short p_xstat; /* Exit status for wait; also stop signal. */ 1018 | u_short p_acflag; /* Accounting flags. */ 1019 | user_addr_t p_ru __attribute((aligned(8))); /* Exit information. XXX */ 1020 | }; 1021 | 1022 | // FIXME 1023 | struct user64_kinfo_proc { 1024 | struct user64_extern_proc kp_proc; /* proc structure */ 1025 | struct user64_eproc { 1026 | user_addr_t e_paddr; /* address of proc */ 1027 | user_addr_t e_sess; /* session pointer */ 1028 | struct user64_pcred e_pcred; /* process credentials */ 1029 | struct _ucred e_ucred; /* current credentials */ 1030 | struct user_vmspace e_vm; /* address space */ 1031 | pid_t e_ppid; /* parent process id */ 1032 | pid_t e_pgid; /* process group id */ 1033 | short e_jobc; /* job control counter */ 1034 | dev_t e_tdev; /* controlling tty dev */ 1035 | pid_t e_tpgid; /* tty process group id */ 1036 | user64_addr_t e_tsess __attribute((aligned(8))); /* tty session pointer */ 1037 | char e_wmesg[WMESGLEN+1]; /* wchan message */ 1038 | segsz_t e_xsize; /* text size */ 1039 | short e_xrssize; /* text rss */ 1040 | short e_xccount; /* text references */ 1041 | short e_xswrss; 1042 | int32_t e_flag; 1043 | char e_login[COMAPT_MAXLOGNAME]; /* short setlogin() name */ 1044 | #if CONFIG_LCTX 1045 | pid_t e_lcid; 1046 | int32_t e_spare[3]; 1047 | #else 1048 | int32_t e_spare[4]; 1049 | #endif 1050 | } kp_eproc; 1051 | }; 1052 | 1053 | // @ osfmk/mach/vm_types.h 1054 | typedef struct vm_map_copy *vm_map_copy_t; 1055 | 1056 | struct vm_map_copy { 1057 | int type; 1058 | #define VM_MAP_COPY_ENTRY_LIST 1 1059 | #define VM_MAP_COPY_OBJECT 2 1060 | #define VM_MAP_COPY_KERNEL_BUFFER 3 1061 | vm_object_offset_t offset; 1062 | vm_map_size_t size; 1063 | union { 1064 | struct vm_map_header hdr; /* ENTRY_LIST */ 1065 | vm_object_t object; /* OBJECT */ 1066 | struct { 1067 | void *kdata; /* KERNEL_BUFFER */ 1068 | vm_size_t kalloc_size; /* size of this copy_t */ 1069 | } c_k; 1070 | } c_u; 1071 | }; 1072 | 1073 | -------------------------------------------------------------------------------- /hydra/hydra/shared_data.h: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * dddddddd 4 | * HHHHHHHHH HHHHHHHHH d::::::d 5 | * H:::::::H H:::::::H d::::::d 6 | * H:::::::H H:::::::H d::::::d 7 | * HH::::::H H::::::HH d:::::d 8 | * H:::::H H:::::Hyyyyyyy yyyyyyy ddddddddd:::::drrrrr rrrrrrrrr aaaaaaaaaaaaa 9 | * H:::::H H:::::H y:::::y y:::::ydd::::::::::::::dr::::rrr:::::::::r a::::::::::::a 10 | * H::::::HHHHH::::::H y:::::y y:::::yd::::::::::::::::dr:::::::::::::::::r aaaaaaaaa:::::a 11 | * H:::::::::::::::::H y:::::y y:::::yd:::::::ddddd:::::drr::::::rrrrr::::::r a::::a 12 | * H:::::::::::::::::H y:::::y y:::::y d::::::d d:::::d r:::::r r:::::r aaaaaaa:::::a 13 | * H::::::HHHHH::::::H y:::::y y:::::y d:::::d d:::::d r:::::r rrrrrrraa::::::::::::a 14 | * H:::::H H:::::H y:::::y:::::y d:::::d d:::::d r:::::r a::::aaaa::::::a 15 | * H:::::H H:::::H y:::::::::y d:::::d d:::::d r:::::r a::::a a:::::a 16 | * HH::::::H H::::::HH y:::::::y d::::::ddddd::::::ddr:::::r a::::a a:::::a 17 | * H:::::::H H:::::::H y:::::y d:::::::::::::::::dr:::::r a:::::aaaa::::::a 18 | * H:::::::H H:::::::H y:::::y d:::::::::ddd::::dr:::::r a::::::::::aa:::a 19 | * HHHHHHHHH HHHHHHHHH y:::::y ddddddddd dddddrrrrrrr aaaaaaaaaa aaaa 20 | * y:::::y 21 | * y:::::y 22 | * y:::::y 23 | * y:::::y 24 | * yyyyyyy 25 | * 26 | * A kernel extension to suspend applications and notify a userland daemon 27 | * 28 | * Copyright (c) 2012,2013 fG!. All rights reserved. 29 | * reverser@put.as - http://reverse.put.as 30 | * 31 | * shared_data.h 32 | * 33 | * this is the file that should be shared with the userland client 34 | * 35 | * Redistribution and use in source and binary forms, with or without 36 | * modification, are permitted provided that the following conditions 37 | * are met: 38 | * 1. Redistributions of source code must retain the above copyright 39 | * notice, this list of conditions and the following disclaimer. 40 | * 2. Redistributions in binary form must reproduce the above copyright 41 | * notice, this list of conditions and the following disclaimer in the 42 | * documentation and/or other materials provided with the distribution. 43 | * 3. The name of the author may not be used to endorse or promote products 44 | * derived from this software without specific prior written permission. 45 | * 46 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 47 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 48 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 49 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 50 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 51 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 52 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 53 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 54 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 55 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 56 | * 57 | */ 58 | 59 | #ifndef hydra_shared_data_h 60 | #define hydra_shared_data_h 61 | 62 | #define BUNDLE_ID "put.as.hydra" 63 | 64 | #define ADD_APP 0 65 | #define REMOVE_APP 1 66 | #define GET_PID 2 // This isn't used anywhere 67 | #define REMOVE_ALL_APPS 3 68 | 69 | #endif 70 | -------------------------------------------------------------------------------- /hydra/hydra/suspend_proc.c: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * dddddddd 4 | * HHHHHHHHH HHHHHHHHH d::::::d 5 | * H:::::::H H:::::::H d::::::d 6 | * H:::::::H H:::::::H d::::::d 7 | * HH::::::H H::::::HH d:::::d 8 | * H:::::H H:::::Hyyyyyyy yyyyyyy ddddddddd:::::drrrrr rrrrrrrrr aaaaaaaaaaaaa 9 | * H:::::H H:::::H y:::::y y:::::ydd::::::::::::::dr::::rrr:::::::::r a::::::::::::a 10 | * H::::::HHHHH::::::H y:::::y y:::::yd::::::::::::::::dr:::::::::::::::::r aaaaaaaaa:::::a 11 | * H:::::::::::::::::H y:::::y y:::::yd:::::::ddddd:::::drr::::::rrrrr::::::r a::::a 12 | * H:::::::::::::::::H y:::::y y:::::y d::::::d d:::::d r:::::r r:::::r aaaaaaa:::::a 13 | * H::::::HHHHH::::::H y:::::y y:::::y d:::::d d:::::d r:::::r rrrrrrraa::::::::::::a 14 | * H:::::H H:::::H y:::::y:::::y d:::::d d:::::d r:::::r a::::aaaa::::::a 15 | * H:::::H H:::::H y:::::::::y d:::::d d:::::d r:::::r a::::a a:::::a 16 | * HH::::::H H::::::HH y:::::::y d::::::ddddd::::::ddr:::::r a::::a a:::::a 17 | * H:::::::H H:::::::H y:::::y d:::::::::::::::::dr:::::r a:::::aaaa::::::a 18 | * H:::::::H H:::::::H y:::::y d:::::::::ddd::::dr:::::r a::::::::::aa:::a 19 | * HHHHHHHHH HHHHHHHHH y:::::y ddddddddd dddddrrrrrrr aaaaaaaaaa aaaa 20 | * y:::::y 21 | * y:::::y 22 | * y:::::y 23 | * y:::::y 24 | * yyyyyyy 25 | * 26 | * A kernel extension to suspend applications and notify a userland daemon 27 | * 28 | * Copyright (c) 2012,2013 fG!. All rights reserved. 29 | * reverser@put.as - http://reverse.put.as 30 | * 31 | * suspend_proc.c 32 | * 33 | * Redistribution and use in source and binary forms, with or without 34 | * modification, are permitted provided that the following conditions 35 | * are met: 36 | * 1. Redistributions of source code must retain the above copyright 37 | * notice, this list of conditions and the following disclaimer. 38 | * 2. Redistributions in binary form must reproduce the above copyright 39 | * notice, this list of conditions and the following disclaimer in the 40 | * documentation and/or other materials provided with the distribution. 41 | * 3. The name of the author may not be used to endorse or promote products 42 | * derived from this software without specific prior written permission. 43 | * 44 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 45 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 46 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 47 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 48 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 49 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 50 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 51 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 52 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 53 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 54 | * 55 | */ 56 | 57 | #include "suspend_proc.h" 58 | 59 | #include 60 | #include 61 | #include 62 | #include 63 | #include 64 | #include 65 | #include 66 | 67 | #include "kernel_info.h" 68 | #include "kernel_control.h" 69 | 70 | /* Status values. */ 71 | #define SIDL 1 /* Process being created by fork. */ 72 | #define SRUN 2 /* Currently runnable. */ 73 | #define SSLEEP 3 /* Sleeping on an address. */ 74 | #define SSTOP 4 /* Process debugging or suspension. */ 75 | #define SZOMB 5 /* Awaiting collection by parent. */ 76 | 77 | /* other definitions we need to import */ 78 | #define P_LREGISTER 0x00800000 /* thread start fns registered */ 79 | #define proc_lock(p) lck_mtx_lock(&(p)->p_mlock) 80 | #define proc_unlock(p) lck_mtx_unlock(&(p)->p_mlock) 81 | 82 | extern struct kernel_info g_kernel_info; 83 | extern targets_t g_targets_list; 84 | 85 | kern_return_t (*_task_suspend)(task_t target_task); 86 | 87 | /* 88 | * function to replace the original proc_resetregister and suspend the processes we are interested in 89 | */ 90 | void 91 | myproc_resetregister(proc_t p) 92 | { 93 | // this symbol is not exported so we need to solve it first 94 | if (_task_suspend == NULL) 95 | { 96 | _task_suspend = (void*)(solve_kernel_symbol(&g_kernel_info, "_task_suspend")); 97 | // if we can't solve the symbol then get back to the original code 98 | if (_task_suspend == NULL) 99 | { 100 | LOG_MSG("[ERROR] Failed to solve task_suspend() symbol...\n"); 101 | goto original_code; 102 | } 103 | } 104 | // activate proc_t lock to avoid problems 105 | proc_lock(p); 106 | // retrieve the name of the new process being executed 107 | pid_t pid = p->p_pid; 108 | char processname[MAXCOMLEN+1]; 109 | proc_name(p->p_pid, processname, sizeof(processname)); 110 | // try to find it on our targets list 111 | targets_t temp = { 0 }; 112 | HASH_FIND_STR(g_targets_list, processname, temp); 113 | proc_unlock(p); 114 | // found something 115 | if (temp) 116 | { 117 | /* 118 | * If posix_spawned with the START_SUSPENDED flag, stop the 119 | * process before it runs. 120 | */ 121 | /* 122 | if (imgp->ip_px_sa != NULL) { 123 | psa = (struct _posix_spawnattr *) imgp->ip_px_sa; 124 | if (psa->psa_flags & POSIX_SPAWN_START_SUSPENDED) { 125 | proc_lock(p); 126 | p->p_stat = SSTOP; 127 | proc_unlock(p); 128 | (void) task_suspend(p->task); 129 | } 130 | */ 131 | proc_lock(p); 132 | p->p_stat = SSTOP; 133 | proc_unlock(p); 134 | if (_task_suspend(p->task) == KERN_SUCCESS) 135 | { 136 | // queue data for userland process 137 | queue_userland_data(pid); 138 | } 139 | } 140 | // the original function code 141 | original_code: 142 | proc_lock(p); 143 | p->p_lflag &= ~P_LREGISTER; 144 | proc_unlock(p); 145 | } 146 | -------------------------------------------------------------------------------- /hydra/hydra/suspend_proc.h: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * dddddddd 4 | * HHHHHHHHH HHHHHHHHH d::::::d 5 | * H:::::::H H:::::::H d::::::d 6 | * H:::::::H H:::::::H d::::::d 7 | * HH::::::H H::::::HH d:::::d 8 | * H:::::H H:::::Hyyyyyyy yyyyyyy ddddddddd:::::drrrrr rrrrrrrrr aaaaaaaaaaaaa 9 | * H:::::H H:::::H y:::::y y:::::ydd::::::::::::::dr::::rrr:::::::::r a::::::::::::a 10 | * H::::::HHHHH::::::H y:::::y y:::::yd::::::::::::::::dr:::::::::::::::::r aaaaaaaaa:::::a 11 | * H:::::::::::::::::H y:::::y y:::::yd:::::::ddddd:::::drr::::::rrrrr::::::r a::::a 12 | * H:::::::::::::::::H y:::::y y:::::y d::::::d d:::::d r:::::r r:::::r aaaaaaa:::::a 13 | * H::::::HHHHH::::::H y:::::y y:::::y d:::::d d:::::d r:::::r rrrrrrraa::::::::::::a 14 | * H:::::H H:::::H y:::::y:::::y d:::::d d:::::d r:::::r a::::aaaa::::::a 15 | * H:::::H H:::::H y:::::::::y d:::::d d:::::d r:::::r a::::a a:::::a 16 | * HH::::::H H::::::HH y:::::::y d::::::ddddd::::::ddr:::::r a::::a a:::::a 17 | * H:::::::H H:::::::H y:::::y d:::::::::::::::::dr:::::r a:::::aaaa::::::a 18 | * H:::::::H H:::::::H y:::::y d:::::::::ddd::::dr:::::r a::::::::::aa:::a 19 | * HHHHHHHHH HHHHHHHHH y:::::y ddddddddd dddddrrrrrrr aaaaaaaaaa aaaa 20 | * y:::::y 21 | * y:::::y 22 | * y:::::y 23 | * y:::::y 24 | * yyyyyyy 25 | * 26 | * A kernel extension to suspend applications and notify a userland daemon 27 | * 28 | * Copyright (c) 2012,2013 fG!. All rights reserved. 29 | * reverser@put.as - http://reverse.put.as 30 | * 31 | * suspend_proc.h 32 | * 33 | * Redistribution and use in source and binary forms, with or without 34 | * modification, are permitted provided that the following conditions 35 | * are met: 36 | * 1. Redistributions of source code must retain the above copyright 37 | * notice, this list of conditions and the following disclaimer. 38 | * 2. Redistributions in binary form must reproduce the above copyright 39 | * notice, this list of conditions and the following disclaimer in the 40 | * documentation and/or other materials provided with the distribution. 41 | * 3. The name of the author may not be used to endorse or promote products 42 | * derived from this software without specific prior written permission. 43 | * 44 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 45 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 46 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 47 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 48 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 49 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 50 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 51 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 52 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 53 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 54 | * 55 | */ 56 | 57 | #ifndef hydra_suspend_proc_h 58 | #define hydra_suspend_proc_h 59 | 60 | #include "proc.h" 61 | 62 | void myproc_resetregister(proc_t p); 63 | 64 | #endif 65 | -------------------------------------------------------------------------------- /hydra/hydra/uthash.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2003-2013, Troy D. Hanson http://uthash.sourceforge.net 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 8 | * Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | 11 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 12 | IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 13 | TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 14 | PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 15 | OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 16 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 17 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 18 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 19 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 20 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 21 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 22 | */ 23 | 24 | #ifndef UTHASH_H 25 | #define UTHASH_H 26 | 27 | #include /* memcmp,strlen */ 28 | typedef __typeof__(((int*)0)-((int*)0)) ptrdiff_t; 29 | 30 | /* These macros use decltype or the earlier __typeof GNU extension. 31 | As decltype is only available in newer compilers (VS2010 or gcc 4.3+ 32 | when compiling c++ source) this code uses whatever method is needed 33 | or, for VS2008 where neither is available, uses casting workarounds. */ 34 | #ifdef _MSC_VER /* MS compiler */ 35 | #if _MSC_VER >= 1600 && defined(__cplusplus) /* VS2010 or newer in C++ mode */ 36 | #define DECLTYPE(x) (decltype(x)) 37 | #else /* VS2008 or older (or VS2010 in C mode) */ 38 | #define NO_DECLTYPE 39 | #define DECLTYPE(x) 40 | #endif 41 | #else /* GNU, Sun and other compilers */ 42 | #define DECLTYPE(x) (__typeof(x)) 43 | #endif 44 | 45 | #ifdef NO_DECLTYPE 46 | #define DECLTYPE_ASSIGN(dst,src) \ 47 | do { \ 48 | char **_da_dst = (char**)(&(dst)); \ 49 | *_da_dst = (char*)(src); \ 50 | } while(0) 51 | #else 52 | #define DECLTYPE_ASSIGN(dst,src) \ 53 | do { \ 54 | (dst) = DECLTYPE(dst)(src); \ 55 | } while(0) 56 | #endif 57 | 58 | #define UTHASH_VERSION 1.9.7 59 | 60 | #ifndef uthash_fatal 61 | #define uthash_fatal(msg) printf("uthash fatal %s\n", msg); /* fatal error (out of memory,etc) */ 62 | #endif 63 | #ifndef uthash_malloc 64 | #define uthash_malloc(sz) _MALLOC(sz, 1, M_ZERO) /* malloc fcn */ 65 | #endif 66 | #ifndef uthash_free 67 | #define uthash_free(ptr,sz) _FREE(ptr, M_ZERO) /* free fcn */ 68 | #endif 69 | 70 | #ifndef uthash_noexpand_fyi 71 | #define uthash_noexpand_fyi(tbl) /* can be defined to log noexpand */ 72 | #endif 73 | #ifndef uthash_expand_fyi 74 | #define uthash_expand_fyi(tbl) /* can be defined to log expands */ 75 | #endif 76 | 77 | /* initial number of buckets */ 78 | #define HASH_INITIAL_NUM_BUCKETS 32 /* initial number of buckets */ 79 | #define HASH_INITIAL_NUM_BUCKETS_LOG2 5 /* lg2 of initial number of buckets */ 80 | #define HASH_BKT_CAPACITY_THRESH 10 /* expand when bucket count reaches */ 81 | 82 | /* calculate the element whose hash handle address is hhe */ 83 | #define ELMT_FROM_HH(tbl,hhp) ((void*)(((char*)(hhp)) - ((tbl)->hho))) 84 | 85 | #define HASH_FIND(hh,head,keyptr,keylen,out) \ 86 | do { \ 87 | unsigned _hf_bkt,_hf_hashv; \ 88 | out=NULL; \ 89 | if (head) { \ 90 | HASH_FCN(keyptr,keylen, (head)->hh.tbl->num_buckets, _hf_hashv, _hf_bkt); \ 91 | if (HASH_BLOOM_TEST((head)->hh.tbl, _hf_hashv)) { \ 92 | HASH_FIND_IN_BKT((head)->hh.tbl, hh, (head)->hh.tbl->buckets[ _hf_bkt ], \ 93 | keyptr,keylen,out); \ 94 | } \ 95 | } \ 96 | } while (0) 97 | 98 | #ifdef HASH_BLOOM 99 | #define HASH_BLOOM_BITLEN (1ULL << HASH_BLOOM) 100 | #define HASH_BLOOM_BYTELEN (HASH_BLOOM_BITLEN/8) + ((HASH_BLOOM_BITLEN%8) ? 1:0) 101 | #define HASH_BLOOM_MAKE(tbl) \ 102 | do { \ 103 | (tbl)->bloom_nbits = HASH_BLOOM; \ 104 | (tbl)->bloom_bv = (uint8_t*)uthash_malloc(HASH_BLOOM_BYTELEN); \ 105 | if (!((tbl)->bloom_bv)) { uthash_fatal( "out of memory"); } \ 106 | memset((tbl)->bloom_bv, 0, HASH_BLOOM_BYTELEN); \ 107 | (tbl)->bloom_sig = HASH_BLOOM_SIGNATURE; \ 108 | } while (0) 109 | 110 | #define HASH_BLOOM_FREE(tbl) \ 111 | do { \ 112 | uthash_free((tbl)->bloom_bv, HASH_BLOOM_BYTELEN); \ 113 | } while (0) 114 | 115 | #define HASH_BLOOM_BITSET(bv,idx) (bv[(idx)/8] |= (1U << ((idx)%8))) 116 | #define HASH_BLOOM_BITTEST(bv,idx) (bv[(idx)/8] & (1U << ((idx)%8))) 117 | 118 | #define HASH_BLOOM_ADD(tbl,hashv) \ 119 | HASH_BLOOM_BITSET((tbl)->bloom_bv, (hashv & (uint32_t)((1ULL << (tbl)->bloom_nbits) - 1))) 120 | 121 | #define HASH_BLOOM_TEST(tbl,hashv) \ 122 | HASH_BLOOM_BITTEST((tbl)->bloom_bv, (hashv & (uint32_t)((1ULL << (tbl)->bloom_nbits) - 1))) 123 | 124 | #else 125 | #define HASH_BLOOM_MAKE(tbl) 126 | #define HASH_BLOOM_FREE(tbl) 127 | #define HASH_BLOOM_ADD(tbl,hashv) 128 | #define HASH_BLOOM_TEST(tbl,hashv) (1) 129 | #endif 130 | 131 | #define HASH_MAKE_TABLE(hh,head) \ 132 | do { \ 133 | (head)->hh.tbl = (UT_hash_table*)uthash_malloc( \ 134 | sizeof(UT_hash_table)); \ 135 | if (!((head)->hh.tbl)) { uthash_fatal( "out of memory"); } \ 136 | memset((head)->hh.tbl, 0, sizeof(UT_hash_table)); \ 137 | (head)->hh.tbl->tail = &((head)->hh); \ 138 | (head)->hh.tbl->num_buckets = HASH_INITIAL_NUM_BUCKETS; \ 139 | (head)->hh.tbl->log2_num_buckets = HASH_INITIAL_NUM_BUCKETS_LOG2; \ 140 | (head)->hh.tbl->hho = (char*)(&(head)->hh) - (char*)(head); \ 141 | (head)->hh.tbl->buckets = (UT_hash_bucket*)uthash_malloc( \ 142 | HASH_INITIAL_NUM_BUCKETS*sizeof(struct UT_hash_bucket)); \ 143 | if (! (head)->hh.tbl->buckets) { uthash_fatal( "out of memory"); } \ 144 | memset((head)->hh.tbl->buckets, 0, \ 145 | HASH_INITIAL_NUM_BUCKETS*sizeof(struct UT_hash_bucket)); \ 146 | HASH_BLOOM_MAKE((head)->hh.tbl); \ 147 | (head)->hh.tbl->signature = HASH_SIGNATURE; \ 148 | } while(0) 149 | 150 | #define HASH_ADD(hh,head,fieldname,keylen_in,add) \ 151 | HASH_ADD_KEYPTR(hh,head,&((add)->fieldname),keylen_in,add) 152 | 153 | #define HASH_ADD_KEYPTR(hh,head,keyptr,keylen_in,add) \ 154 | do { \ 155 | unsigned _ha_bkt; \ 156 | (add)->hh.next = NULL; \ 157 | (add)->hh.key = (char*)keyptr; \ 158 | (add)->hh.keylen = (unsigned)keylen_in; \ 159 | if (!(head)) { \ 160 | head = (add); \ 161 | (head)->hh.prev = NULL; \ 162 | HASH_MAKE_TABLE(hh,head); \ 163 | } else { \ 164 | (head)->hh.tbl->tail->next = (add); \ 165 | (add)->hh.prev = ELMT_FROM_HH((head)->hh.tbl, (head)->hh.tbl->tail); \ 166 | (head)->hh.tbl->tail = &((add)->hh); \ 167 | } \ 168 | (head)->hh.tbl->num_items++; \ 169 | (add)->hh.tbl = (head)->hh.tbl; \ 170 | HASH_FCN(keyptr,keylen_in, (head)->hh.tbl->num_buckets, \ 171 | (add)->hh.hashv, _ha_bkt); \ 172 | HASH_ADD_TO_BKT((head)->hh.tbl->buckets[_ha_bkt],&(add)->hh); \ 173 | HASH_BLOOM_ADD((head)->hh.tbl,(add)->hh.hashv); \ 174 | HASH_EMIT_KEY(hh,head,keyptr,keylen_in); \ 175 | HASH_FSCK(hh,head); \ 176 | } while(0) 177 | 178 | #define HASH_TO_BKT( hashv, num_bkts, bkt ) \ 179 | do { \ 180 | bkt = ((hashv) & ((num_bkts) - 1)); \ 181 | } while(0) 182 | 183 | /* delete "delptr" from the hash table. 184 | * "the usual" patch-up process for the app-order doubly-linked-list. 185 | * The use of _hd_hh_del below deserves special explanation. 186 | * These used to be expressed using (delptr) but that led to a bug 187 | * if someone used the same symbol for the head and deletee, like 188 | * HASH_DELETE(hh,users,users); 189 | * We want that to work, but by changing the head (users) below 190 | * we were forfeiting our ability to further refer to the deletee (users) 191 | * in the patch-up process. Solution: use scratch space to 192 | * copy the deletee pointer, then the latter references are via that 193 | * scratch pointer rather than through the repointed (users) symbol. 194 | */ 195 | #define HASH_DELETE(hh,head,delptr) \ 196 | do { \ 197 | unsigned _hd_bkt; \ 198 | struct UT_hash_handle *_hd_hh_del; \ 199 | if ( ((delptr)->hh.prev == NULL) && ((delptr)->hh.next == NULL) ) { \ 200 | uthash_free((head)->hh.tbl->buckets, \ 201 | (head)->hh.tbl->num_buckets*sizeof(struct UT_hash_bucket) ); \ 202 | HASH_BLOOM_FREE((head)->hh.tbl); \ 203 | uthash_free((head)->hh.tbl, sizeof(UT_hash_table)); \ 204 | head = NULL; \ 205 | } else { \ 206 | _hd_hh_del = &((delptr)->hh); \ 207 | if ((delptr) == ELMT_FROM_HH((head)->hh.tbl,(head)->hh.tbl->tail)) { \ 208 | (head)->hh.tbl->tail = \ 209 | (UT_hash_handle*)((ptrdiff_t)((delptr)->hh.prev) + \ 210 | (head)->hh.tbl->hho); \ 211 | } \ 212 | if ((delptr)->hh.prev) { \ 213 | ((UT_hash_handle*)((ptrdiff_t)((delptr)->hh.prev) + \ 214 | (head)->hh.tbl->hho))->next = (delptr)->hh.next; \ 215 | } else { \ 216 | DECLTYPE_ASSIGN(head,(delptr)->hh.next); \ 217 | } \ 218 | if (_hd_hh_del->next) { \ 219 | ((UT_hash_handle*)((ptrdiff_t)_hd_hh_del->next + \ 220 | (head)->hh.tbl->hho))->prev = \ 221 | _hd_hh_del->prev; \ 222 | } \ 223 | HASH_TO_BKT( _hd_hh_del->hashv, (head)->hh.tbl->num_buckets, _hd_bkt); \ 224 | HASH_DEL_IN_BKT(hh,(head)->hh.tbl->buckets[_hd_bkt], _hd_hh_del); \ 225 | (head)->hh.tbl->num_items--; \ 226 | } \ 227 | HASH_FSCK(hh,head); \ 228 | } while (0) 229 | 230 | 231 | /* convenience forms of HASH_FIND/HASH_ADD/HASH_DEL */ 232 | #define HASH_FIND_STR(head,findstr,out) \ 233 | HASH_FIND(hh,head,findstr,(int)strlen(findstr),out) 234 | #define HASH_ADD_STR(head,strfield,add) \ 235 | HASH_ADD(hh,head,strfield,strlen(add->strfield),add) 236 | #define HASH_FIND_INT(head,findint,out) \ 237 | HASH_FIND(hh,head,findint,sizeof(int),out) 238 | #define HASH_ADD_INT(head,intfield,add) \ 239 | HASH_ADD(hh,head,intfield,sizeof(int),add) 240 | #define HASH_FIND_PTR(head,findptr,out) \ 241 | HASH_FIND(hh,head,findptr,sizeof(void *),out) 242 | #define HASH_ADD_PTR(head,ptrfield,add) \ 243 | HASH_ADD(hh,head,ptrfield,sizeof(void *),add) 244 | #define HASH_DEL(head,delptr) \ 245 | HASH_DELETE(hh,head,delptr) 246 | 247 | /* HASH_FSCK checks hash integrity on every add/delete when HASH_DEBUG is defined. 248 | * This is for uthash developer only; it compiles away if HASH_DEBUG isn't defined. 249 | */ 250 | #ifdef HASH_DEBUG 251 | #define HASH_OOPS(...) do { fprintf(stderr,__VA_ARGS__); exit(-1); } while (0) 252 | #define HASH_FSCK(hh,head) \ 253 | do { \ 254 | unsigned _bkt_i; \ 255 | unsigned _count, _bkt_count; \ 256 | char *_prev; \ 257 | struct UT_hash_handle *_thh; \ 258 | if (head) { \ 259 | _count = 0; \ 260 | for( _bkt_i = 0; _bkt_i < (head)->hh.tbl->num_buckets; _bkt_i++) { \ 261 | _bkt_count = 0; \ 262 | _thh = (head)->hh.tbl->buckets[_bkt_i].hh_head; \ 263 | _prev = NULL; \ 264 | while (_thh) { \ 265 | if (_prev != (char*)(_thh->hh_prev)) { \ 266 | HASH_OOPS("invalid hh_prev %p, actual %p\n", \ 267 | _thh->hh_prev, _prev ); \ 268 | } \ 269 | _bkt_count++; \ 270 | _prev = (char*)(_thh); \ 271 | _thh = _thh->hh_next; \ 272 | } \ 273 | _count += _bkt_count; \ 274 | if ((head)->hh.tbl->buckets[_bkt_i].count != _bkt_count) { \ 275 | HASH_OOPS("invalid bucket count %d, actual %d\n", \ 276 | (head)->hh.tbl->buckets[_bkt_i].count, _bkt_count); \ 277 | } \ 278 | } \ 279 | if (_count != (head)->hh.tbl->num_items) { \ 280 | HASH_OOPS("invalid hh item count %d, actual %d\n", \ 281 | (head)->hh.tbl->num_items, _count ); \ 282 | } \ 283 | /* traverse hh in app order; check next/prev integrity, count */ \ 284 | _count = 0; \ 285 | _prev = NULL; \ 286 | _thh = &(head)->hh; \ 287 | while (_thh) { \ 288 | _count++; \ 289 | if (_prev !=(char*)(_thh->prev)) { \ 290 | HASH_OOPS("invalid prev %p, actual %p\n", \ 291 | _thh->prev, _prev ); \ 292 | } \ 293 | _prev = (char*)ELMT_FROM_HH((head)->hh.tbl, _thh); \ 294 | _thh = ( _thh->next ? (UT_hash_handle*)((char*)(_thh->next) + \ 295 | (head)->hh.tbl->hho) : NULL ); \ 296 | } \ 297 | if (_count != (head)->hh.tbl->num_items) { \ 298 | HASH_OOPS("invalid app item count %d, actual %d\n", \ 299 | (head)->hh.tbl->num_items, _count ); \ 300 | } \ 301 | } \ 302 | } while (0) 303 | #else 304 | #define HASH_FSCK(hh,head) 305 | #endif 306 | 307 | /* When compiled with -DHASH_EMIT_KEYS, length-prefixed keys are emitted to 308 | * the descriptor to which this macro is defined for tuning the hash function. 309 | * The app can #include to get the prototype for write(2). */ 310 | #ifdef HASH_EMIT_KEYS 311 | #define HASH_EMIT_KEY(hh,head,keyptr,fieldlen) \ 312 | do { \ 313 | unsigned _klen = fieldlen; \ 314 | write(HASH_EMIT_KEYS, &_klen, sizeof(_klen)); \ 315 | write(HASH_EMIT_KEYS, keyptr, fieldlen); \ 316 | } while (0) 317 | #else 318 | #define HASH_EMIT_KEY(hh,head,keyptr,fieldlen) 319 | #endif 320 | 321 | /* default to Jenkin's hash unless overridden e.g. DHASH_FUNCTION=HASH_SAX */ 322 | #ifdef HASH_FUNCTION 323 | #define HASH_FCN HASH_FUNCTION 324 | #else 325 | #define HASH_FCN HASH_JEN 326 | #endif 327 | 328 | /* The Bernstein hash function, used in Perl prior to v5.6 */ 329 | #define HASH_BER(key,keylen,num_bkts,hashv,bkt) \ 330 | do { \ 331 | unsigned _hb_keylen=keylen; \ 332 | char *_hb_key=(char*)(key); \ 333 | (hashv) = 0; \ 334 | while (_hb_keylen--) { (hashv) = ((hashv) * 33) + *_hb_key++; } \ 335 | bkt = (hashv) & (num_bkts-1); \ 336 | } while (0) 337 | 338 | 339 | /* SAX/FNV/OAT/JEN hash functions are macro variants of those listed at 340 | * http://eternallyconfuzzled.com/tuts/algorithms/jsw_tut_hashing.aspx */ 341 | #define HASH_SAX(key,keylen,num_bkts,hashv,bkt) \ 342 | do { \ 343 | unsigned _sx_i; \ 344 | char *_hs_key=(char*)(key); \ 345 | hashv = 0; \ 346 | for(_sx_i=0; _sx_i < keylen; _sx_i++) \ 347 | hashv ^= (hashv << 5) + (hashv >> 2) + _hs_key[_sx_i]; \ 348 | bkt = hashv & (num_bkts-1); \ 349 | } while (0) 350 | 351 | #define HASH_FNV(key,keylen,num_bkts,hashv,bkt) \ 352 | do { \ 353 | unsigned _fn_i; \ 354 | char *_hf_key=(char*)(key); \ 355 | hashv = 2166136261UL; \ 356 | for(_fn_i=0; _fn_i < keylen; _fn_i++) \ 357 | hashv = (hashv * 16777619) ^ _hf_key[_fn_i]; \ 358 | bkt = hashv & (num_bkts-1); \ 359 | } while(0) 360 | 361 | #define HASH_OAT(key,keylen,num_bkts,hashv,bkt) \ 362 | do { \ 363 | unsigned _ho_i; \ 364 | char *_ho_key=(char*)(key); \ 365 | hashv = 0; \ 366 | for(_ho_i=0; _ho_i < keylen; _ho_i++) { \ 367 | hashv += _ho_key[_ho_i]; \ 368 | hashv += (hashv << 10); \ 369 | hashv ^= (hashv >> 6); \ 370 | } \ 371 | hashv += (hashv << 3); \ 372 | hashv ^= (hashv >> 11); \ 373 | hashv += (hashv << 15); \ 374 | bkt = hashv & (num_bkts-1); \ 375 | } while(0) 376 | 377 | #define HASH_JEN_MIX(a,b,c) \ 378 | do { \ 379 | a -= b; a -= c; a ^= ( c >> 13 ); \ 380 | b -= c; b -= a; b ^= ( a << 8 ); \ 381 | c -= a; c -= b; c ^= ( b >> 13 ); \ 382 | a -= b; a -= c; a ^= ( c >> 12 ); \ 383 | b -= c; b -= a; b ^= ( a << 16 ); \ 384 | c -= a; c -= b; c ^= ( b >> 5 ); \ 385 | a -= b; a -= c; a ^= ( c >> 3 ); \ 386 | b -= c; b -= a; b ^= ( a << 10 ); \ 387 | c -= a; c -= b; c ^= ( b >> 15 ); \ 388 | } while (0) 389 | 390 | #define HASH_JEN(key,keylen,num_bkts,hashv,bkt) \ 391 | do { \ 392 | unsigned _hj_i,_hj_j,_hj_k; \ 393 | char *_hj_key=(char*)(key); \ 394 | hashv = 0xfeedbeef; \ 395 | _hj_i = _hj_j = 0x9e3779b9; \ 396 | _hj_k = (unsigned)keylen; \ 397 | while (_hj_k >= 12) { \ 398 | _hj_i += (_hj_key[0] + ( (unsigned)_hj_key[1] << 8 ) \ 399 | + ( (unsigned)_hj_key[2] << 16 ) \ 400 | + ( (unsigned)_hj_key[3] << 24 ) ); \ 401 | _hj_j += (_hj_key[4] + ( (unsigned)_hj_key[5] << 8 ) \ 402 | + ( (unsigned)_hj_key[6] << 16 ) \ 403 | + ( (unsigned)_hj_key[7] << 24 ) ); \ 404 | hashv += (_hj_key[8] + ( (unsigned)_hj_key[9] << 8 ) \ 405 | + ( (unsigned)_hj_key[10] << 16 ) \ 406 | + ( (unsigned)_hj_key[11] << 24 ) ); \ 407 | \ 408 | HASH_JEN_MIX(_hj_i, _hj_j, hashv); \ 409 | \ 410 | _hj_key += 12; \ 411 | _hj_k -= 12; \ 412 | } \ 413 | hashv += keylen; \ 414 | switch ( _hj_k ) { \ 415 | case 11: hashv += ( (unsigned)_hj_key[10] << 24 ); \ 416 | case 10: hashv += ( (unsigned)_hj_key[9] << 16 ); \ 417 | case 9: hashv += ( (unsigned)_hj_key[8] << 8 ); \ 418 | case 8: _hj_j += ( (unsigned)_hj_key[7] << 24 ); \ 419 | case 7: _hj_j += ( (unsigned)_hj_key[6] << 16 ); \ 420 | case 6: _hj_j += ( (unsigned)_hj_key[5] << 8 ); \ 421 | case 5: _hj_j += _hj_key[4]; \ 422 | case 4: _hj_i += ( (unsigned)_hj_key[3] << 24 ); \ 423 | case 3: _hj_i += ( (unsigned)_hj_key[2] << 16 ); \ 424 | case 2: _hj_i += ( (unsigned)_hj_key[1] << 8 ); \ 425 | case 1: _hj_i += _hj_key[0]; \ 426 | } \ 427 | HASH_JEN_MIX(_hj_i, _hj_j, hashv); \ 428 | bkt = hashv & (num_bkts-1); \ 429 | } while(0) 430 | 431 | /* The Paul Hsieh hash function */ 432 | #undef get16bits 433 | #if (defined(__GNUC__) && defined(__i386__)) || defined(__WATCOMC__) \ 434 | || defined(_MSC_VER) || defined (__BORLANDC__) || defined (__TURBOC__) 435 | #define get16bits(d) (*((const uint16_t *) (d))) 436 | #endif 437 | 438 | #if !defined (get16bits) 439 | #define get16bits(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8) \ 440 | +(uint32_t)(((const uint8_t *)(d))[0]) ) 441 | #endif 442 | #define HASH_SFH(key,keylen,num_bkts,hashv,bkt) \ 443 | do { \ 444 | char *_sfh_key=(char*)(key); \ 445 | uint32_t _sfh_tmp, _sfh_len = keylen; \ 446 | \ 447 | int _sfh_rem = _sfh_len & 3; \ 448 | _sfh_len >>= 2; \ 449 | hashv = 0xcafebabe; \ 450 | \ 451 | /* Main loop */ \ 452 | for (;_sfh_len > 0; _sfh_len--) { \ 453 | hashv += get16bits (_sfh_key); \ 454 | _sfh_tmp = (get16bits (_sfh_key+2) << 11) ^ hashv; \ 455 | hashv = (hashv << 16) ^ _sfh_tmp; \ 456 | _sfh_key += 2*sizeof (uint16_t); \ 457 | hashv += hashv >> 11; \ 458 | } \ 459 | \ 460 | /* Handle end cases */ \ 461 | switch (_sfh_rem) { \ 462 | case 3: hashv += get16bits (_sfh_key); \ 463 | hashv ^= hashv << 16; \ 464 | hashv ^= _sfh_key[sizeof (uint16_t)] << 18; \ 465 | hashv += hashv >> 11; \ 466 | break; \ 467 | case 2: hashv += get16bits (_sfh_key); \ 468 | hashv ^= hashv << 11; \ 469 | hashv += hashv >> 17; \ 470 | break; \ 471 | case 1: hashv += *_sfh_key; \ 472 | hashv ^= hashv << 10; \ 473 | hashv += hashv >> 1; \ 474 | } \ 475 | \ 476 | /* Force "avalanching" of final 127 bits */ \ 477 | hashv ^= hashv << 3; \ 478 | hashv += hashv >> 5; \ 479 | hashv ^= hashv << 4; \ 480 | hashv += hashv >> 17; \ 481 | hashv ^= hashv << 25; \ 482 | hashv += hashv >> 6; \ 483 | bkt = hashv & (num_bkts-1); \ 484 | } while(0) 485 | 486 | #ifdef HASH_USING_NO_STRICT_ALIASING 487 | /* The MurmurHash exploits some CPU's (x86,x86_64) tolerance for unaligned reads. 488 | * For other types of CPU's (e.g. Sparc) an unaligned read causes a bus error. 489 | * MurmurHash uses the faster approach only on CPU's where we know it's safe. 490 | * 491 | * Note the preprocessor built-in defines can be emitted using: 492 | * 493 | * gcc -m64 -dM -E - < /dev/null (on gcc) 494 | * cc -## a.c (where a.c is a simple test file) (Sun Studio) 495 | */ 496 | #if (defined(__i386__) || defined(__x86_64__) || defined(_M_IX86)) 497 | #define MUR_GETBLOCK(p,i) p[i] 498 | #else /* non intel */ 499 | #define MUR_PLUS0_ALIGNED(p) (((unsigned long)p & 0x3) == 0) 500 | #define MUR_PLUS1_ALIGNED(p) (((unsigned long)p & 0x3) == 1) 501 | #define MUR_PLUS2_ALIGNED(p) (((unsigned long)p & 0x3) == 2) 502 | #define MUR_PLUS3_ALIGNED(p) (((unsigned long)p & 0x3) == 3) 503 | #define WP(p) ((uint32_t*)((unsigned long)(p) & ~3UL)) 504 | #if (defined(__BIG_ENDIAN__) || defined(SPARC) || defined(__ppc__) || defined(__ppc64__)) 505 | #define MUR_THREE_ONE(p) ((((*WP(p))&0x00ffffff) << 8) | (((*(WP(p)+1))&0xff000000) >> 24)) 506 | #define MUR_TWO_TWO(p) ((((*WP(p))&0x0000ffff) <<16) | (((*(WP(p)+1))&0xffff0000) >> 16)) 507 | #define MUR_ONE_THREE(p) ((((*WP(p))&0x000000ff) <<24) | (((*(WP(p)+1))&0xffffff00) >> 8)) 508 | #else /* assume little endian non-intel */ 509 | #define MUR_THREE_ONE(p) ((((*WP(p))&0xffffff00) >> 8) | (((*(WP(p)+1))&0x000000ff) << 24)) 510 | #define MUR_TWO_TWO(p) ((((*WP(p))&0xffff0000) >>16) | (((*(WP(p)+1))&0x0000ffff) << 16)) 511 | #define MUR_ONE_THREE(p) ((((*WP(p))&0xff000000) >>24) | (((*(WP(p)+1))&0x00ffffff) << 8)) 512 | #endif 513 | #define MUR_GETBLOCK(p,i) (MUR_PLUS0_ALIGNED(p) ? ((p)[i]) : \ 514 | (MUR_PLUS1_ALIGNED(p) ? MUR_THREE_ONE(p) : \ 515 | (MUR_PLUS2_ALIGNED(p) ? MUR_TWO_TWO(p) : \ 516 | MUR_ONE_THREE(p)))) 517 | #endif 518 | #define MUR_ROTL32(x,r) (((x) << (r)) | ((x) >> (32 - (r)))) 519 | #define MUR_FMIX(_h) \ 520 | do { \ 521 | _h ^= _h >> 16; \ 522 | _h *= 0x85ebca6b; \ 523 | _h ^= _h >> 13; \ 524 | _h *= 0xc2b2ae35l; \ 525 | _h ^= _h >> 16; \ 526 | } while(0) 527 | 528 | #define HASH_MUR(key,keylen,num_bkts,hashv,bkt) \ 529 | do { \ 530 | const uint8_t *_mur_data = (const uint8_t*)(key); \ 531 | const int _mur_nblocks = (keylen) / 4; \ 532 | uint32_t _mur_h1 = 0xf88D5353; \ 533 | uint32_t _mur_c1 = 0xcc9e2d51; \ 534 | uint32_t _mur_c2 = 0x1b873593; \ 535 | uint32_t _mur_k1 = 0; \ 536 | const uint8_t *_mur_tail; \ 537 | const uint32_t *_mur_blocks = (const uint32_t*)(_mur_data+_mur_nblocks*4); \ 538 | int _mur_i; \ 539 | for(_mur_i = -_mur_nblocks; _mur_i; _mur_i++) { \ 540 | _mur_k1 = MUR_GETBLOCK(_mur_blocks,_mur_i); \ 541 | _mur_k1 *= _mur_c1; \ 542 | _mur_k1 = MUR_ROTL32(_mur_k1,15); \ 543 | _mur_k1 *= _mur_c2; \ 544 | \ 545 | _mur_h1 ^= _mur_k1; \ 546 | _mur_h1 = MUR_ROTL32(_mur_h1,13); \ 547 | _mur_h1 = _mur_h1*5+0xe6546b64; \ 548 | } \ 549 | _mur_tail = (const uint8_t*)(_mur_data + _mur_nblocks*4); \ 550 | _mur_k1=0; \ 551 | switch((keylen) & 3) { \ 552 | case 3: _mur_k1 ^= _mur_tail[2] << 16; \ 553 | case 2: _mur_k1 ^= _mur_tail[1] << 8; \ 554 | case 1: _mur_k1 ^= _mur_tail[0]; \ 555 | _mur_k1 *= _mur_c1; \ 556 | _mur_k1 = MUR_ROTL32(_mur_k1,15); \ 557 | _mur_k1 *= _mur_c2; \ 558 | _mur_h1 ^= _mur_k1; \ 559 | } \ 560 | _mur_h1 ^= (keylen); \ 561 | MUR_FMIX(_mur_h1); \ 562 | hashv = _mur_h1; \ 563 | bkt = hashv & (num_bkts-1); \ 564 | } while(0) 565 | #endif /* HASH_USING_NO_STRICT_ALIASING */ 566 | 567 | /* key comparison function; return 0 if keys equal */ 568 | #define HASH_KEYCMP(a,b,len) memcmp(a,b,len) 569 | 570 | /* iterate over items in a known bucket to find desired item */ 571 | #define HASH_FIND_IN_BKT(tbl,hh,head,keyptr,keylen_in,out) \ 572 | do { \ 573 | if (head.hh_head) DECLTYPE_ASSIGN(out,ELMT_FROM_HH(tbl,head.hh_head)); \ 574 | else out=NULL; \ 575 | while (out) { \ 576 | if ((out)->hh.keylen == keylen_in) { \ 577 | if ((HASH_KEYCMP((out)->hh.key,keyptr,keylen_in)) == 0) break; \ 578 | } \ 579 | if ((out)->hh.hh_next) DECLTYPE_ASSIGN(out,ELMT_FROM_HH(tbl,(out)->hh.hh_next)); \ 580 | else out = NULL; \ 581 | } \ 582 | } while(0) 583 | 584 | /* add an item to a bucket */ 585 | #define HASH_ADD_TO_BKT(head,addhh) \ 586 | do { \ 587 | head.count++; \ 588 | (addhh)->hh_next = head.hh_head; \ 589 | (addhh)->hh_prev = NULL; \ 590 | if (head.hh_head) { (head).hh_head->hh_prev = (addhh); } \ 591 | (head).hh_head=addhh; \ 592 | if (head.count >= ((head.expand_mult+1) * HASH_BKT_CAPACITY_THRESH) \ 593 | && (addhh)->tbl->noexpand != 1) { \ 594 | HASH_EXPAND_BUCKETS((addhh)->tbl); \ 595 | } \ 596 | } while(0) 597 | 598 | /* remove an item from a given bucket */ 599 | #define HASH_DEL_IN_BKT(hh,head,hh_del) \ 600 | (head).count--; \ 601 | if ((head).hh_head == hh_del) { \ 602 | (head).hh_head = hh_del->hh_next; \ 603 | } \ 604 | if (hh_del->hh_prev) { \ 605 | hh_del->hh_prev->hh_next = hh_del->hh_next; \ 606 | } \ 607 | if (hh_del->hh_next) { \ 608 | hh_del->hh_next->hh_prev = hh_del->hh_prev; \ 609 | } 610 | 611 | /* Bucket expansion has the effect of doubling the number of buckets 612 | * and redistributing the items into the new buckets. Ideally the 613 | * items will distribute more or less evenly into the new buckets 614 | * (the extent to which this is true is a measure of the quality of 615 | * the hash function as it applies to the key domain). 616 | * 617 | * With the items distributed into more buckets, the chain length 618 | * (item count) in each bucket is reduced. Thus by expanding buckets 619 | * the hash keeps a bound on the chain length. This bounded chain 620 | * length is the essence of how a hash provides constant time lookup. 621 | * 622 | * The calculation of tbl->ideal_chain_maxlen below deserves some 623 | * explanation. First, keep in mind that we're calculating the ideal 624 | * maximum chain length based on the *new* (doubled) bucket count. 625 | * In fractions this is just n/b (n=number of items,b=new num buckets). 626 | * Since the ideal chain length is an integer, we want to calculate 627 | * ceil(n/b). We don't depend on floating point arithmetic in this 628 | * hash, so to calculate ceil(n/b) with integers we could write 629 | * 630 | * ceil(n/b) = (n/b) + ((n%b)?1:0) 631 | * 632 | * and in fact a previous version of this hash did just that. 633 | * But now we have improved things a bit by recognizing that b is 634 | * always a power of two. We keep its base 2 log handy (call it lb), 635 | * so now we can write this with a bit shift and logical AND: 636 | * 637 | * ceil(n/b) = (n>>lb) + ( (n & (b-1)) ? 1:0) 638 | * 639 | */ 640 | #define HASH_EXPAND_BUCKETS(tbl) \ 641 | do { \ 642 | unsigned _he_bkt; \ 643 | unsigned _he_bkt_i; \ 644 | struct UT_hash_handle *_he_thh, *_he_hh_nxt; \ 645 | UT_hash_bucket *_he_new_buckets, *_he_newbkt; \ 646 | _he_new_buckets = (UT_hash_bucket*)uthash_malloc( \ 647 | 2 * tbl->num_buckets * sizeof(struct UT_hash_bucket)); \ 648 | if (!_he_new_buckets) { uthash_fatal( "out of memory"); } \ 649 | memset(_he_new_buckets, 0, \ 650 | 2 * tbl->num_buckets * sizeof(struct UT_hash_bucket)); \ 651 | tbl->ideal_chain_maxlen = \ 652 | (tbl->num_items >> (tbl->log2_num_buckets+1)) + \ 653 | ((tbl->num_items & ((tbl->num_buckets*2)-1)) ? 1 : 0); \ 654 | tbl->nonideal_items = 0; \ 655 | for(_he_bkt_i = 0; _he_bkt_i < tbl->num_buckets; _he_bkt_i++) \ 656 | { \ 657 | _he_thh = tbl->buckets[ _he_bkt_i ].hh_head; \ 658 | while (_he_thh) { \ 659 | _he_hh_nxt = _he_thh->hh_next; \ 660 | HASH_TO_BKT( _he_thh->hashv, tbl->num_buckets*2, _he_bkt); \ 661 | _he_newbkt = &(_he_new_buckets[ _he_bkt ]); \ 662 | if (++(_he_newbkt->count) > tbl->ideal_chain_maxlen) { \ 663 | tbl->nonideal_items++; \ 664 | _he_newbkt->expand_mult = _he_newbkt->count / \ 665 | tbl->ideal_chain_maxlen; \ 666 | } \ 667 | _he_thh->hh_prev = NULL; \ 668 | _he_thh->hh_next = _he_newbkt->hh_head; \ 669 | if (_he_newbkt->hh_head) _he_newbkt->hh_head->hh_prev = \ 670 | _he_thh; \ 671 | _he_newbkt->hh_head = _he_thh; \ 672 | _he_thh = _he_hh_nxt; \ 673 | } \ 674 | } \ 675 | uthash_free( tbl->buckets, tbl->num_buckets*sizeof(struct UT_hash_bucket) ); \ 676 | tbl->num_buckets *= 2; \ 677 | tbl->log2_num_buckets++; \ 678 | tbl->buckets = _he_new_buckets; \ 679 | tbl->ineff_expands = (tbl->nonideal_items > (tbl->num_items >> 1)) ? \ 680 | (tbl->ineff_expands+1) : 0; \ 681 | if (tbl->ineff_expands > 1) { \ 682 | tbl->noexpand=1; \ 683 | uthash_noexpand_fyi(tbl); \ 684 | } \ 685 | uthash_expand_fyi(tbl); \ 686 | } while(0) 687 | 688 | 689 | /* This is an adaptation of Simon Tatham's O(n log(n)) mergesort */ 690 | /* Note that HASH_SORT assumes the hash handle name to be hh. 691 | * HASH_SRT was added to allow the hash handle name to be passed in. */ 692 | #define HASH_SORT(head,cmpfcn) HASH_SRT(hh,head,cmpfcn) 693 | #define HASH_SRT(hh,head,cmpfcn) \ 694 | do { \ 695 | unsigned _hs_i; \ 696 | unsigned _hs_looping,_hs_nmerges,_hs_insize,_hs_psize,_hs_qsize; \ 697 | struct UT_hash_handle *_hs_p, *_hs_q, *_hs_e, *_hs_list, *_hs_tail; \ 698 | if (head) { \ 699 | _hs_insize = 1; \ 700 | _hs_looping = 1; \ 701 | _hs_list = &((head)->hh); \ 702 | while (_hs_looping) { \ 703 | _hs_p = _hs_list; \ 704 | _hs_list = NULL; \ 705 | _hs_tail = NULL; \ 706 | _hs_nmerges = 0; \ 707 | while (_hs_p) { \ 708 | _hs_nmerges++; \ 709 | _hs_q = _hs_p; \ 710 | _hs_psize = 0; \ 711 | for ( _hs_i = 0; _hs_i < _hs_insize; _hs_i++ ) { \ 712 | _hs_psize++; \ 713 | _hs_q = (UT_hash_handle*)((_hs_q->next) ? \ 714 | ((void*)((char*)(_hs_q->next) + \ 715 | (head)->hh.tbl->hho)) : NULL); \ 716 | if (! (_hs_q) ) break; \ 717 | } \ 718 | _hs_qsize = _hs_insize; \ 719 | while ((_hs_psize > 0) || ((_hs_qsize > 0) && _hs_q )) { \ 720 | if (_hs_psize == 0) { \ 721 | _hs_e = _hs_q; \ 722 | _hs_q = (UT_hash_handle*)((_hs_q->next) ? \ 723 | ((void*)((char*)(_hs_q->next) + \ 724 | (head)->hh.tbl->hho)) : NULL); \ 725 | _hs_qsize--; \ 726 | } else if ( (_hs_qsize == 0) || !(_hs_q) ) { \ 727 | _hs_e = _hs_p; \ 728 | _hs_p = (UT_hash_handle*)((_hs_p->next) ? \ 729 | ((void*)((char*)(_hs_p->next) + \ 730 | (head)->hh.tbl->hho)) : NULL); \ 731 | _hs_psize--; \ 732 | } else if (( \ 733 | cmpfcn(DECLTYPE(head)(ELMT_FROM_HH((head)->hh.tbl,_hs_p)), \ 734 | DECLTYPE(head)(ELMT_FROM_HH((head)->hh.tbl,_hs_q))) \ 735 | ) <= 0) { \ 736 | _hs_e = _hs_p; \ 737 | _hs_p = (UT_hash_handle*)((_hs_p->next) ? \ 738 | ((void*)((char*)(_hs_p->next) + \ 739 | (head)->hh.tbl->hho)) : NULL); \ 740 | _hs_psize--; \ 741 | } else { \ 742 | _hs_e = _hs_q; \ 743 | _hs_q = (UT_hash_handle*)((_hs_q->next) ? \ 744 | ((void*)((char*)(_hs_q->next) + \ 745 | (head)->hh.tbl->hho)) : NULL); \ 746 | _hs_qsize--; \ 747 | } \ 748 | if ( _hs_tail ) { \ 749 | _hs_tail->next = ((_hs_e) ? \ 750 | ELMT_FROM_HH((head)->hh.tbl,_hs_e) : NULL); \ 751 | } else { \ 752 | _hs_list = _hs_e; \ 753 | } \ 754 | _hs_e->prev = ((_hs_tail) ? \ 755 | ELMT_FROM_HH((head)->hh.tbl,_hs_tail) : NULL); \ 756 | _hs_tail = _hs_e; \ 757 | } \ 758 | _hs_p = _hs_q; \ 759 | } \ 760 | _hs_tail->next = NULL; \ 761 | if ( _hs_nmerges <= 1 ) { \ 762 | _hs_looping=0; \ 763 | (head)->hh.tbl->tail = _hs_tail; \ 764 | DECLTYPE_ASSIGN(head,ELMT_FROM_HH((head)->hh.tbl, _hs_list)); \ 765 | } \ 766 | _hs_insize *= 2; \ 767 | } \ 768 | HASH_FSCK(hh,head); \ 769 | } \ 770 | } while (0) 771 | 772 | /* This function selects items from one hash into another hash. 773 | * The end result is that the selected items have dual presence 774 | * in both hashes. There is no copy of the items made; rather 775 | * they are added into the new hash through a secondary hash 776 | * hash handle that must be present in the structure. */ 777 | #define HASH_SELECT(hh_dst, dst, hh_src, src, cond) \ 778 | do { \ 779 | unsigned _src_bkt, _dst_bkt; \ 780 | void *_last_elt=NULL, *_elt; \ 781 | UT_hash_handle *_src_hh, *_dst_hh, *_last_elt_hh=NULL; \ 782 | ptrdiff_t _dst_hho = ((char*)(&(dst)->hh_dst) - (char*)(dst)); \ 783 | if (src) { \ 784 | for(_src_bkt=0; _src_bkt < (src)->hh_src.tbl->num_buckets; _src_bkt++) { \ 785 | for(_src_hh = (src)->hh_src.tbl->buckets[_src_bkt].hh_head; \ 786 | _src_hh; \ 787 | _src_hh = _src_hh->hh_next) { \ 788 | _elt = ELMT_FROM_HH((src)->hh_src.tbl, _src_hh); \ 789 | if (cond(_elt)) { \ 790 | _dst_hh = (UT_hash_handle*)(((char*)_elt) + _dst_hho); \ 791 | _dst_hh->key = _src_hh->key; \ 792 | _dst_hh->keylen = _src_hh->keylen; \ 793 | _dst_hh->hashv = _src_hh->hashv; \ 794 | _dst_hh->prev = _last_elt; \ 795 | _dst_hh->next = NULL; \ 796 | if (_last_elt_hh) { _last_elt_hh->next = _elt; } \ 797 | if (!dst) { \ 798 | DECLTYPE_ASSIGN(dst,_elt); \ 799 | HASH_MAKE_TABLE(hh_dst,dst); \ 800 | } else { \ 801 | _dst_hh->tbl = (dst)->hh_dst.tbl; \ 802 | } \ 803 | HASH_TO_BKT(_dst_hh->hashv, _dst_hh->tbl->num_buckets, _dst_bkt); \ 804 | HASH_ADD_TO_BKT(_dst_hh->tbl->buckets[_dst_bkt],_dst_hh); \ 805 | (dst)->hh_dst.tbl->num_items++; \ 806 | _last_elt = _elt; \ 807 | _last_elt_hh = _dst_hh; \ 808 | } \ 809 | } \ 810 | } \ 811 | } \ 812 | HASH_FSCK(hh_dst,dst); \ 813 | } while (0) 814 | 815 | #define HASH_CLEAR(hh,head) \ 816 | do { \ 817 | if (head) { \ 818 | uthash_free((head)->hh.tbl->buckets, \ 819 | (head)->hh.tbl->num_buckets*sizeof(struct UT_hash_bucket)); \ 820 | HASH_BLOOM_FREE((head)->hh.tbl); \ 821 | uthash_free((head)->hh.tbl, sizeof(UT_hash_table)); \ 822 | (head)=NULL; \ 823 | } \ 824 | } while(0) 825 | 826 | #ifdef NO_DECLTYPE 827 | #define HASH_ITER(hh,head,el,tmp) \ 828 | for((el)=(head), (*(char**)(&(tmp)))=(char*)((head)?(head)->hh.next:NULL); \ 829 | el; (el)=(tmp),(*(char**)(&(tmp)))=(char*)((tmp)?(tmp)->hh.next:NULL)) 830 | #else 831 | #define HASH_ITER(hh,head,el,tmp) \ 832 | for((el)=(head),(tmp)=DECLTYPE(el)((head)?(head)->hh.next:NULL); \ 833 | el; (el)=(tmp),(tmp)=DECLTYPE(el)((tmp)?(tmp)->hh.next:NULL)) 834 | #endif 835 | 836 | /* obtain a count of items in the hash */ 837 | #define HASH_COUNT(head) HASH_CNT(hh,head) 838 | #define HASH_CNT(hh,head) ((head)?((head)->hh.tbl->num_items):0) 839 | 840 | typedef struct UT_hash_bucket { 841 | struct UT_hash_handle *hh_head; 842 | unsigned count; 843 | 844 | /* expand_mult is normally set to 0. In this situation, the max chain length 845 | * threshold is enforced at its default value, HASH_BKT_CAPACITY_THRESH. (If 846 | * the bucket's chain exceeds this length, bucket expansion is triggered). 847 | * However, setting expand_mult to a non-zero value delays bucket expansion 848 | * (that would be triggered by additions to this particular bucket) 849 | * until its chain length reaches a *multiple* of HASH_BKT_CAPACITY_THRESH. 850 | * (The multiplier is simply expand_mult+1). The whole idea of this 851 | * multiplier is to reduce bucket expansions, since they are expensive, in 852 | * situations where we know that a particular bucket tends to be overused. 853 | * It is better to let its chain length grow to a longer yet-still-bounded 854 | * value, than to do an O(n) bucket expansion too often. 855 | */ 856 | unsigned expand_mult; 857 | 858 | } UT_hash_bucket; 859 | 860 | /* random signature used only to find hash tables in external analysis */ 861 | #define HASH_SIGNATURE 0xa0111fe1 862 | #define HASH_BLOOM_SIGNATURE 0xb12220f2 863 | 864 | typedef struct UT_hash_table { 865 | UT_hash_bucket *buckets; 866 | unsigned num_buckets, log2_num_buckets; 867 | unsigned num_items; 868 | struct UT_hash_handle *tail; /* tail hh in app order, for fast append */ 869 | ptrdiff_t hho; /* hash handle offset (byte pos of hash handle in element */ 870 | 871 | /* in an ideal situation (all buckets used equally), no bucket would have 872 | * more than ceil(#items/#buckets) items. that's the ideal chain length. */ 873 | unsigned ideal_chain_maxlen; 874 | 875 | /* nonideal_items is the number of items in the hash whose chain position 876 | * exceeds the ideal chain maxlen. these items pay the penalty for an uneven 877 | * hash distribution; reaching them in a chain traversal takes >ideal steps */ 878 | unsigned nonideal_items; 879 | 880 | /* ineffective expands occur when a bucket doubling was performed, but 881 | * afterward, more than half the items in the hash had nonideal chain 882 | * positions. If this happens on two consecutive expansions we inhibit any 883 | * further expansion, as it's not helping; this happens when the hash 884 | * function isn't a good fit for the key domain. When expansion is inhibited 885 | * the hash will still work, albeit no longer in constant time. */ 886 | unsigned ineff_expands, noexpand; 887 | 888 | uint32_t signature; /* used only to find hash tables in external analysis */ 889 | #ifdef HASH_BLOOM 890 | uint32_t bloom_sig; /* used only to test bloom exists in external analysis */ 891 | uint8_t *bloom_bv; 892 | char bloom_nbits; 893 | #endif 894 | 895 | } UT_hash_table; 896 | 897 | typedef struct UT_hash_handle { 898 | struct UT_hash_table *tbl; 899 | void *prev; /* prev element in app order */ 900 | void *next; /* next element in app order */ 901 | struct UT_hash_handle *hh_prev; /* previous hh in bucket order */ 902 | struct UT_hash_handle *hh_next; /* next hh in bucket order */ 903 | void *key; /* ptr to enclosing struct's key */ 904 | unsigned keylen; /* enclosing struct's key len */ 905 | unsigned hashv; /* result of hash-fcn(key) */ 906 | } UT_hash_handle; 907 | 908 | #endif /* UTHASH_H */ 909 | --------------------------------------------------------------------------------