123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369 |
- /*
- * uicache.m
- * nitoTV
- *
- * Based on asu_inject.c in AppSyncUnified
- * https://github.com/angelXwind/AppSync
- * http://cydia.angelxwind.net/?page/net.angelxwind.appsyncunified
- *
- * Copyright (c) 2014 Karen Tsai <angelXwind@angelxwind.net>
- *
- * AppSync Unified is NOT for piracy. Use it legally.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
- /*
-
- this is the main source of the uicache binary, it will inject librespring.dylib
- into PineBoard, register for some notifications and then fire off
- the distributed notification that gets received by librespring inside PineBoard.app
-
-
- */
- #include <dlfcn.h>
- #import <Foundation/Foundation.h>
- #include <mach-o/dyld.h>
- #import <objc/runtime.h>
- #include <sys/cdefs.h>
- #include <sys/types.h>
- #include <sys/param.h>
- #include <mach/mach.h>
- #include <mach/boolean.h>
- #include <dispatch/dispatch.h>
- #include <stdint.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <spawn.h>
- #include <assert.h>
- #import <objc/runtime.h>
- //#import "rocketbootstrap.h"
- #import "AppSupport/CPDistributedMessagingCenter.h"
- #import <MobileCoreServices/MobileCoreServices.h>
- #import "NSTask.h"
- #include <errno.h>
- #include <libgen.h>
- #include <string.h>
- #include <unistd.h>
- #include <getopt.h>
- @interface PBSSystemService : NSObject
- +(id)sharedInstance;
- -(void)endpointForProviderType:(id)arg1 withIdentifier:(id)arg2 responseBlock:(/*^block*/id)arg3 ;
- -(void)launchKioskApp;
- -(void)sleepSystemForReason:(id)arg1 ;
- -(void)wakeSystemForReason:(id)arg1 ;
- -(void)relaunchBackboardd;
- -(void)relaunch;
- -(void)reboot;
- -(id)infoForProvidersWithType:(id)arg1 ;
- -(void)deactivateApplication;
- -(void)registerServiceProviderEndpoint:(id)arg1 forProviderType:(id)arg2 ;
- -(void)deactivateScreenSaver;
- @end
- @interface LSApplicationWorkspace : NSObject
- + (id)defaultWorkspace;
- - (BOOL)_LSPrivateRebuildApplicationDatabasesForSystemApps:(BOOL)arg1 internal:(BOOL)arg2 user:(BOOL)arg3;
- - (BOOL)registerApplicationDictionary:(NSDictionary *)applicationDictionary;
- - (BOOL)registerBundleWithInfo:(NSDictionary *)bundleInfo options:(NSDictionary *)options type:(unsigned long long)arg3 progress:(id)arg4 ;
- - (BOOL)registerApplication:(NSURL *)url;
- - (BOOL)registerPlugin:(NSURL *)url;
- - (BOOL)unregisterApplication:(NSURL *)url;
- - (NSArray *)installedPlugins;
- -(void)_LSPrivateSyncWithMobileInstallation;
- @end
- #define DLog(format, ...) CFShow((__bridge CFStringRef)[NSString stringWithFormat:format, ## __VA_ARGS__]);
- extern char*** _NSGetEnviron(void);
- extern int proc_listallpids(void*, int);
- extern int proc_pidpath(int, void*, uint32_t);
- static const char* cynject_path = "/usr/bin/cynject";
- static const char* dylib_path = "/usr/lib/librespring.dylib";
- static const char* dispatch_queue_name = NULL;
- static const char* process_name = "PineBoard";
- static int process_buffer_size = 4096;
- static pid_t process_pid = -1;
- static boolean_t find_process(const char* name, pid_t* ppid_ret) {
- pid_t *pid_buffer;
- char path_buffer[MAXPATHLEN];
- int count, i, ret;
- boolean_t res = FALSE;
-
- pid_buffer = (pid_t*)calloc(1, process_buffer_size);
- assert(pid_buffer != NULL);
- count = proc_listallpids(pid_buffer, process_buffer_size);
- if(count) {
- for(i = 0; i < count; i++) {
- pid_t ppid = pid_buffer[i];
- ret = proc_pidpath(ppid, (void*)path_buffer, sizeof(path_buffer));
- if(ret < 0) {
- printf("(%s:%d) proc_pidinfo() call failed.\n", __FILE__, __LINE__);
- continue;
- }
- if(strstr(path_buffer, name)) {
- res = TRUE;
- *ppid_ret = ppid;
- break;
- }
- }
- }
- free(pid_buffer);
- return res;
- }
- /* Set platform binary flag */
- #define FLAG_PLATFORMIZE (1 << 1)
- void platformize_me() {
- void* handle = dlopen("/usr/lib/libjailbreak.dylib", RTLD_LAZY);
- if (!handle) return;
-
- // Reset errors
- dlerror();
- typedef void (*fix_entitle_prt_t)(pid_t pid, uint32_t what);
- fix_entitle_prt_t ptr = (fix_entitle_prt_t)dlsym(handle, "jb_oneshot_entitle_now");
-
- const char *dlsym_error = dlerror();
- if (dlsym_error) return;
-
- ptr(getpid(), FLAG_PLATFORMIZE);
- }
- static void inject_dylib(const char* name, pid_t pid, const char* dylib) {
- char** argv;
- char pid_buf[32];
- int res;
- pid_t child;
- argv = calloc(4, sizeof(char*));
- assert(argv != NULL);
- snprintf(pid_buf, sizeof(pid_buf), "%d", pid);
- argv[0] = (char*)name;
- argv[1] = (char*)pid_buf;
- argv[2] = (char*)dylib;
- argv[3] = NULL;
- printf("(%s:%d) calling \"%s %s %s\"\n", __FILE__, __LINE__, argv[0], argv[1], argv[2]);
- res = posix_spawn(&child, argv[0], NULL, NULL, argv, (char* const*)_NSGetEnviron());
- assert(res == 0);
- return;
- }
- @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)rebuildCache:(id)a;
- @end
- @implementation MessageHandler
- + (NSString *)returnForProcess:(NSString *)call
- {
- if (call==nil)
- return 0;
- char line[200];
- FILE* fp = popen([call UTF8String], "r");
- NSMutableArray *lines = [[NSMutableArray alloc]init];
- if (fp)
- {
- while (fgets(line, sizeof line, fp))
- {
- NSString *s = [NSString stringWithCString:line encoding:NSUTF8StringEncoding];
- s = [s stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
- [lines addObject:s];
- }
- }
- pclose(fp);
- return [lines componentsJoinedByString:@"\n"];
- }
- - (BOOL)forceReboot {
-
- NSString *command = @"/usr/bin/dpkg -s com.nito.nitotv4 | grep Version | cut -d \" \" -f2";
- int _returnCode = 0;
- BOOL _finished = FALSE;
- NSMutableArray *lines = [NSMutableArray new];
- char line[200];
-
- FILE* fp = popen([command UTF8String], "r");
-
- if (fp)
- {
- while (fgets(line, sizeof line, fp))
- {
- NSString *s = [NSString stringWithCString:line encoding:NSUTF8StringEncoding];
- s = [s stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
- [lines addObject:s];
- }
- }
-
- pclose(fp);
- BOOL reboot = FALSE;
- NSString *version = [lines lastObject];
-
- //DLog(@"nitoTV version: -%@-", version);
-
- NSString *minimumVersion = @"2.4-103";
-
- //DDLogInfo(@"package: '%@' online version: '%@' installed version: '%@'", objectName, onlineVersion, installedVersion);
- NSComparisonResult theResult = [minimumVersion compare:version options:NSNumericSearch];
-
- if ( theResult == NSOrderedDescending )
- {
- //DLog(@"minimum version %@ is less than installedVersion: %@", minimumVersion, version);
- reboot = true;
-
- }
-
- return reboot;
-
- }
- //called from PBReloadHelper in tvOS 9 circumstances so we can rebuild the cache with proper entitlements
- -(void)rebuildCache:(BOOL)reboot
- {
- DLog(@"Rebuilding cache...\n");
- LSApplicationWorkspace *workspace = [LSApplicationWorkspace defaultWorkspace];
- [workspace _LSClearSchemaCaches]; //may or may not be necessary
- [workspace _LSPrivateRebuildApplicationDatabasesForSystemApps:YES internal:YES user:NO];
-
- BOOL forceReboot = [self forceReboot];
-
- if (reboot || forceReboot){
- DLog(@"Respringing...\n");
- /*
- dlopen("/System/Library/PrivateFrameworks/PineBoardServices.framework/PineBoardServices", RTLD_NOW);
- id systemService = [objc_getClass("PBSSystemService") sharedInstance];
- DLog(@"system service: %@", systemService);
- [systemService relaunchBackboardd];
- */
- NSString *killallPath = [MessageHandler returnForProcess:@"/usr/bin/which killall"];
- NSTask *installTask = [NSTask launchedTaskWithLaunchPath:killallPath arguments:@[@"-9", @"backboardd"]];
-
- }
-
-
-
- }
- //called from PBReloadHelper in tvOS 10, just to close things up.
- -(void)donewithit:(id)a
- {
- DLog(@"Finished!\n");
- exit(0);
- }
- @end
- #define OPTION_FLAGS "r"
- char *progname;
- static struct option longopts[] = {
- { "reboot", no_argument, NULL, 'r' },
- { NULL, 0, NULL, 0 }
- };
- int main(int argc, char* argv[]) {
-
- platformize_me();
- printf("uicache for tvOS slim edition\n");
- bool reboot = false;
- int flag;
- // NSString *value = nil;
- while ((flag = getopt_long(argc, argv, OPTION_FLAGS, longopts, NULL)) != -1) {
- switch(flag) {
- case 'r':
- reboot = true;
- break;
- }
- }
-
- MessageHandler *mh = [MessageHandler new];
- [mh rebuildCache:reboot];
- return 0;
- //[[LSApplicationWorkspace defaultWorkspace] _LSPrivateRebuildApplicationDatabasesForSystemApps:YES internal:YES user:NO];
-
- /*
-
- printf("based on asu_inject from AppSyncUnified\n");
- printf("Creating queue...\n");
- dispatch_queue_t queue = dispatch_queue_create(dispatch_queue_name, 0);
- printf("Finding PineBoard PID...\n");
- dispatch_async(queue, ^{ while (!find_process(process_name, &process_pid)); });
- printf("Waiting for queue to come back...\n");
-
- */
-
- /* wait for queue to come back */
-
- /*
- dispatch_sync(queue, ^{});
- printf("PineBoard PID is %d\n", process_pid);
- printf("Injecting librespring.dylib into PineBoard...\n");
- inject_dylib(cynject_path, process_pid, dylib_path);
-
- sleep(1);
- */
- /*
- since we can only inject the library once, need to actually trigger the
- respring with some notifications, due to some restrictions with entitlements
- we need to start a runloop to receive some notifications back to do the actual
- database rebuilding.
-
- */
-
- NSDistributedNotificationCenter* notificationCenter;
- notificationCenter = [NSDistributedNotificationCenter defaultCenter];
- [notificationCenter addObserver:[MessageHandler new] selector:@selector(rebuildCache:) name:@"kjc.AppEnabler.rebuild_appdb" object:nil];
- [notificationCenter addObserver:[MessageHandler new] selector:@selector(donewithit:) name:@"kjc.AppEnabler.done" object:nil];
-
- [[NSDistributedNotificationCenter defaultCenter] postNotificationName:@"kjc.AppEnabler.recache" object:nil userInfo:nil];
- CFRunLoopRun();
- return 0;
- }
|