diff --git a/scripts/vphoned/entitlements.plist b/scripts/vphoned/entitlements.plist index 5226176..bee6eb6 100644 --- a/scripts/vphoned/entitlements.plist +++ b/scripts/vphoned/entitlements.plist @@ -505,6 +505,8 @@ IOSurfaceRootUserClient RootDomainUserClient + com.apple.springboard.debugapplications + com.apple.springboard.launchapplications com.apple.springboard.launchapplicationswithoptions diff --git a/scripts/vphoned/vphoned_apps.m b/scripts/vphoned/vphoned_apps.m index ff047ff..437169b 100644 --- a/scripts/vphoned/vphoned_apps.m +++ b/scripts/vphoned/vphoned_apps.m @@ -9,6 +9,7 @@ #import "vphoned_apps.h" #import "vphoned_protocol.h" #include +#include #include #include #include @@ -34,6 +35,10 @@ static Class gFBSSystemServiceClass = Nil; // SBSCopyFrontmostApplicationDisplayIdentifier loaded via dlsym static NSString *(*pSBSCopyFrontmost)(void) = NULL; +// Low-level MIG variants +static mach_port_t (*pSBSSpringBoardServerPort)(void) = NULL; +static void (*pSBFrontmostApplicationDisplayIdentifier)(mach_port_t port, + char *result) = NULL; static BOOL gAppsLoaded = NO; @@ -61,6 +66,9 @@ BOOL vp_apps_load(void) { if (!pSBSCopyFrontmost) { NSLog(@"vphoned: SBSCopyFrontmostApplicationDisplayIdentifier not found"); } + pSBSSpringBoardServerPort = dlsym(sbs, "SBSSpringBoardServerPort"); + pSBFrontmostApplicationDisplayIdentifier = + dlsym(sbs, "SBFrontmostApplicationDisplayIdentifier"); } else { NSLog(@"vphoned: dlopen SpringBoardServices failed: %s", dlerror()); } @@ -231,10 +239,61 @@ NSDictionary *vp_handle_apps_command(NSDictionary *msg) { pid_t pid = 0; NSString *name = @""; + // SBS functions talk to SpringBoard via mach IPC. When running as root, + // the bootstrap port resolves in the system domain, which cannot see + // SpringBoard's per-user mach service. Temporarily drop to mobile (501) + // so the port lookup hits the user-session namespace. + uid_t orig_euid = geteuid(); + BOOL switched = NO; + if (orig_euid == 0) { + if (seteuid(501) == 0) { + switched = YES; + } + } + + // Method 1: High-level SBSCopyFrontmostApplicationDisplayIdentifier if (pSBSCopyFrontmost) { frontApp = pSBSCopyFrontmost(); } + // Method 2: Low-level SBFrontmostApplicationDisplayIdentifier(port, buf) + if ((!frontApp || frontApp.length == 0) && pSBSSpringBoardServerPort && + pSBFrontmostApplicationDisplayIdentifier) { + mach_port_t port = pSBSSpringBoardServerPort(); + if (port != MACH_PORT_NULL) { + char buf[256] = {0}; + pSBFrontmostApplicationDisplayIdentifier(port, buf); + if (buf[0] != '\0') { + frontApp = [NSString stringWithUTF8String:buf]; + } + } + } + + if (switched) { + seteuid(orig_euid); + } + + // Method 3: Walk running apps, pick the one with highest PID (most + // recently launched) that isn't SpringBoard — rough heuristic fallback + if ((!frontApp || frontApp.length == 0) && gFBSSystemServiceClass) { + LSApplicationWorkspace *ws = [LSApplicationWorkspace defaultWorkspace]; + pid_t bestPid = 0; + NSString *bestApp = nil; + for (LSApplicationProxy *proxy in [ws allInstalledApplications]) { + pid_t p = pid_for_app(proxy.bundleIdentifier); + if (p > 0 && + ![proxy.bundleIdentifier isEqualToString:@"com.apple.springboard"]) + { + if (p > bestPid) { + bestPid = p; + bestApp = proxy.bundleIdentifier; + } + } + } + if (bestApp) + frontApp = bestApp; + } + if (!frontApp || frontApp.length == 0) { frontApp = @"com.apple.springboard"; }