/** * AppEnabler for nitoTV * * Makes it possible to load Applications from /var/mobile/Applications * * By Luca Todesco and Kevin Bradley * */ #import #import #include #import //#import "rocketbootstrap.h" //#import "AppSupport/CPDistributedMessagingCenter.h" #import "../PBReloadHelper.h" #import #import "AppSupport/CPDistributedMessagingCenter.h" @interface NSDistributedNotificationCenter : NSNotificationCenter + (id)defaultCenter; - (void)addObserver:(id)arg1 selector:(SEL)arg2 name:(id)arg3 object:(id)arg4; - (void)postNotificationName:(id)arg1 object:(id)arg2 userInfo:(id)arg3; @end @interface MessageHandler : NSObject -(void)runAppEnabler:(id)a; @end @implementation MessageHandler -(void)runAppEnabler:(id)a { //NSLog(@"#### for luck!"); [PBReloadHelper reloadApplications]; } @end %class LSContext %class FSNode /* Some fun magic happens in here. We hook _MobileInstallationEnumerateAllInstalledItemDictionaries in tvOS 10 and _MobileInstallationCopyInstalledAppsForLaunchServices in tvOS 9 to inject our "whitelist" of applications that is created during uicache process. */ //tvOS 10 function for _MobileInstallationEnumerateAllInstalledItemDictionaries id (*original_func)(uint64_t a, id b); //tvOS 9 function for _MobileInstallationCopyInstalledAppsForLaunchServices id (*original_func2)(uint64_t a); //hook for _MobileInstallationCopyInstalledAppsForLaunchServices id we_really_out_here_nine(uint64_t a) { /* in tvOS 9 this list is just one huge plist that we need to inject ourselves into the System key of. */ id retv = original_func2(a); //read the list created in uicache of apps to inject NSString* pth = @"/var/mobile/Library/Preferences/kjc.appenabler.state.plist"; NSArray* arr = [NSArray arrayWithContentsOfFile: pth]; if(!arr) return retv; NSLog(@"got apps to inject!!"); [retv autorelease]; retv = [retv mutableCopy]; NSLog(@"retv allKeys:%@", [(NSDictionary*)retv allKeys]); //get the System key of the installed plist id sysdb = retv[@"System"]; id pkp = retv[@"PluginKitPlugin"]; if(sysdb){ NSLog(@"injecting to system apps"); sysdb=[sysdb mutableCopy]; pkp=[pkp mutableCopy]; retv[@"System"] = sysdb; retv[@"PluginKitPlugin"] = pkp; for (NSDictionary* appb in arr) { NSString *appType = appb[@"ApplicationType"]; if (![appType isEqualToString:@"PluginKitPlugin"]) { NSLog(@"injecting %@", appb[@"CFBundleIdentifier"]); if (sysdb[appb[@"CFBundleIdentifier"]]) { NSLog(@"already present!! WTF??? overwriting.."); } //add current CFBundleIdentifier to System bundle sysdb[appb[@"CFBundleIdentifier"]] = appb; } else { //its a plugin NSLog(@"injecting %@", appb[@"CFBundleIdentifier"]); if (pkp[appb[@"CFBundleIdentifier"]]) { NSLog(@"already present!! WTF??? overwriting.."); } //add current CFBundleIdentifier to System bundle pkp[appb[@"CFBundleIdentifier"]] = appb; } } } //NSLog(@"return: %@",retv); //at this point we've injected our bundle ids into the System list/ //from here, some other process adds the entry to PBAppDepot for us! :) return retv; } //hook for _MobileInstallationEnumerateAllInstalledItemDictionaries id we_really_out_here(uint64_t a, uint64_t (^block)(id b1, uint64_t b2, uint64_t b3)) { //NSLog(@"Stack trace : %@",[NSThread callStackSymbols]); //define the return block uint64_t (^blockz)(id b1, uint64_t b2, uint64_t b3) = ^(id b1, uint64_t b2, uint64_t b3){ //NSLog(@"called!!! %@ %llx %llx", b1, b2, b3); return block(b1, b2, b3); }; //load our whitelist that is created in uicache NSString* pth = @"/var/mobile/Library/Preferences/kjc.appenabler.state.plist"; NSArray* arr = [NSArray arrayWithContentsOfFile: pth]; //get original return value id retv = original_func(a, blockz); //NSLog(@"crack out of coke"); //loop through our apps an call the block to add the application to the list, //from here it will be added to PBAppDepot automatically, but in a disabled state. for (NSDictionary* appb in arr) { //blockz(@{@"ApplicationType": @"System", @"CFBundleIdentifier": appb[0], @"CodeInfoIdentifier": appb[0], @"Path": appb[1]},0,0); blockz(appb,0,0); } return retv; } %ctor { dlopen("/System/Library/PrivateFrameworks/MobileInstallation.framework/MobileInstallation", RTLD_LAZY); MSImageRef gangshit = MSGetImageByName("/System/Library/PrivateFrameworks/MobileInstallation.framework/MobileInstallation"); //tvos 10 symbol void* weouthere = MSFindSymbol(gangshit, "_MobileInstallationEnumerateAllInstalledItemDictionaries"); NSLog(@"tvOS 10 hooking %p", weouthere); if (weouthere) { MSHookFunction((void*)weouthere, (void*)we_really_out_here, (void**)&original_func); //void (*lolz)() = weouthere; //lolz(); } //tvos 9 symbol void* weouthere2 = MSFindSymbol(gangshit, "_MobileInstallationCopyInstalledAppsForLaunchServices"); NSLog(@"ios 9 hooking %p", weouthere2); if (weouthere2) { MSHookFunction((void*)weouthere2, (void*)we_really_out_here_nine, (void**)&original_func2); //void (*lolz)() = weouthere; //lolz(); } //NSLog(@"before note center"); NSDistributedNotificationCenter* notificationCenter = [NSDistributedNotificationCenter defaultCenter]; //NSLog(@"after note center"); [notificationCenter addObserver:[MessageHandler new] selector:@selector(runAppEnabler:) name:@"kjc.AppEnabler.recache" object:nil]; // NSLog(@"after observe"); }