├── .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 |
--------------------------------------------------------------------------------