1 | #include <mach-o/dyld.h> |
---|
2 | #include <syslog.h> |
---|
3 | #include <pthread.h> |
---|
4 | #include <CoreFoundation/CoreFoundation.h> |
---|
5 | #include "SCPatchPrivate.h" |
---|
6 | #include "SCPatchCommon.h" |
---|
7 | #include "SCPatchController.h" |
---|
8 | #include "mach_inject.h" |
---|
9 | |
---|
10 | typedef list<SCPatchRecord>::iterator SCPatchRecordIterator; |
---|
11 | |
---|
12 | //------------------------------------------------------------------------------------------------------------- |
---|
13 | mach_error_t SCmac_err_FromOSErr(OSErr err) { |
---|
14 | return err ? (err_mac|err) : err_none; |
---|
15 | } |
---|
16 | |
---|
17 | //------------------------------------------------------------------------------------------------------------- |
---|
18 | OSErr SCOSErrFrom_mac_err(mach_error_t error) { |
---|
19 | return (error & err_mac) ? (err_mac) : noErr; |
---|
20 | } |
---|
21 | |
---|
22 | //------------------------------------------------------------------------------------------------------------- |
---|
23 | #pragma mark - |
---|
24 | //------------------------------------------------------------------------------------------------------------- |
---|
25 | SCPatchController::SCPatchController() |
---|
26 | { |
---|
27 | mBundle = CFBundleGetMainBundle(); |
---|
28 | CFRetain(mBundle); |
---|
29 | |
---|
30 | mApplicationBundleIdentifier = CFBundleGetIdentifier(mBundle); |
---|
31 | CFRetain(mApplicationBundleIdentifier); |
---|
32 | } |
---|
33 | |
---|
34 | //------------------------------------------------------------------------------------------------------------- |
---|
35 | SCPatchController::SCPatchController(CFStringRef bundleIdentifier) |
---|
36 | { |
---|
37 | mBundle = CFBundleGetBundleWithIdentifier(bundleIdentifier); |
---|
38 | CFRetain(mBundle); |
---|
39 | |
---|
40 | mApplicationBundleIdentifier = bundleIdentifier; |
---|
41 | CFRetain(mApplicationBundleIdentifier); |
---|
42 | } |
---|
43 | |
---|
44 | //------------------------------------------------------------------------------------------------------------- |
---|
45 | SCPatchController::~SCPatchController(void) |
---|
46 | { |
---|
47 | if(mApplicationBundleIdentifier) |
---|
48 | CFRelease(mApplicationBundleIdentifier); |
---|
49 | |
---|
50 | if(mBundle) |
---|
51 | CFRelease(mBundle); |
---|
52 | } |
---|
53 | |
---|
54 | //------------------------------------------------------------------------------------------------------------- |
---|
55 | #pragma mark - |
---|
56 | //------------------------------------------------------------------------------------------------------------- |
---|
57 | void SCPatchController::AddPatch(CFStringRef bundleIdentifier, |
---|
58 | CFStringRef subPath, |
---|
59 | CFStringRef name) |
---|
60 | { |
---|
61 | SCPatchRecord patch(mBundle, bundleIdentifier, subPath, name); |
---|
62 | |
---|
63 | mPatchList.push_back(patch); |
---|
64 | } |
---|
65 | |
---|
66 | //------------------------------------------------------------------------------------------------------------- |
---|
67 | // Inject the patches into running applications and start watching app launches |
---|
68 | OSErr SCPatchController::InstallPatches(void) |
---|
69 | { |
---|
70 | OSErr procErr = noErr, err = noErr; |
---|
71 | EventTypeSpec appSpec[] = { { kEventClassApplication, kEventAppLaunched }, |
---|
72 | { kEventClassApplication, kEventAppTerminated } }; |
---|
73 | |
---|
74 | // Start listening for messages from patches |
---|
75 | SetMessageRetryInterval(0.1); // Try resending messages to patches every 1/10 second. |
---|
76 | SetMessageRetryLimit(600); // Give up after 60 seconds. |
---|
77 | |
---|
78 | if((err = StartListening(mApplicationBundleIdentifier, false, true)) != noErr) |
---|
79 | { |
---|
80 | printf("SCPC: controller could not open port for listening\n"); |
---|
81 | } |
---|
82 | |
---|
83 | if(err == noErr) |
---|
84 | { |
---|
85 | InstallApplicationEventHandler(NewEventHandlerUPP(ApplicationEventHandler), 2, appSpec, this, NULL); |
---|
86 | |
---|
87 | ProcessSerialNumber psn = { 0, kNoProcess }; |
---|
88 | |
---|
89 | while(!procErr) |
---|
90 | { |
---|
91 | if((procErr = GetNextProcess(&psn)) == noErr) |
---|
92 | { |
---|
93 | if(!IsProcessPatched(&psn)) |
---|
94 | { |
---|
95 | InstallPatchesInProcess(&psn); |
---|
96 | } |
---|
97 | else |
---|
98 | { |
---|
99 | ProcessInfoRec info; |
---|
100 | CFStringRef str; |
---|
101 | Str255 pStr; |
---|
102 | |
---|
103 | info.processInfoLength = sizeof(ProcessInfoRec); |
---|
104 | info.processName = pStr; |
---|
105 | info.processAppSpec = nil; |
---|
106 | |
---|
107 | if((err = GetProcessInformation(&psn, &info)) == noErr && |
---|
108 | (str = CFStringCreateWithPascalString(NULL, pStr, kCFStringEncodingMacRoman)) != NULL) |
---|
109 | { |
---|
110 | PatchNotification(&psn, info.processSignature, info.processType, str, info.processMode); |
---|
111 | CFRelease(str); |
---|
112 | } |
---|
113 | |
---|
114 | } |
---|
115 | } |
---|
116 | } |
---|
117 | } |
---|
118 | return err; |
---|
119 | } |
---|
120 | |
---|
121 | // Patch a single process (ignoring return value of ShouldPatchProcess) |
---|
122 | mach_error_t SCPatchController::PatchProcess(ProcessSerialNumber *psn) |
---|
123 | { |
---|
124 | return InstallPatchesInProcess(psn, true); |
---|
125 | } |
---|
126 | |
---|
127 | //------------------------------------------------------------------------------------------------------------- |
---|
128 | // Get info and keep tabs on patched processes |
---|
129 | Boolean SCPatchController::IsProcessPatched(ProcessSerialNumber *inPSN) |
---|
130 | { |
---|
131 | SCPatchRecordIterator iter; |
---|
132 | |
---|
133 | if(mPatchContextList.GetContext(inPSN)) |
---|
134 | { |
---|
135 | // fprintf(stderr, "Process patched (found context)\n"); |
---|
136 | return true; |
---|
137 | } |
---|
138 | |
---|
139 | for(iter = mPatchList.begin(); iter != mPatchList.end(); iter++) |
---|
140 | { |
---|
141 | OSErr err; |
---|
142 | |
---|
143 | err = SendPing(iter->GetIdentifier(), inPSN); |
---|
144 | |
---|
145 | // If we get a destPortErr, no one's listening on the desired port. |
---|
146 | // If we get noErr or noResponseErr, there's someone listening. |
---|
147 | if(err == noErr || err == noResponseErr) |
---|
148 | { |
---|
149 | pid_t pid; |
---|
150 | ProcessInfoRec info; |
---|
151 | Str255 pStr; |
---|
152 | |
---|
153 | info.processInfoLength = sizeof(ProcessInfoRec); |
---|
154 | info.processName = pStr; |
---|
155 | info.processAppSpec = nil; |
---|
156 | |
---|
157 | if((err = GetProcessInformation(inPSN, &info)) == noErr && |
---|
158 | (err = GetProcessPID(inPSN, &pid)) == noErr) |
---|
159 | { |
---|
160 | mPatchContextList.NewContext(inPSN, pid, info.processSignature); |
---|
161 | } |
---|
162 | // fprintf(stderr, "Process patched (ping succeeded)\n"); |
---|
163 | return true; |
---|
164 | } |
---|
165 | else |
---|
166 | { |
---|
167 | // fprintf(stderr, "Process not patched (ping failed)\n"); |
---|
168 | } |
---|
169 | } |
---|
170 | |
---|
171 | return false; |
---|
172 | } |
---|
173 | |
---|
174 | //------------------------------------------------------------------------------------------------------------- |
---|
175 | UInt32 SCPatchController::GetPatchFlags(ProcessSerialNumber *inPSN) |
---|
176 | { |
---|
177 | SCPatchContext *context = mPatchContextList.GetContext(inPSN); |
---|
178 | |
---|
179 | if(context) |
---|
180 | return context->flags; |
---|
181 | else |
---|
182 | return 0; |
---|
183 | } |
---|
184 | |
---|
185 | //------------------------------------------------------------------------------------------------------------- |
---|
186 | void SCPatchController::SetPatchFlags(ProcessSerialNumber *inPSN, UInt32 flags, UInt32 whichFlags) |
---|
187 | { |
---|
188 | SCPatchContext *context = mPatchContextList.GetContext(inPSN); |
---|
189 | |
---|
190 | if(context) |
---|
191 | context->flags = (context->flags & ~whichFlags) | flags; |
---|
192 | } |
---|
193 | |
---|
194 | //------------------------------------------------------------------------------------------------------------- |
---|
195 | OSErr SCPatchController::ForEachPatchedProcess(SCPatchIterationProc proc, void *data) |
---|
196 | { |
---|
197 | SCPatchContextIterator iter; |
---|
198 | OSErr err = noErr; |
---|
199 | |
---|
200 | for(iter = mPatchContextList.begin(); iter != mPatchContextList.end(); iter++) |
---|
201 | if((err = proc(&iter->second.psn, iter->second.creator, iter->second.flags, data)) != noErr) |
---|
202 | break; |
---|
203 | return err; |
---|
204 | } |
---|
205 | |
---|
206 | //------------------------------------------------------------------------------------------------------------- |
---|
207 | #pragma mark - |
---|
208 | //------------------------------------------------------------------------------------------------------------- |
---|
209 | OSErr SCPatchController::HandleMessage(const AppleEvent *theAE) |
---|
210 | { |
---|
211 | OSErr err = eventNotHandledErr; |
---|
212 | OSType eventClass, eventID; |
---|
213 | Size actualSize; |
---|
214 | DescType actualType; |
---|
215 | ProcessSerialNumber psn; |
---|
216 | |
---|
217 | if((err = AEGetAttributePtr(theAE, keyEventIDAttr, typeType, &actualType, &eventID, sizeof(OSType), &actualSize)) != noErr || |
---|
218 | (err = AEGetAttributePtr(theAE, keyEventClassAttr, typeType, &actualType, &eventClass, sizeof(OSType), &actualSize)) != noErr) |
---|
219 | { |
---|
220 | return err; |
---|
221 | } |
---|
222 | |
---|
223 | if(eventClass == kSCMessageClass && eventID == kSCPatchSuccess && |
---|
224 | (err = AEGetParamPtr(theAE, keyPSN, typeProcessSerialNumber, &actualType, &psn, sizeof(ProcessSerialNumber), &actualSize)) == noErr) |
---|
225 | { |
---|
226 | RecordPatchAndNotify(&psn, NULL); |
---|
227 | } |
---|
228 | |
---|
229 | // Return eventNotHandledErr even though we've done our |
---|
230 | // thing so that the subclass gets a chance at it too. |
---|
231 | return eventNotHandledErr; |
---|
232 | } |
---|
233 | |
---|
234 | //------------------------------------------------------------------------------------------------------------- |
---|
235 | pascal OSStatus SCPatchController::ApplicationEventHandler(EventHandlerCallRef handlerRef, |
---|
236 | EventRef event, void *userData) |
---|
237 | { |
---|
238 | #pragma unused (handlerRef) |
---|
239 | |
---|
240 | SCPatchController *self = (SCPatchController *)userData; |
---|
241 | UInt32 kind = GetEventKind(event); |
---|
242 | OSStatus err; |
---|
243 | ProcessSerialNumber psn; |
---|
244 | |
---|
245 | err = GetEventParameter(event, kEventParamProcessID, typeProcessSerialNumber, |
---|
246 | NULL, sizeof(ProcessSerialNumber), NULL, &psn); |
---|
247 | |
---|
248 | fprintf(stderr, "ApplicationEventHandler called\n"); |
---|
249 | if(err == noErr) |
---|
250 | { |
---|
251 | if(kind == kEventAppLaunched) |
---|
252 | { |
---|
253 | // fprintf(stderr, "SCPC: App launched\n"); |
---|
254 | if(!self->IsProcessPatched(&psn)) |
---|
255 | self->InstallPatchesInProcess(&psn); |
---|
256 | } |
---|
257 | else if(kind == kEventAppTerminated) |
---|
258 | { |
---|
259 | pid_t pid; |
---|
260 | ProcessInfoRec info; |
---|
261 | CFStringRef str; |
---|
262 | Str255 pStr; |
---|
263 | |
---|
264 | info.processInfoLength = sizeof(ProcessInfoRec); |
---|
265 | info.processName = pStr; |
---|
266 | info.processAppSpec = nil; |
---|
267 | |
---|
268 | if((err = GetProcessInformation(&psn, &info)) == noErr && |
---|
269 | (err = GetProcessPID(&psn, &pid)) == noErr && |
---|
270 | (str = CFStringCreateWithPascalString(NULL, pStr, kCFStringEncodingMacRoman)) != NULL) |
---|
271 | { |
---|
272 | self->UnpatchNotification(&psn, info.processSignature, info.processType, str, info.processMode); |
---|
273 | CFRelease(str); |
---|
274 | } |
---|
275 | // fprintf(stderr, "SCPC: App died\n"); |
---|
276 | self->mPatchContextList.DeleteContext(&psn); |
---|
277 | } |
---|
278 | } |
---|
279 | |
---|
280 | // Always pass the event down |
---|
281 | return eventNotHandledErr; |
---|
282 | } |
---|
283 | |
---|
284 | //------------------------------------------------------------------------------------------------------------- |
---|
285 | mach_error_t SCPatchController::InstallPatchesInProcess(ProcessSerialNumber *psn, bool onDemand) |
---|
286 | { |
---|
287 | SCPatchRecordIterator iter; |
---|
288 | pid_t pid; |
---|
289 | ProcessInfoRec info; |
---|
290 | CFStringRef str; |
---|
291 | Str255 pStr; |
---|
292 | OSErr err = noErr; |
---|
293 | mach_error_t error = err_none; |
---|
294 | SCPatchLoaderParams *params = NULL; |
---|
295 | |
---|
296 | info.processInfoLength = sizeof(ProcessInfoRec); |
---|
297 | info.processName = pStr; |
---|
298 | info.processAppSpec = nil; |
---|
299 | |
---|
300 | if((err = GetProcessInformation(psn, &info)) == noErr && |
---|
301 | (err = GetProcessPID(psn, &pid)) == noErr && |
---|
302 | (str = CFStringCreateWithPascalString(NULL, pStr, kCFStringEncodingMacRoman)) != NULL) |
---|
303 | { |
---|
304 | // fprintf(stderr, "SCPC: examining application (sig = %.4s, type = %.4s, flags = 0x%x, name = %s)\n", |
---|
305 | // &info.processSignature, &info.processType, info.processMode, |
---|
306 | // CFStringGetCStringPtr(str, kCFStringEncodingMacRoman)); |
---|
307 | |
---|
308 | if((onDemand || |
---|
309 | ShouldPatchProcess(psn, info.processSignature, info.processType, str, info.processMode)) && |
---|
310 | (params = (SCPatchLoaderParams *)malloc(sizeof(SCPatchLoaderParams))) != NULL) |
---|
311 | { |
---|
312 | // fprintf(stderr, "SCPC: patching application (sig = %.4s, type = %.4s, flags = 0x%x, name = %s)\n", |
---|
313 | // &info.processSignature, &info.processType, info.processMode, |
---|
314 | // CFStringGetCStringPtr(str, kCFStringEncodingMacRoman)); |
---|
315 | |
---|
316 | params->version = 1; |
---|
317 | params->size = sizeof(SCPatchLoaderParams); |
---|
318 | params->patchCount = 0; |
---|
319 | |
---|
320 | for(iter = mPatchList.begin(); iter != mPatchList.end() && err == noErr; iter++) |
---|
321 | err = AddPatchToParams(iter->GetIdentifier(), iter->GetURL(), ¶ms); |
---|
322 | |
---|
323 | if(err == noErr) |
---|
324 | error = InjectPatches(psn, params); |
---|
325 | free(params); |
---|
326 | } |
---|
327 | CFRelease(str); |
---|
328 | } |
---|
329 | |
---|
330 | if (error != err_none) return error; |
---|
331 | else return mac_err(err); |
---|
332 | } |
---|
333 | |
---|
334 | //------------------------------------------------------------------------------------------------------------- |
---|
335 | OSErr SCPatchController::AddPatchToParams(CFStringRef bundleIdentifier, CFURLRef url, SCPatchLoaderParams **params) |
---|
336 | { |
---|
337 | OSErr err = err_couldnt_find_patch_bundle; |
---|
338 | CFStringRef patchPath = NULL; |
---|
339 | size_t newSize; |
---|
340 | |
---|
341 | if(bundleIdentifier == NULL || url == NULL || params == NULL) |
---|
342 | return paramErr; |
---|
343 | |
---|
344 | #if 0 |
---|
345 | if((patchPath = CFURLGetString(url)) != NULL) |
---|
346 | err = noErr; |
---|
347 | #else |
---|
348 | CFBundleRef patchBundle; |
---|
349 | CFURLRef patchURL; |
---|
350 | |
---|
351 | // Find out where the patch lives |
---|
352 | if((patchBundle = CFBundleCreate(kCFAllocatorDefault, url)) != NULL && |
---|
353 | (patchURL = CFBundleCopyExecutableURL(patchBundle)) != NULL) |
---|
354 | { |
---|
355 | CFURLRef absoluteURL; |
---|
356 | |
---|
357 | if((absoluteURL = CFURLCopyAbsoluteURL(patchURL)) != NULL) |
---|
358 | { |
---|
359 | CFRelease(patchURL); |
---|
360 | patchURL = absoluteURL; |
---|
361 | } |
---|
362 | |
---|
363 | if((patchPath = CFURLCopyFileSystemPath(patchURL, kCFURLPOSIXPathStyle)) != NULL) |
---|
364 | err = noErr; |
---|
365 | |
---|
366 | CFRelease(patchURL); |
---|
367 | CFRelease(patchBundle); |
---|
368 | } |
---|
369 | #endif |
---|
370 | |
---|
371 | // Increase the size of params. This allocation may have waste - CFStringGetLength * 2 is the max _possible_ size. |
---|
372 | if(!err) |
---|
373 | { |
---|
374 | newSize = (*params)->size + sizeof(SCPatchLoaderData) + CFStringGetLength(patchPath) * 2; |
---|
375 | |
---|
376 | if((*params = (SCPatchLoaderParams *)realloc(*params, newSize)) != NULL) |
---|
377 | (*params)->size = newSize; |
---|
378 | else |
---|
379 | err = ENOMEM; |
---|
380 | } |
---|
381 | |
---|
382 | // Fill in all the params |
---|
383 | if(!err) |
---|
384 | { |
---|
385 | HFSUniStr255 *bundleID = SCPatchGetHFSUniStrPointer(*params, (*params)->patchCount); |
---|
386 | char *urlData =SCPatchGetStringPointer(*params, (*params)->patchCount); |
---|
387 | |
---|
388 | if((bundleID->length = CFStringGetLength(bundleIdentifier)) > 256) |
---|
389 | { |
---|
390 | fprintf(stderr, "SCPC: patch bundleIdentifier is too long. It must be 256 chars or less.\n"); |
---|
391 | err = err_couldnt_load_injection_bundle; |
---|
392 | } |
---|
393 | else |
---|
394 | { |
---|
395 | CFStringGetCharacters(bundleIdentifier, CFRangeMake(0, bundleID->length), bundleID->unicode); |
---|
396 | if(CFStringGetCString(patchPath, urlData, CFStringGetLength(patchPath) * 2, kCFStringEncodingUTF8)) |
---|
397 | (*params)->patchCount++; |
---|
398 | else |
---|
399 | err = err_couldnt_load_injection_bundle; |
---|
400 | } |
---|
401 | } |
---|
402 | #if 1 |
---|
403 | if(patchPath) |
---|
404 | CFRelease(patchPath); |
---|
405 | #endif |
---|
406 | |
---|
407 | return err; |
---|
408 | } |
---|
409 | |
---|
410 | //------------------------------------------------------------------------------------------------------------- |
---|
411 | mach_error_t SCPatchController::InjectPatches(ProcessSerialNumber *psn, SCPatchLoaderParams *params) |
---|
412 | { |
---|
413 | mach_error_t err = err_none; |
---|
414 | |
---|
415 | // Convert PSN to PID. |
---|
416 | pid_t pid; |
---|
417 | if(!err) |
---|
418 | err = mac_err(GetProcessPID(psn, &pid)); |
---|
419 | |
---|
420 | // Fill in all the params |
---|
421 | if(!err) |
---|
422 | { |
---|
423 | // Make copies of the bundle identifiers and set up other params |
---|
424 | if((params->parentBundleID.length = CFStringGetLength(mApplicationBundleIdentifier)) > 256) |
---|
425 | { |
---|
426 | fprintf(stderr, "SCPC: app bundleIdentifier is too long. It must be 256 chars or less.\n"); |
---|
427 | err = err_couldnt_load_injection_bundle; |
---|
428 | } |
---|
429 | else |
---|
430 | { |
---|
431 | params->parent = pid; |
---|
432 | CFStringGetCharacters(mApplicationBundleIdentifier, CFRangeMake(0, params->parentBundleID.length), params->parentBundleID.unicode); |
---|
433 | } |
---|
434 | } |
---|
435 | |
---|
436 | // Find the loader |
---|
437 | CFURLRef loaderURL = NULL; |
---|
438 | #if defined(__ppc__) || defined(__ppc64__) |
---|
439 | if(!err) |
---|
440 | if((loaderURL = CFBundleCopyResourceURL(mBundle, CFSTR("SCPatchLoader"), CFSTR("bundle"), NULL)) == NULL) |
---|
441 | err = err_couldnt_find_injection_bundle; |
---|
442 | #else |
---|
443 | if(!err) |
---|
444 | if((loaderURL = CFBundleCopyResourceURL(mBundle, CFSTR("SCPatchLoader-intel"), CFSTR("bundle"), NULL)) == NULL) |
---|
445 | err = err_couldnt_find_injection_bundle; |
---|
446 | #endif |
---|
447 | |
---|
448 | #if 0 |
---|
449 | // If we get "file not found", the user must have moved our application bundle. Try finding it |
---|
450 | // with Launch Services and going on that way. |
---|
451 | if(err == err_couldnt_load_injection_bundle) // REVISIT |
---|
452 | { |
---|
453 | CFURLRef appURL, patchURL; |
---|
454 | CFStringRef patchPath; |
---|
455 | |
---|
456 | if(LSFindApplicationForInfo(NULL, sApplicationBundleIdentifier, NULL, NULL, &appURL) == noErr) |
---|
457 | { |
---|
458 | if((patchURL = CFURLCreateCopyAppendingPathComponent(NULL, appURL, subPath, false)) != NULL && |
---|
459 | (patchPath = CFURLCopyFileSystemPath(patchURL, kCFURLPOSIXPathStyle)) != NULL) |
---|
460 | { |
---|
461 | err = PatchControllerLoadPatchForProcess(pid, bundleID, patchPath, true); |
---|
462 | CFRelease(patchPath); |
---|
463 | CFRelease(patchURL); |
---|
464 | } |
---|
465 | CFRelease(appURL); |
---|
466 | } |
---|
467 | } |
---|
468 | #endif |
---|
469 | |
---|
470 | // Create injection bundle instance. |
---|
471 | CFBundleRef injectionBundle = NULL; |
---|
472 | if(!err) |
---|
473 | if((injectionBundle = CFBundleCreate(kCFAllocatorDefault, loaderURL)) == NULL) |
---|
474 | err = err_couldnt_load_injection_bundle; |
---|
475 | |
---|
476 | // Load the thread code injection. |
---|
477 | void *injectionCode = NULL; |
---|
478 | if(!err) |
---|
479 | if((injectionCode = CFBundleGetFunctionPointerForName(injectionBundle, CFSTR(INJECT_ENTRY_SYMBOL))) == NULL) |
---|
480 | err = err_couldnt_find_injectedThread_symbol; |
---|
481 | |
---|
482 | // Inject the code. |
---|
483 | if(!err) |
---|
484 | { |
---|
485 | err = ::mach_inject((mach_inject_entry)injectionCode, params, params->size, pid, 0); |
---|
486 | } |
---|
487 | else |
---|
488 | { |
---|
489 | fprintf(stderr, "Patcher got error %d\n", err); |
---|
490 | } |
---|
491 | |
---|
492 | // Clean up. |
---|
493 | if(loaderURL) |
---|
494 | CFRelease(loaderURL); |
---|
495 | if(injectionBundle) |
---|
496 | CFRelease(injectionBundle); |
---|
497 | |
---|
498 | return err; |
---|
499 | } |
---|
500 | |
---|
501 | //------------------------------------------------------------------------------------------------------------- |
---|
502 | OSErr SCPatchController::RecordPatchAndNotify(ProcessSerialNumber *psn, ProcessInfoRec *info) |
---|
503 | { |
---|
504 | OSErr err = noErr; |
---|
505 | ProcessInfoRec localInfo; |
---|
506 | Str255 pStr; |
---|
507 | CFStringRef str; |
---|
508 | pid_t pid; |
---|
509 | |
---|
510 | // Make sure we haven't already added this process |
---|
511 | if(mPatchContextList.GetContext(psn)) |
---|
512 | return noErr; |
---|
513 | |
---|
514 | // If no info was given, get it ourselves |
---|
515 | if(!info) |
---|
516 | { |
---|
517 | info = &localInfo; |
---|
518 | info->processInfoLength = sizeof(ProcessInfoRec); |
---|
519 | info->processName = pStr; |
---|
520 | info->processAppSpec = nil; |
---|
521 | err = GetProcessInformation(psn, info); |
---|
522 | } |
---|
523 | |
---|
524 | // Now add it to our context list and let the subclass know |
---|
525 | if(err == noErr && (err = GetProcessPID(psn, &pid)) == noErr && |
---|
526 | (str = CFStringCreateWithPascalString(NULL, info->processName, kCFStringEncodingMacRoman)) != NULL) |
---|
527 | { |
---|
528 | mPatchContextList.NewContext(psn, pid, info->processSignature); |
---|
529 | PatchNotification(psn, info->processSignature, info->processType, str, info->processMode); |
---|
530 | CFRelease(str); |
---|
531 | } |
---|
532 | return err; |
---|
533 | } |
---|