DebugServer + LLDB is nice to use, but too cumbersome to start up? We have developed a small iOS Springboard Tweak plugin to simplify the debugServer startup process. Brother, please double click!

0x00 Laziness is the primary productivity

We often need to debug APP through debugserver, there are books and forums to explain the relevant technology and practice, but the actual application is still some trouble. First, re-sign the copy, then start the terminal SSH to iPhone and start DebugServer. Add various ls and grep to find the application you want to debug, press the command to start DebugServer, and then start LLDB from Mac local terminal. The result is at least two terminals open, and sometimes more. There is an ISSH tool on GitHub that encapsulates and optimizes the above operation, but you still need to type the command to find the App, and then run the debugServer.

So do a tweak to improve your productivity. Just double-click the application icon to launch the DebugServer with one click.

See GitHub for the code

https://github.com/TalkingDat…

Operation interface

The development environment we are using is iOS 13.3, but we don’t use a special version of the API, and the lower version of the phone should be OK.

The development process is briefly shared below:

0x01 Find the application execution path through the icon

From the interface to find the logic, reverse the SpringBoard icon is SBiconView. And one attribute applicationBundleIdentifierForShortcuts returns the icon of the corresponding App Bundle ID. The LSApplicationProxy object is constructed from the Bundle ID and the CanonicalExecutablePath property, which is the application’s executable file path, is obtained.

Class LSApplicationProxy_class = objc_getClass("LSApplicationProxy"); NSObject* proxyObj = [LSApplicationProxy_class performSelector:@selector(applicationProxyForIdentifier:) withObject:bundle]; NSString * canonicalExecutablePath = [proxyObj performSelector:@selector(canonicalExecutablePath)]; Copy the code

0x02 Find the injection point to add the extension

Continuing with the SBiconView, there are two gesture objects on the icon:

  • Click to launch the App.
  • Long press to enter the edit state, delete and arrange ICONS and other operations.

So, let’s add a double-click extension to the icon interaction.

%hook SBIconView

- (void)didMoveToWindow{ %orig; UITapGestureRecognizer *doubleTap = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(handleDoubleClick:)]; [doubleTap setNumberOfTapsRequired:2]; [self addGestureRecognizer:doubleTap]; NSArray * ges = self.gestureRecognizers; for(UITapGestureRecognizer * each in ges){ if([each isKindOfClass:[UITapGestureRecognizer class]]){ [each requireGestureRecognizerToFail: doubleTap]; }}} Copy code

Here, extra [each requireGestureRecognizerToFail: doubleTap] added double-click gesture command, because internal iOS maintained the gestures of State machine, when we click operation, actually had two Possible State. The first is to identify as a click and then end. The second method is to identify the first click as a double click and wait for the second one to happen, and then judge whether it is a valid double click according to the time interval threshold between two clicks.

So we manually add the constraint, which is equivalent to specifying the priority of recognition, and only continue to execute the click callback if the double click fails. This operation introduces an almost insensitive flaw: the delay after a click waiting for the double-click to fail, the value of which is the threshold for the double-click to fail (about a few tenths of a second).

0x03 DebugServer starts and closes

The debugserver is a binary file, the tutorial on how to resign is in the god of the doggy, issh simplifies this process. -rwxr-xr-x 1 root admin 9876848 Jan 19 11:28 /iOSRE/tools/debugserver*

-rwxr-xr-x 1 Root Wheel 71264 Dec 5 13:15 Springboard *

The primary user is root, so there is nothing wrong with that. Find a function to call:

  1. The system function
  2. Posix_spawn function
  3. NSTask, object oriented, easy to manage, asynchronous execution, no block UI, just use it.

The code is as follows:

task = [[NSTask alloc]init]; [task setLaunchPath:bin_serverpath]; [task setArguments:args]; [task launch]; Copy the code

Each time before the server launch, it should terminate the previous task.

- (void)interrupt; // Not always possible. Sends SIGINT. Copy the code
- (void)terminate; // Not always possible. Sends SIGTERM. Copy the code

The NSTask header actually told me Not always possible. In fact, it is not possible at the time of the call. In the actual test, the server started normally on the first time, and failed to start the second time because it failed to shut down successfully.

So let’s close it the other way. The simple and crude kill function:

NSTask * task = [TaskManager sharedManager].runningTask; if(task){ kill(task.processIdentifier,SIGKILL); task = nil; } Copy code

0x04 Add UI interaction

I’m just going to use an Alert, and I’m going to have a button and I’m going to have an input field, but UIAlertView is deprecated, so I’m going to use UIAlertController. Because the popup Controller needs a parent Controller, find the current Controller through the View. This code should be written in the forward direction:

@implementation UIView(find)-(UIViewController*)findViewController{ UIResponder* target= self; while (target) { target = target.nextResponder; if ([target isKindOfClass:[UIViewController class]]) { break; } } return (UIViewController*)target; }@end copies the code

0x05 Optimize the user experience

The IP in the input box and the path of the debugserver are different for everyone, so after the first input is completed, these values are stored with NSUserDefault persistence, and the next direct read is populated.

0 x06 afterword.

After reading a post on a related technology forum about running an App as Root, and studying the tips and practices in this post to improve your understanding of the operating system, I realized that if you really want RootApp to run, SpringBoard itself is a RootApp. We treat SpringBoard as a RootViewController, making it easy to interface some of the system tools to increase productivity. For example, smash shell, re-sign, copy APP and so on.

** Author: TalkingData Xiao Zhang

The copyright of this article belongs to TalkingData. If you need to reprint, please indicate the source **