@@ -541,6 +541,7 @@ int enable_debug_overlay(RemoteCall *proc) {
541541 uint64_t clsUIApplication = remote_getClass (proc, " UIApplication" );
542542 uint64_t clsUITapGestureRecognizer = remote_getClass (proc, " UITapGestureRecognizer" );
543543 uint64_t clsUIWindow = remote_getClass (proc, " UIWindow" );
544+ uint64_t clsUIViewController = remote_getClass (proc, " UIViewController" );
544545
545546 if (!clsDebugOverlayWindow) {
546547 printf (" (rc) UIDebuggingInformationOverlay class not found\n " );
@@ -550,20 +551,34 @@ int enable_debug_overlay(RemoteCall *proc) {
550551 uint64_t selInit = remote_sel (proc, " init" );
551552 uint64_t selOverlay = remote_sel (proc, " overlay" );
552553 uint64_t selPrepare = remote_sel (proc, " prepareDebuggingOverlay" );
554+ uint64_t selOverlayStatus = remote_sel (proc, " overlayStatus" );
553555 uint64_t selPerform = remote_sel (proc, " performSelectorOnMainThread:withObject:waitUntilDone:" );
554556
555- // 1. Swizzle -[UIDebuggingInformationOverlay init] to -[UIWindow init] to bypass internal check
557+ // 1. Get return 1 gadget from UIViewController _canShowWhileLocked
558+ if (clsUIViewController) {
559+ uint64_t selReturn1 = remote_sel (proc, " _canShowWhileLocked" );
560+ uint64_t methodReturn1 = RemoteArbCall (proc, class_getInstanceMethod , clsUIViewController, selReturn1);
561+ uint64_t return1Imp = RemoteArbCall (proc, method_getImplementation , methodReturn1);
562+
563+ // 2. Swizzle +[UIDebuggingInformationOverlay overlayStatus] to return 1 (YES)
564+ uint64_t methodOverlayStatus = RemoteArbCall (proc, class_getClassMethod , clsDebugOverlayWindow, selOverlayStatus);
565+ if (methodOverlayStatus && return1Imp) {
566+ RemoteArbCall (proc, method_setImplementation , methodOverlayStatus, (uint64_t )return1Imp);
567+ }
568+ }
569+
570+ // 3. Swizzle -[UIDebuggingInformationOverlay init] to -[UIWindow init] to bypass internal check
556571 uint64_t methodWindowInit = RemoteArbCall (proc, class_getInstanceMethod , clsUIWindow, selInit);
557572 uint64_t methodOverlayInit = RemoteArbCall (proc, class_getInstanceMethod , clsDebugOverlayWindow, selInit);
558573 uint64_t impWindowInit = RemoteArbCall (proc, method_getImplementation , methodWindowInit);
559574 if (methodOverlayInit && impWindowInit) {
560575 RemoteArbCall (proc, method_setImplementation , methodOverlayInit, impWindowInit);
561576 }
562577
563- // 2 . Call +[UIDebuggingInformationOverlay prepareDebuggingOverlay] to prevent UIDebuggingInformationOverlayNotPrepared exception
578+ // 4 . Call +[UIDebuggingInformationOverlay prepareDebuggingOverlay]
564579 remote_msg (proc, clsDebugOverlayWindow, selPerform, selPrepare, 0 , 1 , 0 );
565580
566- // 3 . Get or allocate overlay window
581+ // 5 . Get or allocate overlay window
567582 remote_msg (proc, clsDebugOverlayWindow, selPerform, selOverlay, 0 , 1 , 0 );
568583 uint64_t debugOverlay = remote_msg (proc, clsDebugOverlayWindow, selOverlay, 0 , 0 , 0 , 0 );
569584 if (!debugOverlay) {
@@ -572,26 +587,46 @@ int enable_debug_overlay(RemoteCall *proc) {
572587 debugOverlay = remote_msg (proc, debugOverlay, selInit, 0 , 0 , 0 , 0 );
573588 }
574589 }
575-
576- // 4. Set windowScene
590+
591+ if (!debugOverlay) {
592+ printf (" (rc) Failed to obtain UIDebuggingInformationOverlay instance\n " );
593+ return -1 ;
594+ }
595+
596+ // 6. Ensure rootViewController is NEVER nil (prevents app crash when UIWindow is unhidden!)
597+ uint64_t selRootVC = remote_sel (proc, " rootViewController" );
598+ uint64_t selSetRootVC = remote_sel (proc, " setRootViewController:" );
599+ uint64_t rootVC = remote_msg (proc, debugOverlay, selRootVC, 0 , 0 , 0 , 0 );
600+ if (!rootVC) {
601+ uint64_t clsRootTVC = remote_getClass (proc, " UIDebuggingInformationRootTableViewController" );
602+ if (!clsRootTVC) clsRootTVC = remote_getClass (proc, " UIDebuggingInformationOverlayViewController" );
603+ if (!clsRootTVC) clsRootTVC = clsUIViewController;
604+
605+ if (clsRootTVC) {
606+ uint64_t newRootVC = RemoteArbCall (proc, objc_alloc, clsRootTVC);
607+ newRootVC = remote_msg (proc, newRootVC, selInit, 0 , 0 , 0 , 0 );
608+ if (newRootVC) {
609+ remote_msg (proc, debugOverlay, selPerform, selSetRootVC, newRootVC, 1 , 0 );
610+ }
611+ }
612+ }
613+
614+ // 7. Set windowScene
577615 uint64_t mainWindowScene = get_main_window_scene (proc);
578616 if (debugOverlay && mainWindowScene) {
579617 uint64_t selSetWindowScene = remote_sel (proc, " setWindowScene:" );
580618 remote_msg (proc, debugOverlay, selPerform, selSetWindowScene, mainWindowScene, 1 , 0 );
581619 }
582620
583- // 5 . Show overlay window immediately
621+ // 8 . Show overlay window
584622 if (debugOverlay) {
585623 uint64_t selSetHidden = remote_sel (proc, " setHidden:" );
586- uint64_t selMakeKeyAndVisible = remote_sel (proc, " makeKeyAndVisible" );
587624 uint64_t selToggle = remote_sel (proc, " toggleVisibility" );
588-
589- remote_msg (proc, debugOverlay, selPerform, selSetHidden, 0 , 1 , 0 );
590- remote_msg (proc, debugOverlay, selPerform, selMakeKeyAndVisible, 0 , 1 , 0 );
625+ remote_msg (proc, debugOverlay, selPerform, selSetHidden, 0 , 1 , 0 ); // setHidden:NO
591626 remote_msg (proc, debugOverlay, selPerform, selToggle, 0 , 1 , 0 );
592627 }
593628
594- // 6 . Register gesture recognizer to status bar and main window
629+ // 9 . Register activation gesture recognizers to status bar and main window
595630 if (clsDebugOverlayHandler && clsUITapGestureRecognizer) {
596631 uint64_t selMainHandler = remote_sel (proc, " mainHandler" );
597632 uint64_t selSharedInstance = remote_sel (proc, " sharedInstance" );
0 commit comments