aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--darwin-bootstrap/bundle-loader.c50
-rw-r--r--darwin-bootstrap/posixspawn-hook.c5
-rw-r--r--darwin-bootstrap/safemode-ui-hook.m4
-rw-r--r--darwin-bootstrap/safety-dance/main.m76
-rw-r--r--darwin-bootstrap/substituted.m51
-rw-r--r--lib/darwin/xxpc.h2
-rw-r--r--lib/substitute-internal.h7
7 files changed, 183 insertions, 12 deletions
diff --git a/darwin-bootstrap/bundle-loader.c b/darwin-bootstrap/bundle-loader.c
index 7a90414..3b29b55 100644
--- a/darwin-bootstrap/bundle-loader.c
+++ b/darwin-bootstrap/bundle-loader.c
@@ -3,10 +3,12 @@
#include "ib-log.h"
#include "darwin/mach-decls.h"
#include "darwin/xxpc.h"
+#include "substitute-internal.h"
#include <dlfcn.h>
#include <mach/mach.h>
#include <mach/mach_time.h>
#include <mach/mig.h>
+#include <mach-o/loader.h>
#include <objc/runtime.h>
#include <CoreFoundation/CoreFoundation.h>
#include <syslog.h>
@@ -146,12 +148,60 @@ do_load:;
return true;
}
+static void notify_added_removed(const struct mach_header *mh32, bool is_add) {
+ char id_dylib_buf[32];
+ const char *id_dylib;
+
+ const mach_header_x *mh = (void *) mh32;
+ uint32_t ncmds = mh->ncmds;
+ const struct load_command *lc = (void *) (mh + 1);
+ for (uint32_t i = 0; i < ncmds; i++) {
+ if (lc->cmd == LC_ID_DYLIB) {
+ const struct dylib_command *dc = (void *) lc;
+ id_dylib = (const char *) dc + dc->dylib.name.offset;
+ goto ok;
+ }
+ lc = (void *) lc + lc->cmdsize;
+ }
+ /* no name? */
+ sprintf(id_dylib_buf, "unknown.%p", mh32);
+ id_dylib = id_dylib_buf;
+
+ok:;
+ xxpc_object_t message = xxpc_dictionary_create(NULL, NULL, 0);
+ xxpc_dictionary_set_string(message, "type", "add-remove");
+ xxpc_dictionary_set_bool(message, "is-add", is_add);
+ xxpc_dictionary_set_string(message, "id-dylib", id_dylib);
+ xxpc_connection_send_message(substituted_conn, message);
+ xxpc_release(message);
+}
+
+static void add_image_cb(const struct mach_header *mh, intptr_t vmaddr_slide) {
+ notify_added_removed(mh, true);
+
+}
+
+static void remove_image_cb(const struct mach_header *mh, intptr_t vmaddr_slide) {
+ notify_added_removed(mh, false);
+}
+
static bool handle_hello_reply(xxpc_object_t dict) {
if (IB_VERBOSE) {
char *desc = xxpc_copy_description(dict);
ib_log("hello_reply: %s", desc);
free(desc);
}
+ bool notify = xxpc_dictionary_get_bool(dict, "notify-me-of-add-remove");
+ if (notify) {
+ _dyld_register_func_for_add_image(add_image_cb);
+ _dyld_register_func_for_remove_image(remove_image_cb);
+
+ for (uint32_t i = 0, count = _dyld_image_count(); i < count; i++) {
+ const struct mach_header *mh32 = _dyld_get_image_header(i);
+ if (mh32)
+ notify_added_removed(mh32, true);
+ }
+ }
xxpc_object_t bundles = xxpc_dictionary_get_value(dict, "bundles");
if (!bundles || xxpc_get_type(bundles) != XXPC_TYPE_ARRAY)
return false;
diff --git a/darwin-bootstrap/posixspawn-hook.c b/darwin-bootstrap/posixspawn-hook.c
index 50c4ca9..893cfee 100644
--- a/darwin-bootstrap/posixspawn-hook.c
+++ b/darwin-bootstrap/posixspawn-hook.c
@@ -170,11 +170,6 @@ end:
return ret;
}
-static const char *xbasename(const char *path) {
- const char *slash = strrchr(path, '/');
- return slash ? slash + 1 : path;
-}
-
static int hook_posix_spawn_generic(__typeof__(posix_spawn) *old,
pid_t *restrict pidp, const char *restrict path,
const posix_spawn_file_actions_t *file_actions,
diff --git a/darwin-bootstrap/safemode-ui-hook.m b/darwin-bootstrap/safemode-ui-hook.m
index dbae60c..dc505dc 100644
--- a/darwin-bootstrap/safemode-ui-hook.m
+++ b/darwin-bootstrap/safemode-ui-hook.m
@@ -43,8 +43,10 @@ static bool detect_substrate_safe_mode() {
void (*old_applicationDidFinishLaunching)(id, SEL, id);
static void my_applicationDidFinishLaunching(id self, SEL sel, id app) {
old_applicationDidFinishLaunching(self, sel, app);
- if (detect_substrate_safe_mode())
+ if (detect_substrate_safe_mode()) {
+ NSLog(@"Deferring to Substrate's safe mode.");
return;
+ }
id controller = [SBApplicationController sharedInstanceIfExists];
if (!controller) {
NSLog(@"substitute safe mode: sharedInstanceIfExists => nil!");
diff --git a/darwin-bootstrap/safety-dance/main.m b/darwin-bootstrap/safety-dance/main.m
index 64e0e64..8366430 100644
--- a/darwin-bootstrap/safety-dance/main.m
+++ b/darwin-bootstrap/safety-dance/main.m
@@ -1,6 +1,10 @@
+#include "darwin/xxpc.h"
+#include "substitute-internal.h"
#import <UIKit/UIKit.h>
-#include <notify.h>
#import "AutoGrid.h"
+#include <notify.h>
+
+static NSArray *g_dylibs_to_show;
@interface UIApplication (Private)
- (void)terminateWithSuccess;
@@ -23,11 +27,14 @@
- (void)viewDidLoad {
[super viewDidLoad];
[self loadStuff];
+ /*
NSMutableArray *names = [NSMutableArray array];
for (int i = 0; i < 200; i++)
[names addObject:[NSString stringWithFormat:@"Some Dylib %d", i]];
+ g_dylibs_to_show = names;
+ */
NSMutableArray *views = [NSMutableArray array];
- for (NSString *name in names) {
+ for (NSString *name in g_dylibs_to_show) {
UILabel *label = [[UILabel alloc] init];
label.text = name;
[views addObject:label];
@@ -191,9 +198,72 @@ static void compression(UIView *view, UILayoutPriority pri) {
@end
+static const char *test_and_transform_id_dylib(const char *id_dylib) {
+ const char *base = xbasename(id_dylib);
+ static const char dir1[] = "/Library/MobileSubstrate/DynamicLibraries/";
+ static const char dir2[] = "/Library/Substitute/DynamicLibraries/";
+ if (!strncmp(id_dylib, dir1, sizeof(dir1) - 1) ||
+ !strncmp(id_dylib, dir2, sizeof(dir2) - 1))
+ return base;
+ char *fn = NULL, *fn2 = NULL;
+ asprintf(&fn, "%s%s", dir1, base);
+ asprintf(&fn2, "%s%s", dir2, base);
+ bool found = !access(fn, F_OK) || !access(fn2, F_OK);
+ free(fn);
+ free(fn2);
+ if (found)
+ return base;
+ return NULL;
+}
+
+static void do_bad() {
+ NSLog(@"problem asking substituted for springboard-fatal-loaded-dylibs...");
+ g_dylibs_to_show = @[@"<error>"];
+}
+
+static void startup() {
+ xxpc_connection_t conn = xxpc_connection_create_mach_service(
+ "com.ex.substituted", NULL, 0);
+ if (!conn)
+ return do_bad();
+ xxpc_connection_set_event_handler(conn, ^(xxpc_object_t event) {
+ NSLog(@"< %@", event);
+ });
+ xxpc_connection_resume(conn);
+ xxpc_object_t request = xxpc_dictionary_create(NULL, NULL, 0);
+ xxpc_dictionary_set_string(request, "type",
+ "springboard-fatal-loaded-dylibs");
+ NSLog(@"asking substituted...");
+ xxpc_object_t reply = xxpc_connection_send_message_with_reply_sync(
+ conn, request);
+ NSLog(@"done.");
+ if (!reply || xxpc_get_type(reply) != XXPC_TYPE_DICTIONARY)
+ return do_bad();
+ NS_VALID_UNTIL_END_OF_SCOPE
+ xxpc_object_t dylibs = xxpc_dictionary_get_value(reply, "dylibs");
+ if (!dylibs) {
+ g_dylibs_to_show = @[@"<unknown>"];
+ return;
+ }
+ if (xxpc_get_type(dylibs) != XXPC_TYPE_ARRAY)
+ return do_bad();
+ NSMutableArray *ary = [NSMutableArray array];
+ for (size_t i = 0, count = xxpc_array_get_count(dylibs);
+ i < count; i++) {
+ const char *dylib = xxpc_array_get_string(dylibs, i);
+ if (!dylib)
+ return do_bad();
+ const char *dylib_to_show = test_and_transform_id_dylib(dylib);
+ if (dylib_to_show)
+ [ary addObject:[NSString stringWithCString:dylib_to_show
+ encoding:NSUTF8StringEncoding]];
+ }
+ g_dylibs_to_show = ary;
+}
+
int main(int argc, char *argv[]) {
- NSLog(@"main");
@autoreleasepool {
+ startup();
return UIApplicationMain(argc, argv, nil, @"AppDelegate");
}
}
diff --git a/darwin-bootstrap/substituted.m b/darwin-bootstrap/substituted.m
index 3dd17a4..f30ab9f 100644
--- a/darwin-bootstrap/substituted.m
+++ b/darwin-bootstrap/substituted.m
@@ -18,6 +18,9 @@ static enum {
REALLY_SAFE,
} g_springboard_needs_safe;
+static NSSet *g_springboard_loaded_dylibs;
+static NSSet *g_springboard_last_loaded_dylibs;
+
extern kern_return_t bootstrap_look_up3(mach_port_t bp,
const char *service_name, mach_port_t *sp, pid_t target_pid,
const uuid_t instance_id, uint64_t flags);
@@ -63,6 +66,7 @@ static xxpc_object_t nsstring_to_xpc(NSString *in) {
xxpc_object_t _connection;
NSString *_argv0;
bool _is_springboard;
+ NSMutableSet *_loaded_dylibs;
}
@end
@@ -272,12 +276,16 @@ enum convert_filters_ret {
_is_springboard = [_argv0 isEqualToString:sb_exe];
- if (_is_springboard)
+ if (_is_springboard) {
+ g_springboard_last_loaded_dylibs = g_springboard_loaded_dylibs;
+ g_springboard_loaded_dylibs = _loaded_dylibs = [NSMutableSet set];
+
[self updateSpringBoardNeedsSafeThen:^{
[self handleMessageHelloRest:request];
}];
- else
+ } else {
[self handleMessageHelloRest:request];
+ }
return;
bad:
@@ -322,12 +330,45 @@ bad:
NSString *dylib_path = [base stringByAppendingPathComponent:dylib];
xxpc_dictionary_set_value(info, "dylib", nsstring_to_xpc(dylib_path));
-
xxpc_array_append_value(bundles, info);
}
xxpc_object_t reply = xxpc_dictionary_create_reply(request);
xxpc_dictionary_set_value(reply, "bundles", bundles);
+ if (_is_springboard)
+ xxpc_dictionary_set_bool(reply, "notify-me-of-add-remove", true);
+ xxpc_connection_send_message(_connection, reply);
+}
+
+- (void)handleMessageAddRemove:(NS_VALID_UNTIL_END_OF_SCOPE
+ xxpc_object_t)request {
+ bool is_add = xxpc_dictionary_get_bool(request, "is-add");
+ const char *id_dylib = xxpc_dictionary_get_string(request, "id-dylib");
+ if (!id_dylib || !_loaded_dylibs)
+ return [self handleBadMessage:request];
+ NSString *id_dylib_s = [NSString stringWithCString:id_dylib
+ encoding:NSUTF8StringEncoding];
+ if (is_add)
+ [_loaded_dylibs addObject:id_dylib_s];
+ else
+ [_loaded_dylibs removeObject:id_dylib_s];
+}
+
+- (void)handleMessageSBFatalLoadedDylibs:(xxpc_object_t)request {
+ /* This should probably be secured somehow... */
+ NSLog(@"handleMessageSBFatalLoadedDylibs");
+ NSSet *set = g_springboard_last_loaded_dylibs;
+ xxpc_object_t reply = xxpc_dictionary_create_reply(request);
+ if (set) {
+ xxpc_object_t dylibs = xxpc_array_create(NULL, 0);
+ xxpc_dictionary_set_value(reply, "dylibs", dylibs);
+ for (NSString *dylib in set) {
+ xxpc_array_set_string(dylibs, XXPC_ARRAY_APPEND,
+ [dylib cStringUsingEncoding:
+ NSUTF8StringEncoding]);
+
+ }
+ }
xxpc_connection_send_message(_connection, reply);
}
@@ -342,6 +383,10 @@ bad:
goto bad;
if (!strcmp(type, "hello"))
return [self handleMessageHello:request];
+ else if (!strcmp(type, "add-remove"))
+ return [self handleMessageAddRemove:request];
+ else if (!strcmp(type, "springboard-fatal-loaded-dylibs"))
+ return [self handleMessageSBFatalLoadedDylibs:request];
else
goto bad;
bad:
diff --git a/lib/darwin/xxpc.h b/lib/darwin/xxpc.h
index 7df28f6..d1bcb9d 100644
--- a/lib/darwin/xxpc.h
+++ b/lib/darwin/xxpc.h
@@ -80,6 +80,8 @@ void WRAP(xpc_connection_resume, (xxpc_connection_t));
void WRAP(xpc_connection_set_event_handler, (xxpc_connection_t, xxpc_handler_t));
void WRAP(xpc_connection_send_message_with_reply,
(xxpc_connection_t, xxpc_object_t, dispatch_queue_t, xxpc_handler_t));
+xxpc_object_t WRAP(xpc_connection_send_message_with_reply_sync,
+ (xxpc_connection_t, xxpc_object_t));
void WRAP(xpc_connection_send_message, (xxpc_connection_t, xxpc_object_t));
void WRAP(xpc_connection_cancel, (xxpc_connection_t));
int WRAP(xpc_pipe_routine_reply, (xxpc_object_t));
diff --git a/lib/substitute-internal.h b/lib/substitute-internal.h
index 80c8b22..675f6eb 100644
--- a/lib/substitute-internal.h
+++ b/lib/substitute-internal.h
@@ -1,6 +1,8 @@
#pragma once
#include <stdio.h>
+#include <string.h>
+
#define substitute_panic(...) do { \
fprintf(stderr, __VA_ARGS__); \
abort(); \
@@ -100,3 +102,8 @@ int substitute_dlopen_in_pid(int pid, const char *filename, int options,
int substitute_ios_unrestrict(task_t task, char **error);
#endif
+static const char *xbasename(const char *path) {
+ const char *slash = strrchr(path, '/');
+ return slash ? slash + 1 : path;
+}
+