├── .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 |
--------------------------------------------------------------------------------