Skip to content

Instantly share code, notes, and snippets.

@leptos-null
Last active May 14, 2023 17:30
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save leptos-null/763eb136b100df75815fa3bd2ff53f0d to your computer and use it in GitHub Desktop.
Save leptos-null/763eb136b100df75815fa3bd2ff53f0d to your computer and use it in GitHub Desktop.
Dump URL schemes from an iOS system image (stock applications)
//
// ios_image_app_url_dump
//
// Created by Leptos on 2/19/19.
// Copyright © 2019 Leptos. All rights reserved.
//
/* compile with:
* $ clang -fobjc-arc -framework Foundation
*/
#import <Foundation/Foundation.h>
static void dumpBundleURLsToStdout(NSBundle *bundle, BOOL publicOnly, BOOL schemeIndicator) {
NSArray<NSDictionary *> *appURLs = [bundle objectForInfoDictionaryKey:@"CFBundleURLTypes"];
if (appURLs.count == 0) {
return;
}
NSString *bundleIdentifier = [bundle objectForInfoDictionaryKey:(NSString *)kCFBundleIdentifierKey];
NSString *bundleDisplayName = [bundle objectForInfoDictionaryKey:(NSString *)kCFBundleNameKey];
NSMutableString *formatted = [NSMutableString stringWithFormat:@"%@ (%@):\n", bundleDisplayName, bundleIdentifier];
BOOL shouldPrint = !publicOnly;
for (NSDictionary *urlInfo in appURLs) {
NSString *urlName = urlInfo[@"CFBundleURLName"] ?: @"UNKNUNKN";
BOOL isPrivate = [urlInfo[@"CFBundleURLIsPrivate"] boolValue];
if (isPrivate && publicOnly) {
continue;
}
shouldPrint = YES;
[formatted appendFormat:@" %@", urlName];
if (!publicOnly) {
[formatted appendFormat:@" (%s)", isPrivate ? "Private" : "Public"];
}
[formatted appendString:@":\n"];
for (NSString *urlScheme in urlInfo[@"CFBundleURLSchemes"]) {
[formatted appendFormat:@" %@%@\n", urlScheme, schemeIndicator ? @"://_" : @""];
}
[formatted appendString:@"\n"];
}
if (shouldPrint) {
fputs(formatted.UTF8String, stdout);
}
}
static void dumpBundlesInDirectory(NSString *path, BOOL publicOnly, BOOL schemeIndicator, NSError **error) {
NSFileManager *const fileManager = [NSFileManager defaultManager];
NSArray<NSString *> *apps = [fileManager contentsOfDirectoryAtPath:path error:error];
for (NSString *appPath in apps) {
NSString *fullPath = [path stringByAppendingPathComponent:appPath];
dumpBundleURLsToStdout([NSBundle bundleWithPath:fullPath], publicOnly, schemeIndicator);
}
}
static int putUsage(const char *progname) {
return fprintf(stderr, "Usage: %s [-pl] <ios_root>\n"
" -p : public Schemes only\n"
" -l : generate a list of clickable links\n"
" ios_root : path to the iOS system root\n", progname);
}
int main(int argc, char *argv[]) {
const char *progname = argv[0];
int publicOnly = NO;
int schemeIndicator = NO;
if (argc < 2) {
putUsage(progname);
return 1;
}
argc--;
NSString *systemRoot = @(argv[argc]);
int c;
while ((c = getopt(argc, argv, ":pl")) != -1) {
switch (c) {
case 'p':
publicOnly = YES;
break;
case 'l':
schemeIndicator = YES;
break;
case '?': {
putUsage(progname);
return 1;
} break;
}
}
NSArray<NSString *> *searchDirectories = @[
@"/Applications",
// there are versions at "/System/Library/AppPlaceholders" which are asset-only (they should have the same `Info.plist`)
@"/var/staged_system_apps"
];
for (NSString *searchDirectory in searchDirectories) {
NSError *err = nil;
dumpBundlesInDirectory([systemRoot stringByAppendingPathComponent:searchDirectory], publicOnly, schemeIndicator, &err);
if (err) {
NSLog(@"[Fatal] %@", err);
return 1;
}
}
/* there are some additional apps at (checked at a 12.2 and 13.1 beta)
* /System/Library/PrivateFrameworks/IDS.framework/identityservicesd.app
* /System/Library/PrivateFrameworks/IDSFoundation.framework/IDSCredentialsAgent.app
* /System/Library/PrivateFrameworks/IDSFoundation.framework/IDSRemoteURLConnectionAgent.app
* /System/Library/PrivateFrameworks/IMCore.framework/imagent.app
* /System/Library/PrivateFrameworks/IMDPersistence.framework/IMAutomaticHistoryDeletionAgent.app
* /System/Library/PrivateFrameworks/IMTransferServices.framework/IMTransferAgent.app
*
* none of them had URL schemes
*/
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment