|
#include <objc/runtime.h> |
|
|
|
@interface EBInjector : NSObject |
|
@end |
|
|
|
/* ------------------------------------------------------ */ |
|
|
|
@implementation EBInjector |
|
|
|
+ (void)replaceMethod: (SEL)selector inClass: (Class)class |
|
{ |
|
Method originalMethod = class_getInstanceMethod(class, selector); |
|
if (!originalMethod) return; |
|
Method newMethod = class_getInstanceMethod(self, selector); |
|
if (!newMethod) return; |
|
IMP newImp = method_getImplementation(newMethod); |
|
if (!class_addMethod(class, selector, newImp, method_getTypeEncoding(originalMethod))) { |
|
method_exchangeImplementations(originalMethod, newMethod); |
|
} |
|
} |
|
|
|
- (NSDirectoryEnumerator *)enumeratorAtURL: (NSURL *)url |
|
includingPropertiesForKeys: (NSArray *)keys |
|
options: (NSDirectoryEnumerationOptions)mask |
|
errorHandler: (BOOL (^)(NSURL *url, NSError *error))handler |
|
{ |
|
/* If we try to enumerate ./Contents/Frameworks directory then |
|
return an enumerator for ./Contents/MacOS. |
|
*/ |
|
CFURLRef private_frameworks_url = CFBundleCopyPrivateFrameworksURL(CFBundleGetMainBundle()); |
|
if ([[url path] isEqualToString: [(NSURL *)private_frameworks_url path]]) { |
|
NSString *path = [NSString stringWithFormat: |
|
@"%@/Contents/MacOS", [[NSBundle mainBundle] bundlePath]]; |
|
NSURL *executables_url = [NSURL fileURLWithPath: path]; |
|
return [self enumeratorAtURL: executables_url includingPropertiesForKeys: keys |
|
options: mask errorHandler: handler]; |
|
} else { |
|
/* The original implementation is stored in this class now */ |
|
EBInjector *foo = [[[EBInjector alloc] init] autorelease]; |
|
return [foo enumeratorAtURL: url includingPropertiesForKeys: keys |
|
options: mask errorHandler: handler]; |
|
} |
|
} |
|
|
|
/* |
|
* CMMainWindowController |
|
*/ |
|
- (void)applicationDidFinishLaunching |
|
{ |
|
/* Hide the «Unlock Full Version» button */ |
|
SEL unlockFullVersionButton_sel = NSSelectorFromString(@"unlockFullVersionButton"); |
|
if ([self respondsToSelector: unlockFullVersionButton_sel]) { |
|
[(NSButton *)[self performSelector: unlockFullVersionButton_sel] setHidden: YES]; |
|
} |
|
/* And make it unavailable for anybody */ |
|
[EBInjector replaceMethod: NSSelectorFromString(@"unlockFullVersionButton") |
|
inClass: NSClassFromString(@"CMMainWindowController")]; |
|
} |
|
- (id)unlockFullVersionButton |
|
{ |
|
return nil; |
|
} |
|
- (void)updateTrialSizeLeft: (id)size |
|
{ |
|
return; |
|
} |
|
- (void)scannerController: (id)controller shouldPauseCleaningForItemSize: (id)size |
|
{ |
|
return; |
|
} |
|
|
|
#define failme(x) do { if (!(x)) { goto end; }} while(0) |
|
|
|
- (void)initHardOperations |
|
{ |
|
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; |
|
|
|
Class nc_class = NSClassFromString(@"CMNotificationController"), |
|
growl_ab_class = NSClassFromString(@"GrowlApplicationBridge"), |
|
sys_info_class = NSClassFromString(@"CMSystemInfo"); |
|
|
|
SEL shared_instance_sel = NSSelectorFromString(@"sharedInstance"), |
|
set_growl_delegate_sel = NSSelectorFromString(@"setGrowlDelegate:"), |
|
preload_data_sel = NSSelectorFromString(@"preloadData"), |
|
init_schedulers_sel = NSSelectorFromString(@"initSchedulers"), |
|
app_controller_sel = NSSelectorFromString(@"applicationsController"), |
|
scan_sel = NSSelectorFromString(@"scan"); |
|
|
|
failme([nc_class respondsToSelector: shared_instance_sel]); |
|
failme([growl_ab_class respondsToSelector: set_growl_delegate_sel]); |
|
failme([sys_info_class respondsToSelector: shared_instance_sel]); |
|
failme([self respondsToSelector: init_schedulers_sel]); |
|
failme([self respondsToSelector: app_controller_sel]); |
|
|
|
/* |
|
CMNotificationController *notifier = [CMNotificationController sharedInstance]; |
|
[GrowlApplicationBridge setGrowlDelegate: notifier]; |
|
*/ |
|
id notification_center =[[nc_class performSelector: shared_instance_sel] retain]; |
|
[growl_ab_class performSelector: set_growl_delegate_sel |
|
withObject: notification_center]; |
|
[notification_center release]; |
|
|
|
/* |
|
CMSystemInfo *info = [[MSystemInfo sharedInstance]; |
|
[info preloadData]; |
|
*/ |
|
id cm_system_info = [[sys_info_class performSelector: shared_instance_sel] retain]; |
|
failme([cm_system_info respondsToSelector: preload_data_sel]); |
|
[cm_system_info performSelector: preload_data_sel]; |
|
[cm_system_info release]; |
|
|
|
/* |
|
[self initSchedulers]; |
|
CMApplicationController *controller = [self applicationsController]; |
|
[controller scan]; |
|
|
|
*/ |
|
[self performSelector: init_schedulers_sel]; |
|
id app_controller = [[self performSelector: app_controller_sel] retain]; |
|
failme([app_controller respondsToSelector: scan_sel]); |
|
[app_controller performSelector: scan_sel]; |
|
[app_controller release]; |
|
|
|
end: |
|
[pool drain]; |
|
} |
|
|
|
/* |
|
* CMActivationManager |
|
*/ |
|
|
|
- (void)showCleanActivationReminderIfNeedsWithContinueHandler: (void *)handler |
|
{ |
|
/* Really, we don't care about anything, so just call this handlers */ |
|
void (^myBlock)() = Block_copy(handler); |
|
myBlock(); |
|
Block_release(myBlock); |
|
} |
|
- (NSInteger)appActivationStatus |
|
{ |
|
NSInteger magic = 0x6d3; |
|
/* We can not be sure, that this value won't be read from the ivar directly */ |
|
object_setInstanceVariable(self, [@"_appActivationStatus" UTF8String], *(NSInteger **)&magic); |
|
return magic; |
|
} |
|
- (NSInteger)isAppActivated { return 0x1; } |
|
/* Just for fun; actually has no effect until you remove |
|
-appActivationStatus and -isAppActivated |
|
from |todo| dictionary in +load |
|
*/ |
|
- (NSUInteger)trialSizeLeft { return 0xffffffffffffffff; } |
|
|
|
/* |
|
* NSApplication |
|
*/ |
|
- (NSDictionary *)licenseUserInfo |
|
{ |
|
return @{ |
|
@"activation_date" : [NSDate dateWithString: @"2000-01-01 00:00:00 +0000"], |
|
@"expiration_date" : [NSDate dateWithString: @"2666-01-01 00:00:00 +0000"], |
|
@"activation_id" : @"(^^,)", |
|
@"expiration_version" : @"666" |
|
}; |
|
} |
|
|
|
|
|
+ (void)load |
|
{ |
|
NSDictionary *todo = @ { |
|
@"CMActivationManager" : @[@"isAppActivated", |
|
@"appActivationStatus", |
|
@"trialSizeLeft", |
|
@"showCleanActivationReminderIfNeedsWithContinueHandler:"], |
|
|
|
@"NSFileManager" : @[@"enumeratorAtURL:includingPropertiesForKeys:options:errorHandler:"], |
|
|
|
@"NSApplication" : @[@"licenseUserInfo"], |
|
|
|
@"CMMainWindowController": @[@"applicationDidFinishLaunching", |
|
@"scannerController:shouldPauseCleaningForItemSize:", |
|
@"updateTrialSizeLeft:", |
|
@"initHardOperations"] |
|
|
|
}; |
|
[todo enumerateKeysAndObjectsUsingBlock: ^(NSString *class_name, NSArray *selectors, BOOL *stop1) { |
|
[selectors enumerateObjectsUsingBlock: ^(NSString *selector_name, NSUInteger index, BOOL *stop2) { |
|
[self replaceMethod: NSSelectorFromString(selector_name) |
|
inClass: NSClassFromString(class_name)]; |
|
}]; |
|
}]; |
|
} |
|
|
|
@end |