├── .gitignore ├── ParasiteLoader ├── ParasiteLoader.xcodeproj │ ├── project.xcworkspace │ │ └── contents.xcworkspacedata │ ├── xcuserdata │ │ └── Alex.xcuserdatad │ │ │ └── xcschemes │ │ │ ├── xcschememanagement.plist │ │ │ └── ParasiteLoader.xcscheme │ └── project.pbxproj ├── loader.h ├── runtime.h ├── runtime.c ├── main.h ├── main.c └── loader.c └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | xcuserdata 2 | *.DS_Store 3 | -------------------------------------------------------------------------------- /ParasiteLoader/ParasiteLoader.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ParasiteLoader/loader.h: -------------------------------------------------------------------------------- 1 | // 2 | // loader.h 3 | // ParasiteLoader 4 | // 5 | // Created by Alexander Zielenski on 3/30/16. 6 | // Copyright © 2016 ParasiteTeam. All rights reserved. 7 | // 8 | 9 | #ifndef loader_h 10 | #define loader_h 11 | 12 | #include 13 | #include 14 | 15 | void __ParasiteProcessExtensions(CFURLRef libraries, CFBundleRef bndl, CFStringRef executableName); 16 | 17 | #endif /* loader_h */ 18 | -------------------------------------------------------------------------------- /ParasiteLoader/runtime.h: -------------------------------------------------------------------------------- 1 | // 2 | // runtime.h 3 | // ParasiteLoader 4 | // 5 | // Created by Alexander Zielenski on 4/7/16. 6 | // Copyright © 2016 ParasiteTeam. All rights reserved. 7 | // 8 | 9 | #ifndef runtime_h 10 | #define runtime_h 11 | 12 | #include 13 | 14 | typedef void(*PSLoaderCallback)(CFURLRef path, CFIndex idx, CFIndex total); 15 | 16 | void PSNotify(CFURLRef path, CFIndex idx, CFIndex total); 17 | 18 | #endif /* runtime_h */ 19 | -------------------------------------------------------------------------------- /ParasiteLoader/ParasiteLoader.xcodeproj/xcuserdata/Alex.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | ParasiteLoader.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | FA42F1221CAC744300AB959B 16 | 17 | primary 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /ParasiteLoader/runtime.c: -------------------------------------------------------------------------------- 1 | // 2 | // runtime.c 3 | // ParasiteLoader 4 | // 5 | // Created by Alexander Zielenski on 4/7/16. 6 | // Copyright © 2016 ParasiteTeam. All rights reserved. 7 | // 8 | 9 | #include "runtime.h" 10 | static CFMutableArrayRef callbacks; 11 | 12 | static dispatch_queue_t callback_queue() { 13 | static dispatch_queue_t callback_queue = NULL; 14 | static dispatch_once_t onceToken; 15 | dispatch_once(&onceToken, ^{ 16 | callback_queue = dispatch_queue_create("com.parasite.loader.callbacks.queue", DISPATCH_QUEUE_SERIAL); 17 | }); 18 | return callback_queue; 19 | } 20 | 21 | void PSNotify(CFURLRef path, CFIndex idx, CFIndex total) { 22 | if (callbacks == NULL) return; 23 | 24 | dispatch_async(callback_queue(), ^{ 25 | CFIndex i = 0; 26 | CFIndex tot = CFArrayGetCount(callbacks); 27 | for (i = 0; i < tot; i++) { 28 | PSLoaderCallback cb = CFArrayGetValueAtIndex(callbacks, i); 29 | dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 30 | cb(path, idx, total); 31 | }); 32 | } 33 | 34 | if (idx == total - 1 && callbacks != NULL) { 35 | CFRelease(callbacks); 36 | callbacks = NULL; 37 | } 38 | }); 39 | } 40 | 41 | void _PSRegisterCallback(PSLoaderCallback callback) { 42 | dispatch_async(callback_queue(), ^{ 43 | if (callbacks == NULL) { 44 | callbacks = CFArrayCreateMutable(kCFAllocatorDefault, 45 | 0, 46 | NULL); 47 | } 48 | 49 | CFArrayAppendValue(callbacks, callback); 50 | }); 51 | } 52 | -------------------------------------------------------------------------------- /ParasiteLoader/main.h: -------------------------------------------------------------------------------- 1 | // 2 | // main.h 3 | // ParasiteLoader 4 | // 5 | // Created by Alexander Zielenski on 3/30/16. 6 | // Copyright © 2016 ParasiteTeam. All rights reserved. 7 | // 8 | 9 | #ifndef main_h 10 | #define main_h 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #define OPLogLevelNotice LOG_NOTICE 17 | #define OPLogLevelWarning LOG_WARNING 18 | #define OPLogLevelKernel LOG_KERN 19 | #define OPLogLevelError LOG_ERR 20 | 21 | #ifdef DEBUG 22 | #define OPLog(level, format, ...) do { \ 23 | CFStringRef _formatted = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR(format), ## __VA_ARGS__); \ 24 | size_t _size = CFStringGetMaximumSizeForEncoding(CFStringGetLength(_formatted), kCFStringEncodingUTF8); \ 25 | char _utf8[_size + sizeof('\0')]; \ 26 | CFStringGetCString(_formatted, _utf8, sizeof(_utf8), kCFStringEncodingUTF8); \ 27 | CFRelease(_formatted); \ 28 | syslog(level, "[ParasiteLoader] " "%s", _utf8); \ 29 | } while (false) 30 | #else 31 | #define OPLog(...) (void)1 32 | #endif 33 | 34 | extern const CFStringRef kPSFiltersKey; 35 | extern const CFStringRef kOPFiltersKey; 36 | extern const CFStringRef kSIMBLFiltersKey; 37 | extern const char *PSLibrariesPath; 38 | 39 | // SIMBL 40 | extern const CFStringRef kPSBundleIdentifierKey; 41 | extern const CFStringRef kPSMinBundleVersionKey; 42 | extern const CFStringRef kPSMaxBundleVersionKey; 43 | 44 | // OPFilters 45 | extern const CFStringRef kPSCoreFoundationVersionKey; 46 | extern const CFStringRef kPSModeKey; 47 | extern const CFStringRef kPSAnyValue; 48 | extern const CFStringRef kPSExecutablesKey; 49 | extern const CFStringRef kPSBundlesKey; 50 | extern const CFStringRef kPSClassesKey; 51 | 52 | #endif /* main_h */ 53 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ParasiteLoader.dylib 2 | After the [kext](https://github.com/ParasiteTeam/kext) inserts a LC_LOAD_WEAK_DYLIB command pointing to ParasiteLoader.dylib 3 | into the MachO header of the currently launching process, dyld will load this library and call `__ParasiteInit`. That function 4 | makes sure it is safe to continue by checking a list of blacklisted processes and then goes on to loop through every bundle in the folder 5 | `/Library/Parasite/Extensions` to see which bundles should be loaded into the process. 6 | 7 | # Extension Format 8 | Each extension is a `.bundle` located in `/Library/Parasite/Extensions`. In each bundle is an `Info.plist` file containing metadata 9 | about the creator of the bundle, version, etc. This is where the filters go. Add a key into your `Info.plist` file called `PSFilters` 10 | of type `dictionary`. 11 | 12 | Here are the types of filters that can go into the PSFilters dictionary. You may recognize these from MobileSubstrate filters. That's because 13 | it's the same with a few extensions. 14 | 15 | 16 | | Key | Type | Description | 17 | |-----|:----:|-------------| 18 | | CoreFoundationVersion | array | An array of one or two `real`s. The first one is the minimum CoreFoundation version of a system this bundle should load on and the second value, if it exists refers to the maximum verison. | 19 | | Bundles | array | An array of bundle identifiers or SIMBL-style bundle entries that if are loaded into the current process will cause the bundle to be loaded, too. | 20 | | Executables | array | List of executable names to load into. This is useful for loading into processes that do not have a bundle identifier | 21 | | Classes | array | An array of zero or more strings of the names of classes that, if present, will cause the bundle to load. | 22 | | Mode | String | `Any` is the only allowed option if this key is present. If `Mode` is not set to `Any` then all of the above filters must match for this bundle to be loaded. | 23 | 24 | For more detailed information on the filter format, check out [CydiaSubstrate](http://www.cydiasubstrate.com/inject/darwin/), Parasite supports all of it. 25 | 26 | A key difference is that the `Bundles` key not only allows strings of bundle id's but also dictionaries that follow the same format as SIMBL. Example: 27 | 28 | | Key | Type | Description | 29 | |-----|:----:|-------------| 30 | | BundleIdentifier | string | identifier of bundle to load into | 31 | | MinBundleVersion | real | seems straightforward enough | 32 | | MaxBundleVersion | real | see above | 33 | 34 | Parasite also supports SIMBL bundles themselves, though this feature is experimental and not guaranteeed to work. You should prefer to use extensions that were developed for Parasite over SIMBL alternatives if you can. 35 | -------------------------------------------------------------------------------- /ParasiteLoader/ParasiteLoader.xcodeproj/xcuserdata/Alex.xcuserdatad/xcschemes/ParasiteLoader.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 | -------------------------------------------------------------------------------- /ParasiteLoader/main.c: -------------------------------------------------------------------------------- 1 | // 2 | // loader.c 3 | // ParasiteLoader 4 | // 5 | // Created by Alexander Zielenski on 3/30/16. 6 | // Copyright © 2016 ParasiteTeam. All rights reserved. 7 | // 8 | 9 | #include "main.h" 10 | #include "loader.h" 11 | 12 | const CFStringRef kPSFiltersKey = CFSTR("PSFilters"); 13 | const CFStringRef kOPFiltersKey = CFSTR("OPFilters"); 14 | const CFStringRef kSIMBLFiltersKey = CFSTR("SIMBLTargetApplications"); 15 | const char *OPLibrariesPath = "/Library/Parasite/Extensions"; 16 | 17 | const CFStringRef kPSBundleIdentifierKey = CFSTR("BundleIdentifier"); 18 | const CFStringRef kPSMinBundleVersionKey = CFSTR("MinBundleVersion"); 19 | const CFStringRef kPSMaxBundleVersionKey = CFSTR("MaxBundleVersion"); 20 | 21 | const CFStringRef kPSCoreFoundationVersionKey = CFSTR("CoreFoundationVersion"); 22 | const CFStringRef kPSModeKey = CFSTR("Mode"); 23 | const CFStringRef kPSAnyValue = CFSTR("Any"); 24 | const CFStringRef kPSExecutablesKey = CFSTR("Executables"); 25 | const CFStringRef kPSBundlesKey = CFSTR("Bundles"); 26 | const CFStringRef kPSClassesKey = CFSTR("Classes"); 27 | 28 | __attribute__((constructor)) 29 | static void __ParasiteInit(int argc, char **argv, char **envp) { 30 | if (dlopen("/System/Library/Frameworks/Security.framework/Security", RTLD_LAZY | RTLD_NOLOAD) == NULL) 31 | return; 32 | 33 | if (argc < 1 || argv == NULL) 34 | return; 35 | 36 | // The first argument is the spawned process 37 | // Get the process name by looking at the last path 38 | // component. 39 | char *executable = strrchr(argv[0], '/'); 40 | executable = (executable == NULL) ? argv[0] : executable + 1; 41 | 42 | #define BLACKLIST(PROCESS) if (strcmp(executable, #PROCESS) == 0) return; 43 | /* 44 | These are processes which are blacklisted because they break 45 | some system functionality 46 | */ 47 | BLACKLIST(coreservicesd); 48 | BLACKLIST(amfid); 49 | 50 | BLACKLIST(ReportCrash); 51 | BLACKLIST(mDNSResponder); 52 | BLACKLIST(useractivityd); 53 | BLACKLIST(syslogd); 54 | BLACKLIST(ssh); 55 | 56 | // Added Parasite 1.0.0b3 57 | BLACKLIST(opendirectoryd); 58 | BLACKLIST(configd); 59 | BLACKLIST(UserEventAgent); 60 | 61 | // Just in case... 62 | BLACKLIST(DumpPanic); 63 | 64 | // Blacklist developer tools 65 | BLACKLIST(clang) 66 | BLACKLIST(git); 67 | BLACKLIST(xcodebuild); 68 | BLACKLIST(gcc); 69 | BLACKLIST(lldb); 70 | BLACKLIST(codesign); 71 | BLACKLIST(svn); 72 | BLACKLIST(com.apple.dt.Xcode.sourcecontrol.Git); 73 | 74 | CFBundleRef mainBundle = CFBundleGetMainBundle(); 75 | CFStringRef executableName = CFStringCreateWithCStringNoCopy(kCFAllocatorDefault, 76 | executable, 77 | kCFStringEncodingUTF8, 78 | kCFAllocatorNull); 79 | if (executableName == NULL) return; 80 | 81 | // Process extensions for all users 82 | CFURLRef libraries = CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault, 83 | (const UInt8 *)OPLibrariesPath, 84 | strlen(OPLibrariesPath), 85 | true); 86 | if (libraries == NULL) { 87 | CFRelease(executableName); 88 | return; 89 | } 90 | 91 | if (access(OPLibrariesPath, X_OK | R_OK) == -1) { 92 | OPLog(OPLogLevelNotice, "Unable to access root libraries directory\n"); 93 | 94 | } else { 95 | __ParasiteProcessExtensions(libraries, mainBundle, executableName); 96 | } 97 | 98 | CFRelease(executableName); 99 | CFRelease(libraries); 100 | 101 | } -------------------------------------------------------------------------------- /ParasiteLoader/ParasiteLoader.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | FA42F12B1CAC746900AB959B /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FA42F12A1CAC746900AB959B /* CoreFoundation.framework */; }; 11 | FA42F12D1CAC747800AB959B /* main.c in Sources */ = {isa = PBXBuildFile; fileRef = FA42F12C1CAC747800AB959B /* main.c */; }; 12 | FA42F1321CAC777400AB959B /* loader.c in Sources */ = {isa = PBXBuildFile; fileRef = FA42F1301CAC777400AB959B /* loader.c */; }; 13 | FA42F1331CAC777400AB959B /* loader.h in Headers */ = {isa = PBXBuildFile; fileRef = FA42F1311CAC777400AB959B /* loader.h */; }; 14 | FAC096E61CB6F8170047496D /* runtime.c in Sources */ = {isa = PBXBuildFile; fileRef = FAC096E41CB6F8170047496D /* runtime.c */; }; 15 | FAC096E71CB6F8170047496D /* runtime.h in Headers */ = {isa = PBXBuildFile; fileRef = FAC096E51CB6F8170047496D /* runtime.h */; }; 16 | /* End PBXBuildFile section */ 17 | 18 | /* Begin PBXFileReference section */ 19 | FA42F1231CAC744300AB959B /* ParasiteLoader.dylib */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = ParasiteLoader.dylib; sourceTree = BUILT_PRODUCTS_DIR; }; 20 | FA42F12A1CAC746900AB959B /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = System/Library/Frameworks/CoreFoundation.framework; sourceTree = SDKROOT; }; 21 | FA42F12C1CAC747800AB959B /* main.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = main.c; sourceTree = ""; }; 22 | FA42F12F1CAC74DE00AB959B /* main.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = main.h; sourceTree = ""; }; 23 | FA42F1301CAC777400AB959B /* loader.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = loader.c; sourceTree = ""; }; 24 | FA42F1311CAC777400AB959B /* loader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = loader.h; sourceTree = ""; }; 25 | FAC096E41CB6F8170047496D /* runtime.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = runtime.c; sourceTree = ""; }; 26 | FAC096E51CB6F8170047496D /* runtime.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = runtime.h; sourceTree = ""; }; 27 | /* End PBXFileReference section */ 28 | 29 | /* Begin PBXFrameworksBuildPhase section */ 30 | FA42F1201CAC744300AB959B /* Frameworks */ = { 31 | isa = PBXFrameworksBuildPhase; 32 | buildActionMask = 2147483647; 33 | files = ( 34 | FA42F12B1CAC746900AB959B /* CoreFoundation.framework in Frameworks */, 35 | ); 36 | runOnlyForDeploymentPostprocessing = 0; 37 | }; 38 | /* End PBXFrameworksBuildPhase section */ 39 | 40 | /* Begin PBXGroup section */ 41 | FA42F11A1CAC744300AB959B = { 42 | isa = PBXGroup; 43 | children = ( 44 | FA42F12E1CAC748100AB959B /* src */, 45 | FA42F12A1CAC746900AB959B /* CoreFoundation.framework */, 46 | FA42F1241CAC744300AB959B /* Products */, 47 | ); 48 | sourceTree = ""; 49 | }; 50 | FA42F1241CAC744300AB959B /* Products */ = { 51 | isa = PBXGroup; 52 | children = ( 53 | FA42F1231CAC744300AB959B /* ParasiteLoader.dylib */, 54 | ); 55 | name = Products; 56 | sourceTree = ""; 57 | }; 58 | FA42F12E1CAC748100AB959B /* src */ = { 59 | isa = PBXGroup; 60 | children = ( 61 | FA42F12F1CAC74DE00AB959B /* main.h */, 62 | FA42F12C1CAC747800AB959B /* main.c */, 63 | FA42F1311CAC777400AB959B /* loader.h */, 64 | FA42F1301CAC777400AB959B /* loader.c */, 65 | FAC096E51CB6F8170047496D /* runtime.h */, 66 | FAC096E41CB6F8170047496D /* runtime.c */, 67 | ); 68 | name = src; 69 | sourceTree = ""; 70 | }; 71 | /* End PBXGroup section */ 72 | 73 | /* Begin PBXHeadersBuildPhase section */ 74 | FA42F1211CAC744300AB959B /* Headers */ = { 75 | isa = PBXHeadersBuildPhase; 76 | buildActionMask = 2147483647; 77 | files = ( 78 | FA42F1331CAC777400AB959B /* loader.h in Headers */, 79 | FAC096E71CB6F8170047496D /* runtime.h in Headers */, 80 | ); 81 | runOnlyForDeploymentPostprocessing = 0; 82 | }; 83 | /* End PBXHeadersBuildPhase section */ 84 | 85 | /* Begin PBXNativeTarget section */ 86 | FA42F1221CAC744300AB959B /* ParasiteLoader */ = { 87 | isa = PBXNativeTarget; 88 | buildConfigurationList = FA42F1271CAC744300AB959B /* Build configuration list for PBXNativeTarget "ParasiteLoader" */; 89 | buildPhases = ( 90 | FA42F11F1CAC744300AB959B /* Sources */, 91 | FA42F1201CAC744300AB959B /* Frameworks */, 92 | FA42F1211CAC744300AB959B /* Headers */, 93 | ); 94 | buildRules = ( 95 | ); 96 | dependencies = ( 97 | ); 98 | name = ParasiteLoader; 99 | productName = ParasiteLoader; 100 | productReference = FA42F1231CAC744300AB959B /* ParasiteLoader.dylib */; 101 | productType = "com.apple.product-type.library.dynamic"; 102 | }; 103 | /* End PBXNativeTarget section */ 104 | 105 | /* Begin PBXProject section */ 106 | FA42F11B1CAC744300AB959B /* Project object */ = { 107 | isa = PBXProject; 108 | attributes = { 109 | LastUpgradeCheck = 0730; 110 | ORGANIZATIONNAME = ParasiteTeam; 111 | TargetAttributes = { 112 | FA42F1221CAC744300AB959B = { 113 | CreatedOnToolsVersion = 7.2; 114 | }; 115 | }; 116 | }; 117 | buildConfigurationList = FA42F11E1CAC744300AB959B /* Build configuration list for PBXProject "ParasiteLoader" */; 118 | compatibilityVersion = "Xcode 3.2"; 119 | developmentRegion = English; 120 | hasScannedForEncodings = 0; 121 | knownRegions = ( 122 | en, 123 | ); 124 | mainGroup = FA42F11A1CAC744300AB959B; 125 | productRefGroup = FA42F1241CAC744300AB959B /* Products */; 126 | projectDirPath = ""; 127 | projectRoot = ""; 128 | targets = ( 129 | FA42F1221CAC744300AB959B /* ParasiteLoader */, 130 | ); 131 | }; 132 | /* End PBXProject section */ 133 | 134 | /* Begin PBXSourcesBuildPhase section */ 135 | FA42F11F1CAC744300AB959B /* Sources */ = { 136 | isa = PBXSourcesBuildPhase; 137 | buildActionMask = 2147483647; 138 | files = ( 139 | FAC096E61CB6F8170047496D /* runtime.c in Sources */, 140 | FA42F1321CAC777400AB959B /* loader.c in Sources */, 141 | FA42F12D1CAC747800AB959B /* main.c in Sources */, 142 | ); 143 | runOnlyForDeploymentPostprocessing = 0; 144 | }; 145 | /* End PBXSourcesBuildPhase section */ 146 | 147 | /* Begin XCBuildConfiguration section */ 148 | FA42F1251CAC744300AB959B /* Debug */ = { 149 | isa = XCBuildConfiguration; 150 | buildSettings = { 151 | ALWAYS_SEARCH_USER_PATHS = NO; 152 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 153 | CLANG_CXX_LIBRARY = "libc++"; 154 | CLANG_ENABLE_MODULES = YES; 155 | CLANG_ENABLE_OBJC_ARC = YES; 156 | CLANG_LINK_OBJC_RUNTIME = NO; 157 | CLANG_WARN_BOOL_CONVERSION = YES; 158 | CLANG_WARN_CONSTANT_CONVERSION = YES; 159 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 160 | CLANG_WARN_EMPTY_BODY = YES; 161 | CLANG_WARN_ENUM_CONVERSION = YES; 162 | CLANG_WARN_INT_CONVERSION = YES; 163 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 164 | CLANG_WARN_UNREACHABLE_CODE = YES; 165 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 166 | CODE_SIGN_IDENTITY = "-"; 167 | COPY_PHASE_STRIP = NO; 168 | DEBUG_INFORMATION_FORMAT = dwarf; 169 | DSTROOT = /tmp/ParasiteLoader.dst; 170 | ENABLE_STRICT_OBJC_MSGSEND = YES; 171 | ENABLE_TESTABILITY = YES; 172 | GCC_C_LANGUAGE_STANDARD = gnu99; 173 | GCC_DYNAMIC_NO_PIC = NO; 174 | GCC_NO_COMMON_BLOCKS = YES; 175 | GCC_OPTIMIZATION_LEVEL = 0; 176 | GCC_PREPROCESSOR_DEFINITIONS = ( 177 | "DEBUG=1", 178 | "$(inherited)", 179 | ); 180 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 181 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 182 | GCC_WARN_UNDECLARED_SELECTOR = YES; 183 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 184 | GCC_WARN_UNUSED_FUNCTION = YES; 185 | GCC_WARN_UNUSED_VARIABLE = YES; 186 | MACOSX_DEPLOYMENT_TARGET = 10.10; 187 | MTL_ENABLE_DEBUG_INFO = YES; 188 | ONLY_ACTIVE_ARCH = YES; 189 | SDKROOT = macosx; 190 | }; 191 | name = Debug; 192 | }; 193 | FA42F1261CAC744300AB959B /* Release */ = { 194 | isa = XCBuildConfiguration; 195 | buildSettings = { 196 | ALWAYS_SEARCH_USER_PATHS = NO; 197 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 198 | CLANG_CXX_LIBRARY = "libc++"; 199 | CLANG_ENABLE_MODULES = YES; 200 | CLANG_ENABLE_OBJC_ARC = YES; 201 | CLANG_LINK_OBJC_RUNTIME = NO; 202 | CLANG_WARN_BOOL_CONVERSION = YES; 203 | CLANG_WARN_CONSTANT_CONVERSION = YES; 204 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 205 | CLANG_WARN_EMPTY_BODY = YES; 206 | CLANG_WARN_ENUM_CONVERSION = YES; 207 | CLANG_WARN_INT_CONVERSION = YES; 208 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 209 | CLANG_WARN_UNREACHABLE_CODE = YES; 210 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 211 | CODE_SIGN_IDENTITY = "-"; 212 | COPY_PHASE_STRIP = NO; 213 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 214 | DEPLOYMENT_LOCATION = NO; 215 | DSTROOT = /tmp/ParasiteLoader.dst; 216 | ENABLE_NS_ASSERTIONS = NO; 217 | ENABLE_STRICT_OBJC_MSGSEND = YES; 218 | GCC_C_LANGUAGE_STANDARD = gnu99; 219 | GCC_NO_COMMON_BLOCKS = YES; 220 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 221 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 222 | GCC_WARN_UNDECLARED_SELECTOR = YES; 223 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 224 | GCC_WARN_UNUSED_FUNCTION = YES; 225 | GCC_WARN_UNUSED_VARIABLE = YES; 226 | MACOSX_DEPLOYMENT_TARGET = 10.10; 227 | MTL_ENABLE_DEBUG_INFO = NO; 228 | SDKROOT = macosx; 229 | }; 230 | name = Release; 231 | }; 232 | FA42F1281CAC744300AB959B /* Debug */ = { 233 | isa = XCBuildConfiguration; 234 | buildSettings = { 235 | COMBINE_HIDPI_IMAGES = YES; 236 | DYLIB_COMPATIBILITY_VERSION = 1; 237 | DYLIB_CURRENT_VERSION = 1; 238 | EXECUTABLE_PREFIX = ""; 239 | INSTALL_PATH = /Library/Extensions/Parasite.kext/Contents/Resources; 240 | OTHER_LDFLAGS = "-flat_namespace"; 241 | PRODUCT_NAME = "$(TARGET_NAME)"; 242 | }; 243 | name = Debug; 244 | }; 245 | FA42F1291CAC744300AB959B /* Release */ = { 246 | isa = XCBuildConfiguration; 247 | buildSettings = { 248 | COMBINE_HIDPI_IMAGES = YES; 249 | DYLIB_COMPATIBILITY_VERSION = 1; 250 | DYLIB_CURRENT_VERSION = 1; 251 | EXECUTABLE_PREFIX = ""; 252 | INSTALL_PATH = /Library/Extensions/Parasite.kext/Contents/Resources; 253 | OTHER_LDFLAGS = "-flat_namespace"; 254 | PRODUCT_NAME = "$(TARGET_NAME)"; 255 | }; 256 | name = Release; 257 | }; 258 | /* End XCBuildConfiguration section */ 259 | 260 | /* Begin XCConfigurationList section */ 261 | FA42F11E1CAC744300AB959B /* Build configuration list for PBXProject "ParasiteLoader" */ = { 262 | isa = XCConfigurationList; 263 | buildConfigurations = ( 264 | FA42F1251CAC744300AB959B /* Debug */, 265 | FA42F1261CAC744300AB959B /* Release */, 266 | ); 267 | defaultConfigurationIsVisible = 0; 268 | defaultConfigurationName = Release; 269 | }; 270 | FA42F1271CAC744300AB959B /* Build configuration list for PBXNativeTarget "ParasiteLoader" */ = { 271 | isa = XCConfigurationList; 272 | buildConfigurations = ( 273 | FA42F1281CAC744300AB959B /* Debug */, 274 | FA42F1291CAC744300AB959B /* Release */, 275 | ); 276 | defaultConfigurationIsVisible = 0; 277 | defaultConfigurationName = Release; 278 | }; 279 | /* End XCConfigurationList section */ 280 | }; 281 | rootObject = FA42F11B1CAC744300AB959B /* Project object */; 282 | } 283 | -------------------------------------------------------------------------------- /ParasiteLoader/loader.c: -------------------------------------------------------------------------------- 1 | // 2 | // loader.c 3 | // ParasiteLoader 4 | // 5 | // Created by Alexander Zielenski on 3/30/16. 6 | // Copyright © 2016 ParasiteTeam. All rights reserved. 7 | // 8 | 9 | #include "main.h" 10 | #include "loader.h" 11 | #include "runtime.h" 12 | 13 | static void *(*getClassObj)(void *) = NULL; 14 | static void *(*getClass)(const char *) = NULL; 15 | static void *(*registerName)(const char *) = NULL; 16 | static bool (*respondsToSelector)(void *, void *) = NULL; 17 | // Not worrying about casting this correctly 18 | // Since I only ever use it on + (void)install; 19 | // which is void (*)(id, SEL) 20 | static void (*msgSend)(void *, void *); 21 | 22 | void solve_symbols() { 23 | static dispatch_once_t onceToken; 24 | dispatch_once(&onceToken, ^{ 25 | getClass = dlsym(RTLD_DEFAULT, "objc_getClass"); 26 | getClassObj = dlsym(RTLD_DEFAULT, "object_getClass"); 27 | registerName = dlsym(RTLD_DEFAULT, "sel_registerName"); 28 | respondsToSelector = dlsym(RTLD_DEFAULT, "class_respondsToSelector"); 29 | msgSend = dlsym(RTLD_DEFAULT, "objc_msgSend"); 30 | }); 31 | } 32 | 33 | unsigned char commit_status(unsigned char orig, unsigned char new, bool match_all) { 34 | // Non-zero, non-one status means unavailable, so skip 35 | if (orig > 1) return new; 36 | if (new > 1) return orig; 37 | 38 | return (orig && new) || ((new || orig) && !match_all); 39 | } 40 | 41 | unsigned char check_cf_version(CFDictionaryRef filters) { 42 | CFArrayRef versionFilter = CFDictionaryGetValue(filters, kPSCoreFoundationVersionKey); 43 | 44 | if (versionFilter != NULL && CFGetTypeID(versionFilter) == CFArrayGetTypeID()) { 45 | CFIndex count = CFArrayGetCount(versionFilter); 46 | if (count > 2) { 47 | return false; 48 | } 49 | 50 | CFNumberRef number; 51 | double value; 52 | 53 | number = CFArrayGetValueAtIndex(versionFilter, 0); 54 | 55 | // get min version 56 | if (CFGetTypeID(number) != CFNumberGetTypeID() || !CFNumberGetValue(number, kCFNumberDoubleType, &value)) { 57 | return false; 58 | } 59 | 60 | // make sure the CF version is above min 61 | if (value > kCFCoreFoundationVersionNumber) 62 | return false; 63 | 64 | if (count != 1) { 65 | number = CFArrayGetValueAtIndex(versionFilter, 1); 66 | // Get max version 67 | if (CFGetTypeID(number) != CFNumberGetTypeID() || !CFNumberGetValue(number, kCFNumberDoubleType, &value)) { 68 | return false; 69 | } 70 | 71 | // make sure the CF version is below max 72 | if (value <= kCFCoreFoundationVersionNumber) 73 | return false; 74 | } 75 | } 76 | 77 | return 2; 78 | } 79 | 80 | unsigned char check_executable_name(CFDictionaryRef filters, CFStringRef executableName) { 81 | CFArrayRef executableFilter = CFDictionaryGetValue(filters, kPSExecutablesKey); 82 | 83 | if (executableFilter != NULL && CFGetTypeID(executableFilter) == CFArrayGetTypeID()) { 84 | for (CFIndex i = 0; i < CFArrayGetCount(executableFilter); i++) { 85 | CFStringRef name = CFArrayGetValueAtIndex(executableFilter, i); 86 | if (CFEqual(executableName, name)) { 87 | return true; 88 | } 89 | } 90 | } 91 | 92 | return 2; 93 | } 94 | 95 | unsigned char check_bundles(CFArrayRef bundlesFilter) { 96 | if (bundlesFilter != NULL && CFGetTypeID(bundlesFilter) == CFArrayGetTypeID()) { 97 | for (CFIndex i = 0; i < CFArrayGetCount(bundlesFilter); i++) { 98 | CFTypeRef entry = CFArrayGetValueAtIndex(bundlesFilter, i); 99 | 100 | if (CFGetTypeID(entry) == CFStringGetTypeID()) { 101 | CFStringRef bundleName = entry; 102 | CFBundleRef bndl = CFBundleGetBundleWithIdentifier(bundleName); 103 | if (bndl != NULL) { 104 | return true; 105 | } 106 | 107 | } else if (CFGetTypeID(entry) == CFDictionaryGetTypeID()) { 108 | CFDictionaryRef filter = entry; 109 | CFStringRef bundleName = CFDictionaryGetValue(filter, kPSBundleIdentifierKey); 110 | 111 | if (bundleName != NULL) { 112 | if (CFEqual(bundleName, CFSTR("*"))) { 113 | // * means we want to load into anything with a bundle 114 | // this is to keep this functionality on par with the behavior of SIMBL 115 | // which only loads into cocoa applications. 116 | // If you really want to load into every process I suggest you rethink 117 | // what you are doing. 118 | return CFBundleGetMainBundle() != NULL; 119 | } 120 | 121 | CFBundleRef bndl = CFBundleGetBundleWithIdentifier(bundleName); 122 | if (bndl == NULL) continue; 123 | 124 | CFNumberRef minNum = CFDictionaryGetValue(filter, kPSMinBundleVersionKey); 125 | CFNumberRef maxNum = CFDictionaryGetValue(filter, kPSMaxBundleVersionKey); 126 | 127 | CFDictionaryRef info = CFBundleGetInfoDictionary(bndl); 128 | CFTypeRef versionNum = CFDictionaryGetValue(info, kCFBundleVersionKey); 129 | 130 | int version; 131 | if (CFGetTypeID(versionNum) == CFStringGetTypeID()) { 132 | version = CFStringGetIntValue((CFStringRef)versionNum); 133 | 134 | } else if (CFGetTypeID(versionNum) == CFNumberGetTypeID()) { 135 | CFNumberGetValue(versionNum, kCFNumberIntType, &version); 136 | 137 | } else { 138 | // Can't read the version, not point in testing it 139 | return true; 140 | } 141 | 142 | if (minNum != NULL) { 143 | int min = 0; 144 | // Some people might put the number as a string instead of a number 145 | // help them with that 146 | if (CFGetTypeID(minNum) == CFStringGetTypeID()) { 147 | min = CFStringGetIntValue((CFStringRef)minNum); 148 | 149 | } else if (CFGetTypeID(minNum) == CFNumberGetTypeID()) { 150 | CFNumberGetValue(minNum, kCFNumberIntType, &min); 151 | } else { 152 | //!TODO log something 153 | continue; 154 | } 155 | 156 | if (min > version) continue; 157 | } 158 | 159 | if (maxNum != NULL) { 160 | int max = 0; 161 | 162 | if (CFGetTypeID(maxNum) == CFStringGetTypeID()) { 163 | max = CFStringGetIntValue((CFStringRef)maxNum); 164 | 165 | } else if (CFGetTypeID(maxNum) == CFNumberGetTypeID()) { 166 | CFNumberGetValue(maxNum, kCFNumberIntType, &max); 167 | } else { 168 | continue; 169 | } 170 | 171 | if (max < version) continue; 172 | } 173 | 174 | return true; 175 | } 176 | } 177 | } 178 | } 179 | 180 | return 2; 181 | } 182 | 183 | unsigned char check_classes(CFDictionaryRef filters) { 184 | CFArrayRef classesFilter = CFDictionaryGetValue(filters, kPSClassesKey); 185 | 186 | if (classesFilter != NULL && CFGetTypeID(classesFilter) == CFArrayGetTypeID()) { 187 | for (CFIndex i = 0; i < CFArrayGetCount(classesFilter); i++) { 188 | CFStringRef class = CFArrayGetValueAtIndex(classesFilter, i); 189 | solve_symbols(); 190 | 191 | if (getClass != NULL) { 192 | if (getClass(CFStringGetCStringPtr(class, kCFStringEncodingUTF8)) != NULL) { 193 | return true; 194 | } 195 | } 196 | } 197 | } 198 | 199 | return 2; 200 | } 201 | 202 | void load_simbl(CFBundleRef bundle) { 203 | // We need to somehow get a pointer to the principal class in this bundle and 204 | // call +install on it 205 | CFDictionaryRef info = CFBundleGetInfoDictionary(bundle); 206 | CFBundleLoadExecutable(bundle); 207 | 208 | solve_symbols(); 209 | 210 | // Could not solve symbols? 211 | if (getClass == NULL) return; 212 | 213 | // Some classes have a +install method that the SIMBL agent calls upon loading. 214 | // We should atleast make an attempt to call it 215 | CFStringRef principalClassName = CFDictionaryGetValue(info, CFSTR("NSPrincipalClass")); 216 | 217 | // want the metaclass of the principal class since install is a class method 218 | void *principalClass = getClassObj(getClass(CFStringGetCStringPtr(principalClassName, kCFStringEncodingUTF8))); 219 | void *install = registerName("install"); 220 | if (principalClass != NULL && respondsToSelector(principalClass, install)) { 221 | msgSend(principalClass, install); 222 | } 223 | } 224 | 225 | void __ParasiteProcessExtensions(CFURLRef libraries, CFBundleRef mainBundle, CFStringRef executableName) { 226 | if (libraries == NULL) 227 | return; 228 | 229 | CFBundleRef folder = CFBundleCreate(kCFAllocatorDefault, libraries); 230 | if (folder == NULL) return; 231 | 232 | CFArrayRef bundles = CFBundleCopyResourceURLsOfType(folder, CFSTR("bundle"), NULL); 233 | CFRelease(folder); 234 | if (bundles == NULL) return; 235 | 236 | CFMutableArrayRef shouldLoad = CFArrayCreateMutable(kCFAllocatorDefault, CFArrayGetCount(bundles), &kCFTypeArrayCallBacks); 237 | CFMutableArrayRef simblLoad = CFArrayCreateMutable(kCFAllocatorDefault, CFArrayGetCount(bundles), &kCFTypeArrayCallBacks); 238 | 239 | for (CFIndex i = 0; i < CFArrayGetCount(bundles); i++) { 240 | CFURLRef bundleURL = CFArrayGetValueAtIndex(bundles, i); 241 | CFBundleRef bundle = CFBundleCreate(kCFAllocatorDefault, bundleURL); 242 | if (bundle == NULL) { 243 | continue; 244 | } 245 | 246 | CFDictionaryRef info = CFBundleGetInfoDictionary(bundle); 247 | if (info == NULL || CFGetTypeID(info) != CFDictionaryGetTypeID()) { 248 | CFRelease(bundle); 249 | continue; 250 | } 251 | 252 | // By default try our filters, if it doesnt exist or is the wrong type 253 | // then we check for SIMBL filters 254 | CFDictionaryRef filters = CFDictionaryGetValue(info, kPSFiltersKey); 255 | 256 | // backwards support for OPFilters instead of PSFilters, they are 257 | // the same format, anyway 258 | if (filters == NULL || CFGetTypeID(filters) != CFDictionaryGetTypeID()) { 259 | filters = CFDictionaryGetValue(info, kOPFiltersKey); 260 | } 261 | 262 | if (filters == NULL || CFGetTypeID(filters) != CFDictionaryGetTypeID()) { 263 | if ((filters = CFDictionaryGetValue(info, kSIMBLFiltersKey)) != NULL && 264 | CFGetTypeID(filters) == CFArrayGetTypeID()) { 265 | // We have a SIMBL plugin, try to load it 266 | // we can safely load it here because unlike Parasite of Opee, SIMBL 267 | // bundle identifiers are specifically the application running rather than 268 | // a library that might be loaded. This is lucky because it saves me about 10 minutes 269 | // reformatting this function. 270 | if (check_bundles((CFArrayRef)filters)) { 271 | CFArrayAppendValue(simblLoad, bundle); 272 | } 273 | } 274 | 275 | } else { 276 | bool match_all = true; 277 | CFStringRef mode = CFDictionaryGetValue(filters, kPSModeKey); 278 | if (mode != NULL) { 279 | match_all = !CFEqual(mode, kPSAnyValue); 280 | } 281 | 282 | unsigned char status = 2; 283 | status = commit_status(status, check_cf_version(filters), match_all); 284 | 285 | status = commit_status(status, check_executable_name(filters, executableName), match_all); 286 | 287 | status = commit_status(status, check_bundles(CFDictionaryGetValue(filters, kPSBundlesKey)), match_all); 288 | status = commit_status(status, check_classes(filters), match_all); 289 | 290 | if (status == 1) { 291 | CFURLRef executableURL = CFBundleCopyExecutableURL(bundle); 292 | if (executableURL != NULL) { 293 | CFArrayAppendValue(shouldLoad, executableURL); 294 | CFRelease(executableURL); 295 | } 296 | } 297 | } 298 | 299 | 300 | CFRelease(bundle); 301 | } 302 | 303 | CFIndex total = CFArrayGetCount(shouldLoad) + CFArrayGetCount(simblLoad); 304 | 305 | for (CFIndex i = 0; i < CFArrayGetCount(shouldLoad); i++) { 306 | CFURLRef executableURL = CFArrayGetValueAtIndex(shouldLoad, i); 307 | const char executablePath[PATH_MAX]; 308 | CFURLGetFileSystemRepresentation(executableURL, true, (UInt8*)&executablePath, PATH_MAX); 309 | 310 | // load the dylib 311 | // CFBundleLoad doesn't use the correct dlopen flags 312 | void *handle = dlopen(executablePath, RTLD_LAZY | RTLD_GLOBAL); 313 | if (handle == NULL) { 314 | OPLog(OPLogLevelError, "%s", dlerror()); 315 | } 316 | 317 | PSNotify(executableURL, i, total); 318 | } 319 | 320 | for (CFIndex i = 0; i < CFArrayGetCount(simblLoad); i++) { 321 | CFBundleRef bndl = (CFBundleRef)CFArrayGetValueAtIndex(simblLoad, i); 322 | if (CFGetTypeID(bndl) == CFBundleGetTypeID()) 323 | load_simbl(bndl); 324 | 325 | CFURLRef ex = CFBundleCopyExecutableURL(bndl); 326 | PSNotify(ex, i + CFArrayGetCount(shouldLoad), total); 327 | CFRelease(ex); 328 | } 329 | 330 | CFRelease(bundles); 331 | CFRelease(shouldLoad); 332 | CFRelease(simblLoad); 333 | } 334 | --------------------------------------------------------------------------------