├── .gitignore ├── Parasite ├── Parasite.xcodeproj │ ├── project.pbxproj │ ├── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcuserdata │ │ │ └── shinvou.xcuserdatad │ │ │ └── UserInterfaceState.xcuserstate │ └── xcuserdata │ │ └── shinvou.xcuserdatad │ │ └── xcschemes │ │ ├── Parasite.xcscheme │ │ └── xcschememanagement.plist └── Parasite │ ├── Info.plist │ ├── Parasite.cpp │ ├── Parasite.hpp │ ├── ParasiteLoader.dylib │ ├── config.h │ ├── kernel_symbols.c │ ├── kernel_symbols.h │ ├── library_injector.c │ ├── library_injector.h │ └── logging.h └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | *.DS_Store 2 | xcuserdata 3 | -------------------------------------------------------------------------------- /Parasite/Parasite.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 1C29A6151CBDB5A000AB7E73 /* ParasiteLoader.dylib in Resources */ = {isa = PBXBuildFile; fileRef = 1C29A6131CBDB59800AB7E73 /* ParasiteLoader.dylib */; }; 11 | 1C906F8C1CBB01FA00B47299 /* Parasite.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 1C906F8B1CBB01FA00B47299 /* Parasite.hpp */; }; 12 | 1C906F8E1CBB01FA00B47299 /* Parasite.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1C906F8D1CBB01FA00B47299 /* Parasite.cpp */; }; 13 | 1CF0A1041CBBAA9700AFF2D5 /* config.h in Headers */ = {isa = PBXBuildFile; fileRef = 1CF0A0FE1CBBAA9700AFF2D5 /* config.h */; }; 14 | 1CF0A1051CBBAA9700AFF2D5 /* kernel_symbols.c in Sources */ = {isa = PBXBuildFile; fileRef = 1CF0A0FF1CBBAA9700AFF2D5 /* kernel_symbols.c */; }; 15 | 1CF0A1061CBBAA9700AFF2D5 /* kernel_symbols.h in Headers */ = {isa = PBXBuildFile; fileRef = 1CF0A1001CBBAA9700AFF2D5 /* kernel_symbols.h */; }; 16 | 1CF0A1071CBBAA9700AFF2D5 /* library_injector.c in Sources */ = {isa = PBXBuildFile; fileRef = 1CF0A1011CBBAA9700AFF2D5 /* library_injector.c */; }; 17 | 1CF0A1081CBBAA9700AFF2D5 /* library_injector.h in Headers */ = {isa = PBXBuildFile; fileRef = 1CF0A1021CBBAA9700AFF2D5 /* library_injector.h */; }; 18 | 1CF0A1091CBBAA9700AFF2D5 /* logging.h in Headers */ = {isa = PBXBuildFile; fileRef = 1CF0A1031CBBAA9700AFF2D5 /* logging.h */; }; 19 | /* End PBXBuildFile section */ 20 | 21 | /* Begin PBXFileReference section */ 22 | 1C29A6131CBDB59800AB7E73 /* ParasiteLoader.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; path = ParasiteLoader.dylib; sourceTree = ""; }; 23 | 1C906F881CBB01FA00B47299 /* Parasite.kext */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Parasite.kext; sourceTree = BUILT_PRODUCTS_DIR; }; 24 | 1C906F8B1CBB01FA00B47299 /* Parasite.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Parasite.hpp; sourceTree = ""; }; 25 | 1C906F8D1CBB01FA00B47299 /* Parasite.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = Parasite.cpp; sourceTree = ""; }; 26 | 1C906F8F1CBB01FA00B47299 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 27 | 1CF0A0FE1CBBAA9700AFF2D5 /* config.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = config.h; sourceTree = ""; }; 28 | 1CF0A0FF1CBBAA9700AFF2D5 /* kernel_symbols.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = kernel_symbols.c; sourceTree = ""; }; 29 | 1CF0A1001CBBAA9700AFF2D5 /* kernel_symbols.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = kernel_symbols.h; sourceTree = ""; }; 30 | 1CF0A1011CBBAA9700AFF2D5 /* library_injector.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = library_injector.c; sourceTree = ""; }; 31 | 1CF0A1021CBBAA9700AFF2D5 /* library_injector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = library_injector.h; sourceTree = ""; }; 32 | 1CF0A1031CBBAA9700AFF2D5 /* logging.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = logging.h; sourceTree = ""; }; 33 | /* End PBXFileReference section */ 34 | 35 | /* Begin PBXFrameworksBuildPhase section */ 36 | 1C906F841CBB01FA00B47299 /* Frameworks */ = { 37 | isa = PBXFrameworksBuildPhase; 38 | buildActionMask = 2147483647; 39 | files = ( 40 | ); 41 | runOnlyForDeploymentPostprocessing = 0; 42 | }; 43 | /* End PBXFrameworksBuildPhase section */ 44 | 45 | /* Begin PBXGroup section */ 46 | 1C906F7E1CBB01FA00B47299 = { 47 | isa = PBXGroup; 48 | children = ( 49 | 1C906F8A1CBB01FA00B47299 /* Parasite */, 50 | 1C906F891CBB01FA00B47299 /* Products */, 51 | ); 52 | sourceTree = ""; 53 | }; 54 | 1C906F891CBB01FA00B47299 /* Products */ = { 55 | isa = PBXGroup; 56 | children = ( 57 | 1C906F881CBB01FA00B47299 /* Parasite.kext */, 58 | ); 59 | name = Products; 60 | sourceTree = ""; 61 | }; 62 | 1C906F8A1CBB01FA00B47299 /* Parasite */ = { 63 | isa = PBXGroup; 64 | children = ( 65 | 1CF0A10A1CBBAA9F00AFF2D5 /* osxreverser */, 66 | 1C906F8B1CBB01FA00B47299 /* Parasite.hpp */, 67 | 1C906F8D1CBB01FA00B47299 /* Parasite.cpp */, 68 | 1C906F8F1CBB01FA00B47299 /* Info.plist */, 69 | 1C29A6131CBDB59800AB7E73 /* ParasiteLoader.dylib */, 70 | ); 71 | path = Parasite; 72 | sourceTree = ""; 73 | }; 74 | 1CF0A10A1CBBAA9F00AFF2D5 /* osxreverser */ = { 75 | isa = PBXGroup; 76 | children = ( 77 | 1CF0A0FE1CBBAA9700AFF2D5 /* config.h */, 78 | 1CF0A1031CBBAA9700AFF2D5 /* logging.h */, 79 | 1CF0A0FF1CBBAA9700AFF2D5 /* kernel_symbols.c */, 80 | 1CF0A1001CBBAA9700AFF2D5 /* kernel_symbols.h */, 81 | 1CF0A1011CBBAA9700AFF2D5 /* library_injector.c */, 82 | 1CF0A1021CBBAA9700AFF2D5 /* library_injector.h */, 83 | ); 84 | name = osxreverser; 85 | sourceTree = ""; 86 | }; 87 | /* End PBXGroup section */ 88 | 89 | /* Begin PBXHeadersBuildPhase section */ 90 | 1C906F851CBB01FA00B47299 /* Headers */ = { 91 | isa = PBXHeadersBuildPhase; 92 | buildActionMask = 2147483647; 93 | files = ( 94 | 1CF0A1061CBBAA9700AFF2D5 /* kernel_symbols.h in Headers */, 95 | 1CF0A1041CBBAA9700AFF2D5 /* config.h in Headers */, 96 | 1CF0A1081CBBAA9700AFF2D5 /* library_injector.h in Headers */, 97 | 1CF0A1091CBBAA9700AFF2D5 /* logging.h in Headers */, 98 | 1C906F8C1CBB01FA00B47299 /* Parasite.hpp in Headers */, 99 | ); 100 | runOnlyForDeploymentPostprocessing = 0; 101 | }; 102 | /* End PBXHeadersBuildPhase section */ 103 | 104 | /* Begin PBXNativeTarget section */ 105 | 1C906F871CBB01FA00B47299 /* Parasite */ = { 106 | isa = PBXNativeTarget; 107 | buildConfigurationList = 1C906F921CBB01FA00B47299 /* Build configuration list for PBXNativeTarget "Parasite" */; 108 | buildPhases = ( 109 | 1C906F831CBB01FA00B47299 /* Sources */, 110 | 1C906F841CBB01FA00B47299 /* Frameworks */, 111 | 1C906F851CBB01FA00B47299 /* Headers */, 112 | 1C906F861CBB01FA00B47299 /* Resources */, 113 | 1C79BDC71CBB0FC700C04D0A /* ShellScript */, 114 | ); 115 | buildRules = ( 116 | ); 117 | dependencies = ( 118 | ); 119 | name = Parasite; 120 | productName = Parasite; 121 | productReference = 1C906F881CBB01FA00B47299 /* Parasite.kext */; 122 | productType = "com.apple.product-type.kernel-extension"; 123 | }; 124 | /* End PBXNativeTarget section */ 125 | 126 | /* Begin PBXProject section */ 127 | 1C906F7F1CBB01FA00B47299 /* Project object */ = { 128 | isa = PBXProject; 129 | attributes = { 130 | LastUpgradeCheck = 0730; 131 | ORGANIZATIONNAME = "Timm Kandziora"; 132 | TargetAttributes = { 133 | 1C906F871CBB01FA00B47299 = { 134 | CreatedOnToolsVersion = 7.3; 135 | }; 136 | }; 137 | }; 138 | buildConfigurationList = 1C906F821CBB01FA00B47299 /* Build configuration list for PBXProject "Parasite" */; 139 | compatibilityVersion = "Xcode 3.2"; 140 | developmentRegion = English; 141 | hasScannedForEncodings = 0; 142 | knownRegions = ( 143 | en, 144 | ); 145 | mainGroup = 1C906F7E1CBB01FA00B47299; 146 | productRefGroup = 1C906F891CBB01FA00B47299 /* Products */; 147 | projectDirPath = ""; 148 | projectRoot = ""; 149 | targets = ( 150 | 1C906F871CBB01FA00B47299 /* Parasite */, 151 | ); 152 | }; 153 | /* End PBXProject section */ 154 | 155 | /* Begin PBXResourcesBuildPhase section */ 156 | 1C906F861CBB01FA00B47299 /* Resources */ = { 157 | isa = PBXResourcesBuildPhase; 158 | buildActionMask = 2147483647; 159 | files = ( 160 | 1C29A6151CBDB5A000AB7E73 /* ParasiteLoader.dylib in Resources */, 161 | ); 162 | runOnlyForDeploymentPostprocessing = 0; 163 | }; 164 | /* End PBXResourcesBuildPhase section */ 165 | 166 | /* Begin PBXShellScriptBuildPhase section */ 167 | 1C79BDC71CBB0FC700C04D0A /* ShellScript */ = { 168 | isa = PBXShellScriptBuildPhase; 169 | buildActionMask = 2147483647; 170 | files = ( 171 | ); 172 | inputPaths = ( 173 | ); 174 | outputPaths = ( 175 | ); 176 | runOnlyForDeploymentPostprocessing = 0; 177 | shellPath = /bin/sh; 178 | shellScript = "export SUDO_ASKPASS=~/Desktop/print_password.sh\nsudo -A rm -rf /Library/Extensions/Parasite.kext\nsudo -A cp -R $BUILT_PRODUCTS_DIR/Parasite.kext /Library/Extensions/\nsudo -A chown -R root:wheel /Library/Extensions/Parasite.kext"; 179 | }; 180 | /* End PBXShellScriptBuildPhase section */ 181 | 182 | /* Begin PBXSourcesBuildPhase section */ 183 | 1C906F831CBB01FA00B47299 /* Sources */ = { 184 | isa = PBXSourcesBuildPhase; 185 | buildActionMask = 2147483647; 186 | files = ( 187 | 1CF0A1071CBBAA9700AFF2D5 /* library_injector.c in Sources */, 188 | 1CF0A1051CBBAA9700AFF2D5 /* kernel_symbols.c in Sources */, 189 | 1C906F8E1CBB01FA00B47299 /* Parasite.cpp in Sources */, 190 | ); 191 | runOnlyForDeploymentPostprocessing = 0; 192 | }; 193 | /* End PBXSourcesBuildPhase section */ 194 | 195 | /* Begin XCBuildConfiguration section */ 196 | 1C906F901CBB01FA00B47299 /* Debug */ = { 197 | isa = XCBuildConfiguration; 198 | buildSettings = { 199 | ALWAYS_SEARCH_USER_PATHS = NO; 200 | CLANG_ANALYZER_NONNULL = YES; 201 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 202 | CLANG_CXX_LIBRARY = "libc++"; 203 | CLANG_ENABLE_MODULES = YES; 204 | CLANG_ENABLE_OBJC_ARC = YES; 205 | CLANG_WARN_BOOL_CONVERSION = YES; 206 | CLANG_WARN_CONSTANT_CONVERSION = YES; 207 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 208 | CLANG_WARN_EMPTY_BODY = YES; 209 | CLANG_WARN_ENUM_CONVERSION = YES; 210 | CLANG_WARN_INT_CONVERSION = YES; 211 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 212 | CLANG_WARN_UNREACHABLE_CODE = YES; 213 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 214 | CODE_SIGN_IDENTITY = ""; 215 | COPY_PHASE_STRIP = NO; 216 | DEBUG_INFORMATION_FORMAT = dwarf; 217 | ENABLE_STRICT_OBJC_MSGSEND = YES; 218 | ENABLE_TESTABILITY = YES; 219 | GCC_C_LANGUAGE_STANDARD = gnu99; 220 | GCC_DYNAMIC_NO_PIC = NO; 221 | GCC_NO_COMMON_BLOCKS = YES; 222 | GCC_OPTIMIZATION_LEVEL = 0; 223 | GCC_PREPROCESSOR_DEFINITIONS = ( 224 | "DEBUG=1", 225 | "$(inherited)", 226 | ); 227 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 228 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 229 | GCC_WARN_UNDECLARED_SELECTOR = YES; 230 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 231 | GCC_WARN_UNUSED_FUNCTION = YES; 232 | GCC_WARN_UNUSED_VARIABLE = YES; 233 | MACOSX_DEPLOYMENT_TARGET = 10.11; 234 | MTL_ENABLE_DEBUG_INFO = YES; 235 | ONLY_ACTIVE_ARCH = YES; 236 | SDKROOT = macosx; 237 | }; 238 | name = Debug; 239 | }; 240 | 1C906F911CBB01FA00B47299 /* Release */ = { 241 | isa = XCBuildConfiguration; 242 | buildSettings = { 243 | ALWAYS_SEARCH_USER_PATHS = NO; 244 | CLANG_ANALYZER_NONNULL = YES; 245 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 246 | CLANG_CXX_LIBRARY = "libc++"; 247 | CLANG_ENABLE_MODULES = YES; 248 | CLANG_ENABLE_OBJC_ARC = YES; 249 | CLANG_WARN_BOOL_CONVERSION = YES; 250 | CLANG_WARN_CONSTANT_CONVERSION = YES; 251 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 252 | CLANG_WARN_EMPTY_BODY = YES; 253 | CLANG_WARN_ENUM_CONVERSION = YES; 254 | CLANG_WARN_INT_CONVERSION = YES; 255 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 256 | CLANG_WARN_UNREACHABLE_CODE = YES; 257 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 258 | CODE_SIGN_IDENTITY = ""; 259 | COPY_PHASE_STRIP = NO; 260 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 261 | ENABLE_NS_ASSERTIONS = NO; 262 | ENABLE_STRICT_OBJC_MSGSEND = YES; 263 | GCC_C_LANGUAGE_STANDARD = gnu99; 264 | GCC_NO_COMMON_BLOCKS = YES; 265 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 266 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 267 | GCC_WARN_UNDECLARED_SELECTOR = YES; 268 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 269 | GCC_WARN_UNUSED_FUNCTION = YES; 270 | GCC_WARN_UNUSED_VARIABLE = YES; 271 | MACOSX_DEPLOYMENT_TARGET = 10.11; 272 | MTL_ENABLE_DEBUG_INFO = NO; 273 | SDKROOT = macosx; 274 | }; 275 | name = Release; 276 | }; 277 | 1C906F931CBB01FA00B47299 /* Debug */ = { 278 | isa = XCBuildConfiguration; 279 | buildSettings = { 280 | CODE_SIGN_IDENTITY = ""; 281 | COMBINE_HIDPI_IMAGES = YES; 282 | CURRENT_PROJECT_VERSION = 1.0.0d1; 283 | INFOPLIST_FILE = Parasite/Info.plist; 284 | LIBRARY_SEARCH_PATHS = ( 285 | "$(inherited)", 286 | "$(PROJECT_DIR)/Parasite", 287 | ); 288 | MODULE_NAME = com.shinvou.kext.Parasite; 289 | MODULE_START = Parasite_start; 290 | MODULE_STOP = Parasite_stop; 291 | MODULE_VERSION = 1.0.0d1; 292 | PRODUCT_BUNDLE_IDENTIFIER = com.shinvou.driver.Parasite; 293 | PRODUCT_NAME = "$(TARGET_NAME)"; 294 | WRAPPER_EXTENSION = kext; 295 | }; 296 | name = Debug; 297 | }; 298 | 1C906F941CBB01FA00B47299 /* Release */ = { 299 | isa = XCBuildConfiguration; 300 | buildSettings = { 301 | CODE_SIGN_IDENTITY = ""; 302 | COMBINE_HIDPI_IMAGES = YES; 303 | CURRENT_PROJECT_VERSION = 1.0.0d1; 304 | INFOPLIST_FILE = Parasite/Info.plist; 305 | LIBRARY_SEARCH_PATHS = ( 306 | "$(inherited)", 307 | "$(PROJECT_DIR)/Parasite", 308 | ); 309 | MODULE_NAME = com.shinvou.kext.Parasite; 310 | MODULE_START = Parasite_start; 311 | MODULE_STOP = Parasite_stop; 312 | MODULE_VERSION = 1.0.0d1; 313 | PRODUCT_BUNDLE_IDENTIFIER = com.shinvou.driver.Parasite; 314 | PRODUCT_NAME = "$(TARGET_NAME)"; 315 | WRAPPER_EXTENSION = kext; 316 | }; 317 | name = Release; 318 | }; 319 | /* End XCBuildConfiguration section */ 320 | 321 | /* Begin XCConfigurationList section */ 322 | 1C906F821CBB01FA00B47299 /* Build configuration list for PBXProject "Parasite" */ = { 323 | isa = XCConfigurationList; 324 | buildConfigurations = ( 325 | 1C906F901CBB01FA00B47299 /* Debug */, 326 | 1C906F911CBB01FA00B47299 /* Release */, 327 | ); 328 | defaultConfigurationIsVisible = 0; 329 | defaultConfigurationName = Release; 330 | }; 331 | 1C906F921CBB01FA00B47299 /* Build configuration list for PBXNativeTarget "Parasite" */ = { 332 | isa = XCConfigurationList; 333 | buildConfigurations = ( 334 | 1C906F931CBB01FA00B47299 /* Debug */, 335 | 1C906F941CBB01FA00B47299 /* Release */, 336 | ); 337 | defaultConfigurationIsVisible = 0; 338 | defaultConfigurationName = Release; 339 | }; 340 | /* End XCConfigurationList section */ 341 | }; 342 | rootObject = 1C906F7F1CBB01FA00B47299 /* Project object */; 343 | } 344 | -------------------------------------------------------------------------------- /Parasite/Parasite.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Parasite/Parasite.xcodeproj/project.xcworkspace/xcuserdata/shinvou.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ParasiteTeam/kext/afa0e8e9623124e40a284f5900c56eb54dafe0ef/Parasite/Parasite.xcodeproj/project.xcworkspace/xcuserdata/shinvou.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /Parasite/Parasite.xcodeproj/xcuserdata/shinvou.xcuserdatad/xcschemes/Parasite.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 34 | 35 | 45 | 46 | 52 | 53 | 54 | 55 | 56 | 57 | 63 | 64 | 70 | 71 | 72 | 73 | 75 | 76 | 79 | 80 | 81 | -------------------------------------------------------------------------------- /Parasite/Parasite.xcodeproj/xcuserdata/shinvou.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | Parasite.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | 1C906F871CBB01FA00B47299 16 | 17 | primary 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /Parasite/Parasite/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | KEXT 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | IOKitPersonalities 24 | 25 | PARASITE 26 | 27 | CFBundleIdentifier 28 | com.shinvou.driver.$(PRODUCT_NAME:rfc1034identifier) 29 | IOClass 30 | com_shinvou_driver_Parasite 31 | IOKitDebug 32 | 0 33 | IOMatchCategory 34 | com_shinvou_driver_Parasite 35 | IOProviderClass 36 | IOResources 37 | IOResourceMatch 38 | IOBSD 39 | 40 | 41 | NSHumanReadableCopyright 42 | Copyright © 2016 Timm Kandziora. All rights reserved. 43 | OSBundleLibraries 44 | 45 | com.apple.kpi.bsd 46 | 14.0 47 | com.apple.kpi.dsep 48 | 14.0 49 | com.apple.kpi.iokit 50 | 14.0 51 | com.apple.kpi.libkern 52 | 14.0 53 | com.apple.kpi.mach 54 | 14.0 55 | com.apple.kpi.unsupported 56 | 14.0 57 | 58 | OSBundleRequired 59 | Root 60 | 61 | 62 | -------------------------------------------------------------------------------- /Parasite/Parasite/Parasite.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | extern "C" { 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #define CONFIG_MACF 1 15 | #include 16 | #include 17 | #include 18 | 19 | #include "Parasite.hpp" 20 | 21 | #include "config.h" 22 | #include "kernel_symbols.h" 23 | #include "library_injector.h" 24 | 25 | struct kernel_info g_kinfo; 26 | static boolean_t kernel_symbols_solved = FALSE; 27 | static kauth_listener_t listener = NULL; 28 | 29 | #define BLACKLIST(PROCESS) if (_strstr(path, #PROCESS)) return KAUTH_RESULT_DEFER; 30 | 31 | char* _strstr(const char *in, const char *str) 32 | { 33 | char c; 34 | size_t len; 35 | 36 | c = *str++; 37 | if (!c) 38 | return (char *) in; // Trivial empty string case 39 | 40 | len = strlen(str); 41 | do { 42 | char sc; 43 | 44 | do { 45 | sc = *in++; 46 | if (!sc) 47 | return (char *) 0; 48 | } while (sc != c); 49 | } while (strncmp(in, str, len) != 0); 50 | 51 | return (char *) (in - 1); 52 | } 53 | 54 | static int infection_overwatch(kauth_cred_t credential, void *idata, kauth_action_t action, uintptr_t arg0, uintptr_t arg1, uintptr_t arg2, uintptr_t arg3) 55 | { 56 | if (action == KAUTH_FILEOP_EXEC) { 57 | char *path = (char *)arg1; 58 | 59 | BLACKLIST(Hopper); 60 | 61 | if (path != NULL) { 62 | printf("[Parasite] %s\n", path); 63 | 64 | vm_map_t task_map = _get_task_map(current_task()); 65 | vm_map_offset_t base_address = _get_map_min(task_map); 66 | 67 | inject_library(task_map, base_address, path, sizeof(path)); 68 | } 69 | } 70 | 71 | return KAUTH_RESULT_DEFER; 72 | } 73 | 74 | int parasite_cred_label_update_execve(kauth_cred_t old_cred, kauth_cred_t new_cred, struct proc *p, struct vnode *vp, off_t offset, struct vnode *scriptvp, struct label *vnodelabel, struct label *scriptvnodelabel, struct label *execlabel, u_int *csflags, void *macpolicyattr, size_t macpolicyattrlen, int *disjointp) 75 | { 76 | if (!kernel_symbols_solved) { 77 | if (init_kernel_info()) return 0; 78 | 79 | SOLVE_KERNEL_SYMBOL("_get_map_min", _get_map_min) 80 | SOLVE_KERNEL_SYMBOL("_get_task_map", _get_task_map) 81 | SOLVE_KERNEL_SYMBOL("_mach_vm_region", _mach_vm_region) 82 | SOLVE_KERNEL_SYMBOL("_mach_vm_protect", _mach_vm_protect) 83 | SOLVE_KERNEL_SYMBOL("_vm_map_read_user", _vm_map_read_user) 84 | SOLVE_KERNEL_SYMBOL("_vm_map_write_user", _vm_map_write_user) 85 | 86 | kernel_symbols_solved = TRUE; 87 | } 88 | 89 | return 0; 90 | } 91 | 92 | static mac_policy_handle_t handle = 0; 93 | 94 | static struct mac_policy_ops ops = 95 | { 96 | .mpo_cred_label_update_execve = parasite_cred_label_update_execve 97 | }; 98 | 99 | static struct mac_policy_conf conf = { 100 | .mpc_name = "parasite", 101 | .mpc_fullname = "Parasite Kernel Extension", 102 | .mpc_ops = &ops, 103 | .mpc_loadtime_flags = MPC_LOADTIME_FLAG_UNLOADOK 104 | }; 105 | 106 | kern_return_t Parasite_start(kmod_info_t * ki, void *d); 107 | kern_return_t Parasite_stop(kmod_info_t *ki, void *d); 108 | 109 | kern_return_t Parasite_start(kmod_info_t * ki, void *d) 110 | { 111 | listener = kauth_listen_scope(KAUTH_SCOPE_FILEOP, &infection_overwatch, NULL); 112 | 113 | if (listener == NULL) { 114 | printf("[Parasite] Damn, could not create listener.\n"); 115 | } else { 116 | printf("[Parasite] Successfully created listener.\n"); 117 | } 118 | 119 | return mac_policy_register(&conf, &handle, d); 120 | } 121 | 122 | kern_return_t Parasite_stop(kmod_info_t *ki, void *d) 123 | { 124 | if (listener != NULL) { 125 | kauth_unlisten_scope(listener); 126 | listener = NULL; 127 | } 128 | 129 | return mac_policy_unregister(handle); 130 | } 131 | } 132 | // This required macro defines the class's constructors, destructors, 133 | // and several other methods I/O Kit requires. 134 | OSDefineMetaClassAndStructors(com_shinvou_driver_Parasite, IOService) 135 | 136 | // Define the driver's superclass. 137 | #define super IOService 138 | 139 | bool com_shinvou_driver_Parasite::init(OSDictionary *dict) 140 | { 141 | bool result = super::init(dict); 142 | return result; 143 | } 144 | 145 | void com_shinvou_driver_Parasite::free(void) 146 | { 147 | super::free(); 148 | } 149 | 150 | IOService *com_shinvou_driver_Parasite::probe(IOService *provider, 151 | SInt32 *score) 152 | { 153 | IOService *result = super::probe(provider, score); 154 | return result; 155 | } 156 | 157 | bool com_shinvou_driver_Parasite::start(IOService *provider) 158 | { 159 | bool result = super::start(provider); 160 | return result; 161 | } 162 | 163 | void com_shinvou_driver_Parasite::stop(IOService *provider) 164 | { 165 | super::stop(provider); 166 | } 167 | -------------------------------------------------------------------------------- /Parasite/Parasite/Parasite.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | class com_shinvou_driver_Parasite : public IOService 4 | { 5 | OSDeclareDefaultStructors(com_shinvou_driver_Parasite) 6 | public: 7 | virtual bool init(OSDictionary *dictionary = 0); 8 | virtual void free(void); 9 | virtual IOService *probe(IOService *provider, SInt32 *score); 10 | virtual bool start(IOService *provider); 11 | virtual void stop(IOService *provider); 12 | }; 13 | -------------------------------------------------------------------------------- /Parasite/Parasite/ParasiteLoader.dylib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ParasiteTeam/kext/afa0e8e9623124e40a284f5900c56eb54dafe0ef/Parasite/Parasite/ParasiteLoader.dylib -------------------------------------------------------------------------------- /Parasite/Parasite/config.h: -------------------------------------------------------------------------------- 1 | /* 2 | * <-. (`-') (`-') _ (`-') _ 3 | * \(OO )_ (OO ).-/ <-.(OO ) (_) .-> 4 | * ,--./ ,-.) / ,---. ,------,) ,-(`-')(`-')----. 5 | * | `.' | | \ /`.\ | /`. ' | ( OO)( OO).-. ' 6 | * | |'.'| | '-'|_.' || |_.' | | | )( _) | | | 7 | * | | | |(| .-. || . .'(| |_/ \| |)| | 8 | * | | | | | | | || |\ \ | |'-> ' '-' ' 9 | * `--' `--' `--' `--'`--' '--' `--' `-----' 10 | * 11 | * Mario - The kernel component to fix rootpipe 12 | * 13 | * This is a TrustedBSD kernel driver to inject a dynamic library 14 | * or a __RESTRICT segment into specific processes 15 | * 16 | * Copyright (c) fG!, 2015. All rights reserved. 17 | * reverser@put.as - https://reverse.put.as 18 | * 19 | * config.h 20 | * 21 | * Configuration options 22 | * 23 | * Redistribution and use in source and binary forms, with or without 24 | * modification, are permitted provided that the following conditions 25 | * are met: 26 | * 1. Redistributions of source code must retain the above copyright 27 | * notice, this list of conditions and the following disclaimer. 28 | * 2. Redistributions in binary form must reproduce the above copyright 29 | * notice, this list of conditions and the following disclaimer in the 30 | * documentation and/or other materials provided with the distribution. 31 | * 3. The name of the author may not be used to endorse or promote products 32 | * derived from this software without specific prior written permission. 33 | * 34 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 35 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 36 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 37 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 38 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 39 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 40 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 41 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 42 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 43 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 44 | * 45 | */ 46 | 47 | #ifndef mario_config_h 48 | #define mario_config_h 49 | 50 | #define MACH_KERNEL "/System/Library/Kernels/kernel" /* kernel file location */ 51 | #define PATCH_LIBRARY "/Library/Extensions/Parasite.kext/Contents/Resources/ParasiteLoader.dylib" /* location of the patching library to inject */ 52 | 53 | #endif 54 | -------------------------------------------------------------------------------- /Parasite/Parasite/kernel_symbols.c: -------------------------------------------------------------------------------- 1 | /* 2 | * <-. (`-') (`-') _ (`-') _ 3 | * \(OO )_ (OO ).-/ <-.(OO ) (_) .-> 4 | * ,--./ ,-.) / ,---. ,------,) ,-(`-')(`-')----. 5 | * | `.' | | \ /`.\ | /`. ' | ( OO)( OO).-. ' 6 | * | |'.'| | '-'|_.' || |_.' | | | )( _) | | | 7 | * | | | |(| .-. || . .'(| |_/ \| |)| | 8 | * | | | | | | | || |\ \ | |'-> ' '-' ' 9 | * `--' `--' `--' `--'`--' '--' `--' `-----' 10 | * 11 | * Mario - The kernel component to fix rootpipe 12 | * 13 | * This is a TrustedBSD kernel driver to inject a dynamic library 14 | * or a __RESTRICT segment into specific processes 15 | * 16 | * Copyright (c) fG!, 2015. All rights reserved. 17 | * reverser@put.as - https://reverse.put.as 18 | * 19 | * kernel_symbols.c 20 | * 21 | * Functions to solve kernel symbols 22 | * 23 | * Redistribution and use in source and binary forms, with or without 24 | * modification, are permitted provided that the following conditions 25 | * are met: 26 | * 1. Redistributions of source code must retain the above copyright 27 | * notice, this list of conditions and the following disclaimer. 28 | * 2. Redistributions in binary form must reproduce the above copyright 29 | * notice, this list of conditions and the following disclaimer in the 30 | * documentation and/or other materials provided with the distribution. 31 | * 3. The name of the author may not be used to endorse or promote products 32 | * derived from this software without specific prior written permission. 33 | * 34 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 35 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 36 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 37 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 38 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 39 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 40 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 41 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 42 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 43 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 44 | * 45 | */ 46 | 47 | #include "kernel_symbols.h" 48 | 49 | #include 50 | #include 51 | #include 52 | #include 53 | #include 54 | #include 55 | #include 56 | #include 57 | 58 | #include "config.h" 59 | #include "logging.h" 60 | 61 | /* global variables */ 62 | extern struct kernel_info g_kinfo; 63 | 64 | /* kernel symbols to be manually solved */ 65 | vm_offset_t (*_vm_map_min)(vm_map_t map); 66 | kern_return_t (*_vm_map_read_user)(vm_map_t map, vm_map_offset_t src_addr, void *dst_p, vm_size_t size); 67 | kern_return_t (*_vm_map_write_user)(vm_map_t map, void *src_p, vm_map_address_t dst_addr, vm_size_t size); 68 | kern_return_t (*_mach_vm_protect)(vm_map_t target_task, mach_vm_address_t address, mach_vm_size_t size, boolean_t set_maximum, vm_prot_t new_protection); 69 | kern_return_t (*_mach_vm_region)(vm_map_t target_task, mach_vm_address_t *address, mach_vm_size_t *size, vm_region_flavor_t flavor, vm_region_info_t info, mach_msg_type_number_t *infoCnt, mach_port_t *object_name); 70 | vm_map_offset_t (*_get_map_min)(vm_map_t); 71 | vm_map_t (*_get_task_map)(task_t); 72 | 73 | /* local functions */ 74 | static kern_return_t get_kernel_mach_header(void *buffer, vnode_t kernel_vnode); 75 | static kern_return_t process_kernel_mach_header(void *kernel_header, struct kernel_info *kinfo); 76 | static kern_return_t get_kernel_linkedit(vnode_t kernel_vnode, struct kernel_info *kinfo); 77 | static mach_vm_address_t calculate_int80address(const mach_vm_address_t idt_address); 78 | static kern_return_t get_running_text_address(struct kernel_info *kinfo); 79 | static mach_vm_address_t find_kernel_base(const mach_vm_address_t int80_address); 80 | static kern_return_t get_addr_idt(mach_vm_address_t* idt); 81 | 82 | /* 16 bytes IDT descriptor, used for 32 and 64 bits kernels (64 bit capable cpus!) */ 83 | struct descriptor_idt 84 | { 85 | uint16_t offset_low; 86 | uint16_t seg_selector; 87 | uint8_t reserved; 88 | uint8_t flag; 89 | uint16_t offset_middle; 90 | uint32_t offset_high; 91 | uint32_t reserved2; 92 | }; 93 | 94 | # pragma mark Exported functions 95 | 96 | /* 97 | * entrypoint function to read necessary information from running kernel and kernel at disk 98 | * such as kaslr slide, linkedit location 99 | * the reads from disk are implemented using the available KPI VFS functions 100 | */ 101 | kern_return_t 102 | init_kernel_info(void) 103 | { 104 | struct kernel_info *kinfo = &g_kinfo; 105 | /* lookup vnode for /mach_kernel - remember to free reference count if successful */ 106 | vnode_t kernel_vnode = NULLVP; 107 | /* 108 | * if we want to put the driver booting very early we need to create our own context 109 | * instead of passing NULL as usual 110 | * the reference count increases so we must release it later 111 | * the vfs_context_create() call is valid because it's made in a process context 112 | */ 113 | vfs_context_t myvfs_context = vfs_context_create(NULL); 114 | if (myvfs_context == NULL) 115 | { 116 | LOG_ERROR("Failed to create context."); 117 | return KERN_FAILURE; 118 | } 119 | if (vnode_lookup(MACH_KERNEL, 0, &kernel_vnode, myvfs_context) != KERN_SUCCESS) 120 | { 121 | LOG_ERROR("Vnode lookup on %s failed!", MACH_KERNEL); 122 | return KERN_FAILURE; 123 | } 124 | /* 125 | * the first thing we do is to read 4k of the kernel header so we can extract 126 | * a bunch of information and __LINKEDIT location 127 | * we also must account for FAT kernels since we still target Lion 128 | */ 129 | void *kernel_header = _MALLOC(PAGE_SIZE_64, M_TEMP, M_WAITOK | M_ZERO); 130 | if (kernel_header == NULL) 131 | { 132 | LOG_ERROR("Can't allocate memory for initial kernel mach-o header."); 133 | goto failure; 134 | } 135 | 136 | if (get_kernel_mach_header(kernel_header, kernel_vnode)) 137 | { 138 | LOG_ERROR("Failed to get initial kernel mach-o header!"); 139 | goto failure; 140 | } 141 | if (process_kernel_mach_header(kernel_header, kinfo)) 142 | { 143 | LOG_ERROR("Failed to process kernel mach-o header!"); 144 | goto failure; 145 | } 146 | 147 | /* compute kaslr slide - difference between __TEXT in memory and disk*/ 148 | if (get_running_text_address(kinfo)) 149 | { 150 | LOG_ERROR("Can't find kernel's running text address!"); 151 | goto failure; 152 | } 153 | kinfo->kaslr_slide = kinfo->memory_text_addr - kinfo->disk_text_addr; 154 | if (kinfo->kaslr_slide > kinfo->memory_text_addr) 155 | { 156 | LOG_ERROR("overflow?"); 157 | goto failure; 158 | } 159 | // LOG_DEBUG("kernel aslr slide is 0x%llx", kinfo->kaslr_slide); 160 | /* 161 | * we know the location of linkedit and offsets into symbols and their strings 162 | * now we need to read linkedit into a buffer so we can process it later 163 | * __LINKEDIT total size is around 1MB 164 | * we should free this buffer later when we don't need anymore to solve symbols 165 | * the fat_offset is passed so the offset is correct in case it's a FAT kernel 166 | */ 167 | kinfo->linkedit_buf = _MALLOC(kinfo->linkedit_size, M_TEMP, M_WAITOK | M_ZERO); 168 | if (kinfo->linkedit_buf == NULL) 169 | { 170 | LOG_ERROR("Could not allocate enough memory for __LINKEDIT segment"); 171 | goto failure; 172 | } 173 | if (get_kernel_linkedit(kernel_vnode, kinfo)) 174 | { 175 | LOG_ERROR("Failed to get kernel linkedit info!"); 176 | goto failure; 177 | } 178 | 179 | success: 180 | /* kernel_header is a local buffer so we can get rid of it */ 181 | _FREE(kernel_header, M_TEMP); 182 | kernel_header = NULL; 183 | /* 184 | * drop the iocount due to vnode_lookup() 185 | * we must do this else machine will block on shutdown/reboot 186 | */ 187 | vnode_put(kernel_vnode); 188 | vfs_context_rele(myvfs_context); 189 | return KERN_SUCCESS; 190 | 191 | failure: 192 | if (kinfo->linkedit_buf) 193 | { 194 | _FREE(kinfo->linkedit_buf, M_TEMP); 195 | kinfo->linkedit_buf = NULL; 196 | } 197 | if (kernel_header) 198 | { 199 | _FREE(kernel_header, M_TEMP); 200 | kernel_header = NULL; 201 | } 202 | vnode_put(kernel_vnode); 203 | vfs_context_rele(myvfs_context); 204 | return KERN_FAILURE; 205 | } 206 | 207 | /* 208 | * cleanup the kernel info buffer to avoid memory leak. 209 | * there's nothing else to cleanup here, for now 210 | */ 211 | kern_return_t 212 | cleanup_kernel_info(void) 213 | { 214 | if (g_kinfo.linkedit_buf) 215 | { 216 | _FREE(g_kinfo.linkedit_buf, M_TEMP); 217 | } 218 | return KERN_SUCCESS; 219 | } 220 | 221 | /* 222 | * function to solve a kernel symbol 223 | */ 224 | kern_return_t 225 | solve_kernel_symbol(char *symbol_to_solve, void **symbol_ptr) 226 | { 227 | struct kernel_info *kinfo = &g_kinfo; 228 | struct nlist_64 *nlist = NULL; 229 | LOG_DEBUG("Trying to solve kernel symbol %s...", symbol_to_solve); 230 | if (kinfo == NULL || kinfo->linkedit_buf == NULL) 231 | { 232 | LOG_ERROR("g_kernel_info is null or no kernel __LINKEDIT buffer available!"); 233 | return 0; 234 | } 235 | // symbols and strings offsets into LINKEDIT 236 | // we just read the __LINKEDIT but fileoff values are relative to the full /mach_kernel 237 | // subtract the base of LINKEDIT to fix the value into our buffer 238 | mach_vm_address_t symbol_off = kinfo->symboltable_fileoff - kinfo->linkedit_fileoff; 239 | mach_vm_address_t string_off = kinfo->stringtable_fileoff - kinfo->linkedit_fileoff; 240 | if (symbol_off > kinfo->symboltable_fileoff || string_off > kinfo->stringtable_fileoff) 241 | { 242 | LOG_ERROR("bad offsets."); 243 | return KERN_FAILURE; 244 | } 245 | 246 | // search for the symbol and get its location if found 247 | for (uint32_t i = 0; i < kinfo->symboltable_nr_symbols; i++) 248 | { 249 | // get the pointer to the symbol entry and extract its symbol string 250 | nlist = (struct nlist_64*)((char*)kinfo->linkedit_buf + symbol_off + i * sizeof(struct nlist_64)); 251 | char *symbol_string = ((char*)kinfo->linkedit_buf + string_off + nlist->n_un.n_strx); 252 | // find if symbol matches 253 | if (strncmp(symbol_to_solve, symbol_string, strlen(symbol_to_solve)) == 0) 254 | { 255 | //LOG_DEBUG("found symbol %s at 0x%llx (non-aslr 0x%llx)", symbol_to_solve, nlist->n_value + kinfo->kaslr_slide, nlist->n_value); 256 | /* the symbols values are without kernel ASLR so we need to add it */ 257 | mach_vm_address_t solved_addr = nlist->n_value + kinfo->kaslr_slide; 258 | /* verify if symbol is in the kernel __text section */ 259 | mach_vm_address_t floor = kinfo->memory_text_addr; 260 | mach_vm_address_t cap = kinfo->memory_text_addr + kinfo->text_size; 261 | if (solved_addr < floor || solved_addr > cap) 262 | { 263 | LOG_ERROR("Solved symbol address doesn't belong to running __text section. Something is wrong!"); 264 | return KERN_FAILURE; 265 | } 266 | *symbol_ptr = (void*)solved_addr; 267 | return KERN_SUCCESS; 268 | } 269 | } 270 | /* failure */ 271 | LOG_ERROR("Failed to solve symbol %s", symbol_to_solve); 272 | return KERN_FAILURE; 273 | } 274 | 275 | #pragma mark Internal helper functions 276 | 277 | /* 278 | * retrieve the first page of kernel binary at disk into a buffer 279 | * version that uses KPI VFS functions and a ripped uio_createwithbuffer() from XNU 280 | * the buffer always end with a 64 bits kernel or error 281 | */ 282 | static kern_return_t 283 | get_kernel_mach_header(void *buffer, vnode_t kernel_vnode) 284 | { 285 | if (buffer == NULL || kernel_vnode == NULLVP) 286 | { 287 | LOG_ERROR("Bad arguments."); 288 | return KERN_FAILURE; 289 | } 290 | 291 | int error = 0; 292 | 293 | uio_t uio = NULL; 294 | uio = uio_create(1, 0, UIO_SYSSPACE, UIO_READ); 295 | if (uio == NULL) 296 | { 297 | LOG_ERROR("uio_create returned null!"); 298 | return KERN_FAILURE; 299 | } 300 | // imitate the kernel and read a single page from the header 301 | if ( (error = uio_addiov(uio, CAST_USER_ADDR_T(buffer), PAGE_SIZE_64)) ) 302 | { 303 | LOG_ERROR("uio_addiov returned error %d!", error); 304 | return KERN_FAILURE; 305 | } 306 | 307 | vfs_context_t context = vfs_context_create(NULL); 308 | if (context == NULL) 309 | { 310 | LOG_ERROR("Failed to create context."); 311 | return KERN_FAILURE; 312 | } 313 | // read kernel vnode into the buffer 314 | if ( (error = VNOP_READ(kernel_vnode, uio, 0, context)) ) 315 | { 316 | LOG_ERROR("VNOP_READ failed %d!", error); 317 | vfs_context_rele(context); 318 | return KERN_FAILURE; 319 | } 320 | else if (uio_resid(uio)) 321 | { 322 | LOG_ERROR("uio_resid!"); 323 | vfs_context_rele(context); 324 | return KERN_FAILURE; 325 | } 326 | 327 | vfs_context_rele(context); 328 | return KERN_SUCCESS; 329 | } 330 | 331 | /* 332 | * retrieve the whole linkedit segment into target buffer from kernel binary at disk 333 | * we keep this buffer until we don't need to solve symbols anymore 334 | */ 335 | static kern_return_t 336 | get_kernel_linkedit(vnode_t kernel_vnode, struct kernel_info *kinfo) 337 | { 338 | if (kernel_vnode == NULLVP || kinfo == NULL) 339 | { 340 | LOG_ERROR("Bad arguments."); 341 | return KERN_FAILURE; 342 | } 343 | 344 | int error = 0; 345 | uio_t uio = uio_create(1, kinfo->linkedit_fileoff, UIO_SYSSPACE, UIO_READ); 346 | if (uio == NULL) 347 | { 348 | LOG_ERROR("uio_create returned null!"); 349 | return KERN_FAILURE; 350 | } 351 | if ( (error = uio_addiov(uio, CAST_USER_ADDR_T(kinfo->linkedit_buf), kinfo->linkedit_size)) ) 352 | { 353 | LOG_ERROR("uio_addiov returned error %d!", error); 354 | return KERN_FAILURE; 355 | } 356 | 357 | vfs_context_t context = vfs_context_create(NULL); 358 | if (context == NULL) 359 | { 360 | LOG_ERROR("Failed to create context."); 361 | return KERN_FAILURE; 362 | } 363 | if ( (error = VNOP_READ(kernel_vnode, uio, 0, context)) ) 364 | { 365 | LOG_ERROR("VNOP_READ failed %d!", error); 366 | vfs_context_rele(context); 367 | return KERN_FAILURE; 368 | } 369 | else if (uio_resid(uio)) 370 | { 371 | LOG_ERROR("uio_resid!"); 372 | vfs_context_rele(context); 373 | return KERN_FAILURE; 374 | } 375 | 376 | vfs_context_rele(context); 377 | return KERN_SUCCESS; 378 | } 379 | 380 | /* 381 | * retrieve necessary mach-o header information from the kernel buffer 382 | * stored at our kernel_info structure 383 | * XXX: we only process 64 bits kernels 384 | */ 385 | static kern_return_t 386 | process_kernel_mach_header(void *kernel_header, struct kernel_info *kinfo) 387 | { 388 | if (kernel_header == NULL || kinfo == NULL) 389 | { 390 | LOG_ERROR("Invalid arguments."); 391 | return KERN_FAILURE; 392 | } 393 | 394 | struct mach_header_64 *mh = (struct mach_header_64*)kernel_header; 395 | if (mh->magic != MH_MAGIC_64) 396 | { 397 | LOG_ERROR("Kernel is not 64bits!"); 398 | return KERN_FAILURE; 399 | } 400 | if (mh->ncmds == 0 || mh->sizeofcmds == 0) 401 | { 402 | LOG_ERROR("Invalid nr of commands or size."); 403 | return KERN_FAILURE; 404 | } 405 | 406 | struct load_command *load_cmd = NULL; 407 | /* point to the first load command */ 408 | char *load_cmd_addr = (char*)kernel_header + sizeof(struct mach_header_64); 409 | /* iterate over all load cmds and retrieve required info to solve symbols */ 410 | /* __LINKEDIT location and symbol/string table location */ 411 | int found_linkedit = 0; 412 | int found_symtab = 0; 413 | int found_text = 0; 414 | 415 | for (uint32_t i = 0; i < mh->ncmds; i++) 416 | { 417 | load_cmd = (struct load_command*)load_cmd_addr; 418 | if (load_cmd->cmd == LC_SEGMENT_64) 419 | { 420 | struct segment_command_64 *seg_cmd = (struct segment_command_64*)load_cmd; 421 | /* use this one to retrieve the original vm address of __TEXT so we can compute kernel aslr slide */ 422 | if (strncmp(seg_cmd->segname, "__TEXT", 16) == 0) 423 | { 424 | kinfo->disk_text_addr = seg_cmd->vmaddr; 425 | /* lookup the __text section - we want the size which can be retrieve here or from the running version */ 426 | char *section_addr = load_cmd_addr + sizeof(struct segment_command_64); 427 | for (uint32_t x = 0; x < seg_cmd->nsects; x++) 428 | { 429 | struct section_64 *section_cmd = (struct section_64*)section_addr; 430 | if (strncmp(section_cmd->sectname, "__text", 16) == 0) 431 | { 432 | kinfo->text_size = section_cmd->size; 433 | found_text++; 434 | break; 435 | } 436 | section_addr += sizeof(struct section_64); 437 | } 438 | } 439 | else if (strncmp(seg_cmd->segname, "__LINKEDIT", 16) == 0) 440 | { 441 | kinfo->linkedit_fileoff = seg_cmd->fileoff; 442 | kinfo->linkedit_size = seg_cmd->filesize; 443 | found_linkedit++; 444 | } 445 | } 446 | /* table information available at LC_SYMTAB command */ 447 | else if (load_cmd->cmd == LC_SYMTAB) 448 | { 449 | struct symtab_command *symtab_cmd = (struct symtab_command*)load_cmd; 450 | kinfo->symboltable_fileoff = symtab_cmd->symoff; 451 | kinfo->symboltable_nr_symbols = symtab_cmd->nsyms; 452 | kinfo->stringtable_fileoff = symtab_cmd->stroff; 453 | found_symtab++; 454 | } 455 | load_cmd_addr += load_cmd->cmdsize; 456 | } 457 | 458 | /* validate if we got all info we need */ 459 | if (found_linkedit == 0 || found_symtab == 0 || found_text == 0) 460 | { 461 | LOG_ERROR("Failed to find all necessary kernel mach-o header info."); 462 | return KERN_FAILURE; 463 | } 464 | 465 | return KERN_SUCCESS; 466 | } 467 | 468 | /* 469 | * retrieve the __TEXT address of current loaded kernel so we can compute the KASLR slide 470 | * also the size of __text 471 | * XXX: only processing 64 bits kernels! 472 | */ 473 | static kern_return_t 474 | get_running_text_address(struct kernel_info *kinfo) 475 | { 476 | if (kinfo == NULL) 477 | { 478 | LOG_ERROR("Bad parameter!"); 479 | return KERN_FAILURE; 480 | } 481 | 482 | /* retrieves the address of the IDT */ 483 | mach_vm_address_t idt_address = 0; 484 | if (get_addr_idt(&idt_address) != KERN_SUCCESS) 485 | { 486 | return KERN_FAILURE; 487 | } 488 | /* calculate the address of the int80 handler */ 489 | mach_vm_address_t int80_address = calculate_int80address(idt_address); 490 | /* search backwards for the kernel base address (mach-o header) */ 491 | mach_vm_address_t kernel_base = find_kernel_base(int80_address); 492 | if (kernel_base != 0) 493 | { 494 | /* get the vm address of __TEXT segment */ 495 | struct mach_header_64 *mh = (struct mach_header_64*)kernel_base; 496 | struct load_command *load_cmd = NULL; 497 | char *load_cmd_addr = (char*)kernel_base + sizeof(struct mach_header_64); 498 | for (uint32_t i = 0; i < mh->ncmds; i++) 499 | { 500 | load_cmd = (struct load_command*)load_cmd_addr; 501 | if (load_cmd->cmd == LC_SEGMENT_64) 502 | { 503 | struct segment_command_64 *seg_cmd = (struct segment_command_64*)load_cmd; 504 | if (strncmp(seg_cmd->segname, "__TEXT", 16) == 0) 505 | { 506 | kinfo->memory_text_addr = seg_cmd->vmaddr; 507 | return KERN_SUCCESS; 508 | } 509 | } 510 | load_cmd_addr += load_cmd->cmdsize; 511 | } 512 | } 513 | return KERN_FAILURE; 514 | } 515 | 516 | /* calculate the address of the kernel int80 handler using the IDT array */ 517 | static mach_vm_address_t 518 | calculate_int80address(const mach_vm_address_t idt_address) 519 | { 520 | if (idt_address == 0) 521 | { 522 | LOG_ERROR("Bad parameter!"); 523 | return 0; 524 | } 525 | /* find the address of interrupt 0x80 - EXCEP64_SPC_USR(0x80,hi64_unix_scall) @ osfmk/i386/idt64.s */ 526 | struct descriptor_idt *int80_descriptor = NULL; 527 | mach_vm_address_t int80_address = 0; 528 | // we need to compute the address, it's not direct 529 | // extract the stub address 530 | // retrieve the descriptor for interrupt 0x80 531 | // the IDT is an array of descriptors 532 | int80_descriptor = (struct descriptor_idt*)(idt_address+sizeof(struct descriptor_idt)*0x80); 533 | uint64_t high = (unsigned long)int80_descriptor->offset_high << 32; 534 | uint32_t middle = (unsigned int)int80_descriptor->offset_middle << 16; 535 | int80_address = (mach_vm_address_t)(high + middle + int80_descriptor->offset_low); 536 | //LOG_DEBUG("Address of interrupt 80 stub is 0x%llx", int80_address); 537 | return int80_address; 538 | } 539 | 540 | /* 541 | * find the kernel base address (mach-o header) 542 | * by searching backwards using the int80 handler as starting point 543 | */ 544 | static mach_vm_address_t 545 | find_kernel_base(const mach_vm_address_t int80_address) 546 | { 547 | if (int80_address == 0) 548 | { 549 | LOG_ERROR("Bad parameter!"); 550 | return 0; 551 | } 552 | mach_vm_address_t temp_address = int80_address; 553 | struct segment_command_64 *segment_command = NULL; 554 | struct mach_header_64 *mh = NULL; 555 | while (temp_address > 0) 556 | { 557 | mh = (struct mach_header_64*)temp_address; 558 | if (mh->magic == MH_MAGIC_64 && 559 | mh->filetype == MH_EXECUTE && 560 | mh->ncmds > 0 && 561 | mh->sizeofcmds > 0) 562 | { 563 | /* make sure it's the header and not some reference to the MAGIC number */ 564 | segment_command = (struct segment_command_64*)(temp_address + sizeof(struct mach_header_64)); 565 | if (strncmp(segment_command->segname, "__TEXT", 16) == 0) 566 | { 567 | //LOG_DEBUG("Found running kernel mach-o header address at %p", (void*)(temp_address)); 568 | return temp_address; 569 | } 570 | } 571 | /* check for int overflow */ 572 | if (temp_address - 1 > temp_address) 573 | { 574 | break; 575 | } 576 | temp_address--; 577 | } 578 | return 0; 579 | } 580 | 581 | /* retrieve the address of the IDT */ 582 | static kern_return_t 583 | get_addr_idt(mach_vm_address_t *idt) 584 | { 585 | if (idt == NULL) 586 | { 587 | LOG_ERROR("Bad parameter!"); 588 | return KERN_FAILURE; 589 | } 590 | 591 | uint8_t idtr[10]; 592 | __asm__ volatile ("sidt %0": "=m" (idtr)); 593 | *idt = *(mach_vm_address_t *)(idtr+2); 594 | return KERN_SUCCESS; 595 | } 596 | -------------------------------------------------------------------------------- /Parasite/Parasite/kernel_symbols.h: -------------------------------------------------------------------------------- 1 | /* 2 | * <-. (`-') (`-') _ (`-') _ 3 | * \(OO )_ (OO ).-/ <-.(OO ) (_) .-> 4 | * ,--./ ,-.) / ,---. ,------,) ,-(`-')(`-')----. 5 | * | `.' | | \ /`.\ | /`. ' | ( OO)( OO).-. ' 6 | * | |'.'| | '-'|_.' || |_.' | | | )( _) | | | 7 | * | | | |(| .-. || . .'(| |_/ \| |)| | 8 | * | | | | | | | || |\ \ | |'-> ' '-' ' 9 | * `--' `--' `--' `--'`--' '--' `--' `-----' 10 | * 11 | * Mario - The kernel component to fix rootpipe 12 | * 13 | * This is a TrustedBSD kernel driver to inject a dynamic library 14 | * or a __RESTRICT segment into specific processes 15 | * 16 | * Copyright (c) fG!, 2015. All rights reserved. 17 | * reverser@put.as - https://reverse.put.as 18 | * 19 | * kernel_symbols.h 20 | * 21 | * Functions to solve kernel symbols 22 | * 23 | * Redistribution and use in source and binary forms, with or without 24 | * modification, are permitted provided that the following conditions 25 | * are met: 26 | * 1. Redistributions of source code must retain the above copyright 27 | * notice, this list of conditions and the following disclaimer. 28 | * 2. Redistributions in binary form must reproduce the above copyright 29 | * notice, this list of conditions and the following disclaimer in the 30 | * documentation and/or other materials provided with the distribution. 31 | * 3. The name of the author may not be used to endorse or promote products 32 | * derived from this software without specific prior written permission. 33 | * 34 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 35 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 36 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 37 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 38 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 39 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 40 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 41 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 42 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 43 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 44 | * 45 | */ 46 | 47 | #ifndef mario_kernel_symbols_h 48 | #define mario_kernel_symbols_h 49 | 50 | #include 51 | #include 52 | #include 53 | #include 54 | 55 | /* exported data structures */ 56 | struct kernel_info 57 | { 58 | mach_vm_address_t memory_text_addr; // the address of __TEXT segment in kernel memory 59 | mach_vm_address_t disk_text_addr; // the same address at /mach_kernel in filesystem 60 | mach_vm_address_t kaslr_slide; // the kernel aslr slide, computed as the difference between above's addresses 61 | void *linkedit_buf; // pointer to __LINKEDIT buffer containing symbols to solve 62 | uint64_t linkedit_fileoff; // __LINKEDIT file offset so we can read 63 | // WARNING: does not contain the fat offset value in case it's a FAT kernel 64 | uint64_t linkedit_size; 65 | uint32_t symboltable_fileoff; // file offset to symbol table - used to position inside the __LINKEDIT buffer 66 | uint32_t symboltable_nr_symbols; 67 | uint32_t stringtable_fileoff; // file offset to string table 68 | // other info from the header we might need 69 | uint64_t text_size; // size of __text section to disassemble 70 | }; 71 | 72 | /* exported functions */ 73 | kern_return_t init_kernel_info(void); 74 | kern_return_t cleanup_kernel_info(void); 75 | kern_return_t solve_kernel_symbol(char *symbol_to_solve, void **symbol_ptr); 76 | 77 | /* kernel symbols we will manually solve */ 78 | extern kern_return_t (*_vm_map_read_user)(vm_map_t map, vm_map_offset_t src_addr, void *dst_p, vm_size_t size); 79 | extern kern_return_t (*_vm_map_write_user)(vm_map_t map, void *src_p, vm_map_address_t dst_addr, vm_size_t size); 80 | extern kern_return_t (*_mach_vm_protect)(vm_map_t target_task, mach_vm_address_t address, mach_vm_size_t size, boolean_t set_maximum, vm_prot_t new_protection); 81 | extern vm_map_offset_t (*_get_map_min)(vm_map_t); 82 | extern vm_map_t (*_get_task_map)(task_t); 83 | extern kern_return_t (*_mach_vm_region)(vm_map_t target_task, mach_vm_address_t *address, mach_vm_size_t *size, vm_region_flavor_t flavor, vm_region_info_t info, mach_msg_type_number_t *infoCnt, mach_port_t *object_name); 84 | 85 | #define SOLVE_KERNEL_SYMBOL(string, pointer) if (solve_kernel_symbol((string), (void**)&(pointer))) { printf("Can't solve kernel symbol %s", (string)); return KERN_FAILURE;} 86 | 87 | #endif 88 | -------------------------------------------------------------------------------- /Parasite/Parasite/library_injector.c: -------------------------------------------------------------------------------- 1 | /* 2 | * <-. (`-') (`-') _ (`-') _ 3 | * \(OO )_ (OO ).-/ <-.(OO ) (_) .-> 4 | * ,--./ ,-.) / ,---. ,------,) ,-(`-')(`-')----. 5 | * | `.' | | \ /`.\ | /`. ' | ( OO)( OO).-. ' 6 | * | |'.'| | '-'|_.' || |_.' | | | )( _) | | | 7 | * | | | |(| .-. || . .'(| |_/ \| |)| | 8 | * | | | | | | | || |\ \ | |'-> ' '-' ' 9 | * `--' `--' `--' `--'`--' '--' `--' `-----' 10 | * 11 | * Mario - The kernel component to fix rootpipe 12 | * 13 | * This is a TrustedBSD kernel driver to inject a dynamic library 14 | * or a __RESTRICT segment into specific processes 15 | * 16 | * Copyright (c) fG!, 2015. All rights reserved. 17 | * reverser@put.as - https://reverse.put.as 18 | * 19 | * library_injector.c 20 | * 21 | * Functions to inject the library into userspace target 22 | * 23 | * Redistribution and use in source and binary forms, with or without 24 | * modification, are permitted provided that the following conditions 25 | * are met: 26 | * 1. Redistributions of source code must retain the above copyright 27 | * notice, this list of conditions and the following disclaimer. 28 | * 2. Redistributions in binary form must reproduce the above copyright 29 | * notice, this list of conditions and the following disclaimer in the 30 | * documentation and/or other materials provided with the distribution. 31 | * 3. The name of the author may not be used to endorse or promote products 32 | * derived from this software without specific prior written permission. 33 | * 34 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 35 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 36 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 37 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 38 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 39 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 40 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 41 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 42 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 43 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 44 | * 45 | */ 46 | 47 | #include "library_injector.h" 48 | 49 | #include 50 | #include 51 | #include 52 | #include 53 | #include 54 | #include 55 | #include 56 | #include 57 | #include 58 | #include 59 | #include "kernel_symbols.h" 60 | #include "config.h" 61 | #include "logging.h" 62 | 63 | /* local data structures */ 64 | struct header_info 65 | { 66 | uint8_t is64bits; 67 | uint64_t aslr_slide; 68 | uint64_t linkedit_size; 69 | uint64_t linkedit_offset; 70 | mach_vm_address_t linkedit_addr; 71 | struct dyld_info_command *dyldinfo_cmd; 72 | struct symtab_command *symtab_cmd; 73 | uint32_t text_section_off; /* location of __text section */ 74 | uint32_t first_lib_offset; /* offset of first dynamic library */ 75 | uint32_t lib_count; /* number of linked dynamic libraries */ 76 | uint32_t free_space; /* free space in mach-o header for injection */ 77 | uint8_t *linkedit_buf; /* buffer that will hold __LINKED segment */ 78 | mach_vm_address_t highestvmaddr; /* highest vm addr in segment commands */ 79 | uint64_t highestvmsize; 80 | uint32_t lowest_fileoff; /* lowest data file offset to find out free header space */ 81 | vm_map_t taskport; /* task port of the target binary */ 82 | }; 83 | 84 | /* local functions */ 85 | static vm_prot_t get_protection(vm_map_t task, mach_vm_address_t address); 86 | static kern_return_t process_target_header(vm_map_t task_port, uint8_t *header, uint32_t header_size, mach_vm_address_t base_address, struct header_info *header_info); 87 | static void find_lowest_offset(uint8_t *load_cmd_addr, struct header_info *header_info); 88 | static kern_return_t write_user_mem(vm_map_t task_port, mach_vm_address_t target_addr, void* buf, uint32_t buf_len); 89 | static kern_return_t inject_normal_method(uint8_t *header_buf, struct header_info *hi, mach_vm_address_t base_addr, uint32_t offset, struct dylib_command *cmd, char *lib_path); 90 | 91 | /* 92 | * inject a dynamic library into the header 93 | */ 94 | kern_return_t 95 | inject_library(vm_map_t task_port, mach_vm_address_t base_address, char *path, int path_len) 96 | { 97 | char library_to_inject[MAXPATHLEN] = {0}; 98 | /* verify is library to be injected exists in the filesystem */ 99 | vnode_t lib_vnode = NULLVP; 100 | vfs_context_t libvfs_context = vfs_context_create(NULL); 101 | if (vnode_lookup(PATCH_LIBRARY, 0, &lib_vnode, libvfs_context)) 102 | { 103 | LOG_ERROR("Library to be injected not found in filesystem! Please copy it to the configured path %s.", PATCH_LIBRARY); 104 | vfs_context_rele(libvfs_context); 105 | return KERN_FAILURE; 106 | } 107 | vnode_put(lib_vnode); 108 | vfs_context_rele(libvfs_context); 109 | /* set library to be injected to patch version */ 110 | strlcpy(library_to_inject, PATCH_LIBRARY, sizeof(library_to_inject)); 111 | 112 | kern_return_t kr = 0; 113 | struct header_info header_info = {0}; 114 | /* 115 | * we need to read the header of the target process so we can find the injection space and modify it 116 | */ 117 | struct mach_header_64 header = {0}; 118 | kr = _vm_map_read_user(task_port, base_address, (void*)&header, sizeof(header)); 119 | if (kr != KERN_SUCCESS) 120 | { 121 | LOG_ERROR("Couldn't read target mach-o header. error %x at address 0x%llx", kr, base_address); 122 | return KERN_FAILURE; 123 | } 124 | uint32_t header_size = sizeof(struct mach_header); 125 | switch (header.magic) 126 | { 127 | case MH_MAGIC_64: 128 | header_size = sizeof(struct mach_header_64); 129 | header_info.is64bits = 1; 130 | break; 131 | case MH_MAGIC: 132 | header_info.is64bits = 0; 133 | break; 134 | default: 135 | LOG_ERROR("Unknown header magic value %x!", header.magic); 136 | return KERN_FAILURE; 137 | } 138 | if (header.ncmds == 0 || header.sizeofcmds == 0) 139 | { 140 | LOG_ERROR("Bad ncmds or sizeofcmds!"); 141 | return KERN_FAILURE; 142 | } 143 | 144 | /* calculate the buffer size we will need to hold the whole mach-o header */ 145 | uint32_t total_header_size = header.sizeofcmds + header_size; 146 | uint8_t *full_header = _MALLOC(total_header_size, M_TEMP, M_WAITOK | M_ZERO); 147 | if (full_header == NULL) 148 | { 149 | LOG_ERROR("Can't allocate space for target full mach-o header!"); 150 | return KERN_FAILURE; 151 | } 152 | /* copy the full header into our buffer */ 153 | if (_vm_map_read_user(task_port, base_address, (void*)full_header, total_header_size)) 154 | { 155 | LOG_ERROR("Can't read full target header!"); 156 | goto failure; 157 | } 158 | 159 | header_info.lowest_fileoff = 0xFFFFFFFF; 160 | struct mach_header_64 *mh = (struct mach_header_64*)full_header; 161 | 162 | /* process the header and retrieve some information we will use */ 163 | if (process_target_header(task_port, full_header, header_size, base_address, &header_info)) 164 | { 165 | LOG_ERROR("Can't process mach-o header!"); 166 | goto failure; 167 | } 168 | 169 | /* the injection position is after the last command */ 170 | uint32_t injection_offset = mh->sizeofcmds + header_size; // overflow checked inside find_library_injection_space 171 | uint32_t libpath_len = (uint32_t)strlen(library_to_inject) + 1; 172 | /* prepare the LC_LOAD_DYLIB command to be injected */ 173 | struct dylib_command newlib_cmd = {0}; 174 | newlib_cmd.cmd = LC_LOAD_WEAK_DYLIB; 175 | newlib_cmd.dylib.name.offset = 24; // usually the name string is located just after the command 176 | newlib_cmd.dylib.timestamp = 0; 177 | newlib_cmd.dylib.current_version = 0; 178 | newlib_cmd.dylib.compatibility_version = 0; 179 | newlib_cmd.cmdsize = sizeof(struct dylib_command) + libpath_len; 180 | /* cmdsize must be a multiple of uint32_t */ 181 | uint32_t remainder = ( sizeof(struct dylib_command) + libpath_len ) % sizeof(uint32_t); 182 | if (remainder != 0) 183 | { 184 | newlib_cmd.cmdsize += sizeof(uint32_t) - remainder; 185 | } 186 | if (header_info.free_space < newlib_cmd.cmdsize) 187 | { 188 | /* 189 | Sometimes we don't have enough space in the header for binary x, even if we had before 190 | */ 191 | LOG_ERROR("Not enough space to inject library at %s!", path); 192 | goto failure; 193 | } 194 | else 195 | { 196 | if (inject_normal_method(full_header, &header_info, base_address, injection_offset, &newlib_cmd, library_to_inject)) 197 | { 198 | goto failure; 199 | } 200 | } 201 | 202 | success: 203 | _FREE(full_header, M_TEMP); 204 | full_header = NULL; 205 | _FREE(header_info.linkedit_buf, M_TEMP); 206 | header_info.linkedit_buf = NULL; 207 | return KERN_SUCCESS; 208 | failure: 209 | if (full_header) 210 | { 211 | _FREE(full_header, M_TEMP); 212 | full_header = NULL; 213 | } 214 | if (header_info.linkedit_buf) 215 | { 216 | _FREE(header_info.linkedit_buf, M_TEMP); 217 | header_info.linkedit_buf = NULL; 218 | } 219 | return KERN_FAILURE; 220 | } 221 | 222 | #pragma Local helper functions 223 | 224 | /* 225 | * the normal method is to inject the LC_DYLIB_COMMAND at the start of the free space 226 | * and the string with path to the injected library after the command (24 bytes offset) 227 | */ 228 | static kern_return_t 229 | inject_normal_method(uint8_t *header_buf, struct header_info *hi, mach_vm_address_t base_addr, uint32_t offset, struct dylib_command *cmd, char *lib_path) 230 | { 231 | write_user_mem(hi->taskport, base_addr+offset, (void*)cmd, sizeof(struct dylib_command)); 232 | write_user_mem(hi->taskport, base_addr+offset+sizeof(struct dylib_command), (void*)lib_path, (uint32_t)strlen(lib_path)+1); 233 | /* 234 | * if everything went ok above finally fix mach-o header 235 | * this is what enables the library because nr of commands are changed 236 | */ 237 | struct mach_header_64 *mh = (struct mach_header_64*)header_buf; 238 | mh->ncmds += 1; 239 | mh->sizeofcmds += cmd->cmdsize; 240 | /* we could use mach_header_64 for both 32 and 64 since it holds the correct data */ 241 | if (hi->is64bits) 242 | { 243 | write_user_mem(hi->taskport, base_addr, (void*)mh, sizeof(struct mach_header_64)); 244 | } 245 | else 246 | { 247 | write_user_mem(hi->taskport, base_addr, (void*)mh, sizeof(struct mach_header)); 248 | } 249 | return KERN_SUCCESS; 250 | } 251 | 252 | static kern_return_t 253 | write_user_mem(vm_map_t task_port, mach_vm_address_t target_addr, void* buf, uint32_t buf_len) 254 | { 255 | vm_prot_t orig_protection = get_protection(task_port, target_addr); 256 | /* 257 | * read current protection so we can restore it 258 | */ 259 | if (_mach_vm_protect(task_port, target_addr, buf_len, FALSE, VM_PROT_WRITE | VM_PROT_READ)) 260 | { 261 | LOG_ERROR("vm_protect to write injected library failed!"); 262 | return KERN_FAILURE; 263 | } 264 | /* write the modified header to process */ 265 | if (_vm_map_write_user(task_port, buf, target_addr, buf_len)) 266 | { 267 | LOG_ERROR("write of modified header failed!"); 268 | /* we want to try to protect again the memory segment else it will end real bad! */ 269 | } 270 | /* restore original protection */ 271 | if (_mach_vm_protect(task_port, target_addr, buf_len, FALSE, orig_protection)) 272 | { 273 | /* XXX: this will leave application in a bad state. what to do here? */ 274 | LOG_ERROR("vm_protect to original prot failed!"); 275 | return KERN_FAILURE; 276 | } 277 | return KERN_SUCCESS; 278 | } 279 | 280 | /* 281 | * process the target mach-o header and retrieve all information we will need later on 282 | */ 283 | static kern_return_t 284 | process_target_header(vm_map_t task_port, uint8_t *header, uint32_t header_size, mach_vm_address_t base_address, struct header_info *header_info) 285 | { 286 | struct mach_header_64 *mh = (struct mach_header_64*)header; 287 | uint8_t lib_found = 0; 288 | if (UINT_MAX - mh->sizeofcmds < header_size) 289 | { 290 | LOG_ERROR("overflow?"); 291 | return KERN_FAILURE; 292 | } 293 | if (mh->ncmds == 0 || mh->sizeofcmds == 0) 294 | { 295 | LOG_ERROR("Bad ncmds or sizeofcmds"); 296 | return KERN_FAILURE; 297 | } 298 | 299 | /* find the last command offset */ 300 | struct load_command *load_cmd = NULL; 301 | uint8_t *load_cmd_addr = (uint8_t*)header + header_size; 302 | 303 | for (uint32_t i = 0; i < mh->ncmds; i++) 304 | { 305 | load_cmd = (struct load_command*)load_cmd_addr; 306 | /* 307 | * 64 bits segment commands 308 | */ 309 | if (load_cmd->cmd == LC_SEGMENT_64) 310 | { 311 | struct segment_command_64 *seg_cmd = (struct segment_command_64*)load_cmd_addr; 312 | if (seg_cmd->vmaddr > header_info->highestvmaddr) 313 | { 314 | header_info->highestvmaddr = seg_cmd->vmaddr; 315 | header_info->highestvmsize = seg_cmd->vmsize; 316 | } 317 | /* lookup this section to find out global lowest file offset */ 318 | find_lowest_offset(load_cmd_addr, header_info); 319 | 320 | if (strncmp(seg_cmd->segname, "__TEXT", 16) == 0) 321 | { 322 | // address of the first section 323 | uint8_t *section_addr = load_cmd_addr + sizeof(struct segment_command_64); 324 | for (uint32_t x = 0; x < seg_cmd->nsects; x++) 325 | { 326 | struct section_64 *section_cmd = (struct section_64*)section_addr; 327 | if (strncmp(section_cmd->sectname, "__text", 16) == 0) 328 | { 329 | header_info->text_section_off = section_cmd->offset; 330 | break; 331 | } 332 | section_addr += sizeof(struct section_64); 333 | } 334 | /* the vmaddr value of __TEXT segment starts at the mach-o header location */ 335 | /* base address is memory address where process is loaded */ 336 | if (seg_cmd->vmaddr > base_address) 337 | { 338 | LOG_ERROR("overflow?"); 339 | return KERN_FAILURE; 340 | } 341 | header_info->aslr_slide = base_address - seg_cmd->vmaddr; 342 | } 343 | else if (strncmp(seg_cmd->segname, "__LINKEDIT", 16) == 0) 344 | { 345 | header_info->linkedit_size = seg_cmd->vmsize; 346 | header_info->linkedit_addr = seg_cmd->vmaddr; 347 | header_info->linkedit_offset = seg_cmd->fileoff; 348 | } 349 | } 350 | /* 351 | * all other commands we are interested in 352 | */ 353 | /* find first location of a dynamic library */ 354 | // XXX: test the other two commads! 355 | else if (load_cmd->cmd == LC_LOAD_DYLIB || 356 | load_cmd->cmd == LC_LOAD_WEAK_DYLIB || 357 | load_cmd->cmd == LC_REEXPORT_DYLIB) 358 | { 359 | if (lib_found == 0) 360 | { 361 | if ((uint32_t)header > (uint32_t)load_cmd_addr) 362 | { 363 | LOG_ERROR("overflow?"); 364 | return KERN_FAILURE; 365 | } 366 | header_info->first_lib_offset = (uint32_t)(load_cmd_addr - header); 367 | lib_found = 1; 368 | } 369 | header_info->lib_count += 1; 370 | } 371 | else if (load_cmd->cmd == LC_SYMTAB) 372 | { 373 | header_info->symtab_cmd = (struct symtab_command*)load_cmd; 374 | } 375 | else if (load_cmd->cmd == LC_DYLD_INFO_ONLY) 376 | { 377 | header_info->dyldinfo_cmd = (struct dyld_info_command*)load_cmd; 378 | } 379 | /* other commands that have file offset information */ 380 | else if (load_cmd->cmd == LC_ENCRYPTION_INFO) 381 | { 382 | struct encryption_info_command *tcmd = (struct encryption_info_command*)load_cmd; 383 | if ( tcmd->cryptoff != 0 && ( tcmd->cryptoff < header_info->lowest_fileoff) ) 384 | { 385 | header_info->lowest_fileoff = tcmd->cryptoff; 386 | } 387 | } 388 | // advance to next command, size field holds the total size of each command, including sections 389 | load_cmd_addr += load_cmd->cmdsize; 390 | } 391 | /* 392 | * verify if there's enough free header space to inject the new command 393 | * between mach-o header + sizeofcmds and lowest data/code file offset 394 | * we found out the lowest file offset above so the difference between the two is the free header space 395 | */ 396 | if ((mh->sizeofcmds + header_size) > header_info->lowest_fileoff) 397 | { 398 | LOG_ERROR("overflow?"); 399 | return KERN_FAILURE; 400 | } 401 | header_info->free_space = header_info->lowest_fileoff - (mh->sizeofcmds + header_size); 402 | 403 | /* read whole __LINKEDIT */ 404 | header_info->linkedit_buf = _MALLOC(header_info->linkedit_size, M_TEMP, M_WAITOK); 405 | if (header_info->linkedit_buf == NULL) 406 | { 407 | LOG_ERROR("Can't allocate buffer for __LINKEDIT!"); 408 | return KERN_FAILURE; 409 | } 410 | if (_vm_map_read_user(task_port, header_info->linkedit_addr + header_info->aslr_slide, (void*)header_info->linkedit_buf, header_info->linkedit_size)) 411 | { 412 | LOG_ERROR("Can't read __LINKEDIT from target!"); 413 | /* free memory and return the pointer in a clean state */ 414 | _FREE(header_info->linkedit_buf, M_TEMP); 415 | header_info->linkedit_buf = NULL; 416 | return KERN_FAILURE; 417 | } 418 | /* set the task port */ 419 | header_info->taskport = task_port; 420 | 421 | return KERN_SUCCESS; 422 | } 423 | 424 | /* 425 | * aux function to find the lowest offset in mach-o header 426 | * its input is a LC_SEGMENT* command 427 | */ 428 | static void 429 | find_lowest_offset(uint8_t *load_cmd_addr, struct header_info *header_info) 430 | { 431 | /* 64 bits LC_SEGMENT_64 */ 432 | struct segment_command_64 *seg_cmd = (struct segment_command_64*)load_cmd_addr; 433 | /* __TEXT segment usually has fileoff == 0 */ 434 | /* iterate thru sections */ 435 | /* XXX: how to deal with my section/segment anti-debug here ? */ 436 | /* if segment fileoff is zero we should scan the sections */ 437 | if (seg_cmd->fileoff == 0) 438 | { 439 | if (seg_cmd->nsects != 0) 440 | { 441 | uint8_t *section_addr = load_cmd_addr + sizeof(struct segment_command_64); 442 | for (uint32_t x = 0; x < seg_cmd->nsects; x++) 443 | { 444 | struct section_64 *section_cmd = (struct section_64*)section_addr; 445 | if (section_cmd->offset != 0 && section_cmd->offset < header_info->lowest_fileoff) 446 | { 447 | header_info->lowest_fileoff = section_cmd->offset; 448 | } 449 | section_addr += sizeof(struct section_64); 450 | } 451 | } 452 | } 453 | /* 454 | * if segment fileoff is not zero, first test the segment and then sections if they exist 455 | */ 456 | else 457 | { 458 | if (seg_cmd->fileoff < header_info->lowest_fileoff) 459 | { 460 | /* XXX: fileoff is uint64_t in LC_SEGMENT_64 */ 461 | header_info->lowest_fileoff = (uint32_t)seg_cmd->fileoff; 462 | } 463 | if (seg_cmd->nsects != 0) 464 | { 465 | uint8_t *section_addr = load_cmd_addr + sizeof(struct segment_command_64); 466 | for (uint32_t x = 0; x < seg_cmd->nsects; x++) 467 | { 468 | struct section_64 *section_cmd = (struct section_64*)section_addr; 469 | /* there are sections with offset = 0, __common and __bss for example */ 470 | if (section_cmd->offset != 0 && section_cmd->offset < header_info->lowest_fileoff) 471 | { 472 | header_info->lowest_fileoff = section_cmd->offset; 473 | } 474 | section_addr += sizeof(struct section_64); 475 | } 476 | } 477 | } 478 | } 479 | 480 | #pragma mark Generic auxiliar functions 481 | 482 | /* 483 | * retrieve the current memory protection flags of an address 484 | */ 485 | static vm_prot_t 486 | get_protection(vm_map_t task_port, mach_vm_address_t address) 487 | { 488 | if (task_port == NULL || address == 0) 489 | { 490 | LOG_ERROR("Bad parameters!"); 491 | return -1; 492 | } 493 | vm_region_basic_info_data_64_t info = {0}; 494 | mach_vm_size_t size = 0; 495 | mach_port_t object_name = 0; 496 | mach_msg_type_number_t count = VM_REGION_BASIC_INFO_COUNT_64; 497 | 498 | if (_mach_vm_region(task_port, &address, &size, VM_REGION_BASIC_INFO_64, (vm_region_info_t)&info, &count, &object_name) != KERN_SUCCESS) 499 | { 500 | LOG_ERROR("get_protection failed!"); 501 | return -1; 502 | } 503 | /* just return the protection field */ 504 | return(info.protection); 505 | } 506 | -------------------------------------------------------------------------------- /Parasite/Parasite/library_injector.h: -------------------------------------------------------------------------------- 1 | /* 2 | * <-. (`-') (`-') _ (`-') _ 3 | * \(OO )_ (OO ).-/ <-.(OO ) (_) .-> 4 | * ,--./ ,-.) / ,---. ,------,) ,-(`-')(`-')----. 5 | * | `.' | | \ /`.\ | /`. ' | ( OO)( OO).-. ' 6 | * | |'.'| | '-'|_.' || |_.' | | | )( _) | | | 7 | * | | | |(| .-. || . .'(| |_/ \| |)| | 8 | * | | | | | | | || |\ \ | |'-> ' '-' ' 9 | * `--' `--' `--' `--'`--' '--' `--' `-----' 10 | * 11 | * Mario - The kernel component to fix rootpipe 12 | * 13 | * This is a TrustedBSD kernel driver to inject a dynamic library 14 | * or a __RESTRICT segment into specific processes 15 | * 16 | * Copyright (c) fG!, 2015. All rights reserved. 17 | * reverser@put.as - https://reverse.put.as 18 | * 19 | * library_injector.h 20 | * 21 | * Functions to inject the library into userspace target 22 | * 23 | * Redistribution and use in source and binary forms, with or without 24 | * modification, are permitted provided that the following conditions 25 | * are met: 26 | * 1. Redistributions of source code must retain the above copyright 27 | * notice, this list of conditions and the following disclaimer. 28 | * 2. Redistributions in binary form must reproduce the above copyright 29 | * notice, this list of conditions and the following disclaimer in the 30 | * documentation and/or other materials provided with the distribution. 31 | * 3. The name of the author may not be used to endorse or promote products 32 | * derived from this software without specific prior written permission. 33 | * 34 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 35 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 36 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 37 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 38 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 39 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 40 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 41 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 42 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 43 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 44 | * 45 | */ 46 | 47 | #ifndef mario_library_injector_h 48 | #define mario_library_injector_h 49 | 50 | #include 51 | #include 52 | #include 53 | 54 | kern_return_t inject_library(vm_map_t task_port, mach_vm_address_t base_address, char *path, int path_len); 55 | kern_return_t inject_restricted(vm_map_t task_port, mach_vm_address_t base_address, char *path, int path_len); 56 | 57 | #endif 58 | -------------------------------------------------------------------------------- /Parasite/Parasite/logging.h: -------------------------------------------------------------------------------- 1 | /* 2 | * <-. (`-') (`-') _ (`-') _ 3 | * \(OO )_ (OO ).-/ <-.(OO ) (_) .-> 4 | * ,--./ ,-.) / ,---. ,------,) ,-(`-')(`-')----. 5 | * | `.' | | \ /`.\ | /`. ' | ( OO)( OO).-. ' 6 | * | |'.'| | '-'|_.' || |_.' | | | )( _) | | | 7 | * | | | |(| .-. || . .'(| |_/ \| |)| | 8 | * | | | | | | | || |\ \ | |'-> ' '-' ' 9 | * `--' `--' `--' `--'`--' '--' `--' `-----' 10 | * 11 | * Mario - The kernel component to fix rootpipe 12 | * 13 | * This is a TrustedBSD kernel driver to inject a dynamic library 14 | * or a __RESTRICT segment into specific processes 15 | * 16 | * Copyright (c) fG!, 2015. All rights reserved. 17 | * reverser@put.as - https://reverse.put.as 18 | * 19 | * logging.h 20 | * 21 | * Redistribution and use in source and binary forms, with or without 22 | * modification, are permitted provided that the following conditions 23 | * are met: 24 | * 1. Redistributions of source code must retain the above copyright 25 | * notice, this list of conditions and the following disclaimer. 26 | * 2. Redistributions in binary form must reproduce the above copyright 27 | * notice, this list of conditions and the following disclaimer in the 28 | * documentation and/or other materials provided with the distribution. 29 | * 3. The name of the author may not be used to endorse or promote products 30 | * derived from this software without specific prior written permission. 31 | * 32 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 33 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 34 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 35 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 36 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 37 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 38 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 39 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 40 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 41 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 42 | * 43 | */ 44 | 45 | #ifndef mario_logging_h 46 | #define mario_logging_h 47 | 48 | #include "config.h" 49 | #include 50 | 51 | #if DEBUG == 0 52 | #define LOG_DEBUG(fmt, ...) do {} while (0) 53 | #else 54 | #define LOG_DEBUG(fmt, ...) printf("[DEBUG] " fmt "\n", ## __VA_ARGS__) 55 | #endif 56 | 57 | #define LOG_ERROR(fmt, ...) printf("[ERROR] " fmt " (%s, %d)\n", ## __VA_ARGS__, __func__, __LINE__) 58 | 59 | #endif 60 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Parasite 2 | ## Powerful Code Insertion Platform for OS X 3 | 4 | ### What this fork adds 5 | 6 | **NOTE** Don't use yet 7 | 8 | This fork adds compatibility with Opee for those who do not want to patch Foundation and are comfortable using an unsigned kernel extension. 9 | 10 | Changes: 11 | 12 | 1. Sets the payload to the OpeeLoader.dylib trampoline. 13 | 14 | 2. Uses LC_LOAD_WEAK_DYLIB so that apps do not crash if OpeeLoader.dylib is not present on the filesystem. 15 | 16 | 3. Injects into all processes instead of the Dock 17 | 18 | #### Usage with Opee: 19 | Follow all the installation instructions on the Opee page except for the part using optool. Then load this kext. 20 | 21 | ### Intro 22 | Parasite allows you to change the expected behavior of apps and stuff. Sounds scary. 23 | 24 | ### How do I Parasite? 25 | If you are experienced enough you'll know how to use it. If not, keep out for your own safety. 26 | 27 | ### How do I get? 28 | Compile it for yourself. 29 | 30 | ### How do I compile? 31 | You should know that. :P 32 | 33 | ### License? 34 | Pretty much the BSD license, just don't repackage it and call it your own please! 35 | 36 | Also if you do make some changes, feel free to make a pull request and help make things more awesome! 37 | 38 | ### Contact Info? 39 | If you have any support requests please feel free to email me at shinvou[at]gmail[dot]com. 40 | 41 | Otherwise, feel free to follow me on twitter: [@biscoditch](https:///www.twitter.com/biscoditch)! 42 | 43 | ### Special Thanks 44 | Thanks to [@osxreverser](https:///www.twitter.com/osxreverser). ATM I use slightly modified code (userspace injection/kernel solving) from his project [mario](https://github.com/gdbinit/mario). 45 | --------------------------------------------------------------------------------