From 907d20416333ce7a16953cafc2b938a1758f2bee Mon Sep 17 00:00:00 2001 From: Sam Bingner Date: Wed, 23 Oct 2019 23:26:45 -1000 Subject: Update sbreload to avoid strange apple(?) bug --- data/uikittools/1_uicache.diff | 1170 ++++++++++++++++++++++++++++++++++++ data/uikittools/2_sbreload.diff | 43 ++ data/uikittools/_metadata/version | 2 +- data/uikittools/ldrestart-jbd.diff | 3 +- data/uikittools/uicache.diff | 1109 ---------------------------------- 5 files changed, 1216 insertions(+), 1111 deletions(-) create mode 100644 data/uikittools/1_uicache.diff create mode 100644 data/uikittools/2_sbreload.diff delete mode 100644 data/uikittools/uicache.diff diff --git a/data/uikittools/1_uicache.diff b/data/uikittools/1_uicache.diff new file mode 100644 index 000000000..8a01dd2e3 --- /dev/null +++ b/data/uikittools/1_uicache.diff @@ -0,0 +1,1170 @@ +diff -urN uikittools/sbreload.c uikittools+uicache/sbreload.c +--- uikittools/sbreload.c 2018-10-04 15:58:42.000000000 -1000 ++++ uikittools+uicache/sbreload.c 1969-12-31 14:00:00.000000000 -1000 +@@ -1,270 +0,0 @@ +-/* UIKit Tools - command-line utilities for UIKit +- * Copyright (C) 2008-2012 Jay Freeman (saurik) +-*/ +- +-/* Modified BSD License {{{ */ +-/* +- * Redistribution and use in source and binary +- * forms, with or without modification, are permitted +- * provided that the following conditions are met: +- * +- * 1. Redistributions of source code must retain the +- * above copyright notice, this list of conditions +- * and the following disclaimer. +- * 2. Redistributions in binary form must reproduce the +- * above copyright notice, this list of conditions +- * and the following disclaimer in the documentation +- * and/or other materials provided with the +- * distribution. +- * 3. The name of the author may not be used to endorse +- * or promote products derived from this software +- * without specific prior written permission. +- * +- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' +- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +- * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE +- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR +- * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +- * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +-*/ +-/* }}} */ +- +-#include +-#include +- +-#include +-#include +- +-#include +- +-/* Set platform binary flag */ +-#define FLAG_PLATFORMIZE (1 << 1) +-#include +- +-void platformizeme() { +- 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); +-} +- +-launch_data_t +-CF2launch_data(CFTypeRef cfr); +- +-void +-myCFDictionaryApplyFunction(const void *key, const void *value, void *context) +-{ +- launch_data_t ik, iw, where = context; +- +- ik = CF2launch_data(key); +- iw = CF2launch_data(value); +- +- launch_data_dict_insert(where, iw, launch_data_get_string(ik)); +- launch_data_free(ik); +-} +- +-launch_data_t +-CF2launch_data(CFTypeRef cfr) +-{ +- launch_data_t r; +- CFTypeID cft = CFGetTypeID(cfr); +- +- if (cft == CFStringGetTypeID()) { +- char buf[4096]; +- CFStringGetCString(cfr, buf, sizeof(buf), kCFStringEncodingUTF8); +- r = launch_data_alloc(LAUNCH_DATA_STRING); +- launch_data_set_string(r, buf); +- } else if (cft == CFBooleanGetTypeID()) { +- r = launch_data_alloc(LAUNCH_DATA_BOOL); +- launch_data_set_bool(r, CFBooleanGetValue(cfr)); +- } else if (cft == CFArrayGetTypeID()) { +- CFIndex i, ac = CFArrayGetCount(cfr); +- r = launch_data_alloc(LAUNCH_DATA_ARRAY); +- for (i = 0; i < ac; i++) { +- CFTypeRef v = CFArrayGetValueAtIndex(cfr, i); +- if (v) { +- launch_data_t iv = CF2launch_data(v); +- launch_data_array_set_index(r, iv, i); +- } +- } +- } else if (cft == CFDictionaryGetTypeID()) { +- r = launch_data_alloc(LAUNCH_DATA_DICTIONARY); +- CFDictionaryApplyFunction(cfr, myCFDictionaryApplyFunction, r); +- } else if (cft == CFDataGetTypeID()) { +- r = launch_data_alloc(LAUNCH_DATA_ARRAY); +- launch_data_set_opaque(r, CFDataGetBytePtr(cfr), CFDataGetLength(cfr)); +- } else if (cft == CFNumberGetTypeID()) { +- long long n; +- double d; +- CFNumberType cfnt = CFNumberGetType(cfr); +- switch (cfnt) { +- case kCFNumberSInt8Type: +- case kCFNumberSInt16Type: +- case kCFNumberSInt32Type: +- case kCFNumberSInt64Type: +- case kCFNumberCharType: +- case kCFNumberShortType: +- case kCFNumberIntType: +- case kCFNumberLongType: +- case kCFNumberLongLongType: +- CFNumberGetValue(cfr, kCFNumberLongLongType, &n); +- r = launch_data_alloc(LAUNCH_DATA_INTEGER); +- launch_data_set_integer(r, n); +- break; +- case kCFNumberFloat32Type: +- case kCFNumberFloat64Type: +- case kCFNumberFloatType: +- case kCFNumberDoubleType: +- CFNumberGetValue(cfr, kCFNumberDoubleType, &d); +- r = launch_data_alloc(LAUNCH_DATA_REAL); +- launch_data_set_real(r, d); +- break; +- default: +- r = NULL; +- break; +- } +- } else { +- r = NULL; +- } +- return r; +-} +- +-CFPropertyListRef +-CreateMyPropertyListFromFile(const char *posixfile) +-{ +- CFPropertyListRef propertyList; +- CFStringRef errorString; +- CFDataRef resourceData; +- SInt32 errorCode; +- CFURLRef fileURL; +- +- fileURL = CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault, (const UInt8 *)posixfile, strlen(posixfile), false); +- if (!fileURL) { +- fprintf(stderr, "%s: CFURLCreateFromFileSystemRepresentation(%s) failed\n", getprogname(), posixfile); +- } +- if (!CFURLCreateDataAndPropertiesFromResource(kCFAllocatorDefault, fileURL, &resourceData, NULL, NULL, &errorCode)) { +- fprintf(stderr, "%s: CFURLCreateDataAndPropertiesFromResource(%s) failed: %d\n", getprogname(), posixfile, (int)errorCode); +- } +- propertyList = CFPropertyListCreateFromXMLData(kCFAllocatorDefault, resourceData, kCFPropertyListMutableContainers, &errorString); +- if (!propertyList) { +- fprintf(stderr, "%s: propertyList is NULL\n", getprogname()); +- } +- +- return propertyList; +-} +- +-#define _assert(test, format, args...) do { \ +- if (test) break; \ +- fprintf(stderr, format "\n", ##args); \ +- return 1; \ +-} while (false) +- +-void stop() { +- sleep(1); +-} +- +-#define SpringBoard_plist "/System/Library/LaunchDaemons/com.apple.SpringBoard.plist" +- +-int main(int argc, const char *argv[]) { +- platformizeme(); +- _assert(argc == 1, "usage: sbreload"); +- +- CFDictionaryRef plist = CreateMyPropertyListFromFile(SpringBoard_plist); +- _assert(plist != NULL, "CreateMyPropertyListFromFile() == NULL"); +- +- launch_data_t job = CF2launch_data(plist); +- _assert(job != NULL, "CF2launch_data() == NULL"); +- +- launch_data_t data, request, response; +- +- data = launch_data_dict_lookup(job, LAUNCH_JOBKEY_LABEL); +- _assert(data != NULL, "launch_data_dict_lookup(LABEL) == NULL"); +- const char *label = launch_data_get_string(data); +- +- request = launch_data_alloc(LAUNCH_DATA_DICTIONARY); +- launch_data_dict_insert(request, launch_data_new_string(label), LAUNCH_KEY_GETJOB); +- +- response = launch_msg(request); +- _assert(response != NULL, "launch_msg(GetJob) == NULL"); +- launch_data_free(request); +- +- pid_t pid; +- +- if (launch_data_get_type(response) == LAUNCH_DATA_ERRNO) { +- int error = launch_data_get_errno(response); +- _assert(error == ESRCH, "GetJob(%s): %s", label, strerror(error)); +- pid = -1; +- } else if (launch_data_get_type(response) == LAUNCH_DATA_DICTIONARY) { +- data = launch_data_dict_lookup(response, LAUNCH_JOBKEY_PID); +- _assert(data != NULL, "launch_data_dict_lookup(PID) == NULL"); +- pid = launch_data_get_integer(data); +- } else _assert(false, "launch_data_get_type() not in (DICTIONARY, ERRNO)"); +- +- launch_data_free(response); +- +- // 600 is being used to approximate 4.x/5.x boundary +- if (kCFCoreFoundationVersionNumber < 600) { +- fprintf(stderr, "notify_post(com.apple.mobile.springboard_teardown)\n"); +- notify_post("com.apple.mobile.springboard_teardown"); +- } else { +- // XXX: this code is preferable to launchctl unoad but it requires libvproc? :( +- //vproc_err_t *error = _vproc_send_signal_by_label(label, VPROC_MAGIC_UNLOAD_SIGNAL); +- //_assert(error == NULL, "_vproc_send_signal_by_label(UNLOAD) != NULL"); +- +- fprintf(stderr, "launchctl unload SpringBoard.plist\n"); +- system("launchctl unload " SpringBoard_plist); +- } +- +- if (pid != -1) { +- fprintf(stderr, "waiting for kill(%u) != 0...\n", pid); +- while (kill(pid, 0) == 0) +- stop(); +- +- int error = errno; +- _assert(error == ESRCH, "kill(%u): %s", pid, strerror(error)); +- } +- +- request = launch_data_alloc(LAUNCH_DATA_DICTIONARY); +- launch_data_dict_insert(request, job, LAUNCH_KEY_SUBMITJOB); +- +- for (;;) { +- response = launch_msg(request); +- _assert(response != NULL, "launch_msg(SubmitJob) == NULL"); +- +- _assert(launch_data_get_type(response) == LAUNCH_DATA_ERRNO, "launch_data_get_type() != ERRNO"); +- int error = launch_data_get_errno(response); +- launch_data_free(response); +- +- const char *string = strerror(error); +- +- if (error == EEXIST) { +- fprintf(stderr, "SubmitJob(%s): %s, retrying...\n", label, string); +- stop(); +- } else { +- _assert(error == 0, "SubmitJob(%s): %s", label, string); +- break; +- } +- } +- +- launch_data_free(request); +- +- return 0; +-} +diff -urN uikittools/sbreload.m uikittools+uicache/sbreload.m +--- uikittools/sbreload.m 1969-12-31 14:00:00.000000000 -1000 ++++ uikittools+uicache/sbreload.m 2019-06-07 22:37:29.000000000 -1000 +@@ -0,0 +1,336 @@ ++/* UIKit Tools - command-line utilities for UIKit ++ * Copyright (C) 2008-2012 Jay Freeman (saurik) ++*/ ++ ++/* Modified BSD License {{{ */ ++/* ++ * Redistribution and use in source and binary ++ * forms, with or without modification, are permitted ++ * provided that the following conditions are met: ++ * ++ * 1. Redistributions of source code must retain the ++ * above copyright notice, this list of conditions ++ * and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the ++ * above copyright notice, this list of conditions ++ * and the following disclaimer in the documentation ++ * and/or other materials provided with the ++ * distribution. ++ * 3. The name of the author may not be used to endorse ++ * or promote products derived from this software ++ * without specific prior written permission. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' ++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, ++ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE ++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, ++ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT ++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR ++ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF ++ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR ++ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ++ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++*/ ++/* }}} */ ++ ++#include ++#include ++ ++#include ++#include ++ ++#include ++ ++/* Set platform binary flag */ ++#define FLAG_PLATFORMIZE (1 << 1) ++#include ++#include ++ ++@interface FBSSystemService +++(id)sharedService; ++-(void)sendActions:(NSSet*)actions withResult:(id)result; ++@end ++ ++typedef enum { ++ None = 0, ++ RestartRenderServer = (1 << 0), // also relaunch backboardd ++ SnapshotTransition = (1 << 1), ++ FadeToBlackTransition = (1 << 2), ++} SBSRelaunchActionStyle; ++ ++@interface SBSRelaunchAction +++(id)actionWithReason:(id)reason options:(int64_t)options targetURL:(NSURL*)url; ++@end ++ ++void platformizeme() { ++ 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); ++} ++ ++launch_data_t ++CF2launch_data(CFTypeRef cfr); ++ ++void ++myCFDictionaryApplyFunction(const void *key, const void *value, void *context) ++{ ++ launch_data_t ik, iw, where = context; ++ ++ ik = CF2launch_data(key); ++ iw = CF2launch_data(value); ++ ++ launch_data_dict_insert(where, iw, launch_data_get_string(ik)); ++ launch_data_free(ik); ++} ++ ++launch_data_t ++CF2launch_data(CFTypeRef cfr) ++{ ++ launch_data_t r; ++ CFTypeID cft = CFGetTypeID(cfr); ++ ++ if (cft == CFStringGetTypeID()) { ++ char buf[4096]; ++ CFStringGetCString(cfr, buf, sizeof(buf), kCFStringEncodingUTF8); ++ r = launch_data_alloc(LAUNCH_DATA_STRING); ++ launch_data_set_string(r, buf); ++ } else if (cft == CFBooleanGetTypeID()) { ++ r = launch_data_alloc(LAUNCH_DATA_BOOL); ++ launch_data_set_bool(r, CFBooleanGetValue(cfr)); ++ } else if (cft == CFArrayGetTypeID()) { ++ CFIndex i, ac = CFArrayGetCount(cfr); ++ r = launch_data_alloc(LAUNCH_DATA_ARRAY); ++ for (i = 0; i < ac; i++) { ++ CFTypeRef v = CFArrayGetValueAtIndex(cfr, i); ++ if (v) { ++ launch_data_t iv = CF2launch_data(v); ++ launch_data_array_set_index(r, iv, i); ++ } ++ } ++ } else if (cft == CFDictionaryGetTypeID()) { ++ r = launch_data_alloc(LAUNCH_DATA_DICTIONARY); ++ CFDictionaryApplyFunction(cfr, myCFDictionaryApplyFunction, r); ++ } else if (cft == CFDataGetTypeID()) { ++ r = launch_data_alloc(LAUNCH_DATA_ARRAY); ++ launch_data_set_opaque(r, CFDataGetBytePtr(cfr), CFDataGetLength(cfr)); ++ } else if (cft == CFNumberGetTypeID()) { ++ long long n; ++ double d; ++ CFNumberType cfnt = CFNumberGetType(cfr); ++ switch (cfnt) { ++ case kCFNumberSInt8Type: ++ case kCFNumberSInt16Type: ++ case kCFNumberSInt32Type: ++ case kCFNumberSInt64Type: ++ case kCFNumberCharType: ++ case kCFNumberShortType: ++ case kCFNumberIntType: ++ case kCFNumberLongType: ++ case kCFNumberLongLongType: ++ CFNumberGetValue(cfr, kCFNumberLongLongType, &n); ++ r = launch_data_alloc(LAUNCH_DATA_INTEGER); ++ launch_data_set_integer(r, n); ++ break; ++ case kCFNumberFloat32Type: ++ case kCFNumberFloat64Type: ++ case kCFNumberFloatType: ++ case kCFNumberDoubleType: ++ CFNumberGetValue(cfr, kCFNumberDoubleType, &d); ++ r = launch_data_alloc(LAUNCH_DATA_REAL); ++ launch_data_set_real(r, d); ++ break; ++ default: ++ r = NULL; ++ break; ++ } ++ } else { ++ r = NULL; ++ } ++ return r; ++} ++ ++CFPropertyListRef ++CreateMyPropertyListFromFile(const char *posixfile) ++{ ++ CFPropertyListRef propertyList; ++ CFStringRef errorString; ++ CFDataRef resourceData; ++ SInt32 errorCode; ++ CFURLRef fileURL; ++ ++ fileURL = CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault, (const UInt8 *)posixfile, strlen(posixfile), false); ++ if (!fileURL) { ++ fprintf(stderr, "%s: CFURLCreateFromFileSystemRepresentation(%s) failed\n", getprogname(), posixfile); ++ } ++ if (!CFURLCreateDataAndPropertiesFromResource(kCFAllocatorDefault, fileURL, &resourceData, NULL, NULL, &errorCode)) { ++ fprintf(stderr, "%s: CFURLCreateDataAndPropertiesFromResource(%s) failed: %d\n", getprogname(), posixfile, (int)errorCode); ++ } ++ propertyList = CFPropertyListCreateFromXMLData(kCFAllocatorDefault, resourceData, kCFPropertyListMutableContainers, &errorString); ++ if (!propertyList) { ++ fprintf(stderr, "%s: propertyList is NULL\n", getprogname()); ++ } ++ ++ return propertyList; ++} ++ ++#define _assert(test, format, args...) do { \ ++ if (test) break; \ ++ fprintf(stderr, format "\n", ##args); \ ++ return 1; \ ++} while (false) ++ ++void stop() { ++ sleep(1); ++} ++ ++#define SpringBoard_plist "/System/Library/LaunchDaemons/com.apple.SpringBoard.plist" ++ ++pid_t launch_get_job_pid(const char * job) ++{ ++ launch_data_t resp; ++ launch_data_t msg; ++ ++ msg = launch_data_alloc(LAUNCH_DATA_DICTIONARY); ++ if (msg == NULL) { ++ return -1; ++ } ++ ++ launch_data_dict_insert(msg, launch_data_new_string(job), LAUNCH_KEY_GETJOB); ++ ++ resp = launch_msg(msg); ++ launch_data_free(msg); ++ ++ if (resp == NULL) { ++ return -1; ++ } ++ ++ if (launch_data_get_type(resp) != LAUNCH_DATA_DICTIONARY) return -1; ++ ++ launch_data_t pid_data = launch_data_dict_lookup(resp, "PID"); ++ if (launch_data_get_type(pid_data) != LAUNCH_DATA_INTEGER) return -1; ++ ++ pid_t pid = (pid_t)launch_data_get_integer(pid_data); ++ launch_data_free(resp); ++ return pid; ++} ++ ++int main(int argc, const char *argv[]) { ++ platformizeme(); ++ _assert(argc == 1, "usage: sbreload"); ++ ++ if (kCFCoreFoundationVersionNumber >= 1443.00) { ++ dlopen("/System/Library/PrivateFrameworks/FrontBoardServices.framework/FrontBoardServices", RTLD_LAZY); ++ dlopen("/System/Library/PrivateFrameworks/SpringBoardServices.framework/SpringBoardServices", RTLD_LAZY); ++ Class $SBSRelaunchAction = objc_getClass("SBSRelaunchAction"); ++ Class $FBSSystemService = objc_getClass("FBSSystemService"); ++ pid_t sb_pid = launch_get_job_pid("com.apple.SpringBoard"); ++ if ($SBSRelaunchAction && $FBSSystemService) { ++ @autoreleasepool { ++ id action = [$SBSRelaunchAction actionWithReason:@"respring" options:RestartRenderServer targetURL:nil]; ++ id sharedService = [$FBSSystemService sharedService]; ++ [sharedService sendActions:[NSSet setWithObject:action] withResult:nil]; ++ for (int i=0; i<100; i++) { ++ if (kill(sb_pid, 0)) { ++ return 0; ++ } ++ usleep(1000); ++ } ++ } ++ } ++ } ++ CFDictionaryRef plist = CreateMyPropertyListFromFile(SpringBoard_plist); ++ _assert(plist != NULL, "CreateMyPropertyListFromFile() == NULL"); ++ ++ launch_data_t job = CF2launch_data(plist); ++ _assert(job != NULL, "CF2launch_data() == NULL"); ++ ++ launch_data_t data, request, response; ++ ++ data = launch_data_dict_lookup(job, LAUNCH_JOBKEY_LABEL); ++ _assert(data != NULL, "launch_data_dict_lookup(LABEL) == NULL"); ++ const char *label = launch_data_get_string(data); ++ ++ request = launch_data_alloc(LAUNCH_DATA_DICTIONARY); ++ launch_data_dict_insert(request, launch_data_new_string(label), LAUNCH_KEY_GETJOB); ++ ++ response = launch_msg(request); ++ _assert(response != NULL, "launch_msg(GetJob) == NULL"); ++ launch_data_free(request); ++ ++ pid_t pid; ++ ++ if (launch_data_get_type(response) == LAUNCH_DATA_ERRNO) { ++ int error = launch_data_get_errno(response); ++ _assert(error == ESRCH, "GetJob(%s): %s", label, strerror(error)); ++ pid = -1; ++ } else if (launch_data_get_type(response) == LAUNCH_DATA_DICTIONARY) { ++ data = launch_data_dict_lookup(response, LAUNCH_JOBKEY_PID); ++ _assert(data != NULL, "launch_data_dict_lookup(PID) == NULL"); ++ pid = launch_data_get_integer(data); ++ } else _assert(false, "launch_data_get_type() not in (DICTIONARY, ERRNO)"); ++ ++ launch_data_free(response); ++ ++ // 600 is being used to approximate 4.x/5.x boundary ++ if (kCFCoreFoundationVersionNumber < 600) { ++ fprintf(stderr, "notify_post(com.apple.mobile.springboard_teardown)\n"); ++ notify_post("com.apple.mobile.springboard_teardown"); ++ } else { ++ // XXX: this code is preferable to launchctl unoad but it requires libvproc? :( ++ //vproc_err_t *error = _vproc_send_signal_by_label(label, VPROC_MAGIC_UNLOAD_SIGNAL); ++ //_assert(error == NULL, "_vproc_send_signal_by_label(UNLOAD) != NULL"); ++ ++ fprintf(stderr, "launchctl unload SpringBoard.plist\n"); ++ system("launchctl unload " SpringBoard_plist); ++ } ++ ++ if (pid != -1) { ++ fprintf(stderr, "waiting for kill(%u) != 0...\n", pid); ++ while (kill(pid, 0) == 0) ++ stop(); ++ ++ int error = errno; ++ _assert(error == ESRCH, "kill(%u): %s", pid, strerror(error)); ++ } ++ ++ request = launch_data_alloc(LAUNCH_DATA_DICTIONARY); ++ launch_data_dict_insert(request, job, LAUNCH_KEY_SUBMITJOB); ++ ++ for (;;) { ++ response = launch_msg(request); ++ _assert(response != NULL, "launch_msg(SubmitJob) == NULL"); ++ ++ _assert(launch_data_get_type(response) == LAUNCH_DATA_ERRNO, "launch_data_get_type() != ERRNO"); ++ int error = launch_data_get_errno(response); ++ launch_data_free(response); ++ ++ const char *string = strerror(error); ++ ++ if (error == EEXIST) { ++ fprintf(stderr, "SubmitJob(%s): %s, retrying...\n", label, string); ++ stop(); ++ } else { ++ _assert(error == 0, "SubmitJob(%s): %s", label, string); ++ break; ++ } ++ } ++ ++ launch_data_free(request); ++ ++ return 0; ++} +diff -urN uikittools/sbreload.xml uikittools+uicache/sbreload.xml +--- uikittools/sbreload.xml 1969-12-31 14:00:00.000000000 -1000 ++++ uikittools+uicache/sbreload.xml 2019-06-07 22:37:29.000000000 -1000 +@@ -0,0 +1,13 @@ ++ ++ ++ ++ com.apple.frontboard.launchapplications ++ ++ com.apple.frontboard.shutdown ++ ++ platform-application ++ ++ com.apple.private.skip-library-validation ++ ++ ++ +diff -urN uikittools/uicache.mm uikittools+uicache/uicache.mm +--- uikittools/uicache.mm 2018-10-04 15:58:19.000000000 -1000 ++++ uikittools+uicache/uicache.mm 2019-06-07 22:37:39.000000000 -1000 +@@ -1,7 +1,17 @@ + /* UIKit Tools - command-line utilities for UIKit + * Copyright (C) 2008-2012 Jay Freeman (saurik) ++ * Portions Copyright (C) 2019 Sam Bingner + */ + ++/* uicache.mm ++ * ++ * Licensed under GPL v2.0 license as available at: ++ * https://www.gnu.org/licenses/gpl2.txt ++ * ++ * In adition, usage must meet the following ++ * Modified BSD terms: ++ */ ++ + /* Modified BSD License {{{ */ + /* + * Redistribution and use in source and binary +@@ -38,13 +48,16 @@ + /* }}} */ + + #import +- +-#include +-#include +-#include +-#include +- +-#include ++#import ++#import ++#import ++#import ++#import ++#import ++#import ++#import ++#import ++#import + + #include "csstore.hpp" + +@@ -81,6 +94,12 @@ + + @end + ++@interface LSApplicationProxy : NSObject ++- (NSString*) applicationIdentifier; ++- (NSURL*) resourcesDirectoryURL; ++- (NSDate*) registeredDate; ++@end ++ + @interface LSApplicationWorkspace : NSObject + + (id) defaultWorkspace; + - (BOOL) registerApplication:(id)application; +@@ -89,16 +108,188 @@ + - (BOOL) registerApplicationDictionary:(id)application; + - (BOOL) installApplication:(id)application withOptions:(id)options; + - (BOOL) _LSPrivateRebuildApplicationDatabasesForSystemApps:(BOOL)system internal:(BOOL)internal user:(BOOL)user; ++- (NSArray*) allApplications; ++@end ++ ++@interface MCMAppDataContainer +++(id)containerWithIdentifier:(NSString*)identifier createIfNecessary:(bool)create existed:(bool*)existed error:(NSError*)error; ++-(NSURL*)url; ++@end ++ ++@interface FBSSystemService +++(id)sharedService; ++-(void)sendActions:(NSSet*)actions withResult:(id)result; + @end + +-int main(int argc, const char *argv[]) { +- NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; ++typedef enum { ++ None = 0, ++ RestartRenderServer = (1 << 0), // also relaunch backboardd ++ SnapshotTransition = (1 << 1), ++ FadeToBlackTransition = (1 << 2), ++} SBSRelaunchActionStyle; ++ ++@interface SBSRelaunchAction +++(id)actionWithReason:(id)reason options:(int64_t)options targetURL:(NSURL*)url; ++@end ++ ++static int verbose=0; ++static int standard_uicache(void); ++static Class $MCMPluginKitPluginDataContainer; ++static Class $MCMAppDataContainer; ++static Class $LSApplicationWorkspace; ++LSApplicationWorkspace *workspace=nil; ++ ++NSString *getAppPath(NSString *path) ++{ ++ path = [path stringByResolvingSymlinksInPath]; ++ if (![path hasPrefix:@"/Applications/"]) { ++ fprintf(stderr, "Error: Path must be within /Applications/\n"); ++ return nil; ++ } ++ return [NSString pathWithComponents:[[path pathComponents] subarrayWithRange:NSMakeRange(0, 3)]]; ++} + +- Class $LSApplicationWorkspace(objc_getClass("LSApplicationWorkspace")); +- LSApplicationWorkspace *workspace($LSApplicationWorkspace == nil ? nil : [$LSApplicationWorkspace defaultWorkspace]); ++bool appIsRegistered(NSString *path) ++{ ++ @autoreleasepool { ++ path = getAppPath(path); ++ if (!path) return false; ++ for (LSApplicationProxy *app in [workspace allApplications]) { ++ if ([path isEqualToString:[[app resourcesDirectoryURL] path]]) return true; ++ } ++ return false; ++ } ++} + +- if (kCFCoreFoundationVersionNumber > 1000) // this API is on iOS 7 but invaliding the icon cache is harder there +- if ([workspace respondsToSelector:@selector(_LSPrivateRebuildApplicationDatabasesForSystemApps:internal:user:)]) { ++bool unregisterPath(NSString *path) ++{ ++ @autoreleasepool { ++ if (verbose) fprintf(stderr, "Unregistering %s\n", path.lastPathComponent.UTF8String); ++ path = getAppPath(path); ++ if (!path) return false; ++ if (appIsRegistered(path) && ![workspace unregisterApplication:[NSURL fileURLWithPath:path]]) { ++ fprintf(stderr, "Error: unregisterApplication failed for %s\n", path.lastPathComponent.UTF8String); ++ return false; ++ } ++ } ++ return true; ++} ++ ++// Credit to coolstar for finding how to do this and not sharing with the community thereby forcing me to figure out how to do the same thing. ++bool registerPath(NSString *path) ++{ ++ if (!path) { ++ if (verbose) fprintf(stderr, "registerPath called with no path\n"); ++ return false; ++ } ++ NSString *realPath = getAppPath(path); ++ if (!realPath) { ++ if (verbose) fprintf(stderr, "unable to determine path for %s\n", path.UTF8String); ++ return false; ++ } ++ NSDictionary *infoDictionary = [NSDictionary dictionaryWithContentsOfFile: ++ [realPath stringByAppendingPathComponent:@"Info.plist"]]; ++ NSString *bundleID = [infoDictionary objectForKey:@"CFBundleIdentifier"]; ++ ++ if (bundleID) { ++ NSFileManager *fm = [NSFileManager defaultManager]; ++ ++ if ([infoDictionary objectForKey:@"CFBundleExecutable"]) { ++ NSString *executable = [realPath stringByAppendingPathComponent:[infoDictionary objectForKey:@"CFBundleExecutable"]]; ++ if (![fm fileExistsAtPath:executable]) { ++ fprintf(stderr, "Error: CFBundleExecutable defined but missing for %s - this is a fatal error. Aborting.\n", realPath.lastPathComponent.UTF8String); ++ return false; ++ } ++ } ++ ++ NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithObjectsAndKeys: ++ @"System", @"ApplicationType", ++ @YES, @"BundleNameIsLocalized", ++ bundleID, @"CFBundleIdentifier", ++ @NO, @"CompatibilityState", ++ @NO, @"IsDeletable", ++ realPath, @"Path", ++ [NSMutableDictionary dictionary], @"_LSBundlePlugins", ++ nil]; ++ ++ id appContainer = [$MCMAppDataContainer containerWithIdentifier:bundleID ++ createIfNecessary:YES existed:NULL error:nil]; ++ ++ NSString *appContainerPath = [[appContainer url] path]; ++ if (appContainerPath) { ++ dict[@"Container"] = appContainerPath; ++ } ++ NSString *pluginsPath = [realPath stringByAppendingPathComponent:@"PlugIns"]; ++ for (NSString *plugin in [fm contentsOfDirectoryAtPath:pluginsPath error:nil]) { ++ NSString *pluginPath = [pluginsPath stringByAppendingPathComponent:plugin]; ++ NSString *pluginInfoPlistPath = [pluginPath stringByAppendingPathComponent:@"Info.plist"]; ++ NSString *pluginBundleIdentifier = [[NSDictionary dictionaryWithContentsOfFile:pluginInfoPlistPath] objectForKey:@"CFBundleIdentifier"]; ++ if (pluginBundleIdentifier) { ++ id pluginContainer = [$MCMPluginKitPluginDataContainer containerWithIdentifier:pluginBundleIdentifier ++ createIfNecessary:YES existed:NULL error:nil]; ++ NSURL *pluginContainerURL = [pluginContainer url]; ++ NSString *pluginContainerPath = [pluginContainerURL path]; ++ dict[@"_LSBundlePlugins"][pluginBundleIdentifier] = @{ ++ @"ApplicationType": @"PluginKitPlugin", ++ @"BundleNameIsLocalized": @YES, ++ @"CFBundleIdentifier": pluginBundleIdentifier, ++ @"CompatibilityState": @NO, ++ @"Container": pluginContainerPath, ++ @"Path": pluginPath, ++ @"PluginOwnerBundleID": bundleID ++ }; ++ } ++ } ++ if (![[$LSApplicationWorkspace defaultWorkspace] registerApplicationDictionary:dict]) { ++ fprintf(stderr, "Error: registerApplicationDictionary failed for %s\n", path.lastPathComponent.UTF8String); ++ return false; ++ } ++ } else { ++ return unregisterPath(realPath); ++ } ++ return true; ++} ++ ++void usage(void) ++{ ++ fprintf(stderr, "Usage: %s [-hrv] [[-p | -u] /Applications/App.app]]\n", getprogname()); ++ exit(EXIT_FAILURE); ++} ++ ++pid_t launch_get_job_pid(const char * job) ++{ ++ launch_data_t resp; ++ launch_data_t msg; ++ ++ msg = launch_data_alloc(LAUNCH_DATA_DICTIONARY); ++ if (msg == NULL) { ++ return -1; ++ } ++ ++ launch_data_dict_insert(msg, launch_data_new_string(job), LAUNCH_KEY_GETJOB); ++ ++ resp = launch_msg(msg); ++ launch_data_free(msg); ++ ++ if (resp == NULL) { ++ return -1; ++ } ++ ++ if (launch_data_get_type(resp) != LAUNCH_DATA_DICTIONARY) return -1; ++ ++ launch_data_t pid_data = launch_data_dict_lookup(resp, "PID"); ++ if (launch_data_get_type(pid_data) != LAUNCH_DATA_INTEGER) return -1; ++ ++ pid_t pid = (pid_t)launch_data_get_integer(pid_data); ++ launch_data_free(resp); ++ return pid; ++} ++ ++int standard_uicache(void) ++{ ++ @autoreleasepool { ++ if (kCFCoreFoundationVersionNumber > 1000 && // this API is on iOS 7 but invaliding the icon cache is harder there ++ [workspace respondsToSelector:@selector(_LSPrivateRebuildApplicationDatabasesForSystemApps:internal:user:)]) { + if (![workspace _LSPrivateRebuildApplicationDatabasesForSystemApps:YES internal:YES user:NO]) + fprintf(stderr, "failed to rebuild application databases"); + return 0; +@@ -226,12 +417,247 @@ + system("killall -SIGCONT SpringBoard"); + } + +- if (respring) +- system("launchctl stop com.apple.SpringBoard"); +- else +- notify_post("com.apple.mobile.application_installed"); +- +- [pool release]; ++ notify_post("com.apple.mobile.application_installed"); + + return 0; ++ } ++} ++ ++pid_t pidOfCydia(void) { ++ launch_data_t request = launch_data_new_string(LAUNCH_KEY_GETJOBS); ++ launch_data_t response = launch_msg(request); ++ launch_data_free(request); ++ __block pid_t pid=-1; ++ ++ if (response == NULL || launch_data_get_type(response) != LAUNCH_DATA_DICTIONARY) return -1; ++ ++ xpc_dictionary_apply((xpc_object_t)response, ^bool(const char *key, xpc_object_t value) { ++ if (xpc_get_type(value) == XPC_TYPE_DICTIONARY) { ++ const char *program = xpc_dictionary_get_string(value, "Program"); ++ if (program && strcmp(program, "/Applications/Cydia.app/Cydia") == 0) { ++ pid = (pid_t)xpc_dictionary_get_int64(value, "PID"); ++ if (verbose) fprintf(stderr, "Found Cydia running with PID: %d\n", pid); ++ return false; ++ } ++ } ++ return true; ++ }); ++ ++ if (pid>0) { ++ return pid; ++ } ++ return -1; ++} ++ ++int optimized_uicache(void) { ++ __block int rv=0; ++ NSMutableDictionary *registered = [NSMutableDictionary new]; ++ static void (^readHandler)(NSFileHandle*) = ^(NSFileHandle *fh) { ++ NSData *output = [fh readDataToEndOfFile]; ++ if (output.length==0) return; ++ const char *found_path = (const char *)[output bytes]; ++ NSArray *found = [@(found_path) pathComponents]; ++ if (found.count >= 3) { ++ NSString *appPath = [@"/Applications" stringByAppendingPathComponent:found[2]]; ++ @synchronized (registered) { ++ if (registered[appPath]) return; ++ if (verbose) fprintf(stderr, "Updating %s\n", appPath.lastPathComponent.UTF8String); ++ registered[appPath] = @YES; ++ } ++ pid_t cydia_pid; ++ if ([found[2] isEqualToString:@"Cydia.app"] && ++ (cydia_pid = pidOfCydia()) > 0) { ++ // We are in cydia and trying to refresh it - this will kill it. Let's schedule it for later. ++ if (verbose) fprintf(stderr, "Waiting to refresh Cydia...\n"); ++ pid_t pid = fork(); ++ if (pid == 0) { ++ setpgrp(); ++ signal(SIGHUP, SIG_IGN); ++ signal(SIGPIPE, SIG_IGN); ++ fclose(stdin); ++ freopen("/dev/null", "a", stderr); ++ freopen("/dev/null", "a", stdout); ++ pid = fork(); ++ if (pid == 0) { ++ while (kill(cydia_pid, 0)==0) { ++ sleep(1); ++ } ++ const char *uicache = (*_NSGetArgv())[0]; ++ execl(uicache, uicache, "-vvvvvvv", NULL); ++ fprintf(stderr, "Unable to exec\n"); ++ fflush(stderr); ++ exit(-1); ++ } ++ exit(0); ++ } else if (pid > 0) { ++ int stat; ++ waitpid(pid, &stat, 0); ++ return; ++ } else { ++ fprintf(stderr, "Unable to fork\n"); ++ } ++ } ++ if (!registerPath(appPath)) rv++; ++ } ++ }; ++ NSFileManager *fm = [NSFileManager defaultManager]; ++ NSMutableDictionary *apps = [NSMutableDictionary new]; ++ NSMutableArray *cleanup = [NSMutableArray new]; ++ NSMutableArray *finds = [NSMutableArray new]; ++ if (verbose>1) fprintf(stderr, "Enumerating apps\n"); ++ for (LSApplicationProxy *app in [workspace allApplications]) { ++ NSString *path = [[app resourcesDirectoryURL] path]; ++ if (![path hasPrefix:@"/Applications/"]) continue; ++ if (verbose>1) fprintf(stderr, "Checking %s\n", path.lastPathComponent.UTF8String); ++ ++ NSDate *lastRegistered = [app registeredDate]; ++ ++ if ([fm fileExistsAtPath:path]) { ++ // Check for updated components ++ NSTask *find = [NSTask new]; ++ [find setLaunchPath:@"/usr/bin/find"]; ++ [find setStandardOutput:[NSPipe pipe]]; ++ NSString *stampPath = [NSString stringWithFormat:@"/var/tmp/uicache.stamp.%@", app.applicationIdentifier]; ++ [fm createFileAtPath:stampPath contents:nil attributes:@{NSFileModificationDate: lastRegistered}]; ++ [cleanup addObject:stampPath]; ++ [find setArguments:@[ path, @"-newer", stampPath, @"-print0", @"-quit"]]; ++ [finds addObject:find]; ++ [find launch]; ++ apps[path.lastPathComponent] = app; ++ } else { ++ if (verbose) fprintf(stderr, "De-registering removed app: %s\n", path.lastPathComponent.UTF8String); ++ @synchronized (registered) { ++ if (registered[path]) continue; ++ registered[path] = @YES; ++ } ++ if (!unregisterPath(path)) rv++; ++ } ++ } ++ ++ for (NSString* existing in [[NSFileManager defaultManager] contentsOfDirectoryAtPath:@"/Applications" error:nil]) { ++ NSString *path = [@"/Applications" stringByAppendingPathComponent:existing]; ++ if (apps[existing] || registered[path] || ![existing hasSuffix:@".app"]) continue; ++ if (verbose) fprintf(stderr, "Registering new app: %s\n", existing.UTF8String); ++ @synchronized (registered) { ++ registered[path] = @YES; ++ } ++ if (!registerPath(path)) rv++; ++ } ++ for (NSTask *find in finds) { ++ if (verbose>2) fprintf(stderr, "waiting for find %s\n", [find.arguments componentsJoinedByString:@" "].UTF8String); ++ readHandler([find.standardOutput fileHandleForReading]); ++ [find waitUntilExit]; ++ } ++ for (NSString *path in cleanup) { ++ [fm removeItemAtPath:path error:nil]; ++ } ++ return rv; ++} ++ ++int main(int argc, const char *argv[]) ++{ ++ if (getuid() == 0) { ++ // Be mobile ++ if (setuid(501)) { ++ fprintf(stderr, "Error: unable to become mobile"); ++ return -1; ++ } ++ } ++ dlopen("/System/Library/PrivateFrameworks/MobileContainerManager.framework/MobileContainerManager", RTLD_LAZY); ++ dlopen("/System/Library/PrivateFrameworks/FrontBoardServices.framework/FrontBoardServices", RTLD_LAZY); ++ dlopen("/System/Library/PrivateFrameworks/SpringBoardServices.framework/SpringBoardServices", RTLD_LAZY); ++ Class $SBSRelaunchAction = objc_getClass("SBSRelaunchAction"); ++ Class $FBSSystemService = objc_getClass("FBSSystemService"); ++ $MCMPluginKitPluginDataContainer = objc_getClass("MCMPluginKitPluginDataContainer"); ++ $MCMAppDataContainer = objc_getClass("MCMAppDataContainer"); ++ $LSApplicationWorkspace = objc_getClass("LSApplicationWorkspace"); ++ workspace = [$LSApplicationWorkspace defaultWorkspace]; ++ ++ static int rv=0; ++ @autoreleasepool { ++ bool respring=false, do_all=false; ++ void (*jb_oneshot_entitle_now)(pid_t a, uint64_t b); ++ void *libjb = dlopen("/usr/lib/libjailbreak.dylib", RTLD_LAZY); ++ ++ if (libjb) { ++ dlerror(); ++ jb_oneshot_entitle_now = (void (*)(pid_t, uint64_t))dlsym(libjb, "jb_oneshot_entitle_now"); ++ if (!dlerror()) jb_oneshot_entitle_now(getpid(), 2); ++ } ++ ++ NSMutableDictionary *paths = [NSMutableDictionary new]; ++ NSMutableDictionary *unregister_paths = [NSMutableDictionary new]; ++ static struct option long_options[] = ++ { ++ {"all", no_argument, 0, 'a'}, ++ {"help", no_argument, 0, 'h'}, ++ {"path", required_argument, 0, 'p'}, ++ {"unregister", required_argument, 0, 'u'}, ++ {"respring", no_argument, 0, 'r'}, ++ {"verbose", no_argument, 0, 'v'}, ++ {0, 0, 0, 0} ++ }; ++ int option_index = 0; ++ char ch; ++ bool have_path = false; ++ while ((ch = getopt_long(argc, (char *const *)argv, "ap:ru:vh?", long_options, &option_index)) != -1) { ++ switch (ch) ++ { ++ case 'a': ++ do_all = true; ++ break; ++ case 'h': ++ usage(); ++ break; ++ case 'p': ++ paths[@(optarg)] = @YES; ++ have_path = true; ++ break; ++ case 'r': ++ respring = true; ++ break; ++ case 'u': ++ unregister_paths[@(optarg)] = @YES; ++ have_path = true; ++ break; ++ case 'v': ++ verbose++; ++ break; ++ default: ++ break; ++ } ++ } ++ if (do_all || !$MCMPluginKitPluginDataContainer || !$MCMAppDataContainer || !$LSApplicationWorkspace) { ++ rv = standard_uicache(); ++ } else if (have_path) { ++ for (NSString *path in [paths allKeys]) { ++ if (verbose) fprintf(stderr, "Refreshing %s\n", path.UTF8String); ++ if (!registerPath(path)) rv++; ++ } ++ for (NSString *path in [unregister_paths allKeys]) { ++ if (!unregisterPath(path)) rv++; ++ } ++ } else { ++ rv += optimized_uicache(); ++ } ++ if ( respring ) ++ { ++ pid_t sb_pid = launch_get_job_pid("com.apple.SpringBoard"); ++ if ($SBSRelaunchAction && $FBSSystemService) { ++ id action = [$SBSRelaunchAction actionWithReason:@"respring" options:RestartRenderServer targetURL:nil]; ++ id sharedService = [$FBSSystemService sharedService]; ++ [sharedService sendActions:[NSSet setWithObject:action] withResult:nil]; ++ for (int i=0; i<100; i++) { ++ if (kill(sb_pid, 0)) { ++ break; ++ } ++ usleep(1000); ++ } ++ } else { ++ system("launchctl stop com.apple.SpringBoard"); ++ system("launchctl stop com.apple.backboardd"); ++ } ++ } ++ } // @autoreleasepool ++ return rv; + } +diff -urN uikittools/uicache.xml uikittools+uicache/uicache.xml +--- uikittools/uicache.xml 2018-10-04 15:58:37.000000000 -1000 ++++ uikittools+uicache/uicache.xml 2019-06-07 22:37:29.000000000 -1000 +@@ -4,23 +4,22 @@ + com.apple.private.mobileinstall.allowedSPI + + InstallForLaunchServices ++ UninstallForLaunchServices + +- + com.apple.lsapplicationworkspace.rebuildappdatabases + +- + com.apple.private.MobileContainerManager.allowed + +- + com.apple.private.kernel.override-cpumon + +- + com.apple.vpn.installer_events + +- ++ com.apple.frontboard.launchapplications ++ ++ com.apple.frontboard.shutdown ++ + platform-application + +- + com.apple.private.skip-library-validation + + diff --git a/data/uikittools/2_sbreload.diff b/data/uikittools/2_sbreload.diff new file mode 100644 index 000000000..88dcd40f4 --- /dev/null +++ b/data/uikittools/2_sbreload.diff @@ -0,0 +1,43 @@ +diff --git a/sbreload.m b/sbreload.m +index e36134f..85b8e17 100644 +--- a/sbreload.m ++++ b/sbreload.m +@@ -49,6 +49,7 @@ + #define FLAG_PLATFORMIZE (1 << 1) + #include + #include ++#include + + @interface FBSSystemService + +(id)sharedService; +@@ -143,16 +144,26 @@ void platformizeme() { + case kCFNumberLongType: + case kCFNumberLongLongType: + CFNumberGetValue(cfr, kCFNumberLongLongType, &n); +- r = launch_data_alloc(LAUNCH_DATA_INTEGER); +- launch_data_set_integer(r, n); ++ if (kCFCoreFoundationVersionNumber >= 1443.00) { ++ r = (launch_data_t)xpc_int64_create(n); ++ } else { ++ // This hangs forever if I call it on new iOS??? ++ r = launch_data_alloc(LAUNCH_DATA_INTEGER); ++ launch_data_set_integer(r, n); ++ } + break; + case kCFNumberFloat32Type: + case kCFNumberFloat64Type: + case kCFNumberFloatType: + case kCFNumberDoubleType: + CFNumberGetValue(cfr, kCFNumberDoubleType, &d); +- r = launch_data_alloc(LAUNCH_DATA_REAL); +- launch_data_set_real(r, d); ++ if (kCFCoreFoundationVersionNumber >= 1443.00) { ++ r = (launch_data_t)xpc_double_create(d); ++ } else { ++ // Not sure if this hangs, but added to be safe ++ r = launch_data_alloc(LAUNCH_DATA_REAL); ++ launch_data_set_real(r, d); ++ } + break; + default: + r = NULL; diff --git a/data/uikittools/_metadata/version b/data/uikittools/_metadata/version index 9ea63dbcc..645377eea 100644 --- a/data/uikittools/_metadata/version +++ b/data/uikittools/_metadata/version @@ -1 +1 @@ -1.1.13 +1.1.15 diff --git a/data/uikittools/ldrestart-jbd.diff b/data/uikittools/ldrestart-jbd.diff index 43f66a693..014f7d5c1 100644 --- a/data/uikittools/ldrestart-jbd.diff +++ b/data/uikittools/ldrestart-jbd.diff @@ -2,7 +2,7 @@ diff --git a/ldrestart.cpp b/ldrestart.cpp index a6d6cb6..c9a3b33 100644 --- a/ldrestart.cpp +++ b/ldrestart.cpp -@@ -34,6 +34,30 @@ +@@ -34,6 +34,31 @@ #define FLAG_PLATFORMIZE (1 << 1) #include @@ -20,6 +20,7 @@ index a6d6cb6..c9a3b33 100644 + +const char *skip[] = { + "jailbreakd", ++ "science.xnu.substituted", + "com.saurik.substrated", + "com.apple.MobileFileIntegrity", + "com.openssh.sshd.", diff --git a/data/uikittools/uicache.diff b/data/uikittools/uicache.diff deleted file mode 100644 index 02828f4ed..000000000 --- a/data/uikittools/uicache.diff +++ /dev/null @@ -1,1109 +0,0 @@ -diff -urN uikittools/sbreload.c uikittools+uicache/sbreload.c ---- uikittools/sbreload.c 2018-10-04 15:58:42.000000000 -1000 -+++ uikittools+uicache/sbreload.c 1969-12-31 14:00:00.000000000 -1000 -@@ -1,270 +0,0 @@ --/* UIKit Tools - command-line utilities for UIKit -- * Copyright (C) 2008-2012 Jay Freeman (saurik) --*/ -- --/* Modified BSD License {{{ */ --/* -- * Redistribution and use in source and binary -- * forms, with or without modification, are permitted -- * provided that the following conditions are met: -- * -- * 1. Redistributions of source code must retain the -- * above copyright notice, this list of conditions -- * and the following disclaimer. -- * 2. Redistributions in binary form must reproduce the -- * above copyright notice, this list of conditions -- * and the following disclaimer in the documentation -- * and/or other materials provided with the -- * distribution. -- * 3. The name of the author may not be used to endorse -- * or promote products derived from this software -- * without specific prior written permission. -- * -- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' -- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, -- * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE -- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR -- * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -- * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF -- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. --*/ --/* }}} */ -- --#include --#include -- --#include --#include -- --#include -- --/* Set platform binary flag */ --#define FLAG_PLATFORMIZE (1 << 1) --#include -- --void platformizeme() { -- 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); --} -- --launch_data_t --CF2launch_data(CFTypeRef cfr); -- --void --myCFDictionaryApplyFunction(const void *key, const void *value, void *context) --{ -- launch_data_t ik, iw, where = context; -- -- ik = CF2launch_data(key); -- iw = CF2launch_data(value); -- -- launch_data_dict_insert(where, iw, launch_data_get_string(ik)); -- launch_data_free(ik); --} -- --launch_data_t --CF2launch_data(CFTypeRef cfr) --{ -- launch_data_t r; -- CFTypeID cft = CFGetTypeID(cfr); -- -- if (cft == CFStringGetTypeID()) { -- char buf[4096]; -- CFStringGetCString(cfr, buf, sizeof(buf), kCFStringEncodingUTF8); -- r = launch_data_alloc(LAUNCH_DATA_STRING); -- launch_data_set_string(r, buf); -- } else if (cft == CFBooleanGetTypeID()) { -- r = launch_data_alloc(LAUNCH_DATA_BOOL); -- launch_data_set_bool(r, CFBooleanGetValue(cfr)); -- } else if (cft == CFArrayGetTypeID()) { -- CFIndex i, ac = CFArrayGetCount(cfr); -- r = launch_data_alloc(LAUNCH_DATA_ARRAY); -- for (i = 0; i < ac; i++) { -- CFTypeRef v = CFArrayGetValueAtIndex(cfr, i); -- if (v) { -- launch_data_t iv = CF2launch_data(v); -- launch_data_array_set_index(r, iv, i); -- } -- } -- } else if (cft == CFDictionaryGetTypeID()) { -- r = launch_data_alloc(LAUNCH_DATA_DICTIONARY); -- CFDictionaryApplyFunction(cfr, myCFDictionaryApplyFunction, r); -- } else if (cft == CFDataGetTypeID()) { -- r = launch_data_alloc(LAUNCH_DATA_ARRAY); -- launch_data_set_opaque(r, CFDataGetBytePtr(cfr), CFDataGetLength(cfr)); -- } else if (cft == CFNumberGetTypeID()) { -- long long n; -- double d; -- CFNumberType cfnt = CFNumberGetType(cfr); -- switch (cfnt) { -- case kCFNumberSInt8Type: -- case kCFNumberSInt16Type: -- case kCFNumberSInt32Type: -- case kCFNumberSInt64Type: -- case kCFNumberCharType: -- case kCFNumberShortType: -- case kCFNumberIntType: -- case kCFNumberLongType: -- case kCFNumberLongLongType: -- CFNumberGetValue(cfr, kCFNumberLongLongType, &n); -- r = launch_data_alloc(LAUNCH_DATA_INTEGER); -- launch_data_set_integer(r, n); -- break; -- case kCFNumberFloat32Type: -- case kCFNumberFloat64Type: -- case kCFNumberFloatType: -- case kCFNumberDoubleType: -- CFNumberGetValue(cfr, kCFNumberDoubleType, &d); -- r = launch_data_alloc(LAUNCH_DATA_REAL); -- launch_data_set_real(r, d); -- break; -- default: -- r = NULL; -- break; -- } -- } else { -- r = NULL; -- } -- return r; --} -- --CFPropertyListRef --CreateMyPropertyListFromFile(const char *posixfile) --{ -- CFPropertyListRef propertyList; -- CFStringRef errorString; -- CFDataRef resourceData; -- SInt32 errorCode; -- CFURLRef fileURL; -- -- fileURL = CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault, (const UInt8 *)posixfile, strlen(posixfile), false); -- if (!fileURL) { -- fprintf(stderr, "%s: CFURLCreateFromFileSystemRepresentation(%s) failed\n", getprogname(), posixfile); -- } -- if (!CFURLCreateDataAndPropertiesFromResource(kCFAllocatorDefault, fileURL, &resourceData, NULL, NULL, &errorCode)) { -- fprintf(stderr, "%s: CFURLCreateDataAndPropertiesFromResource(%s) failed: %d\n", getprogname(), posixfile, (int)errorCode); -- } -- propertyList = CFPropertyListCreateFromXMLData(kCFAllocatorDefault, resourceData, kCFPropertyListMutableContainers, &errorString); -- if (!propertyList) { -- fprintf(stderr, "%s: propertyList is NULL\n", getprogname()); -- } -- -- return propertyList; --} -- --#define _assert(test, format, args...) do { \ -- if (test) break; \ -- fprintf(stderr, format "\n", ##args); \ -- return 1; \ --} while (false) -- --void stop() { -- sleep(1); --} -- --#define SpringBoard_plist "/System/Library/LaunchDaemons/com.apple.SpringBoard.plist" -- --int main(int argc, const char *argv[]) { -- platformizeme(); -- _assert(argc == 1, "usage: sbreload"); -- -- CFDictionaryRef plist = CreateMyPropertyListFromFile(SpringBoard_plist); -- _assert(plist != NULL, "CreateMyPropertyListFromFile() == NULL"); -- -- launch_data_t job = CF2launch_data(plist); -- _assert(job != NULL, "CF2launch_data() == NULL"); -- -- launch_data_t data, request, response; -- -- data = launch_data_dict_lookup(job, LAUNCH_JOBKEY_LABEL); -- _assert(data != NULL, "launch_data_dict_lookup(LABEL) == NULL"); -- const char *label = launch_data_get_string(data); -- -- request = launch_data_alloc(LAUNCH_DATA_DICTIONARY); -- launch_data_dict_insert(request, launch_data_new_string(label), LAUNCH_KEY_GETJOB); -- -- response = launch_msg(request); -- _assert(response != NULL, "launch_msg(GetJob) == NULL"); -- launch_data_free(request); -- -- pid_t pid; -- -- if (launch_data_get_type(response) == LAUNCH_DATA_ERRNO) { -- int error = launch_data_get_errno(response); -- _assert(error == ESRCH, "GetJob(%s): %s", label, strerror(error)); -- pid = -1; -- } else if (launch_data_get_type(response) == LAUNCH_DATA_DICTIONARY) { -- data = launch_data_dict_lookup(response, LAUNCH_JOBKEY_PID); -- _assert(data != NULL, "launch_data_dict_lookup(PID) == NULL"); -- pid = launch_data_get_integer(data); -- } else _assert(false, "launch_data_get_type() not in (DICTIONARY, ERRNO)"); -- -- launch_data_free(response); -- -- // 600 is being used to approximate 4.x/5.x boundary -- if (kCFCoreFoundationVersionNumber < 600) { -- fprintf(stderr, "notify_post(com.apple.mobile.springboard_teardown)\n"); -- notify_post("com.apple.mobile.springboard_teardown"); -- } else { -- // XXX: this code is preferable to launchctl unoad but it requires libvproc? :( -- //vproc_err_t *error = _vproc_send_signal_by_label(label, VPROC_MAGIC_UNLOAD_SIGNAL); -- //_assert(error == NULL, "_vproc_send_signal_by_label(UNLOAD) != NULL"); -- -- fprintf(stderr, "launchctl unload SpringBoard.plist\n"); -- system("launchctl unload " SpringBoard_plist); -- } -- -- if (pid != -1) { -- fprintf(stderr, "waiting for kill(%u) != 0...\n", pid); -- while (kill(pid, 0) == 0) -- stop(); -- -- int error = errno; -- _assert(error == ESRCH, "kill(%u): %s", pid, strerror(error)); -- } -- -- request = launch_data_alloc(LAUNCH_DATA_DICTIONARY); -- launch_data_dict_insert(request, job, LAUNCH_KEY_SUBMITJOB); -- -- for (;;) { -- response = launch_msg(request); -- _assert(response != NULL, "launch_msg(SubmitJob) == NULL"); -- -- _assert(launch_data_get_type(response) == LAUNCH_DATA_ERRNO, "launch_data_get_type() != ERRNO"); -- int error = launch_data_get_errno(response); -- launch_data_free(response); -- -- const char *string = strerror(error); -- -- if (error == EEXIST) { -- fprintf(stderr, "SubmitJob(%s): %s, retrying...\n", label, string); -- stop(); -- } else { -- _assert(error == 0, "SubmitJob(%s): %s", label, string); -- break; -- } -- } -- -- launch_data_free(request); -- -- return 0; --} -diff -urN uikittools/sbreload.m uikittools+uicache/sbreload.m ---- uikittools/sbreload.m 1969-12-31 14:00:00.000000000 -1000 -+++ uikittools+uicache/sbreload.m 2019-06-07 22:37:29.000000000 -1000 -@@ -0,0 +1,336 @@ -+/* UIKit Tools - command-line utilities for UIKit -+ * Copyright (C) 2008-2012 Jay Freeman (saurik) -+*/ -+ -+/* Modified BSD License {{{ */ -+/* -+ * Redistribution and use in source and binary -+ * forms, with or without modification, are permitted -+ * provided that the following conditions are met: -+ * -+ * 1. Redistributions of source code must retain the -+ * above copyright notice, this list of conditions -+ * and the following disclaimer. -+ * 2. Redistributions in binary form must reproduce the -+ * above copyright notice, this list of conditions -+ * and the following disclaimer in the documentation -+ * and/or other materials provided with the -+ * distribution. -+ * 3. The name of the author may not be used to endorse -+ * or promote products derived from this software -+ * without specific prior written permission. -+ * -+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' -+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, -+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE -+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR -+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF -+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -+*/ -+/* }}} */ -+ -+#include -+#include -+ -+#include -+#include -+ -+#include -+ -+/* Set platform binary flag */ -+#define FLAG_PLATFORMIZE (1 << 1) -+#include -+#include -+ -+@interface FBSSystemService -++(id)sharedService; -+-(void)sendActions:(NSSet*)actions withResult:(id)result; -+@end -+ -+typedef enum { -+ None = 0, -+ RestartRenderServer = (1 << 0), // also relaunch backboardd -+ SnapshotTransition = (1 << 1), -+ FadeToBlackTransition = (1 << 2), -+} SBSRelaunchActionStyle; -+ -+@interface SBSRelaunchAction -++(id)actionWithReason:(id)reason options:(int64_t)options targetURL:(NSURL*)url; -+@end -+ -+void platformizeme() { -+ 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); -+} -+ -+launch_data_t -+CF2launch_data(CFTypeRef cfr); -+ -+void -+myCFDictionaryApplyFunction(const void *key, const void *value, void *context) -+{ -+ launch_data_t ik, iw, where = context; -+ -+ ik = CF2launch_data(key); -+ iw = CF2launch_data(value); -+ -+ launch_data_dict_insert(where, iw, launch_data_get_string(ik)); -+ launch_data_free(ik); -+} -+ -+launch_data_t -+CF2launch_data(CFTypeRef cfr) -+{ -+ launch_data_t r; -+ CFTypeID cft = CFGetTypeID(cfr); -+ -+ if (cft == CFStringGetTypeID()) { -+ char buf[4096]; -+ CFStringGetCString(cfr, buf, sizeof(buf), kCFStringEncodingUTF8); -+ r = launch_data_alloc(LAUNCH_DATA_STRING); -+ launch_data_set_string(r, buf); -+ } else if (cft == CFBooleanGetTypeID()) { -+ r = launch_data_alloc(LAUNCH_DATA_BOOL); -+ launch_data_set_bool(r, CFBooleanGetValue(cfr)); -+ } else if (cft == CFArrayGetTypeID()) { -+ CFIndex i, ac = CFArrayGetCount(cfr); -+ r = launch_data_alloc(LAUNCH_DATA_ARRAY); -+ for (i = 0; i < ac; i++) { -+ CFTypeRef v = CFArrayGetValueAtIndex(cfr, i); -+ if (v) { -+ launch_data_t iv = CF2launch_data(v); -+ launch_data_array_set_index(r, iv, i); -+ } -+ } -+ } else if (cft == CFDictionaryGetTypeID()) { -+ r = launch_data_alloc(LAUNCH_DATA_DICTIONARY); -+ CFDictionaryApplyFunction(cfr, myCFDictionaryApplyFunction, r); -+ } else if (cft == CFDataGetTypeID()) { -+ r = launch_data_alloc(LAUNCH_DATA_ARRAY); -+ launch_data_set_opaque(r, CFDataGetBytePtr(cfr), CFDataGetLength(cfr)); -+ } else if (cft == CFNumberGetTypeID()) { -+ long long n; -+ double d; -+ CFNumberType cfnt = CFNumberGetType(cfr); -+ switch (cfnt) { -+ case kCFNumberSInt8Type: -+ case kCFNumberSInt16Type: -+ case kCFNumberSInt32Type: -+ case kCFNumberSInt64Type: -+ case kCFNumberCharType: -+ case kCFNumberShortType: -+ case kCFNumberIntType: -+ case kCFNumberLongType: -+ case kCFNumberLongLongType: -+ CFNumberGetValue(cfr, kCFNumberLongLongType, &n); -+ r = launch_data_alloc(LAUNCH_DATA_INTEGER); -+ launch_data_set_integer(r, n); -+ break; -+ case kCFNumberFloat32Type: -+ case kCFNumberFloat64Type: -+ case kCFNumberFloatType: -+ case kCFNumberDoubleType: -+ CFNumberGetValue(cfr, kCFNumberDoubleType, &d); -+ r = launch_data_alloc(LAUNCH_DATA_REAL); -+ launch_data_set_real(r, d); -+ break; -+ default: -+ r = NULL; -+ break; -+ } -+ } else { -+ r = NULL; -+ } -+ return r; -+} -+ -+CFPropertyListRef -+CreateMyPropertyListFromFile(const char *posixfile) -+{ -+ CFPropertyListRef propertyList; -+ CFStringRef errorString; -+ CFDataRef resourceData; -+ SInt32 errorCode; -+ CFURLRef fileURL; -+ -+ fileURL = CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault, (const UInt8 *)posixfile, strlen(posixfile), false); -+ if (!fileURL) { -+ fprintf(stderr, "%s: CFURLCreateFromFileSystemRepresentation(%s) failed\n", getprogname(), posixfile); -+ } -+ if (!CFURLCreateDataAndPropertiesFromResource(kCFAllocatorDefault, fileURL, &resourceData, NULL, NULL, &errorCode)) { -+ fprintf(stderr, "%s: CFURLCreateDataAndPropertiesFromResource(%s) failed: %d\n", getprogname(), posixfile, (int)errorCode); -+ } -+ propertyList = CFPropertyListCreateFromXMLData(kCFAllocatorDefault, resourceData, kCFPropertyListMutableContainers, &errorString); -+ if (!propertyList) { -+ fprintf(stderr, "%s: propertyList is NULL\n", getprogname()); -+ } -+ -+ return propertyList; -+} -+ -+#define _assert(test, format, args...) do { \ -+ if (test) break; \ -+ fprintf(stderr, format "\n", ##args); \ -+ return 1; \ -+} while (false) -+ -+void stop() { -+ sleep(1); -+} -+ -+#define SpringBoard_plist "/System/Library/LaunchDaemons/com.apple.SpringBoard.plist" -+ -+pid_t launch_get_job_pid(const char * job) -+{ -+ launch_data_t resp; -+ launch_data_t msg; -+ -+ msg = launch_data_alloc(LAUNCH_DATA_DICTIONARY); -+ if (msg == NULL) { -+ return -1; -+ } -+ -+ launch_data_dict_insert(msg, launch_data_new_string(job), LAUNCH_KEY_GETJOB); -+ -+ resp = launch_msg(msg); -+ launch_data_free(msg); -+ -+ if (resp == NULL) { -+ return -1; -+ } -+ -+ if (launch_data_get_type(resp) != LAUNCH_DATA_DICTIONARY) return -1; -+ -+ launch_data_t pid_data = launch_data_dict_lookup(resp, "PID"); -+ if (launch_data_get_type(pid_data) != LAUNCH_DATA_INTEGER) return -1; -+ -+ pid_t pid = (pid_t)launch_data_get_integer(pid_data); -+ launch_data_free(resp); -+ return pid; -+} -+ -+int main(int argc, const char *argv[]) { -+ platformizeme(); -+ _assert(argc == 1, "usage: sbreload"); -+ -+ if (kCFCoreFoundationVersionNumber >= 1443.00) { -+ dlopen("/System/Library/PrivateFrameworks/FrontBoardServices.framework/FrontBoardServices", RTLD_LAZY); -+ dlopen("/System/Library/PrivateFrameworks/SpringBoardServices.framework/SpringBoardServices", RTLD_LAZY); -+ Class $SBSRelaunchAction = objc_getClass("SBSRelaunchAction"); -+ Class $FBSSystemService = objc_getClass("FBSSystemService"); -+ pid_t sb_pid = launch_get_job_pid("com.apple.SpringBoard"); -+ if ($SBSRelaunchAction && $FBSSystemService) { -+ @autoreleasepool { -+ id action = [$SBSRelaunchAction actionWithReason:@"respring" options:RestartRenderServer targetURL:nil]; -+ id sharedService = [$FBSSystemService sharedService]; -+ [sharedService sendActions:[NSSet setWithObject:action] withResult:nil]; -+ for (int i=0; i<100; i++) { -+ if (kill(sb_pid, 0)) { -+ return 0; -+ } -+ usleep(1000); -+ } -+ } -+ } -+ } -+ CFDictionaryRef plist = CreateMyPropertyListFromFile(SpringBoard_plist); -+ _assert(plist != NULL, "CreateMyPropertyListFromFile() == NULL"); -+ -+ launch_data_t job = CF2launch_data(plist); -+ _assert(job != NULL, "CF2launch_data() == NULL"); -+ -+ launch_data_t data, request, response; -+ -+ data = launch_data_dict_lookup(job, LAUNCH_JOBKEY_LABEL); -+ _assert(data != NULL, "launch_data_dict_lookup(LABEL) == NULL"); -+ const char *label = launch_data_get_string(data); -+ -+ request = launch_data_alloc(LAUNCH_DATA_DICTIONARY); -+ launch_data_dict_insert(request, launch_data_new_string(label), LAUNCH_KEY_GETJOB); -+ -+ response = launch_msg(request); -+ _assert(response != NULL, "launch_msg(GetJob) == NULL"); -+ launch_data_free(request); -+ -+ pid_t pid; -+ -+ if (launch_data_get_type(response) == LAUNCH_DATA_ERRNO) { -+ int error = launch_data_get_errno(response); -+ _assert(error == ESRCH, "GetJob(%s): %s", label, strerror(error)); -+ pid = -1; -+ } else if (launch_data_get_type(response) == LAUNCH_DATA_DICTIONARY) { -+ data = launch_data_dict_lookup(response, LAUNCH_JOBKEY_PID); -+ _assert(data != NULL, "launch_data_dict_lookup(PID) == NULL"); -+ pid = launch_data_get_integer(data); -+ } else _assert(false, "launch_data_get_type() not in (DICTIONARY, ERRNO)"); -+ -+ launch_data_free(response); -+ -+ // 600 is being used to approximate 4.x/5.x boundary -+ if (kCFCoreFoundationVersionNumber < 600) { -+ fprintf(stderr, "notify_post(com.apple.mobile.springboard_teardown)\n"); -+ notify_post("com.apple.mobile.springboard_teardown"); -+ } else { -+ // XXX: this code is preferable to launchctl unoad but it requires libvproc? :( -+ //vproc_err_t *error = _vproc_send_signal_by_label(label, VPROC_MAGIC_UNLOAD_SIGNAL); -+ //_assert(error == NULL, "_vproc_send_signal_by_label(UNLOAD) != NULL"); -+ -+ fprintf(stderr, "launchctl unload SpringBoard.plist\n"); -+ system("launchctl unload " SpringBoard_plist); -+ } -+ -+ if (pid != -1) { -+ fprintf(stderr, "waiting for kill(%u) != 0...\n", pid); -+ while (kill(pid, 0) == 0) -+ stop(); -+ -+ int error = errno; -+ _assert(error == ESRCH, "kill(%u): %s", pid, strerror(error)); -+ } -+ -+ request = launch_data_alloc(LAUNCH_DATA_DICTIONARY); -+ launch_data_dict_insert(request, job, LAUNCH_KEY_SUBMITJOB); -+ -+ for (;;) { -+ response = launch_msg(request); -+ _assert(response != NULL, "launch_msg(SubmitJob) == NULL"); -+ -+ _assert(launch_data_get_type(response) == LAUNCH_DATA_ERRNO, "launch_data_get_type() != ERRNO"); -+ int error = launch_data_get_errno(response); -+ launch_data_free(response); -+ -+ const char *string = strerror(error); -+ -+ if (error == EEXIST) { -+ fprintf(stderr, "SubmitJob(%s): %s, retrying...\n", label, string); -+ stop(); -+ } else { -+ _assert(error == 0, "SubmitJob(%s): %s", label, string); -+ break; -+ } -+ } -+ -+ launch_data_free(request); -+ -+ return 0; -+} -diff -urN uikittools/sbreload.xml uikittools+uicache/sbreload.xml ---- uikittools/sbreload.xml 1969-12-31 14:00:00.000000000 -1000 -+++ uikittools+uicache/sbreload.xml 2019-06-07 22:37:29.000000000 -1000 -@@ -0,0 +1,13 @@ -+ -+ -+ -+ com.apple.frontboard.launchapplications -+ -+ com.apple.frontboard.shutdown -+ -+ platform-application -+ -+ com.apple.private.skip-library-validation -+ -+ -+ -diff -urN uikittools/uicache.mm uikittools+uicache/uicache.mm ---- uikittools/uicache.mm 2018-10-04 15:58:19.000000000 -1000 -+++ uikittools+uicache/uicache.mm 2019-06-07 22:37:39.000000000 -1000 -@@ -1,7 +1,17 @@ - /* UIKit Tools - command-line utilities for UIKit - * Copyright (C) 2008-2012 Jay Freeman (saurik) -+ * Portions Copyright (C) 2019 Sam Bingner - */ - -+/* uicache.mm -+ * -+ * Licensed under GPL v2.0 license as available at: -+ * https://www.gnu.org/licenses/gpl2.txt -+ * -+ * In adition, usage must meet the following -+ * Modified BSD terms: -+ */ -+ - /* Modified BSD License {{{ */ - /* - * Redistribution and use in source and binary -@@ -38,13 +48,14 @@ - /* }}} */ - - #import -- --#include --#include --#include --#include -- --#include -+#import -+#import -+#import -+#import -+#import -+#import -+#import -+#import - - #include "csstore.hpp" - -@@ -81,6 +92,12 @@ - - @end - -+@interface LSApplicationProxy : NSObject -+- (NSString*) applicationIdentifier; -+- (NSURL*) resourcesDirectoryURL; -+- (NSDate*) registeredDate; -+@end -+ - @interface LSApplicationWorkspace : NSObject - + (id) defaultWorkspace; - - (BOOL) registerApplication:(id)application; -@@ -89,16 +106,188 @@ - - (BOOL) registerApplicationDictionary:(id)application; - - (BOOL) installApplication:(id)application withOptions:(id)options; - - (BOOL) _LSPrivateRebuildApplicationDatabasesForSystemApps:(BOOL)system internal:(BOOL)internal user:(BOOL)user; -+- (NSArray*) allApplications; -+@end -+ -+@interface MCMAppDataContainer -++(id)containerWithIdentifier:(NSString*)identifier createIfNecessary:(bool)create existed:(bool*)existed error:(NSError*)error; -+-(NSURL*)url; - @end - --int main(int argc, const char *argv[]) { -- NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; -+@interface FBSSystemService -++(id)sharedService; -+-(void)sendActions:(NSSet*)actions withResult:(id)result; -+@end -+ -+typedef enum { -+ None = 0, -+ RestartRenderServer = (1 << 0), // also relaunch backboardd -+ SnapshotTransition = (1 << 1), -+ FadeToBlackTransition = (1 << 2), -+} SBSRelaunchActionStyle; -+ -+@interface SBSRelaunchAction -++(id)actionWithReason:(id)reason options:(int64_t)options targetURL:(NSURL*)url; -+@end -+ -+static int verbose=0; -+static int standard_uicache(void); -+static Class $MCMPluginKitPluginDataContainer; -+static Class $MCMAppDataContainer; -+static Class $LSApplicationWorkspace; -+LSApplicationWorkspace *workspace=nil; -+ -+NSString *getAppPath(NSString *path) -+{ -+ path = [path stringByResolvingSymlinksInPath]; -+ if (![path hasPrefix:@"/Applications/"]) { -+ fprintf(stderr, "Error: Path must be within /Applications/\n"); -+ return nil; -+ } -+ return [NSString pathWithComponents:[[path pathComponents] subarrayWithRange:NSMakeRange(0, 3)]]; -+} -+ -+bool appIsRegistered(NSString *path) -+{ -+ @autoreleasepool { -+ path = getAppPath(path); -+ if (!path) return false; -+ for (LSApplicationProxy *app in [workspace allApplications]) { -+ if ([path isEqualToString:[[app resourcesDirectoryURL] path]]) return true; -+ } -+ return false; -+ } -+} -+ -+bool unregisterPath(NSString *path) -+{ -+ @autoreleasepool { -+ if (verbose) fprintf(stderr, "Unregistering %s\n", path.lastPathComponent.UTF8String); -+ path = getAppPath(path); -+ if (!path) return false; -+ if (appIsRegistered(path) && ![workspace unregisterApplication:[NSURL fileURLWithPath:path]]) { -+ fprintf(stderr, "Error: unregisterApplication failed for %s\n", path.lastPathComponent.UTF8String); -+ return false; -+ } -+ } -+ return true; -+} -+ -+// Credit to coolstar for finding how to do this and not sharing with the community thereby forcing me to figure out how to do the same thing. -+bool registerPath(NSString *path) -+{ -+ if (!path) { -+ if (verbose) fprintf(stderr, "registerPath called with no path\n"); -+ return false; -+ } -+ NSString *realPath = getAppPath(path); -+ if (!realPath) { -+ if (verbose) fprintf(stderr, "unable to determine path for %s\n", path.UTF8String); -+ return false; -+ } -+ NSDictionary *infoDictionary = [NSDictionary dictionaryWithContentsOfFile: -+ [realPath stringByAppendingPathComponent:@"Info.plist"]]; -+ NSString *bundleID = [infoDictionary objectForKey:@"CFBundleIdentifier"]; -+ -+ if (bundleID) { -+ NSFileManager *fm = [NSFileManager defaultManager]; -+ -+ if ([infoDictionary objectForKey:@"CFBundleExecutable"]) { -+ NSString *executable = [realPath stringByAppendingPathComponent:[infoDictionary objectForKey:@"CFBundleExecutable"]]; -+ if (![fm fileExistsAtPath:executable]) { -+ fprintf(stderr, "Error: CFBundleExecutable defined but missing for %s - this is a fatal error. Aborting.\n", realPath.lastPathComponent.UTF8String); -+ return false; -+ } -+ } -+ -+ NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithObjectsAndKeys: -+ @"System", @"ApplicationType", -+ @YES, @"BundleNameIsLocalized", -+ bundleID, @"CFBundleIdentifier", -+ @NO, @"CompatibilityState", -+ @NO, @"IsDeletable", -+ realPath, @"Path", -+ [NSMutableDictionary dictionary], @"_LSBundlePlugins", -+ nil]; -+ -+ id appContainer = [$MCMAppDataContainer containerWithIdentifier:bundleID -+ createIfNecessary:YES existed:NULL error:nil]; -+ -+ NSString *appContainerPath = [[appContainer url] path]; -+ if (appContainerPath) { -+ dict[@"Container"] = appContainerPath; -+ } -+ NSString *pluginsPath = [realPath stringByAppendingPathComponent:@"PlugIns"]; -+ for (NSString *plugin in [fm contentsOfDirectoryAtPath:pluginsPath error:nil]) { -+ NSString *pluginPath = [pluginsPath stringByAppendingPathComponent:plugin]; -+ NSString *pluginInfoPlistPath = [pluginPath stringByAppendingPathComponent:@"Info.plist"]; -+ NSString *pluginBundleIdentifier = [[NSDictionary dictionaryWithContentsOfFile:pluginInfoPlistPath] objectForKey:@"CFBundleIdentifier"]; -+ if (pluginBundleIdentifier) { -+ id pluginContainer = [$MCMPluginKitPluginDataContainer containerWithIdentifier:pluginBundleIdentifier -+ createIfNecessary:YES existed:NULL error:nil]; -+ NSURL *pluginContainerURL = [pluginContainer url]; -+ NSString *pluginContainerPath = [pluginContainerURL path]; -+ dict[@"_LSBundlePlugins"][pluginBundleIdentifier] = @{ -+ @"ApplicationType": @"PluginKitPlugin", -+ @"BundleNameIsLocalized": @YES, -+ @"CFBundleIdentifier": pluginBundleIdentifier, -+ @"CompatibilityState": @NO, -+ @"Container": pluginContainerPath, -+ @"Path": pluginPath, -+ @"PluginOwnerBundleID": bundleID -+ }; -+ } -+ } -+ if (![workspace registerApplicationDictionary:dict]) { -+ fprintf(stderr, "Error: registerApplicationDictionary failed for %s\n", path.lastPathComponent.UTF8String); -+ return false; -+ } -+ } else { -+ return unregisterPath(realPath); -+ } -+ return true; -+} -+ -+void usage(void) -+{ -+ fprintf(stderr, "Usage: %s [-hrv] [[-p | -u] /Applications/App.app]]\n", getprogname()); -+ exit(EXIT_FAILURE); -+} - -- Class $LSApplicationWorkspace(objc_getClass("LSApplicationWorkspace")); -- LSApplicationWorkspace *workspace($LSApplicationWorkspace == nil ? nil : [$LSApplicationWorkspace defaultWorkspace]); -+pid_t launch_get_job_pid(const char * job) -+{ -+ launch_data_t resp; -+ launch_data_t msg; -+ -+ msg = launch_data_alloc(LAUNCH_DATA_DICTIONARY); -+ if (msg == NULL) { -+ return -1; -+ } -+ -+ launch_data_dict_insert(msg, launch_data_new_string(job), LAUNCH_KEY_GETJOB); -+ -+ resp = launch_msg(msg); -+ launch_data_free(msg); -+ -+ if (resp == NULL) { -+ return -1; -+ } -+ -+ if (launch_data_get_type(resp) != LAUNCH_DATA_DICTIONARY) return -1; -+ -+ launch_data_t pid_data = launch_data_dict_lookup(resp, "PID"); -+ if (launch_data_get_type(pid_data) != LAUNCH_DATA_INTEGER) return -1; -+ -+ pid_t pid = (pid_t)launch_data_get_integer(pid_data); -+ launch_data_free(resp); -+ return pid; -+} - -- if (kCFCoreFoundationVersionNumber > 1000) // this API is on iOS 7 but invaliding the icon cache is harder there -- if ([workspace respondsToSelector:@selector(_LSPrivateRebuildApplicationDatabasesForSystemApps:internal:user:)]) { -+int standard_uicache(void) -+{ -+ @autoreleasepool { -+ if (kCFCoreFoundationVersionNumber > 1000 && // this API is on iOS 7 but invaliding the icon cache is harder there -+ [workspace respondsToSelector:@selector(_LSPrivateRebuildApplicationDatabasesForSystemApps:internal:user:)]) { - if (![workspace _LSPrivateRebuildApplicationDatabasesForSystemApps:YES internal:YES user:NO]) - fprintf(stderr, "failed to rebuild application databases"); - return 0; -@@ -226,12 +415,188 @@ - system("killall -SIGCONT SpringBoard"); - } - -- if (respring) -- system("launchctl stop com.apple.SpringBoard"); -- else -- notify_post("com.apple.mobile.application_installed"); -- -- [pool release]; -+ notify_post("com.apple.mobile.application_installed"); - - return 0; -+ } -+} -+ -+int optimized_uicache(void) { -+ __block int rv=0; -+ NSMutableDictionary *registered = [NSMutableDictionary new]; -+ static void (^readHandler)(NSFileHandle*) = ^(NSFileHandle *fh) { -+ NSData *output = [fh readDataToEndOfFile]; -+ if (output.length==0) return; -+ const char *found_path = (const char *)[output bytes]; -+ NSArray *found = [@(found_path) pathComponents]; -+ if (found.count >= 3) { -+ NSString *appPath = [@"/Applications" stringByAppendingPathComponent:found[2]]; -+ @synchronized (registered) { -+ if (registered[appPath]) return; -+ if (verbose) fprintf(stderr, "Updating %s\n", appPath.lastPathComponent.UTF8String); -+ registered[appPath] = @YES; -+ } -+ if (!registerPath(appPath)) rv++; -+ } -+ }; -+ NSFileManager *fm = [NSFileManager defaultManager]; -+ NSMutableDictionary *apps = [NSMutableDictionary new]; -+ NSMutableArray *cleanup = [NSMutableArray new]; -+ NSMutableArray *finds = [NSMutableArray new]; -+ if (verbose>1) fprintf(stderr, "Enumerating apps\n"); -+ for (LSApplicationProxy *app in [workspace allApplications]) { -+ NSString *path = [[app resourcesDirectoryURL] path]; -+ if (![path hasPrefix:@"/Applications/"]) continue; -+ if (verbose>1) fprintf(stderr, "Checking %s\n", path.lastPathComponent.UTF8String); -+ -+ NSDate *lastRegistered = [app registeredDate]; -+ -+ if ([fm fileExistsAtPath:path]) { -+ // Check for updated components -+ NSTask *find = [NSTask new]; -+ [find setLaunchPath:@"/usr/bin/find"]; -+ [find setStandardOutput:[NSPipe pipe]]; -+ NSString *stampPath = [NSString stringWithFormat:@"/var/tmp/uicache.stamp.%@", app.applicationIdentifier]; -+ [fm createFileAtPath:stampPath contents:nil attributes:@{NSFileModificationDate: lastRegistered}]; -+ [cleanup addObject:stampPath]; -+ [find setArguments:@[ path, @"-newer", stampPath, @"-print0", @"-quit"]]; -+ [finds addObject:find]; -+ [find launch]; -+ apps[path.lastPathComponent] = app; -+ } else { -+ if (verbose) fprintf(stderr, "De-registering removed app: %s\n", path.lastPathComponent.UTF8String); -+ @synchronized (registered) { -+ if (registered[path]) continue; -+ registered[path] = @YES; -+ } -+ if (!unregisterPath(path)) rv++; -+ } -+ } -+ -+ for (NSString* existing in [[NSFileManager defaultManager] contentsOfDirectoryAtPath:@"/Applications" error:nil]) { -+ NSString *path = [@"/Applications" stringByAppendingPathComponent:existing]; -+ if (apps[existing] || registered[path] || ![existing hasSuffix:@".app"]) continue; -+ if (verbose) fprintf(stderr, "Registering new app: %s\n", existing.UTF8String); -+ @synchronized (registered) { -+ registered[path] = @YES; -+ } -+ if (!registerPath(path)) rv++; -+ } -+ for (NSTask *find in finds) { -+ if (verbose>2) fprintf(stderr, "waiting for find %s\n", [find.arguments componentsJoinedByString:@" "].UTF8String); -+ readHandler([find.standardOutput fileHandleForReading]); -+ [find waitUntilExit]; -+ } -+ for (NSString *path in cleanup) { -+ [fm removeItemAtPath:path error:nil]; -+ } -+ return rv; -+} -+ -+int main(int argc, const char *argv[]) -+{ -+ if (getuid() == 0) { -+ // Be mobile -+ if (setuid(501)) { -+ fprintf(stderr, "Error: unable to become mobile"); -+ return -1; -+ } -+ } -+ dlopen("/System/Library/PrivateFrameworks/MobileContainerManager.framework/MobileContainerManager", RTLD_LAZY); -+ dlopen("/System/Library/PrivateFrameworks/FrontBoardServices.framework/FrontBoardServices", RTLD_LAZY); -+ dlopen("/System/Library/PrivateFrameworks/SpringBoardServices.framework/SpringBoardServices", RTLD_LAZY); -+ Class $SBSRelaunchAction = objc_getClass("SBSRelaunchAction"); -+ Class $FBSSystemService = objc_getClass("FBSSystemService"); -+ $MCMPluginKitPluginDataContainer = objc_getClass("MCMPluginKitPluginDataContainer"); -+ $MCMAppDataContainer = objc_getClass("MCMAppDataContainer"); -+ $LSApplicationWorkspace = objc_getClass("LSApplicationWorkspace"); -+ workspace = [$LSApplicationWorkspace defaultWorkspace]; -+ -+ static int rv=0; -+ @autoreleasepool { -+ bool respring=false, do_all=false; -+ void (*jb_oneshot_entitle_now)(pid_t a, uint64_t b); -+ void *libjb = dlopen("/usr/lib/libjailbreak.dylib", RTLD_LAZY); -+ -+ if (libjb) { -+ dlerror(); -+ jb_oneshot_entitle_now = (void (*)(pid_t, uint64_t))dlsym(libjb, "jb_oneshot_entitle_now"); -+ if (!dlerror()) jb_oneshot_entitle_now(getpid(), 2); -+ } -+ -+ NSMutableDictionary *paths = [NSMutableDictionary new]; -+ NSMutableDictionary *unregister_paths = [NSMutableDictionary new]; -+ static struct option long_options[] = -+ { -+ {"all", no_argument, 0, 'a'}, -+ {"help", no_argument, 0, 'h'}, -+ {"path", required_argument, 0, 'p'}, -+ {"unregister", required_argument, 0, 'u'}, -+ {"respring", no_argument, 0, 'r'}, -+ {"verbose", no_argument, 0, 'v'}, -+ {0, 0, 0, 0} -+ }; -+ int option_index = 0; -+ char ch; -+ bool have_path = false; -+ while ((ch = getopt_long(argc, (char *const *)argv, "ap:ru:vh?", long_options, &option_index)) != -1) { -+ switch (ch) -+ { -+ case 'a': -+ do_all = true; -+ break; -+ case 'h': -+ usage(); -+ break; -+ case 'p': -+ paths[@(optarg)] = @YES; -+ have_path = true; -+ break; -+ case 'r': -+ respring = true; -+ break; -+ case 'u': -+ unregister_paths[@(optarg)] = @YES; -+ have_path = true; -+ break; -+ case 'v': -+ verbose++; -+ break; -+ default: -+ break; -+ } -+ } -+ if (do_all || !$MCMPluginKitPluginDataContainer || !$MCMAppDataContainer || !$LSApplicationWorkspace) { -+ rv = standard_uicache(); -+ } else if (have_path) { -+ for (NSString *path in [paths allKeys]) { -+ if (verbose) fprintf(stderr, "Refreshing %s\n", path.UTF8String); -+ if (!registerPath(path)) rv++; -+ } -+ for (NSString *path in [unregister_paths allKeys]) { -+ if (!unregisterPath(path)) rv++; -+ } -+ } else { -+ rv += optimized_uicache(); -+ } -+ if ( respring ) -+ { -+ pid_t sb_pid = launch_get_job_pid("com.apple.SpringBoard"); -+ if ($SBSRelaunchAction && $FBSSystemService) { -+ id action = [$SBSRelaunchAction actionWithReason:@"respring" options:RestartRenderServer targetURL:nil]; -+ id sharedService = [$FBSSystemService sharedService]; -+ [sharedService sendActions:[NSSet setWithObject:action] withResult:nil]; -+ for (int i=0; i<100; i++) { -+ if (kill(sb_pid, 0)) { -+ break; -+ } -+ usleep(1000); -+ } -+ } else { -+ system("launchctl stop com.apple.SpringBoard"); -+ system("launchctl stop com.apple.backboardd"); -+ } -+ } -+ } // @autoreleasepool -+ return rv; - } -diff -urN uikittools/uicache.xml uikittools+uicache/uicache.xml ---- uikittools/uicache.xml 2018-10-04 15:58:37.000000000 -1000 -+++ uikittools+uicache/uicache.xml 2019-06-07 22:37:29.000000000 -1000 -@@ -4,23 +4,22 @@ - com.apple.private.mobileinstall.allowedSPI - - InstallForLaunchServices -+ UninstallForLaunchServices - -- - com.apple.lsapplicationworkspace.rebuildappdatabases - -- - com.apple.private.MobileContainerManager.allowed - -- - com.apple.private.kernel.override-cpumon - -- - com.apple.vpn.installer_events - -- -+ com.apple.frontboard.launchapplications -+ -+ com.apple.frontboard.shutdown -+ - platform-application - -- - com.apple.private.skip-library-validation - - -- cgit v1.2.3