├── .gitignore ├── Makefile ├── Makefile.ios ├── Makefile.macos ├── README.md ├── ent.plist └── src ├── FindProcess ├── LSFindProcess.h └── LSFindProcess.m ├── LSHelperClass.h ├── LSHelperClass.m ├── NSFileManager+size.h ├── NSFileManager+size.m └── ls.m /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | 5 | ## Build generated 6 | build/ 7 | DerivedData/ 8 | 9 | ## Various settings 10 | *.pbxuser 11 | !default.pbxuser 12 | *.mode1v3 13 | !default.mode1v3 14 | *.mode2v3 15 | !default.mode2v3 16 | *.perspectivev3 17 | !default.perspectivev3 18 | xcuserdata/ 19 | 20 | ## Other 21 | *.moved-aside 22 | *.xccheckout 23 | *.xcscmblueprint 24 | 25 | ## Obj-C/Swift specific 26 | *.hmap 27 | *.ipa 28 | *.dSYM.zip 29 | *.dSYM 30 | 31 | # CocoaPods 32 | # 33 | # We recommend against adding the Pods directory to your .gitignore. However 34 | # you should judge for yourself, the pros and cons are mentioned at: 35 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 36 | # 37 | # Pods/ 38 | 39 | # Carthage 40 | # 41 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 42 | # Carthage/Checkouts 43 | 44 | Carthage/Build 45 | 46 | # fastlane 47 | # 48 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 49 | # screenshots whenever they are needed. 50 | # For more information about the recommended setup visit: 51 | # https://docs.fastlane.tools/best-practices/source-control/#source-control 52 | 53 | fastlane/report.xml 54 | fastlane/Preview.html 55 | fastlane/screenshots/**/*.png 56 | fastlane/test_output 57 | 58 | # Code Injection 59 | # 60 | # After new code Injection tools there's a generated folder /iOSInjectionProject 61 | # https://github.com/johnno1962/injectionforxcode 62 | 63 | iOSInjectionProject/ 64 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | BINDIR ?= bin 2 | PREFIX ?= usr 3 | DESTDIR ?= / 4 | BUILDDIR := ./build 5 | SRC := $(wildcard src/*.m) $(wildcard src/FindProcess/*.m) 6 | OBJ := $(SRC:%.m=$(BUILDDIR)/%.o) 7 | CFLAGS := -ObjC -O2 -g -fno-rtti -fvisibility=hidden -fvisibility-inlines-hidden -Isrc/FindProcess 8 | CPPFLAGS := $(CFLAGS) 9 | LDFLAGS := -framework Foundation -framework MobileCoreServices -framework UIKit -Isrc/FindProcess 10 | LDFLAGS_MAC := -framework Foundation -framework CoreServices -framework AppKit -Isrc/FindProcess 11 | LDID := ldid 12 | TARGET := lsdtrip 13 | 14 | CC = xcrun -sdk appletvos clang -arch arm64 15 | 16 | .PHONY: all clean 17 | 18 | all: $(TARGET) 19 | 20 | $(BUILDDIR)/%.o: %.m $(BUILDDIR)/%.d Makefile 21 | @mkdir -p $(dir $@) 22 | @$(CC) -c $(CFLAGS) -o $@ $< 23 | 24 | $(DESTDIR)/$(PREFIX)/$(BINDIR): 25 | mkdir -p $@ 26 | 27 | $(BUILDDIR)/$(TARGET).bin: $(OBJ) 28 | @$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ 29 | 30 | $(TARGET): $(BUILDDIR)/$(TARGET).bin 31 | @$(LDID) -Sent.plist $^ 32 | @cp $^ $@ 33 | 34 | install: all | $(DESTDIR)/$(PREFIX)/$(BINDIR) 35 | cp $(TARGET) $(DESTDIR)/$(PREFIX)/$(BINDIR)/ 36 | 37 | clean: 38 | rm -rf $(TARGET) $(BUILDDIR)/$(TARGET).bin $(BUILDDIR)/*.o $(BUILDDIR)/*.d $(BUILDDIR)/**/*.o $(BUILDDIR)/**/*.d 39 | 40 | $(BUILDDIR)/%.d: %.m 41 | @mkdir -p $(dir $@) 42 | @echo generating depends for $< 43 | @set -e; rm -f $@; \ 44 | $(CC) -M $(CPPFLAGS) $< > $@.$$$$; \ 45 | sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \ 46 | rm -f $@.$$$$ 47 | 48 | -include $(SRC:.m=.d) 49 | -------------------------------------------------------------------------------- /Makefile.ios: -------------------------------------------------------------------------------- 1 | BINDIR ?= bin 2 | PREFIX ?= usr 3 | DESTDIR ?= / 4 | BUILDDIR := ./build/ios 5 | SRC := $(wildcard src/*.m) $(wildcard src/FindProcess/*.m) 6 | OBJ := $(SRC:%.m=$(BUILDDIR)/%.o) 7 | CFLAGS := -ObjC -O2 -g -fno-rtti -fvisibility=hidden -fvisibility-inlines-hidden -Isrc/FindProcess 8 | CPPFLAGS := $(CFLAGS) 9 | LDFLAGS := -framework Foundation -framework MobileCoreServices -framework UIKit -Isrc/FindProcess 10 | LDFLAGS_MAC := -framework Foundation -framework CoreServices -framework AppKit -Isrc/FindProcess 11 | LDID := ldid 12 | TARGET := lsdtrip_ios 13 | 14 | CC = xcrun -sdk iphoneos clang -arch arm64 15 | 16 | .PHONY: all clean 17 | 18 | all: $(TARGET) 19 | 20 | $(BUILDDIR)/%.o: %.m $(BUILDDIR)/%.d Makefile 21 | @mkdir -p $(dir $@) 22 | @$(CC) -c $(CFLAGS) -o $@ $< 23 | 24 | $(DESTDIR)/$(PREFIX)/$(BINDIR): 25 | mkdir -p $@ 26 | 27 | $(BUILDDIR)/$(TARGET).bin: $(OBJ) 28 | @$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ 29 | 30 | $(TARGET): $(BUILDDIR)/$(TARGET).bin 31 | @$(LDID) -Sent.plist $^ 32 | @cp $^ $@ 33 | 34 | install: all | $(DESTDIR)/$(PREFIX)/$(BINDIR) 35 | cp $(TARGET) $(DESTDIR)/$(PREFIX)/$(BINDIR)/ 36 | 37 | clean: 38 | rm -rf $(TARGET) $(BUILDDIR)/$(TARGET).bin $(BUILDDIR)/*.o $(BUILDDIR)/*.d $(BUILDDIR)/**/*.o $(BUILDDIR)/**/*.d 39 | 40 | $(BUILDDIR)/%.d: %.m 41 | @mkdir -p $(dir $@) 42 | @echo generating depends for $< 43 | @set -e; rm -f $@; \ 44 | $(CC) -M $(CPPFLAGS) $< > $@.$$$$; \ 45 | sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \ 46 | rm -f $@.$$$$ 47 | 48 | -include $(SRC:.m=.d) 49 | -------------------------------------------------------------------------------- /Makefile.macos: -------------------------------------------------------------------------------- 1 | BINDIR ?= bin 2 | PREFIX ?= usr 3 | DESTDIR ?= / 4 | BUILDDIR := ./build/macos 5 | SRC := $(wildcard src/*.m) $(wildcard src/FindProcess/*.m) 6 | OBJ := $(SRC:%.m=$(BUILDDIR)/%.o) 7 | CFLAGS := -ObjC -O2 -g -fno-rtti -fvisibility=hidden -fvisibility-inlines-hidden -Isrc/FindProcess 8 | CPPFLAGS := $(CFLAGS) 9 | LDFLAGS := -framework Foundation -framework CoreServices -framework AppKit -Isrc/FindProcess 10 | LDFLAGS_MAC := -framework Foundation -framework CoreServices -framework AppKit -Isrc/FindProcess 11 | LDID := ldid 12 | TARGET := lsdtrip_mac 13 | 14 | CC = xcrun -sdk macosx clang -arch x86_64 15 | 16 | .PHONY: all clean 17 | 18 | all: $(TARGET) 19 | 20 | $(BUILDDIR)/%.o: %.m $(BUILDDIR)/%.d Makefile 21 | @mkdir -p $(dir $@) 22 | @$(CC) -c $(CFLAGS) -o $@ $< 23 | 24 | $(DESTDIR)/$(PREFIX)/$(BINDIR): 25 | mkdir -p $@ 26 | 27 | $(BUILDDIR)/$(TARGET).bin: $(OBJ) 28 | @$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ 29 | 30 | $(TARGET): $(BUILDDIR)/$(TARGET).bin 31 | @cp $^ $@ 32 | 33 | install: all | $(DESTDIR)/$(PREFIX)/$(BINDIR) 34 | cp $(TARGET) $(DESTDIR)/$(PREFIX)/$(BINDIR)/ 35 | 36 | clean: 37 | rm -rf $(TARGET) $(BUILDDIR)/$(TARGET).bin $(BUILDDIR)/*.o $(BUILDDIR)/*.d $(BUILDDIR)/**/*.o $(BUILDDIR)/**/*.d 38 | 39 | $(BUILDDIR)/%.d: %.m 40 | @mkdir -p $(dir $@) 41 | @echo generating depends for $< 42 | @set -e; rm -f $@; \ 43 | $(CC) -M $(CPPFLAGS) $< > $@.$$$$; \ 44 | sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \ 45 | rm -f $@.$$$$ 46 | 47 | -include $(SRC:.m=.d) 48 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # lsdtrip 2 | slightly modified version of jonathan levins lsdtrip bin available on his website. 3 | -------------------------------------------------------------------------------- /ent.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | platform-application 6 | 7 | com.apple.private.skip-library-validation 8 | 9 | com.apple.private.security.no-container 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/FindProcess/LSFindProcess.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @interface LSFindProcess : NSObject 4 | + (NSString *)processNameFromPID:(pid_t)ppid; 5 | + (pid_t) find_process:(const char*) name; 6 | @end 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/FindProcess/LSFindProcess.m: -------------------------------------------------------------------------------- 1 | #import "LSFindProcess.h" 2 | #include 3 | 4 | extern int proc_pidpath(int, void*, uint32_t); 5 | extern char*** _NSGetEnviron(void); 6 | extern int proc_listallpids(void*, int); 7 | extern int proc_pidpath(int, void*, uint32_t); 8 | static int process_buffer_size = 4096; 9 | 10 | @implementation LSFindProcess 11 | 12 | + (NSString *)processNameFromPID:(pid_t)ppid { 13 | char path_buffer[MAXPATHLEN]; 14 | proc_pidpath(ppid, (void*)path_buffer, sizeof(path_buffer)); 15 | return [NSString stringWithUTF8String:path_buffer]; 16 | } 17 | 18 | + (pid_t) find_process:(const char*) name { 19 | pid_t *pid_buffer; 20 | char path_buffer[MAXPATHLEN]; 21 | int count, i, ret; 22 | boolean_t res = FALSE; 23 | pid_t ppid_ret = 0; 24 | pid_buffer = (pid_t*)calloc(1, process_buffer_size); 25 | assert(pid_buffer != NULL); 26 | 27 | count = proc_listallpids(pid_buffer, process_buffer_size); 28 | NSLog(@"process count: %d", count); 29 | if(count) { 30 | for(i = 0; i < count; i++) { 31 | pid_t ppid = pid_buffer[i]; 32 | 33 | ret = proc_pidpath(ppid, (void*)path_buffer, sizeof(path_buffer)); 34 | if(ret < 0) { 35 | fprintf(stderr, "(%s:%d) proc_pidinfo() call failed.\n", __FILE__, __LINE__); 36 | continue; 37 | } 38 | fprintf(stderr, "comparing %s to %s\n", path_buffer, name); 39 | /* 40 | if (strncmp(path_buffer, name, strlen(path_buffer)) == 0){ 41 | res = TRUE; 42 | ppid_ret = ppid; 43 | break; 44 | }*/ 45 | 46 | if(strstr(path_buffer, name)) { 47 | fprintf(stderr, "match in %s to %s\n", path_buffer, name); 48 | res = TRUE; 49 | ppid_ret = ppid; 50 | break; 51 | } 52 | } 53 | } 54 | 55 | free(pid_buffer); 56 | return ppid_ret; 57 | } 58 | 59 | @end 60 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /src/LSHelperClass.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | NS_ASSUME_NONNULL_BEGIN 4 | 5 | @interface LSHelperClass : NSObject 6 | + (id)proxyForProcessName:(NSString *)processName; 7 | + (NSString *)bundleIDForProcessName:(NSString *)processName; 8 | + (NSURL *)appContainerForIdentifier:(NSString *)identifier; 9 | + (id)smartProxyFromValue:(NSString *)value; 10 | + (BOOL)validBundleId:(NSString *)bundleId; 11 | + (NSNumber *)dynamicDiskUsageForProxy:(id)proxy; 12 | @end 13 | 14 | NS_ASSUME_NONNULL_END 15 | -------------------------------------------------------------------------------- /src/LSHelperClass.m: -------------------------------------------------------------------------------- 1 | #import "LSHelperClass.h" 2 | #import "NSFileManager+size.h" 3 | #import 4 | 5 | #define FM [NSFileManager defaultManager] 6 | #define FANCY_BYTES(B) [NSByteCountFormatter stringFromByteCount:B countStyle:NSByteCountFormatterCountStyleFile] 7 | 8 | @interface NSObject (lazy) 9 | - (id)diskUsage; //_LSDiskUsage 10 | - (id)dynamicUsage; 11 | @end 12 | 13 | @interface LSApplicationProxy : NSObject 14 | 15 | @property (nonatomic,readonly) NSURL * bundleURL; 16 | @property (nonatomic,readonly) NSURL * containerURL; 17 | @property (nonatomic,readonly) NSString * bundleIdentifier; 18 | @property (nonatomic,readonly) NSString * bundleType; //@synthesize bundleType=_bundleType - In the implementation block 19 | @property (nonatomic,readonly) NSString * localizedShortName; 20 | 21 | - (BOOL)isContainerized; 22 | - (id)staticDiskUsage; 23 | - (id)dynamicDiskUsage; 24 | + (id)applicationProxyForItemID:(id)arg1; // IMP=0x0000000000019eca 25 | + (id)applicationProxyForBundleURL:(id)arg1; // IMP=0x0000000000019e9e 26 | + (id)applicationProxyForSystemPlaceholder:(id)arg1; // IMP=0x0000000000019d9b 27 | + (id)applicationProxyForCompanionIdentifier:(id)arg1; // IMP=0x0000000000019d3f 28 | + (id)applicationProxyForIdentifier:(id)arg1 placeholder:(_Bool)arg2; // IMP=0x0000000000019d08 29 | + (id)applicationProxyForIdentifier:(id)arg1; 30 | 31 | @end 32 | 33 | @interface LSApplicationWorkspace: NSObject 34 | 35 | -(id)allInstalledApplications; 36 | - (NSArray *)applicationsOfType:(unsigned long long)arg1 ; 37 | - (id)allApplications; 38 | -(id)placeholderApplications; 39 | -(id)unrestrictedApplications; 40 | - (void)openApplicationWithBundleID:(NSString *)string; 41 | + (id)defaultWorkspace; 42 | -(BOOL)uninstallApplication:(id)arg1 withOptions:(id)arg2; 43 | 44 | @end 45 | 46 | @implementation LSHelperClass 47 | 48 | + (NSNumber *)dynamicDiskUsageForProxy:(id)proxy { 49 | if ([proxy isContainerized]) { 50 | if ([proxy respondsToSelector:@selector(diskUsage)]) 51 | return [[proxy diskUsage] dynamicUsage]; 52 | else 53 | return [proxy dynamicDiskUsage]; 54 | } else { 55 | NSString *container = [[self appContainerForIdentifier:[proxy bundleIdentifier]] path]; 56 | if (container != nil){ 57 | return [NSNumber numberWithUnsignedInteger:[NSFileManager sizeForFolderAtPath:container]]; 58 | } 59 | } 60 | return 0; 61 | } 62 | 63 | + (NSURL *)appContainerForIdentifier:(NSString *)identifier { 64 | id proxy = [LSApplicationProxy applicationProxyForIdentifier:identifier]; 65 | NSString *newId = identifier; //make it possible to change it below if necessary 66 | if (proxy != nil) { 67 | NSURL *container = [proxy containerURL]; 68 | if (container!=nil && ![container.path isEqualToString:@"/var/mobile"]) { 69 | return [proxy containerURL]; 70 | } else { 71 | newId = [proxy bundleIdentifier]; 72 | } 73 | } 74 | NSDictionary *appDict = [self appContainerDictionary:false][newId]; 75 | if (appDict) { 76 | return [NSURL fileURLWithPath:appDict[@"path"]]; 77 | } 78 | return nil; 79 | } 80 | 81 | + (NSDictionary *)appContainerDictionary:(BOOL)withSize { 82 | //NSDate *start = [NSDate date]; 83 | __block NSMutableDictionary *newDicitionary = [NSMutableDictionary new]; 84 | NSString *path = @"/var/mobile/Containers/Data/Application"; 85 | NSArray *contents = [FM contentsOfDirectoryAtPath:path error:nil]; 86 | [contents enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { 87 | NSString *currentPath = [path stringByAppendingPathComponent:obj]; 88 | NSDictionary *attrs = [FM attributesOfItemAtPath:currentPath error:nil]; 89 | NSDate *date = attrs[NSFileModificationDate]; 90 | NSString *metaPath = [currentPath stringByAppendingPathComponent:@".com.apple.mobile_container_manager.metadata.plist"]; 91 | if ([FM fileExistsAtPath:metaPath]){ 92 | NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:metaPath]; 93 | NSString *name = dict[@"MCMMetadataIdentifier"]; 94 | NSDictionary *deets = nil; 95 | if (withSize) { 96 | NSUInteger bytes = [NSFileManager sizeForFolderAtPath:currentPath]; 97 | deets = @{@"identifier": name, 98 | @"path": currentPath, 99 | @"modified": date, 100 | @"size": FANCY_BYTES(bytes) 101 | }; 102 | } else { 103 | deets = @{@"identifier": name, 104 | @"path": currentPath, 105 | @"modified": date, 106 | }; 107 | } 108 | 109 | newDicitionary[name] = deets; 110 | //[newArray addObject:deets]; 111 | } 112 | }]; 113 | //NSTimeInterval interval = [[NSDate date] timeIntervalSinceDate:start]; 114 | return newDicitionary; 115 | } 116 | 117 | 118 | + (id)defaultWorkspace { 119 | return [objc_getClass("LSApplicationWorkspace") defaultWorkspace]; 120 | } 121 | 122 | + (BOOL)validBundleId:(NSString *)bundleId { 123 | return ([bundleId containsString:@"."]); 124 | } 125 | 126 | + (id)smartProxyFromValue:(NSString *)value { 127 | if ([self validBundleId:value]) { 128 | return [LSApplicationProxy applicationProxyForIdentifier:value]; 129 | } 130 | //if we get this far its not a 'valid' bundle id, so it should be a process name 131 | return [self proxyForProcessName:value]; 132 | } 133 | 134 | + (id)proxyForProcessName:(NSString *)processName { 135 | NSPredicate *pred = [NSPredicate predicateWithFormat:@"localizedName =[c] %@", processName]; 136 | return [[[[self defaultWorkspace]allInstalledApplications] filteredArrayUsingPredicate:pred] firstObject]; 137 | } 138 | 139 | + (NSString *)bundleIDForProcessName:(NSString *)processName { 140 | id found = [self proxyForProcessName:processName]; 141 | return [found bundleIdentifier]; 142 | } 143 | 144 | @end 145 | -------------------------------------------------------------------------------- /src/NSFileManager+size.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @interface NSFileManager(Util) 4 | 5 | + (NSUInteger)sizeForFolderAtPath:(NSString *)source; 6 | + (CGFloat)availableSpaceForPath:(NSString *)source; 7 | + (void)ls:(const char *)name completion:(void(^)(NSInteger size, NSInteger count))block; 8 | - (NSNumber *)sizeForFolderAtPath:(NSString *)source error:(NSError **)error; 9 | 10 | @end 11 | -------------------------------------------------------------------------------- /src/NSFileManager+size.m: -------------------------------------------------------------------------------- 1 | 2 | #import "NSFileManager+size.h" 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | @implementation NSFileManager(Util) 11 | 12 | //https://stackoverflow.com/questions/50105231/how-do-i-recursively-go-through-folders-and-count-total-file-size 13 | 14 | long long do_ls(const char *name) { 15 | DIR *dir_ptr; 16 | struct dirent *direntp; 17 | struct stat info; 18 | long long total = 0; 19 | if (stat(name, &info)) { 20 | fprintf(stderr, "ls01: cannot stat %s\n", name); 21 | return 0; 22 | } 23 | if (S_ISDIR(info.st_mode)) { 24 | if ((dir_ptr = opendir(name)) == NULL) { 25 | fprintf(stderr, "ls01: cannot open directory %s\n", name); 26 | } else { 27 | while ((direntp = readdir(dir_ptr)) != NULL) { 28 | char *pathname; 29 | 30 | /* ignore current and parent directories */ 31 | if (!strcmp(direntp->d_name, ".") || !strcmp(direntp->d_name, "..")) 32 | continue; 33 | 34 | pathname = malloc(strlen(name) + 1 + strlen(direntp->d_name) + 1); 35 | if (pathname == NULL) { 36 | fprintf(stderr, "ls01: cannot allocated memory\n"); 37 | exit(1); 38 | } 39 | sprintf(pathname, "%s/%s", name, direntp->d_name); 40 | total += do_ls(pathname); 41 | free(pathname); 42 | } 43 | closedir(dir_ptr); 44 | } 45 | } else { 46 | total = info.st_size; 47 | } 48 | //printf("file count: %i\n", fileCount); 49 | //printf("%10lld %s\n", total, name); 50 | return total; 51 | } 52 | 53 | //same code but with a completion block to offer a non-blocking solution 54 | 55 | + (void)ls:(const char *)name completion:(void(^)(NSInteger size, NSInteger count))block { 56 | DIR *dir_ptr; 57 | struct dirent *direntp; 58 | struct stat info; 59 | __block long long total = 0; 60 | __block int fileCount = 0; 61 | if (stat(name, &info)) { 62 | fprintf(stderr, "ls01: cannot stat %s\n", name); 63 | return; 64 | } 65 | if (S_ISDIR(info.st_mode)) { 66 | if ((dir_ptr = opendir(name)) == NULL) { 67 | fprintf(stderr, "ls01: cannot open directory %s\n", name); 68 | } else { 69 | while ((direntp = readdir(dir_ptr)) != NULL) { 70 | char *pathname; 71 | 72 | /* ignore current and parent directories */ 73 | if (!strcmp(direntp->d_name, ".") || !strcmp(direntp->d_name, "..")) 74 | continue; 75 | 76 | pathname = malloc(strlen(name) + 1 + strlen(direntp->d_name) + 1); 77 | if (pathname == NULL) { 78 | fprintf(stderr, "ls01: cannot allocate memory\n"); 79 | exit(1); 80 | } 81 | sprintf(pathname, "%s/%s", name, direntp->d_name); 82 | [self ls:pathname completion:^(NSInteger size, NSInteger count) { 83 | total+=size; 84 | fileCount+=count; 85 | }]; 86 | free(pathname); 87 | } 88 | closedir(dir_ptr); 89 | } 90 | } else { 91 | total = info.st_size; 92 | fileCount++; 93 | } 94 | //printf("file count: %i\n", fileCount); 95 | //printf("%10lld %s\n", total, name); 96 | if (block) { 97 | block(total,fileCount); 98 | } 99 | } 100 | 101 | + (NSUInteger)sizeForFolderAtPath:(NSString *)source { 102 | return do_ls([source UTF8String]); 103 | } 104 | 105 | + (CGFloat)availableSpaceForPath:(NSString *)source { 106 | NSError *error = nil; 107 | NSDictionary *attrs = [[NSFileManager defaultManager] attributesOfFileSystemForPath:source error:&error]; 108 | if (error) { 109 | //DLog(@"error: %@", error); 110 | attrs = [[NSFileManager defaultManager] attributesOfFileSystemForPath:@"." error:&error]; 111 | } 112 | return [[attrs objectForKey:NSFileSystemFreeSize] floatValue]; 113 | } 114 | 115 | - (NSNumber *)sizeForFolderAtPath:(NSString *) source error:(NSError **)error 116 | { 117 | NSArray * contents; 118 | unsigned long long size = 0; 119 | NSEnumerator * enumerator; 120 | NSString * path; 121 | BOOL isDirectory; 122 | 123 | // Determine Paths to Add 124 | if ([self fileExistsAtPath:source isDirectory:&isDirectory] && isDirectory) 125 | { 126 | contents = [self subpathsAtPath:source]; 127 | } 128 | else 129 | { 130 | contents = [NSArray array]; 131 | } 132 | // Add Size Of All Paths 133 | enumerator = [contents objectEnumerator]; 134 | while (path = [enumerator nextObject]) 135 | { 136 | NSDictionary * fattrs = [self attributesOfItemAtPath: [ source stringByAppendingPathComponent:path ] error:error]; 137 | size += [[fattrs objectForKey:NSFileSize] unsignedLongLongValue]; 138 | } 139 | // Return Total Size in MB 140 | 141 | return [ NSNumber numberWithUnsignedLongLong:size/1024/1024]; 142 | } 143 | 144 | @end 145 | -------------------------------------------------------------------------------- /src/ls.m: -------------------------------------------------------------------------------- 1 | #define ARM 2 | #import 3 | #undef __TVOS_UNAVAILABLE 4 | #define __TVOS_UNAVAILABLE 5 | #undef __TVOS_PROHIBITED 6 | #define __TVOS_PROHIBITED 7 | #undef __API_UNAVAILABLE 8 | #define __API_UNAVAILABLE(...) 9 | #import 10 | #include 11 | #include 12 | #include 13 | #include 14 | #ifdef ARM 15 | #include // NSObject 16 | #if TARGET_OS_IOS || TARGET_OS_TV 17 | #include 18 | #include 19 | #endif 20 | #endif 21 | #import "LSFindProcess.h" 22 | #import "LSHelperClass.h" 23 | #if TARGET_OS_OSX 24 | #import 25 | #endif 26 | 27 | char * tripVersionNumber = "1.0"; 28 | 29 | #if TARGET_OS_IOS || TARGET_OS_TV 30 | @interface UIImage (Private) 31 | + (UIImage *)_applicationIconImageForBundleIdentifier:(NSString *)bundleIdentifier format:(int)format scale:(CGFloat)scale; 32 | @end 33 | #endif 34 | 35 | @interface LSDocumentProxy: NSObject 36 | 37 | -(NSString *)canonicalExecutablePath; 38 | +(id)documentProxyForName:(id)arg1 type:(id)arg2 MIMEType:(id)arg3 ; 39 | -(id)applicationsAvailableForOpeningWithError:(id*)arg1; 40 | //doxy = [objc_getClass("LSDocumentProxy") documentProxyForName:fileName type:fileType MIMEType:nil]; 41 | @end 42 | 43 | @interface LSApplicationProxy : NSObject 44 | - (NSString *)bundleExecutable; 45 | - (id)applicationIdentifier; 46 | - (id)tv_applicationFlatIcon; 47 | -(NSArray *)appTags; 48 | +(id)applicationProxyForIdentifier:(id)arg1; 49 | @end 50 | 51 | @interface LSApplicationWorkspaceRemoteObserver : NSObject 52 | -(id)localObservers; 53 | @end 54 | 55 | 56 | @interface LSApplicationWorkspace : NSObject 57 | + (id) defaultWorkspace; 58 | @property (readonly) LSApplicationWorkspaceRemoteObserver * remoteObserver; 59 | - (BOOL) _LSPrivateSyncWithMobileInstallation; 60 | - (BOOL)openURL:(id)string; 61 | @end 62 | 63 | @interface PBAppDepot : NSObject 64 | + (id)sharedInstance; 65 | @property(retain, nonatomic) NSMutableDictionary *internalAppState; 66 | - (id)_addAppStateForIdentifier:(id)arg1; 67 | - (void)_save; 68 | - (void)_setNeedsNotifyAppStateDidChange; 69 | @end 70 | 71 | #include 72 | #include 73 | #include 74 | #include 75 | #include 76 | #ifdef ARM 77 | #include // NSObject 78 | #endif 79 | CFNotificationCenterRef CFNotificationCenterGetDistributedCenter(void); 80 | 81 | // 82 | // LSDTrip: A simple tool to demonstrate LaunchServices in OS X *and* iOS 83 | // ------- 84 | // 85 | // Jonathan Levin, http://NeWOSXBook.com - @Morpheus______/@TechnoloGeeks 86 | // 87 | // 88 | // License: free, but if you GitHub it or mod it, at least leave a mention and 89 | // don't pass it as your own code (as too many people have been doing with 90 | // my other demo code) 91 | // 92 | // And maybe get Vol. I when it's when it's finally out.. or Tg's training 93 | // where this tool is used: http://Technologeeks.com/OSXRE 94 | // 95 | // Compile: gcc ls.m -o lsdtrip -lobjc -framework Foundation 96 | // or 97 | // gcc-iphone -DARM ls.m -o lsdtrip -lobjc -framework Foundation -framework MobileCoreServices 98 | // 99 | // (that "MobileCoreServices" is required for the dlopen(3) to work) 100 | // 101 | // 102 | // To run: 103 | // Usage: lsdtrip [apps|plugins|publicurls|privateurls] [-v] 104 | // app _bundle_id_ (implies -v for this app) 105 | // 106 | // On iOS: privateurls|publicurls both work (via LSApplicationProxy) 107 | // advid 108 | // launch (CFBundleIdentifier) 109 | // On MacOS: 110 | // front [-v] 111 | // visible 112 | // metainfo 113 | // [app|memory|notification|port|session]status 114 | // whohas _url_ 115 | // types 116 | // dump <-- Try this :-) 117 | // 118 | // Explanation: 119 | // 120 | // Shows what are (IMHO) the most useful of the LaunchServices APIs, as exported by 121 | // [Mobile]CoreServices. In iOS most of the good stuff isn't exported (t), instead wrapped 122 | // by LSApplicationWorkSpace, LSApplicationProxy, and friends. Even though the straight LS 123 | // and _LS calls are much nicer, I chose to use objective-C here in order to maintain 124 | // write-once-run-everywhere, and demonstrate yet again just how OS X and iOS really are 125 | // so similar. 126 | // 127 | // How this works: 128 | // 129 | // Over rather nice XPC to lsd (10.11/9.0) and friends. Full explanation in MOXiI 2. 130 | // (was Chapter 3, "Promenade, A Tour of the OS X and iOS Frameworks", but now in Chapter 5, 131 | // Application Services, to be exact, where more "private" frameworks are exposed). 132 | // 133 | // I use this tool a lot in my MOXiI trainings, and since it's one of the companion tools of 134 | // MOXiI 2 Vol. 1, I thought people would appreciate a hands-on preview :-) This is just one of the many 135 | // open source examples I have planned. 136 | // 137 | // MOXiI 2 Volume 1 is undergoing final review (typos, typos and typos), and will be out imminently. 138 | // 139 | // 140 | // Improvements: 141 | // 142 | // - Can be made into pure C (i.e. not objective-C, .m), but that would make 143 | // the already ugly [] syntax even worse.. 144 | // 145 | // - There's a whole undocumented side to LaunchServices (even as an allegedly 146 | // "public" framework that it is) one can add here. And I left the other 147 | // methods out in an #if 0 block, for future use. 148 | // 149 | // - The UUIDs aren't actually CFUUIDs. They're some $%#$%#$ NS...UUID, which 150 | // isn't compatible, so the UUIDs come with some 0s at the end. Meh. 151 | // 152 | // ChangeLog: 153 | // 154 | // 11/04/2017 - "listen" for notifications re-enabled 155 | // "shmem" added 156 | // 157 | // 07/01/2017 - Lots more functions for MacOS (metainfo-related) 158 | // 159 | // 02/01/2017 - Added advertising identifier stuff 160 | // Fixed dump for iOS 10 and MacOS 12 (stderr) 161 | // 162 | // 06/21/2016 - Added "front" (for MacOS), minor fixes 163 | 164 | // 165 | // License: 166 | // ------- 167 | // As will my other open sources, free - but be so kind as to at least leave the sources intact, 168 | // give credit, cite the MOXiI books, or something. 169 | // 170 | // At the very least, don't github this and claim it as your own. People have been doing that, 171 | // and it's $%#$% annoying and makes me want to quit releasing these things openly. 172 | 173 | 174 | // Ok. Let's begin: 175 | 176 | // My own prototypes and globals: 177 | 178 | typedef int32_t LSSessionID; 179 | BOOL killFirst = false; 180 | int killPid = 0; 181 | #if TARGET_OS_OSX 182 | //#ifndef ARM 183 | extern CFTypeID _LSASNGetTypeID(void); 184 | int _LSASNExtractHighAndLowParts(void *, uint32_t *H, uint32_t *L); 185 | extern CFDictionaryRef _LSCopyApplicationInformation (signed int, 186 | const void *ASN, 187 | uint64_t Zero); 188 | extern void * _LSCopyFrontApplication(signed int); 189 | extern NSArray *_LSCopyApplicationArrayInFrontToBackOrder(signed int, uint64_t unknown); 190 | 191 | 192 | 193 | #endif 194 | 195 | CFStringRef dumpApp (NSObject *AppRef, int Verbose) ; 196 | 197 | NSObject * workspace; // Intentionally void * so as to NOT involve @interface files 198 | NSObject * fbSvcs; 199 | 200 | // OS X and iOS APIs are virtually identical, but the framework name is different 201 | //#ifdef ARM 202 | #if TARGET_OS_IOS || TARGET_OS_TV 203 | #define CORE_SERVICE_FRAMEWORK "/System/Library/Frameworks/MobileCoreServices.framework/MobileCoreServices" 204 | #else 205 | #define CORE_SERVICE_FRAMEWORK "/System/Library/Frameworks/CoreServices.framework/CoreServices" 206 | #endif 207 | 208 | 209 | void keyDumper (CFStringRef Key, void *Value, void *Nesting) 210 | { 211 | // My own dumper, in simplisting format 212 | 213 | 214 | static char buf[1024000]; //big, but not too big - need this for MetaInfo status 215 | 216 | 217 | CFTypeID valueTypeID = CFGetTypeID(Value); 218 | 219 | if (Key ) { 220 | //CFStringGetCStringPtr may fail, so opt for slow path 221 | CFStringGetCString(Key, // theString 222 | buf, // buffer 223 | 1024,// CFIndex 224 | kCFStringEncodingUTF8); //CFStringEncoding 225 | 226 | 227 | } 228 | if (Key && valueTypeID != CFArrayGetTypeID()) { 229 | printf("\t%s%s: ", Nesting ? "\t":"", buf); 230 | 231 | } 232 | 233 | if (valueTypeID == CFStringGetTypeID()) 234 | { 235 | CFStringGetCString(Value, // theString 236 | buf, // buffer 237 | 1024000,// CFIndex 238 | kCFStringEncodingUTF8); //CFStringEncoding 239 | 240 | printf("%s\n", buf); 241 | return; 242 | } 243 | 244 | 245 | if (valueTypeID == CFNumberGetTypeID()) 246 | { 247 | uint64_t valNum; 248 | Boolean conv = CFNumberGetValue(Value, // CFNumberRef number, 249 | CFNumberGetType(Value), // CFNumberType theType, 250 | &valNum); // void *valuePtr); 251 | printf("%llu\n", valNum); // TODO - handle floats, etc 252 | 253 | return; 254 | } 255 | 256 | if (valueTypeID == CFBooleanGetTypeID()) 257 | { 258 | printf("%s\n", CFBooleanGetValue(Value) ? "true" : "false"); 259 | return; 260 | } 261 | 262 | if (valueTypeID == CFURLGetTypeID()) 263 | { 264 | printf("CFURL\n"); 265 | 266 | } 267 | 268 | if (valueTypeID == CFArrayGetTypeID()) 269 | { 270 | 271 | 272 | int count = CFArrayGetCount(Value); 273 | int i = 0; 274 | char key[1024]; // yeah, not null term. ok. I know. 275 | strncpy(key,buf,1024); 276 | // for first element, shove a "\n".. 277 | for (i = 0; i < count; i++) 278 | { 279 | // Call ourselves recursively, but fake a key :-) 280 | // @TODO: proper nesting 281 | printf("\t%s%s[%d]: ", Nesting ? "\t\t" : "", key,i); 282 | 283 | 284 | keyDumper (NULL, // CFStringRef *Key, 285 | (void *)CFArrayGetValueAtIndex(Value, i), // void *Value, 286 | Nesting); // void *Nesting 287 | } 288 | 289 | 290 | return; 291 | } 292 | 293 | if (valueTypeID == CFDateGetTypeID()) 294 | { 295 | // GOD I hate CF. 296 | CFStringRef enUSLocaleIdentifier = CFSTR("en_US"); 297 | CFLocaleRef enUSLocale = CFLocaleCreate(NULL, enUSLocaleIdentifier); 298 | 299 | CFDateFormatterRef fullFormatter = CFDateFormatterCreate 300 | (NULL, enUSLocale, kCFDateFormatterFullStyle, kCFDateFormatterFullStyle); 301 | 302 | CFStringRef dateStr = CFDateFormatterCreateStringWithDate(kCFAllocatorDefault, 303 | fullFormatter, 304 | Value); 305 | keyDumper(NULL,(void*)dateStr,0); 306 | return; 307 | 308 | 309 | } 310 | #pragma clang diagnostic push 311 | #pragma clang diagnostic ignored "-Wincompatible-function-pointer-types" 312 | if (valueTypeID == CFDictionaryGetTypeID()) 313 | { 314 | printf(" (dict)\n"); 315 | CFDictionaryApplyFunction(Value, // CFDictionaryRef theDict, 316 | keyDumper, // CFDictionaryApplierFunction CF_NOESCAPE applier, 317 | (void *)1); //void *context); 318 | 319 | printf("\n"); 320 | return; 321 | 322 | } 323 | 324 | #if TARGET_OS_OSX 325 | //#ifndef ARM 326 | if (valueTypeID == _LSASNGetTypeID() ) 327 | { 328 | uint32_t h, l; 329 | _LSASNExtractHighAndLowParts(Value, &h, &l); 330 | printf("0x%x-0x%x\n", h, l); 331 | return; 332 | 333 | } 334 | 335 | #endif 336 | printf("@TODO: "); 337 | CFShow(Value); 338 | 339 | } 340 | 341 | void 342 | dumpDict(CFDictionaryRef dict) 343 | { 344 | if(getenv("CFSHOW")) { CFShow(dict); return;} 345 | 346 | // @TODO: perfect SimPLIST format 347 | CFDictionaryApplyFunction(dict, // CFDictionaryRef theDict, 348 | keyDumper, // CFDictionaryApplierFunction CF_NOESCAPE applier, 349 | NULL); //void *context); 350 | } 351 | 352 | #pragma clang diagnostic pop 353 | CFStringRef 354 | serializeCFArrayToCFString (CFArrayRef Array, CFStringRef Delimiter) 355 | { 356 | 357 | if (!Array) { return (CFSTR("(null)"));} 358 | CFMutableStringRef returned = CFStringCreateMutable(kCFAllocatorDefault, // CFAllocatorRef alloc, 359 | 4096); //CFIndex maxLength); 360 | 361 | 362 | int len = CFArrayGetCount(Array); 363 | int i = 0; 364 | for (i = 0; i < len ; i++) 365 | 366 | { 367 | CFTypeRef val = (CFTypeRef) CFArrayGetValueAtIndex(Array, i); 368 | 369 | if (i > 0) CFStringAppend(returned, Delimiter); 370 | 371 | // UGLY, I know. But PoC, people. PoC 372 | if (CFGetTypeID(val) == CFStringGetTypeID()) CFStringAppend(returned, val); 373 | 374 | else 375 | if (CFGetTypeID(val) == CFUUIDGetTypeID()){ 376 | CFStringRef UUID = CFUUIDCreateString(kCFAllocatorDefault, val); 377 | CFStringAppend(returned, UUID); 378 | 379 | } 380 | else { 381 | CFStringAppend(returned, dumpApp (val, 0)); 382 | }; 383 | } 384 | 385 | 386 | return (returned); 387 | 388 | 389 | } // serializeCFArrayToCFstring 390 | 391 | 392 | CFStringRef 393 | dumpApp (NSObject *AppRef, int Verbose) 394 | { 395 | // App is an LSApplicationProxy object 396 | 397 | 398 | 399 | CFStringRef appID = (CFStringRef) [AppRef performSelector:@selector( applicationIdentifier)]; 400 | CFStringRef appName = (CFStringRef)[AppRef performSelector:@selector(localizedName)]; 401 | 402 | if (!appName) { appName = CFSTR("Not Set");} 403 | // CFBooleanRef isDeletable = (CFBooleanRef) [AppRef performSelector:@selector(isDeletable)]; 404 | 405 | CFMutableStringRef out = CFStringCreateMutable(kCFAllocatorDefault, // CFAllocatorRef alloc, 406 | 4096); //CFIndex maxLength); 407 | CFStringAppendFormat(out, // CFMutableStringRef theString, 408 | NULL, // CFDictionaryRef formatOptions, 409 | CFSTR("\t%@ (%@) \n"), 410 | appName, appID); 411 | 412 | 413 | 414 | #if 0 415 | // Can also use objective-C to enumerate ivars.. left as an exercise for reader :-) 416 | unsigned int ivarCount; 417 | Ivar *ivars = class_copyIvarList([AppRef class], &ivarCount); 418 | 419 | int i = 0; 420 | for (i = 0; i < ivarCount; i++) 421 | { 422 | fprintf(stderr,"\t%s: \n" , ivar_getName(ivars[i])); 423 | // etc. 424 | } 425 | #endif 426 | if (Verbose) 427 | { 428 | // Dump more - this is just a fraction of the info - 429 | // jtool -v -d LSApplicationProxy /Sy*/L*/Fra*/C*Se*/Frameworks/La*S*/LaunchServices 430 | 431 | CFStringAppendFormat(out, // CFMutableStringRef theString, 432 | NULL, // CFDictionaryRef formatOptions, 433 | CFSTR("\t\tbundleURL: %@\n"), 434 | (CFStringRef)[AppRef performSelector:@selector(bundleURL)]); 435 | 436 | CFStringAppendFormat(out, // CFMutableStringRef theString, 437 | NULL, // CFDictionaryRef formatOptions, 438 | CFSTR("\t\tExecutable: %@\n"), 439 | [AppRef performSelector:@selector(bundleExecutable)]); 440 | 441 | //#ifdef ARM 442 | #if TARGET_OS_IOS || TARGET_OS_TV 443 | // Set on iOS. Can also use versionIdentifier here, but that requires working back from the 444 | // number to a version string (which LaunchServices lets you do with 445 | // LSVersionNumberCopyStringRepresentation/LSVersionNumberGetXXX() 446 | // But why bother when you have a short version string.. 447 | CFStringAppendFormat(out, // CFMutableStringRef theString, 448 | NULL, // CFDictionaryRef formatOptions, 449 | CFSTR("\t\tVersion: %@\n"), 450 | (CFStringRef)[AppRef performSelector:@selector(shortVersionString)]); 451 | 452 | #endif 453 | 454 | // This is apparently unset.. 455 | CFStringAppendFormat(out, // CFMutableStringRef theString, 456 | NULL, // CFDictionaryRef formatOptions, 457 | CFSTR("\t\tVendor Name: %@\n"), 458 | (CFStringRef)[AppRef performSelector:@selector(vendorName)]); 459 | 460 | 461 | 462 | /* 463 | CFStringAppendFormat(out, // CFMutableStringRef theString, 464 | NULL, // CFDictionaryRef formatOptions, 465 | CFSTR("\t\tMach-O UUIDs: %@\n"), 466 | serializeCFArrayToCFString((CFArrayRef)[AppRef performSelector:@selector(machOUUIDs)], CFSTR(","))); 467 | 468 | */ 469 | 470 | CFStringAppendFormat(out, // CFMutableStringRef theString, 471 | NULL, // CFDictionaryRef formatOptions, 472 | CFSTR("\t\tDisk Usage (Static): %@\n"), 473 | (CFStringRef)[AppRef performSelector:@selector(staticDiskUsage)]); 474 | 475 | #if !TARGET_OS_OSX 476 | 477 | CFStringAppendFormat(out, // CFMutableStringRef theString, 478 | NULL, // CFDictionaryRef formatOptions, 479 | CFSTR("\t\tDisk Usage (Dynamic): %@\n"), 480 | [LSHelperClass dynamicDiskUsageForProxy:AppRef]); 481 | #endif 482 | 483 | 484 | 485 | #if 0 486 | // This apparently doesn't work in 9.2 anymore. Not sure about this.. 487 | CFStringAppendFormat(out, // CFMutableStringRef theString, 488 | NULL, // CFDictionaryRef formatOptions, 489 | CFSTR("\t\tDisk Usage (Dynamic): %@\n"), 490 | (CFStringRef)[AppRef performSelector:@selector(dynamicDiskUsage)]); 491 | 492 | #endif 493 | 494 | CFArrayRef UIBackgroundModes = (CFArrayRef) [AppRef performSelector: @selector(UIBackgroundModes)]; 495 | 496 | 497 | // This is a CFArray 498 | if (!CFArrayGetCount(UIBackgroundModes)) { 499 | CFStringAppend (out,CFSTR("\t\tno BackgroundModes")); 500 | } 501 | 502 | else 503 | CFStringAppendFormat(out, // CFMutableStringRef theString, 504 | NULL, // CFDictionaryRef formatOptions, 505 | CFSTR("\t\t BackgroundModes: %@"), 506 | serializeCFArrayToCFString((CFArrayRef)UIBackgroundModes, CFSTR(","))); 507 | 508 | CFStringAppend(out, CFSTR("\n")); 509 | 510 | #if TARGET_OS_IOS || TARGET_OS_TV 511 | //#ifdef ARM 512 | // Only on iOS 513 | CFStringAppendFormat(out, // CFMutableStringRef theString, 514 | NULL, // CFDictionaryRef formatOptions, 515 | CFSTR("\t\tApplication DSID: %@\n"), 516 | (CFStringRef)[AppRef performSelector:@selector(applicationDSID)]); 517 | 518 | 519 | 520 | CFStringAppendFormat(out, // CFMutableStringRef theString, 521 | NULL, // CFDictionaryRef formatOptions, 522 | CFSTR("\t\tPurchaser DSID: %@\n"), 523 | (CFStringRef)[AppRef performSelector:@selector(purchaserDSID)]); 524 | 525 | 526 | 527 | CFStringAppendFormat(out, // CFMutableStringRef theString, 528 | NULL, // CFDictionaryRef formatOptions, 529 | CFSTR("\t\tDownloader DSID: %@\n"), 530 | (CFStringRef)[AppRef performSelector:@selector(downloaderDSID)]); 531 | #endif 532 | 533 | 534 | #if 0 535 | uint64_t modTime = (uint64_t)([AppRef performSelector:@selector( bundleModTime)]); 536 | fprintf(stderr, "\t\tBundle Mod Time: %llu\n", modTime); 537 | #endif 538 | 539 | // 540 | #pragma clang diagnostic push 541 | #pragma clang diagnostic ignored "-Wpointer-to-int-cast" 542 | int cont = (int)([AppRef performSelector:@selector( isContainerized)]); 543 | int restricted = (int)([AppRef performSelector:@selector( isRestricted)]); 544 | #pragma clang diagnostic pop 545 | CFStringAppendFormat(out, 546 | NULL, 547 | CFSTR("\t\tContainerized: %@\n\t\tRestricted: %@\n"), 548 | (cont ? CFSTR("YES (q.v. App-Store Receipt URL for container)") : CFSTR("NO")), 549 | (restricted ? CFSTR("YES") : CFSTR("NO"))); 550 | 551 | 552 | 553 | CFStringAppendFormat(out, // CFMutableStringRef theString, 554 | NULL, // CFDictionaryRef formatOptions, 555 | CFSTR("\t\tApp Store Receipt URL: %@\n"), 556 | (CFStringRef)[AppRef performSelector:@selector( appStoreReceiptURL)]); 557 | 558 | 559 | // These are from LSBundleProxy, which is the parent of LSApplicationProxy 560 | CFStringAppendFormat(out, // CFMutableStringRef theString, 561 | NULL, // CFDictionaryRef formatOptions, 562 | CFSTR("\t\tContainer URL: %@\n"), 563 | [LSHelperClass appContainerForIdentifier:(NSString *)appID]);//[AppRef performSelector:@selector(containerURL)]); 564 | 565 | CFDictionaryRef entitlements = (CFDictionaryRef) [AppRef performSelector:@selector(entitlements)]; 566 | 567 | if (entitlements && CFDictionaryGetCount(entitlements) ) 568 | { 569 | #pragma clang diagnostic push 570 | #pragma clang diagnostic ignored "-Wdeprecated-declarations" 571 | CFDataRef xml = CFPropertyListCreateXMLData(kCFAllocatorDefault, 572 | (CFPropertyListRef)entitlements); 573 | #pragma clang diagnostic pop 574 | 575 | CFStringRef xmlAsString = CFStringCreateFromExternalRepresentation(NULL, xml, kCFStringEncodingUTF8); 576 | 577 | if (xmlAsString) { 578 | CFStringAppendFormat(out, // CFMutableStringRef theString, 579 | NULL, // CFDictionaryRef formatOptions, 580 | CFSTR("\t\tEntitlements:\n-----\n %@\n-----\n"), 581 | xmlAsString); 582 | 583 | } 584 | else { CFStringAppend (out, CFSTR("\t\tEntitlements: Internal error\n"));} 585 | 586 | 587 | } // entitlements 588 | else 589 | CFStringAppend(out,CFSTR("\t\tEntitlements: None\n")); 590 | 591 | //bundleURL 592 | 593 | 594 | } // Verbose 595 | 596 | return (out); 597 | } 598 | 599 | 600 | /* 601 | * 602 | * Soooo much more, courtesy of JTool. Feel free to extend these on your own time: 603 | * 604 | 605 | -[LSApplicationProxy applicationIdentifier]: 606 | -[LSApplicationProxy roleIdentifier]: 607 | -[LSApplicationProxy bundleModTime]: 608 | -[LSApplicationProxy registeredDate]: 609 | -[LSApplicationProxy deviceFamily]: 610 | -[LSApplicationProxy minimumSystemVersion]: 611 | -[LSApplicationProxy sdkVersion]: 612 | -[LSApplicationProxy applicationType]: 613 | -[LSApplicationProxy itemName]: 614 | -[LSApplicationProxy sourceAppIdentifier]: 615 | -[LSApplicationProxy companionApplicationIdentifier]: 616 | -[LSApplicationProxy applicationVariant]: 617 | -[LSApplicationProxy storeCohortMetadata]: 618 | -[LSApplicationProxy shortVersionString]: 619 | -[LSApplicationProxy preferredArchitecture]: 620 | -[LSApplicationProxy familyID]: 621 | -[LSApplicationProxy groupContainers]: 622 | -[LSApplicationProxy directionsModes]: 623 | -[LSApplicationProxy UIBackgroundModes]: 624 | -[LSApplicationProxy audioComponents]: 625 | -[LSApplicationProxy externalAccessoryProtocols]: 626 | -[LSApplicationProxy VPNPlugins]: 627 | -[LSApplicationProxy plugInKitPlugins]: 628 | -[LSApplicationProxy appTags]: 629 | -[LSApplicationProxy requiredDeviceCapabilities]: 630 | -[LSApplicationProxy deviceIdentifierForVendor]: 631 | -[LSApplicationProxy ODRDiskUsage]: 632 | -[LSApplicationProxy storeFront]: 633 | -[LSApplicationProxy externalVersionIdentifier]: 634 | -[LSApplicationProxy betaExternalVersionIdentifier]: 635 | -[LSApplicationProxy appStoreReceiptURL]: 636 | -[LSApplicationProxy installProgress]: 637 | -[LSApplicationProxy installProgressSync]: 638 | -[LSApplicationProxy resourcesDirectoryURL]: 639 | -[LSApplicationProxy privateDocumentIconNames]: 640 | -[LSApplicationProxy setPrivateDocumentIconNames:]: 641 | -[LSApplicationProxy privateIconsDictionary]: 642 | -[LSApplicationProxy privateDocumentIconAllowOverride]: 643 | -[LSApplicationProxy setPrivateDocumentIconAllowOverride:]: 644 | -[LSApplicationProxy iconDataForVariant:]: 645 | -[LSApplicationProxy privateDocumentTypeOwner]: 646 | -[LSApplicationProxy setPrivateDocumentTypeOwner:]: 647 | -[LSApplicationProxy localizedName]: 648 | -[LSApplicationProxy localizedShortName]: 649 | -[LSApplicationProxy localizedNameForContext:]: 650 | -[LSApplicationProxy iconIsPrerendered]: 651 | -[LSApplicationProxy fileSharingEnabled]: 652 | -[LSApplicationProxy profileValidated]: 653 | -[LSApplicationProxy isAdHocCodeSigned]: 654 | -[LSApplicationProxy isPlaceholder]: 655 | -[LSApplicationProxy isAppUpdate]: 656 | -[LSApplicationProxy isNewsstandApp]: 657 | -[LSApplicationProxy isRestricted]: 658 | -[LSApplicationProxy supportsAudiobooks]: 659 | -[LSApplicationProxy supportsExternallyPlayableContent]: 660 | -[LSApplicationProxy supportsOpenInPlace]: 661 | -[LSApplicationProxy hasSettingsBundle]: 662 | -[LSApplicationProxy isInstalled]: 663 | -[LSApplicationProxy isWhitelisted]: 664 | -[LSApplicationProxy isBetaApp]: 665 | -[LSApplicationProxy isPurchasedReDownload]: 666 | -[LSApplicationProxy isWatchKitApp]: 667 | -[LSApplicationProxy hasMIDBasedSINF]: 668 | -[LSApplicationProxy missingRequiredSINF]: 669 | -[LSApplicationProxy isEqual:]: 670 | -[LSApplicationProxy hash]: 671 | -[LSApplicationProxy description]: 672 | -[LSApplicationProxy iconStyleDomain]: 673 | -[LSApplicationProxy userActivityStringForAdvertisementData:]: 674 | -[LSApplicationProxy populateNotificationData]: 675 | -[LSApplicationProxy itemID]: 676 | -[LSApplicationProxy installType]: 677 | -[LSApplicationProxy originalInstallType]: 678 | -[LSApplicationProxy groupIdentifiers]: 679 | -[LSApplicationProxy teamID]: 680 | -[LSApplicationProxy isContainerized]: 681 | */ 682 | 683 | 684 | struct appInfoInShmem { 685 | uint32_t ASN; 686 | uint32_t seed; 687 | uint32_t flags; 688 | uint32_t visibleIndex; 689 | uint32_t pid; 690 | }; 691 | 692 | struct LSShmem { 693 | uint32_t version; 694 | uint32_t sizeInPages; 695 | uint32_t session; 696 | uint32_t zero; 697 | uint32_t debugLogLevel; 698 | uint32_t zero1; 699 | uint64_t alsoZero; 700 | uint32_t frontASNSeed; 701 | uint32_t menuBarOwnerASNSeed; 702 | uint32_t applicationListSeed; 703 | uint32_t pendingApplicationListSeed; 704 | uint32_t visibleApplicationListSeed; 705 | uint32_t applicationInformationSeed; 706 | uint64_t unknown[3]; 707 | uint32_t frontASN; 708 | uint32_t menuBarOwnerASN; 709 | uint32_t systemProcessASN; 710 | uint32_t systemLauncherASN; 711 | uint64_t nevermind[5]; 712 | uint32_t numPids; 713 | uint32_t whatever; 714 | struct appInfoInShmem appList[0]; 715 | 716 | /* 717 | menuBarOwnerASN="Terminal" ASN:0x0-0xa00a: 718 | systemProcessASN="loginwindow" ASN:0x0-0x1001: 719 | systemLauncherASN=ASN:0x0-0x0: 720 | nextAppToBringForwardASNLowHalf=ASN:0x0-0x0: 721 | expectedFrontASNLowerHalf=ASN:0x0-0x0: 722 | systemUIPresentationMode=0 "Normal" systemUIPresentationOptions=0 723 | launchProgress=0 724 | launchProgessUserActivityCount=0 725 | processes = #37 726 | */ 727 | 728 | 729 | }; 730 | #if TARGET_OS_OSX 731 | //#ifndef ARM 732 | void dumpShmem (struct LSShmem *Shmem) 733 | { 734 | printf("Shmem at address %p (%d pages = 0x%x):\n", Shmem, 735 | Shmem->sizeInPages, Shmem->sizeInPages * 0x1000); 736 | printf("Session: %d\n", Shmem->session); 737 | // lockCount=0 738 | printf("DebugLogLevel: %d\n", Shmem->debugLogLevel); 739 | printf("frontASNSeed: %d\n", Shmem->frontASNSeed); 740 | printf("menuBarOwnerASNSeed: %d\n", Shmem->menuBarOwnerASNSeed); 741 | printf("applicationListSeed: %d\n", Shmem->applicationListSeed); 742 | printf("pendingApplicationListSeed: %d\n", Shmem->pendingApplicationListSeed); 743 | printf("visibleApplicationListSeed: %d\n", Shmem->visibleApplicationListSeed); 744 | printf("applicationInformationSeed: %d\n", Shmem->applicationInformationSeed); 745 | printf("frontASN: 0x%x\n", Shmem->frontASN); 746 | printf("systemProcessASN: 0x%x\n", Shmem->systemProcessASN); 747 | printf("systemLauncherASN: 0x%x\n", Shmem->systemLauncherASN); 748 | 749 | printf("Processes: %d\n", Shmem->numPids); 750 | int p = 0; 751 | 752 | 753 | for (p = 0; p < Shmem->numPids; p++) 754 | { 755 | printf("\t App: ASN 0x%x PID: %d Visible Index: %d Seed: %d, Flags: 0x%x\n", 756 | Shmem->appList[p].ASN, 757 | Shmem->appList[p].pid, 758 | Shmem->appList[p].visibleIndex, 759 | Shmem->appList[p].seed, 760 | Shmem->appList[p].flags); 761 | 762 | } 763 | 764 | 765 | 766 | 767 | 768 | } // dump Shmem 769 | #endif 770 | 771 | void 772 | dumpIcon (NSString *identifier) { 773 | #if TARGET_OS_IOS || TARGET_OS_TV 774 | [[NSBundle bundleWithPath:@"/System/Library/PrivateFrameworks/TVKit.framework"] load]; 775 | id proxy = [LSHelperClass smartProxyFromValue:identifier]; 776 | NSLog(@"proxy %@", proxy); 777 | UIImage *image = nil; 778 | NSString *outputPath = [NSString stringWithFormat:@"/var/mobile/Documents/%@.png", [proxy localizedName]]; 779 | 780 | if ([proxy respondsToSelector:@selector(tv_applicationFlatIcon)]){ 781 | 782 | image = [proxy tv_applicationFlatIcon]; 783 | NSLog(@"exporting tvOS icon: %@", outputPath); 784 | 785 | } else { 786 | 787 | image = [UIImage _applicationIconImageForBundleIdentifier:[proxy applicationIdentifier] format:0 scale:[UIScreen mainScreen].scale]; 788 | 789 | NSLog(@"exporting iOS icon: %@", outputPath); 790 | 791 | } 792 | [UIImagePNGRepresentation(image) writeToFile:outputPath atomically:YES]; 793 | NSString *airDropURL = [NSString stringWithFormat:@"airdropper://%@", outputPath]; 794 | NSURL *url = [NSURL URLWithString:airDropURL]; 795 | [(LSApplicationWorkspace*)workspace openURL:url]; 796 | #endif 797 | } 798 | 799 | void 800 | openURL (CFStringRef URL){ 801 | 802 | } 803 | 804 | void 805 | dumpURL (CFStringRef URL, int Verbose) 806 | { 807 | 808 | CFMutableStringRef out = CFStringCreateMutable(kCFAllocatorDefault, // CFAllocatorRef alloc, 809 | 4096); //CFIndex maxLength); 810 | 811 | CFStringAppend(out, URL); 812 | if (Verbose) { 813 | CFArrayRef appsForURL = (CFArrayRef) [workspace performSelector:@selector(applicationsAvailableForHandlingURLScheme:) withObject:(id)URL]; 814 | #pragma clang diagnostic push 815 | #pragma clang diagnostic ignored "-Wreceiver-expr" 816 | if ([appsForURL count] == 0) { 817 | #pragma clang diagnostic pop 818 | // Maybe it's a document type.. 819 | id doxy = [objc_getClass("LSDocumentProxy") documentProxyForName:@"" type:(id)URL MIMEType:nil]; 820 | appsForURL = (CFArrayRef) [workspace performSelector:@selector(applicationsAvailableForOpeningDocument:) withObject:doxy]; 821 | } 822 | // if still no apps, then no claim. 823 | if (!appsForURL) 824 | { 825 | fprintf(stderr,"No app has claimed this URL\n"); exit(1); 826 | } 827 | 828 | 829 | // This is a CFArray 830 | if (CFGetTypeID(appsForURL) != CFArrayGetTypeID()) 831 | { 832 | fprintf(stderr, "Was expecting a CFArray of Apps!\n"); 833 | exit(2); 834 | } 835 | 836 | if (!CFArrayGetCount (appsForURL)) CFStringAppend(out,CFSTR(" - Not claimed by anyone")); 837 | else { 838 | 839 | CFStringRef apps = serializeCFArrayToCFString (appsForURL, CFSTR("\n\t\t\t")); 840 | 841 | CFStringAppend (out, apps); 842 | CFRelease (apps); 843 | } 844 | } 845 | 846 | CFShow(out); 847 | CFRelease(out); 848 | } 849 | void 850 | dumpPlugin (NSObject *PluginRef, int Verbose) 851 | { 852 | 853 | CFStringRef pluginName = (CFStringRef) [PluginRef performSelector:@selector( localizedName)]; 854 | CFStringRef pluginID = (CFStringRef) [PluginRef performSelector:@selector( pluginIdentifier)]; 855 | CFUUIDRef pluginUUID = (CFUUIDRef)[PluginRef performSelector:@selector(pluginUUID)]; 856 | 857 | CFStringRef out = CFStringCreateWithFormat(kCFAllocatorDefault, 858 | NULL, CFSTR("\t%@ (%@) - %@"), 859 | pluginName,pluginID, CFUUIDCreateString(kCFAllocatorDefault, pluginUUID)); 860 | 861 | CFShow(out); 862 | 863 | 864 | } // end Dump 865 | 866 | void monitorCallback() 867 | { 868 | printf("In callback\n"); 869 | } 870 | 871 | 872 | 873 | int notificationCallbackFunc(int a, CFDictionaryRef *Notif, void *todo1, void *x, uint64_t xx, void *y) { 874 | 875 | 876 | printf("Notification Received:\n"); 877 | #pragma clang diagnostic push 878 | #pragma clang diagnostic ignored "-Wincompatible-pointer-types" 879 | dumpDict(Notif); 880 | #pragma clang diagnostic pop 881 | return 0; 882 | } 883 | 884 | void 885 | usage (char *ProgName) 886 | { 887 | #if TARGET_OS_IOS || TARGET_OS_TV 888 | //#ifdef ARM 889 | fprintf(stderr, "Usage: %s %s [apps|plugins|publicurls|privateurls] [-v]\n", basename(ProgName), tripVersionNumber); 890 | fprintf(stderr, " app _bundle_id_ or _localized_name_ (implies -v for this app)\n"); 891 | fprintf(stderr, " launch _bundle_id_ or _localized_name_ [-k]\n"); 892 | fprintf(stderr, " advid [clear]\n"); 893 | fprintf(stderr, " exporticon _bundle_id_ or _localized_name_\n"); 894 | #else 895 | fprintf(stderr, "Usage: %s [apps|plugins] [-v]\n", basename(ProgName)); 896 | fprintf(stderr, " app _bundle_id_ or localized_name (implies -v for this app)\n"); 897 | fprintf(stderr, " launch _bundle_id_ or _localized_name_\n"); 898 | fprintf(stderr, " front [-v]\n"); 899 | fprintf(stderr, " visible\n"); 900 | fprintf(stderr, " listen (Get app launch/foreground notifications - cool)\n"); 901 | fprintf(stderr, " shmem\n"); 902 | fprintf(stderr, " metainfo\n"); 903 | fprintf(stderr, " [app|memory|notification|port|session]status\n"); 904 | #endif 905 | fprintf(stderr, " whohas _url_ or _uti_ (ie url or public.data \n"); 906 | fprintf(stderr, " types (list UTI's)\n"); 907 | fprintf(stderr, " dump (extensive dump of csstore file)\n"); 908 | fprintf(stderr, " open (open a URL)\n"); 909 | fprintf(stderr, "\nSet CFSHOW=1 to use CFshow in place of J's dumping function (which is still a work in progress)\n"); 910 | exit(0); 911 | } // usage 912 | 913 | int 914 | main (int argc, char **argv) 915 | { 916 | 917 | int verbose = 0; 918 | 919 | // So - why dup? because CFShow(), which I use extensively, write to stderr. 920 | // And I really CANNOT stand the whole CFStringToCstr $%#$%#$ just to get a stupid 921 | // printout! So instead, I save stderr, and then reopen stderr to stdout. This 922 | // way, the output can be grep(1)-ed easily. 923 | 924 | dup2(2,3); 925 | dup2(1,2); 926 | 927 | if (argc < 2) { 928 | usage(argv[0]); 929 | } 930 | /* 931 | if (argc >= 3){ 932 | fprintf(stderr, "arc: %i 0: %s 1: %s 2: %s 3: %s\n", argc, argv[0], argv[1], argv[2], argv[3]); 933 | }*/ 934 | if (argv[2] && strcmp(argv[2], "-v")==0) verbose++; 935 | if (argv[3] && strcmp(argv[3], "-k")==0) killFirst = true; 936 | if (argc >= 4){ 937 | if (argv[4] && strcmp(argv[3], "-k")==0) killPid = atoi(argv[4]); 938 | } 939 | 940 | // Getting the LS* classes and functions we need here: 941 | // --------------------------------------------------- 942 | Class LSApplicationWorkspace_class = objc_getClass("LSApplicationWorkspace"); 943 | if (!LSApplicationWorkspace_class) {fprintf(stderr,"Unable to get Workspace class\n"); exit(1);} 944 | workspace = [LSApplicationWorkspace_class performSelector:@selector (defaultWorkspace)]; 945 | if (!workspace) {fprintf(stderr,"Unable to get Workspace\n"); exit(2);} 946 | 947 | void *CS_handle = dlopen (CORE_SERVICE_FRAMEWORK, RTLD_NOW); 948 | if (!CS_handle) { fprintf(stderr,"Can't find %s!\n", CORE_SERVICE_FRAMEWORK); exit(2); }; 949 | 950 | #if TARGET_OS_IOS || TARGET_OS_TV 951 | //#ifdef ARM 952 | 953 | 954 | if (strcmp(argv[1],"running") == 0) 955 | { 956 | #if 0 957 | Class fbSvcs_class = objc_getClass("FBSSystemService"); 958 | 959 | if (!fbSvcs_class) { fprintf(stderr,"Unable to get Workspace\n"); exit(2);} 960 | fbSvcs = [fbSvcs_class performSelector:@selector (sharedService)]; 961 | printf("GOT SVCS %p\n", fbSvcs); 962 | 963 | #endif 964 | printf("Not yet\n"); 965 | exit(0); 966 | } 967 | #endif 968 | if ( (strcmp(argv[1],"apps") == 0) || (strcmp(argv[1], "app") == 0)) 969 | 970 | { 971 | 972 | CFStringRef wantedBundleID = NULL; 973 | 974 | 975 | if (strcmp(argv[1], "apps")) // that is, not all apps 976 | { 977 | // expecting a bundle identifier here 978 | 979 | if (!argv[2]) { fprintf(stderr,"app option requires a specific bundle id. Try 'apps' to get a list\n"); 980 | exit(5); } 981 | 982 | wantedBundleID = CFStringCreateWithCString(kCFAllocatorDefault, // CFAllocatorRef alloc, 983 | argv[2], // const char *cStr, 984 | kCFStringEncodingUTF8); //CFStringEncoding encoding); 985 | 986 | CFTypeRef app = [LSHelperClass smartProxyFromValue:(id)wantedBundleID]; 987 | if (app) { 988 | CFStringRef dump = dumpApp(app, 1); 989 | CFShow(dump); 990 | CFRelease(dump); 991 | exit(0); // only one match here. 992 | } 993 | } 994 | 995 | CFArrayRef apps = (CFArrayRef) [workspace performSelector:@selector(allApplications)]; 996 | // This is a CFArray 997 | if (CFGetTypeID(apps) != CFArrayGetTypeID()) 998 | { 999 | fprintf(stderr, "Was expecting a CFArray of Apps!\n"); 1000 | exit(2); 1001 | } 1002 | 1003 | int len = CFArrayGetCount(apps); 1004 | int i = 0; 1005 | for (i = 0; i < len ; i++) 1006 | { 1007 | CFTypeRef app = CFArrayGetValueAtIndex(apps,i); 1008 | // Got app: Dump if want all, or if matches id. 1009 | 1010 | CFStringRef appID = (CFStringRef) [(id)app performSelector:@selector(applicationIdentifier)]; 1011 | if (!wantedBundleID) { 1012 | CFStringRef dump = dumpApp(app, verbose); 1013 | CFShow(dump); 1014 | CFRelease(dump); 1015 | } 1016 | } 1017 | 1018 | if ( wantedBundleID) { 1019 | fprintf(stderr,"Application with Bundle ID or Executable name %s not found. Try '%s apps' first, and remember case-sensitivity\n", 1020 | argv[2], argv[0]); 1021 | exit(2); 1022 | } 1023 | 1024 | exit(0); 1025 | } 1026 | 1027 | if (strcmp(argv[1], "publicurls") == 0) 1028 | { 1029 | #if TARGET_OS_IOS || TARGET_OS_TV 1030 | //#ifdef ARM 1031 | CFArrayRef puburls = (CFArrayRef) [workspace performSelector:@selector(publicURLSchemes)]; 1032 | 1033 | 1034 | // This is a CFArray 1035 | if (CFGetTypeID(puburls) != CFArrayGetTypeID()) 1036 | { 1037 | fprintf(stderr, "Was expecting a CFArray of publicURLSchemes!\n"); 1038 | exit(2); 1039 | } 1040 | 1041 | int len = CFArrayGetCount(puburls); 1042 | int i = 0; 1043 | for (i = 0; i < len ; i++) 1044 | { 1045 | CFStringRef url = CFArrayGetValueAtIndex(puburls,i); 1046 | dumpURL(url, verbose); 1047 | 1048 | 1049 | 1050 | } 1051 | #else 1052 | fprintf(stderr,"Not implemented on MacOS.. yet\n"); 1053 | #endif 1054 | exit(0); 1055 | 1056 | } 1057 | 1058 | if (strcmp(argv[1], "privateurls") == 0) 1059 | { 1060 | #if TARGET_OS_OSX 1061 | //#ifndef ARM 1062 | 1063 | // MacOS's LSApplicationWorkSpace does not respond to private URLs.. 1064 | 1065 | // @TODO:__LSCopyAllApplicationURLs 1066 | printf("Not implemented on MacOS.. yet\n"); 1067 | 1068 | 1069 | #else 1070 | CFArrayRef (privurls) = (CFArrayRef) [workspace performSelector:@selector(privateURLSchemes)]; 1071 | // This is a CFArray 1072 | if (CFGetTypeID(privurls) != CFArrayGetTypeID()) 1073 | { 1074 | fprintf(stderr, "Was expecting a CFArray of privateURLSchemes!\n"); 1075 | exit(2); 1076 | } 1077 | 1078 | int len = CFArrayGetCount(privurls); 1079 | int i = 0; 1080 | for (i = 0; i < len ; i++) 1081 | { 1082 | CFStringRef url = CFArrayGetValueAtIndex(privurls,i); 1083 | dumpURL(url, verbose); 1084 | 1085 | 1086 | 1087 | } 1088 | #endif 1089 | exit(0); 1090 | 1091 | } 1092 | 1093 | 1094 | if (strcmp(argv[1], "plugins") == 0) 1095 | { 1096 | CFArrayRef plugins = (CFArrayRef) [workspace performSelector:@selector(installedPlugins)]; 1097 | // This, too, is a CFArray 1098 | if (CFGetTypeID(plugins) != CFArrayGetTypeID()) 1099 | { 1100 | fprintf(stderr, "Was expecting a CFArray of plugins!\n"); 1101 | exit(2); 1102 | } 1103 | 1104 | int len = CFArrayGetCount(plugins); 1105 | int i = 0; 1106 | for (i = 0; i < len ; i++) 1107 | { 1108 | CFTypeRef plugin = CFArrayGetValueAtIndex(plugins,i); 1109 | dumpPlugin(plugin, verbose); 1110 | 1111 | 1112 | 1113 | } 1114 | exit(0); 1115 | } 1116 | 1117 | if (strcmp(argv[1], "types") == 0) 1118 | { 1119 | // I resort to dlopen/dlsym here to make linking simpler. You don't have to. 1120 | 1121 | typedef CFArrayRef (*UTCopyDeclaredTypeIdentifiersFunc)(void); 1122 | 1123 | UTCopyDeclaredTypeIdentifiersFunc UTCopyDeclaredTypeIdentifiers 1124 | = dlsym (CS_handle, "_UTCopyDeclaredTypeIdentifiers"); 1125 | 1126 | CFArrayRef utis = UTCopyDeclaredTypeIdentifiers(); 1127 | 1128 | // As usual, this is an array.. 1129 | int len = CFArrayGetCount(utis); 1130 | int i = 0; 1131 | for (i = 0; i < len ; i++) 1132 | { 1133 | // Seriously, AAPL - couldn't you find a better acronym? 1134 | CFTypeRef uti = CFArrayGetValueAtIndex(utis,i); 1135 | CFShow(uti); 1136 | 1137 | } 1138 | exit(0); 1139 | 1140 | 1141 | 1142 | } 1143 | /* 1144 | if (strcmp(argv[1], "open") == 0){ 1145 | if (!argv[2]) { 1146 | fprintf(stderr,"open: Option requires an URL as an argument!\n"); 1147 | exit(3); 1148 | } 1149 | CFStringRef url = CFStringCreateWithCString(kCFAllocatorDefault, // CFAllocatorRef alloc, 1150 | argv[2], // const char *cStr, 1151 | kCFStringEncodingUTF8); //CFStringEncoding encoding); 1152 | openURL(url); 1153 | 1154 | exit(0); 1155 | } 1156 | */ 1157 | if (strcmp(argv[1], "whohas") == 0) 1158 | { 1159 | 1160 | if (!argv[2]) { 1161 | fprintf(stderr,"whohas: Option requires an URL Scheme or UTI as an argument!\n"); 1162 | exit(3); 1163 | } 1164 | 1165 | 1166 | 1167 | CFStringRef url = CFStringCreateWithCString(kCFAllocatorDefault, // CFAllocatorRef alloc, 1168 | argv[2], // const char *cStr, 1169 | kCFStringEncodingUTF8); //CFStringEncoding encoding); 1170 | 1171 | dumpURL(url,1); 1172 | 1173 | 1174 | exit(0); 1175 | } 1176 | 1177 | 1178 | 1179 | #if 0 1180 | // ignore this part for now 1181 | if (strcmp(argv[1],"claims") == 0) 1182 | { 1183 | 1184 | typedef CFStringRef (*LSCopyClaimedActivityIdentifiersAndDomainsFunc)(CFStringRef, CFStringRef); 1185 | 1186 | LSCopyClaimedActivityIdentifiersAndDomainsFunc 1187 | LSCopyClaimedActivityIdentifiersAndDomains = dlsym (CS_handle, "_LSCopyClaimedActivityIdentifiersAndDomains"); 1188 | 1189 | if (!LSCopyClaimedActivityIdentifiersAndDomains ) 1190 | { 1191 | fprintf(stderr,"Unable to find LSCopyClaimedActivityIdentifiersAndDomains "); 1192 | exit(3); 1193 | } 1194 | 1195 | CFStringRef result = LSCopyClaimedActivityIdentifiersAndDomains (NULL, NULL); 1196 | CFShow(result); 1197 | exit(0); 1198 | 1199 | 1200 | } 1201 | #endif 1202 | 1203 | 1204 | 1205 | if (strcmp(argv[1],"advid") == 0) 1206 | { 1207 | 1208 | if ((argc ==3) && strcmp(argv[2], "clear") == 0) { 1209 | (void) [workspace performSelector:@selector(clearAdvertisingIdentifier) ]; 1210 | printf("advertising identifier should be clear\n"); 1211 | } 1212 | else { 1213 | // just show 1214 | #pragma clang diagnostic push 1215 | #pragma clang diagnostic ignored "-Wincompatible-pointer-types" 1216 | CFStringRef advid = [workspace performSelector:@selector(deviceIdentifierForAdvertising)]; 1217 | #pragma clang diagnostic pop 1218 | CFShow(advid); 1219 | 1220 | } 1221 | 1222 | exit(0); 1223 | 1224 | } 1225 | #if TARGET_OS_IOS || TARGET_OS_TV 1226 | //#ifdef ARM 1227 | if (strcmp(argv[1],"open") == 0) 1228 | { 1229 | 1230 | if (!argv[2]) { 1231 | fprintf(stderr,"open: Option requires an argument!\n"); exit(3); 1232 | } 1233 | CFStringRef theURLs = CFStringCreateWithCString(kCFAllocatorDefault, // CFAllocatorRef alloc, 1234 | argv[2], // const char *cStr, 1235 | kCFStringEncodingUTF8); //CFStringEncoding encoding); 1236 | 1237 | CFURLRef theURL; 1238 | theURL = CFURLCreateWithString(kCFAllocatorDefault, // CFAllocatorRef allocator 1239 | theURLs, //CFStringRef URLString, 1240 | NULL); // CFURLRef baseURL); 1241 | 1242 | printf("CREATED URL %p\n", theURL); 1243 | #pragma clang diagnostic push 1244 | #pragma clang diagnostic ignored "-Wpointer-to-int-cast" 1245 | int t = (int) [workspace performSelector:@selector(openURL:) withObject:(id) theURL ]; 1246 | #pragma clang diagnostic pop 1247 | fprintf(stderr, "%s %s (RC: %d)\n", 1248 | t ? "opened" : "Unable to open", 1249 | argv[2], t); 1250 | 1251 | #if 0 1252 | 1253 | extern int 1254 | LSOpenCFURLRef( 1255 | CFURLRef inURL, 1256 | __nullable CFURLRef *__nullable outLaunchedURL) ; 1257 | 1258 | LSOpenCFURLRef(theURL, NULL); 1259 | 1260 | 1261 | 1262 | #endif 1263 | exit(0); 1264 | 1265 | 1266 | } 1267 | #endif 1268 | 1269 | if (strcmp(argv[1],"exporticon") == 0) 1270 | { 1271 | 1272 | 1273 | if (!argv[2]) { 1274 | fprintf(stderr,"exporticon: Option requires an argument!\n"); exit(3); 1275 | } 1276 | CFStringRef bundleID = CFStringCreateWithCString(kCFAllocatorDefault, // CFAllocatorRef alloc, 1277 | argv[2], // const char *cStr, 1278 | kCFStringEncodingUTF8); //CFStringEncoding encoding); 1279 | #pragma clang diagnostic push 1280 | #pragma clang diagnostic ignored "-Wincompatible-pointer-types" 1281 | dumpIcon(bundleID); 1282 | #pragma clang diagnostic pop 1283 | exit(0); 1284 | 1285 | } 1286 | 1287 | if (strcmp(argv[1],"launch") == 0) { 1288 | if (!argv[2]) { 1289 | fprintf(stderr,"launch: Option requires an argument!\n"); exit(3); 1290 | } 1291 | 1292 | 1293 | 1294 | CFStringRef bundleID = CFStringCreateWithCString(kCFAllocatorDefault, // CFAllocatorRef alloc, 1295 | argv[2], // const char *cStr, 1296 | kCFStringEncodingUTF8); //CFStringEncoding encoding); 1297 | 1298 | BOOL validBundle = [LSHelperClass validBundleId:(id)bundleID]; 1299 | if (!validBundle) { 1300 | NSLog(@"invalid bundleID: %@", (id)bundleID); 1301 | bundleID = (CFStringRef)[LSHelperClass bundleIDForProcessName:(id)bundleID]; 1302 | NSLog(@"found bundle id: %@", bundleID); 1303 | } 1304 | #if TARGET_OS_OSX 1305 | 1306 | NSWorkspace *ws = [NSWorkspace sharedWorkspace]; 1307 | id proxy = [LSApplicationProxy applicationProxyForIdentifier:(id)bundleID]; 1308 | NSURL *path = [proxy bundleURL]; 1309 | if (@available(macOS 10.15, *)) { 1310 | [ws openApplicationAtURL:path configuration:[NSWorkspaceOpenConfiguration configuration] completionHandler:^(NSRunningApplication * _Nullable app, NSError * _Nullable error) { 1311 | NSLog(@"running app: %@ error: %@", app, error); 1312 | exit(0); 1313 | }]; 1314 | } else { 1315 | // Fallback on earlier versions 1316 | NSLog(@"error: need to implement for earlier versions..."); 1317 | exit(0); 1318 | } 1319 | sleep(1); 1320 | 1321 | #else 1322 | if (killFirst){ 1323 | 1324 | if (killPid != 0){ 1325 | NSLog(@"killing pid: %i", killPid); 1326 | kill(killPid, 9); 1327 | } else { 1328 | id proxy = [LSApplicationProxy applicationProxyForIdentifier:(id)bundleID]; 1329 | if (!proxy) { 1330 | proxy = [LSHelperClass proxyForProcessName:(id)bundleID]; 1331 | NSLog(@"proxy was nil, checking via name: %@", proxy); 1332 | } 1333 | NSString *exe = [proxy canonicalExecutablePath]; 1334 | NSLog(@"prox: %@", proxy); 1335 | NSLog(@"exe: %@", exe); 1336 | pid_t proc = [LSFindProcess find_process:[exe UTF8String]]; 1337 | fprintf(stderr, "found proc: %d\n", proc); 1338 | if (proc != 0){ 1339 | int status = kill(proc, 9); 1340 | } 1341 | } 1342 | 1343 | } 1344 | sleep(1); 1345 | #pragma clang diagnostic push 1346 | #pragma clang diagnostic ignored "-Wpointer-to-int-cast" 1347 | int t = (int) [workspace performSelector:@selector(openApplicationWithBundleID:) withObject:(id) bundleID ]; 1348 | #pragma clang diagnostic pop 1349 | 1350 | 1351 | fprintf(stderr, "%s %s\n", 1352 | t ? "Launched" : "Unable to launch", 1353 | argv[2]); 1354 | 1355 | exit(0); 1356 | #endif 1357 | } 1358 | 1359 | 1360 | #if TARGET_OS_OSX 1361 | //#ifndef ARM 1362 | 1363 | // This only works on MacOS 1364 | // because A) API doesn't exist in *OS 1365 | // B) there's no "visible application ordering" in *OS, to begin with. 1366 | 1367 | if (strcmp(argv[1], "visible") == 0) 1368 | { 1369 | 1370 | NSArray *apps = _LSCopyApplicationArrayInFrontToBackOrder(-2, 0); 1371 | // Apps is an array of LSASN types 1372 | int a = 0; 1373 | for (a = 0; a < [apps count]; a++) 1374 | { 1375 | void *asn = [apps objectAtIndex:a]; 1376 | 1377 | CFDictionaryRef dict = _LSCopyApplicationInformation (-2, asn,0); 1378 | CFStringRef bn = CFDictionaryGetValue(dict, CFSTR("CFBundleName")); 1379 | CFStringRef bp = CFDictionaryGetValue(dict, CFSTR("CFBundleExecutablePath")); 1380 | // ShowASN (ignoring return value here) 1381 | uint32_t high, low; 1382 | 1383 | //int _LSASNExtractHighAndLowParts(void *, uint32_t *H, uint32_t *L); 1384 | (void) _LSASNExtractHighAndLowParts (asn, &high, &low); 1385 | 1386 | fprintf(stderr,"0x%x-0x%-6x ", high, low); 1387 | 1388 | // CFShow(bn); 1389 | CFShow(bp); 1390 | 1391 | } 1392 | exit(0); 1393 | 1394 | } 1395 | if (strcmp(argv[1], "front") == 0) 1396 | { 1397 | // If you wanted the front most application you could also 1398 | // print the first entry in the array from "Visible" (that is, 1399 | // _LSCopyApplicationArrayInFrontToBackOrder) 1400 | CFStringRef front = _LSCopyFrontApplication(-2); 1401 | if (!front) { 1402 | fprintf(stderr,"Can't get front application?\n"); exit(2); 1403 | } 1404 | if (_LSASNGetTypeID() == CFGetTypeID(front)) 1405 | { 1406 | // Now get info 1407 | CFDictionaryRef dict = _LSCopyApplicationInformation (-2, front,0); 1408 | if (verbose) 1409 | { 1410 | dumpDict(dict); 1411 | } 1412 | else 1413 | { 1414 | CFStringRef dn = CFDictionaryGetValue(dict, CFSTR("CFBundleName")); 1415 | CFShow(dn); 1416 | 1417 | } 1418 | 1419 | exit(0); 1420 | } 1421 | else 1422 | { 1423 | fprintf(stderr,"Got front application but not an LSASN type.. Has AAPL changed the API or something?\n"); exit(3); 1424 | 1425 | 1426 | } 1427 | 1428 | 1429 | 1430 | exit(0); 1431 | } 1432 | 1433 | 1434 | extern CFDictionaryRef _LSCopyMetaApplicationInformation(LSSessionID id, CFArrayRef *What); 1435 | 1436 | 1437 | 1438 | if (strcmp(argv[1], "metainfo") == 0) 1439 | { 1440 | 1441 | 1442 | // A null pointer for What gets you a raw dict. 1443 | CFDictionaryRef meta = _LSCopyMetaApplicationInformation(-2,0); 1444 | if (!meta) { printf("NO META\n"); exit(0);} 1445 | 1446 | dumpDict(meta); 1447 | exit(0); 1448 | 1449 | } 1450 | 1451 | if (strstr(argv[1], "status")) { 1452 | 1453 | CFStringRef vals[4]; 1454 | vals[0] = CFSTR("Status"); 1455 | vals[1] = NULL; 1456 | 1457 | // A non null pointer for What (NS/CFArray) gets you a specific dict 1458 | // which is already human-readable 1459 | // 1460 | if (strcmp(argv[1], "appstatus") == 0) vals[1] = CFSTR("ApplicationStatus"); 1461 | if (strcmp(argv[1], "notificationstatus") == 0) vals[1] = CFSTR("NotificationStatus"); 1462 | if (strcmp(argv[1], "portstatus") == 0) vals[1] = CFSTR("PortStatus"); 1463 | if (strcmp(argv[1], "sessionstatus") == 0) vals[1] = CFSTR("SessionStatus"); 1464 | // Only supported in DEBUG builds :-( 1465 | if (strcmp(argv[1], "memorystatus") == 0) vals[1] = CFSTR("MemoryStatus"); 1466 | 1467 | if (!vals[1]) { fprintf(stderr,"What kind of status is %s?\n", argv[1]); exit(5);} 1468 | 1469 | CFArrayRef what = CFArrayCreate(kCFAllocatorDefault, // CFAllocatorRef allocator, 1470 | (const void **) vals, // const void **values, 1471 | 2, // CFIndex numValues, 1472 | &kCFTypeArrayCallBacks); //const CFArrayCallBacks *callBacks); 1473 | #pragma clang diagnostic push 1474 | #pragma clang diagnostic ignored "-Wincompatible-pointer-types" 1475 | CFDictionaryRef meta = _LSCopyMetaApplicationInformation(-2,what); 1476 | #pragma clang diagnostic pop 1477 | 1478 | dumpDict(meta); 1479 | exit(0); 1480 | 1481 | } 1482 | typedef void *LSNotificationReceiverRef; 1483 | 1484 | if (strcmp(argv[1],"shmem") == 0) 1485 | { 1486 | extern void * _LSDebugGetSharedMemoryPageAddress(LSSessionID); 1487 | 1488 | void *shmem = _LSDebugGetSharedMemoryPageAddress(-2); 1489 | if (shmem) { 1490 | dumpShmem(shmem); 1491 | } 1492 | 1493 | 1494 | 1495 | exit(0); 1496 | } 1497 | extern LSNotificationReceiverRef _LSScheduleNotificationFunction(LSSessionID, 1498 | void *callback, // actually a func pointer 1499 | uint64_t zero, 1500 | NSMutableArray *context, // RCX 1501 | CFRunLoopRef CFRunLoop, 1502 | const CFRunLoopMode CFRunLoopMode); 1503 | 1504 | if (strcmp(argv[1],"listen") == 0) 1505 | { 1506 | 1507 | 1508 | CFRunLoopRef rl = CFRunLoopGetCurrent(); 1509 | 1510 | // If you don't give an array, even empty, you get RC 775 1511 | NSMutableArray *notifs = [[NSMutableArray alloc ] init]; 1512 | 1513 | 1514 | LSNotificationReceiverRef ref = 1515 | _LSScheduleNotificationFunction(-2, 1516 | notificationCallbackFunc, 1517 | 0, 1518 | notifs, // 0, //notifs, 1519 | rl, 1520 | NULL); //kCFRunLoopDefaultMode); //CFRunLoopCopyCurrentMode(rl)); 1521 | 1522 | 1523 | 1524 | // 11/1/2017 This was missing from earlier version 1525 | #pragma clang diagnostic push 1526 | #pragma clang diagnostic ignored "-Wimplicit-int" 1527 | extern _LSModifyNotification(LSNotificationReceiverRef ref, 1528 | int numKeys, 1529 | uint32_t *mask, 1530 | uint32_t unknown, 1531 | uint32_t unknown1, 1532 | uint32_t unknown2); 1533 | #pragma clang diagnostic pop 1534 | 1535 | #pragma clang diagnostic push 1536 | #pragma clang diagnostic ignored "-Wpointer-sign" 1537 | int mask=-1; // get all 1538 | _LSModifyNotification(ref, // 1539 | 1, // uint32 1540 | &mask, 1541 | 0, 1542 | 0, 0); 1543 | #pragma clang diagnostic pop 1544 | 1545 | 1546 | 1547 | 1548 | 1549 | // If you want to actually see the XPC notification, put a breakpoint on: 1550 | //LaunchServices`LSNotificationReceiver::receiveNotificationFromServer(_xpc_connection_s*, void*) 1551 | 1552 | 1553 | // Need a runloop for this, so run. 1554 | 1555 | CFRunLoopRun(); 1556 | /* --- */ 1557 | printf("Not reached ....\n"); 1558 | exit(0); 1559 | 1560 | } 1561 | #endif 1562 | 1563 | // NOT YET 1564 | if (strcmp(argv[1],"monitor-notyet") == 0) 1565 | { 1566 | 1567 | // You can do this with an LSApplicationWorkspaceObserver, but that requires 1568 | // objective C, in order to implement the callback messages. Much easier 1569 | // in a pure C solution to do this by directly accessing the Notification center 1570 | 1571 | // extern void *CFNotificationCenterGetDistributedCenter(void); 1572 | CFNotificationCenterRef distCent = CFNotificationCenterGetDistributedCenter(); 1573 | 1574 | 1575 | //CFStringRef name = CFSTR("com.lsinstallprogress.appcontrols.pause"); // com.apple.LaunchServices.applicationStateChanged"); 1576 | CFStringRef name = CFSTR("com.apple.LaunchServices.applicationStateChanged"); 1577 | extern void CFNotificationCenterAddObserver(CFNotificationCenterRef center, const void *observer, CFNotificationCallback callBack, CFStringRef name, const void *object, CFNotificationSuspensionBehavior suspensionBehavior); 1578 | 1579 | void *observer; 1580 | void *monitorCallback; 1581 | CFNotificationCenterAddObserver(distCent, 1582 | NULL, //observer, 1583 | monitorCallback, 1584 | name, 1585 | NULL, 1586 | CFNotificationSuspensionBehaviorDeliverImmediately); 1587 | 1588 | printf("Runloop\n"); 1589 | CFRunLoopRun(); 1590 | 1591 | #if 0 1592 | 0000000000166c5 callq 0x130cc4 ## symbol stub for: _CFNotificationCenterGetDistributedCenter 1593 | 00000000000166ca leaq _LSApplicationWorkspaceObserverCallback(%rip), %rdx 1594 | 00000000000166d1 leaq 0x16e308(%rip), %rcx ## Objc cfstring ref: @"com.lsinstallprogress.appcontrols.cancel" 1595 | 00000000000166d8 xorl %r8d, %r8d 1596 | 00000000000166db movl $0x4, %r9d 1597 | 00000000000166e1 movq %rax, %rdi 1598 | 00000000000166e4 movq %rbx, %rsi 1599 | 00000000000166e7 callq 0x130cb8 ## symbol stub for: _CFNotificationCenterAddObserver 1600 | #endif 1601 | 1602 | 1603 | 1604 | sleep(100); 1605 | exit(0); 1606 | 1607 | 1608 | } 1609 | // And this is the real fun part: 1610 | // 1611 | // The little known "lsregister" utility in OS X is closed source, and un-man(1)ned, 1612 | // But one of its coolest features is "dump" - to dump the LaunchServices Database. 1613 | // Turns out this is a *single* line of code. And guess what -- it works on iOS too :-) 1614 | // 1615 | if (strcmp(argv[1], "dump") == 0) 1616 | { 1617 | BOOL thirteenOrGreater = false; 1618 | id doxy = [objc_getClass("LSDocumentProxy") documentProxyForName:@"" type:@"public.item" MIMEType:nil];//public.item 1619 | if ([doxy respondsToSelector:@selector(applicationsAvailableForOpeningWithStyle:limit:XPCConnection:error:)]){ 1620 | thirteenOrGreater = true; 1621 | } 1622 | 1623 | // If you want to get the raw format of the file, you can dump with this, instead: 1624 | //extern _LSDisplayRawStoreData(char *, int); 1625 | //_LSDisplayRawStoreData("/var/mobile/Library/Caches/com.apple.LaunchServices-134.csstore", (void *) 0xff); 1626 | 1627 | 1628 | // if (!LSDisplayData) { fprintf(stderr, "Can't find LSDisplayData! Has Apple removed it by now? :-P"); exit(1);} 1629 | // The argument expected here is likely the name of the CoreServices (LaunchServices) 1630 | // DataStore - in iOS "/var/mobile/Library/Caches/com.apple.LaunchServices-###.csstore" 1631 | // but turns out NULL works on both OS X and iOS! 1632 | 1633 | // Until iOS 10, that is - wherein you need FILE * - so I use stderr 1634 | int rc = 0; 1635 | if (thirteenOrGreater){ 1636 | typedef int (*LSDisplayDataFunc)(FILE *, void*, void*, void*, void*, void*, void*); 1637 | LSDisplayDataFunc LSDisplayData; 1638 | LSDisplayData = dlsym (CS_handle, "_LSDisplayData"); 1639 | rc = LSDisplayData(stderr, NULL, 0, 0, 0, 0, 0); 1640 | } else { 1641 | typedef int (*LSDisplayDataFunc)(FILE *, void*); 1642 | LSDisplayDataFunc LSDisplayData; 1643 | LSDisplayData = dlsym (CS_handle, "_LSDisplayData"); 1644 | rc = LSDisplayData(stderr, NULL); 1645 | } 1646 | if (rc != 0) { fprintf(stderr,"LSDisplayData returned %d\n",rc);} 1647 | exit(rc); 1648 | 1649 | } 1650 | 1651 | // Still here? Usage 1652 | fprintf(stderr,"I don't understand '%s'\n", argv[1]); 1653 | usage(argv[0]); 1654 | 1655 | #if 0 1656 | 0000000183063cb8 t +[LSApplicationWorkspaceObserver supportsSecureCoding] 1657 | 0000000183063cc0 t -[LSApplicationWorkspaceObserver encodeWithCoder:] 1658 | 0000000183063d00 t -[LSApplicationWorkspaceObserver init] 1659 | 0000000183063d74 t -[LSApplicationWorkspaceObserver initWithCoder:] 1660 | 0000000183063e08 t -[LSApplicationWorkspaceObserver dealloc] 1661 | 0000000183063e64 t -[LSApplicationWorkspaceObserver applicationInstallsDidStart:] 1662 | 0000000183063fa0 t -[LSApplicationWorkspaceObserver applicationInstallsDidChange:] 1663 | 00000001830640dc t -[LSApplicationWorkspaceObserver applicationInstallsDidUpdateIcon:] 1664 | 0000000183064218 t -[LSApplicationWorkspaceObserver applicationsDidInstall:] 1665 | 0000000183064354 t -[LSApplicationWorkspaceObserver applicationsWillInstall:] 1666 | 0000000183064490 t -[LSApplicationWorkspaceObserver applicationsWillUninstall:] 1667 | 00000001830645cc t -[LSApplicationWorkspaceObserver applicationsDidFailToInstall:] 1668 | 0000000183064708 t -[LSApplicationWorkspaceObserver applicationsDidFailToUninstall:] 1669 | 0000000183064844 t -[LSApplicationWorkspaceObserver applicationsDidUninstall:] 1670 | 0000000183064980 t -[LSApplicationWorkspaceObserver applicationInstallsArePrioritized:arePaused:] 1671 | 0000000183064be8 t -[LSApplicationWorkspaceObserver applicationInstallsDidPause:] 1672 | 0000000183064d24 t -[LSApplicationWorkspaceObserver applicationInstallsDidResume:] 1673 | 0000000183064e60 t -[LSApplicationWorkspaceObserver applicationInstallsDidCancel:] 1674 | 0000000183064f9c t -[LSApplicationWorkspaceObserver applicationInstallsDidPrioritize:] 1675 | 00000001830650d8 t -[LSApplicationWorkspaceObserver applicationStateDidChange:] 1676 | 0000000183065214 t -[LSApplicationWorkspaceObserver networkUsageChanged:] 1677 | 0000000183065368 t -[LSApplicationWorkspaceObserver uuid] 1678 | 0000000183065378 t -[LSApplicationWorkspaceObserver setUuid:] 1679 | #endif 1680 | } 1681 | --------------------------------------------------------------------------------