SpringBoard tweak 双击图标启动debugserver

0x00 懒是第一生产力

狗神的书上和帖子里都有写如何配置debugserver。配置完之后用起来还是有些麻烦,至少要开两个终端窗口,一个手机端的开启debugserver,另外一个开启lldb。在手机端的shell,需要先ssh登录,然后各种ls+grep找到要调试的app,然后敲debugserver xxx 把各种参数配置好。 https://github.com/4ch12dy/issh 对上述操作有封装和优化,但是还是需要敲命令找App,运行debugServer。所以做个tweak提升一下生产力。双击应用图标,一键启动debugserver。 代码zip包和运行截图在本文末尾。

我的开发环境是iOS13.3,但是并没有用到特殊版本的API,低版本手机应该也OK。

0x01 通过图标找到应用执行路径

从界面找逻辑,逆向发现SpringBoard的图标是SBIconView。并且有一个叫属性 applicationBundleIdentifierForShortcuts 返回的是图标对应的App的bundle id。通过bundle id构造LSApplicationProxy对象,并且拿到canonicalExecutablePath属性,也就是应用的可执行文件路径。

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

0x02 寻找注入点添加扩展

接续看SBIconView,图标上有两个手势对象:

  • 单击,用来启动App。
  • 长按,进入编辑状态,执行删除和排列图标等操作。

所以,我们来给图标交互加个双击扩展。

%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];
		}
	}
}

这里额外说一句 [each requireGestureRecognizerToFail: doubleTap] 添加了双击手势指挥,由于iOS内部维护了手势的状态机,我们单击操作发生的时候,其实产生了两种Possible State。第一种是识别为单击,然后结束。第二种是识别为双击的第一下并等待第二下的发生,然后根据两次点击之时间间隔阈值来判断是不是合法的双击。所以我们手动加个约束,相当于指定了识别的优先级,只有双击失败了,才继续执行单击回调。这种操作会带来一点几乎无感的瑕疵:单击等待双击识别失败的延迟,延迟的值就是双击识别执行的阈值(大约零点几秒)。

0x03 debugserver启动和关闭

debugserver是一个二进制文件,狗神的教程里有如何重签,issh把这些过程给简化了。先看一下debugserver的权限:
-rwxr-xr-x 1 root admin 9876848 Jan 19 11:28 /iOSRE/tools/debugserver*

再来看一下SpringBoard的权限:
-rwxr-xr-x 1 root wheel 71264 Dec 5 13:15 SpringBoard*

属主用户都是root,没毛病。找个函数调用一下:

  1. system函数
  2. posix_spawn函数
  3. NSTask ,面向对象方便管理,异步执行,不会block UI,就用它了。

代码

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

每次server在launch之前,要把之前的task结束掉。

- (void)interrupt; // Not always possible. Sends SIGINT.

- (void)terminate; // Not always possible. Sends SIGTERM.

NSTask头文件里竟然告诉我 Not always possible。事实上我调用的时候,还真的不怎么possible,实际测试第一次server正常启动,后续由于没成功关闭,所以第二次就没法启动了。所以还是换种方式关闭吧。简单粗暴的 kill 函数:

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

0x04 添加UI交互

直接用Alert,又有按钮又有输入框,不过UIAlertView已经被废弃掉了,需要用UIAlertController。由于弹出Controller需要父Controller,通过View找到当前的Controller,做正向的应该都写过这段代码吧。。

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

0x05 优化一下用户体验
输入框里的ip和debugserver的path,每个人都不一样,所以在第一次输入完成之后,把这些值用NSUserDefault持久化存储起来,下次直接读取填充。

0x06后记

之前看坛子里一些帖子讨论用Root身份运行App的帖子,学习完帖子里的技巧,增强对操作系统的理解以及实践之后。如果真的想RootApp运行,其实SpringBoard本身就是一个RootApp,我们吧SpringBoard当做RootViewController,很容易把一些系统工具做出界面,从而提升生产力。比如砸壳,重签,拷贝App等。

上代码
tap2debug.zip (53.5 KB)

10 Likes

来个3D touch

1 Like

你这想法还是很有创意的🤣

对上述操作有封装和优化,但是还是需要敲命令找App

这点确实,所以我写了个issh app的命令,能够显示当前正在运行app的路径(算是稍微快速拿到目标app路径的一种方式)

1 Like

站在你们的肩膀上:wink:

xcode 不是全都自动化了吗。

收藏一下,终于不用开三四个窗口了

基于楼主的项目,我增加了shortcut/3D touch的方式(因为双击方式应用会稍微卡顿一下

https://github.com/4ch12dy/Tap2Debug

2 Likes

硬核广告(

这是我见过最优雅的调试方式没有之一(被打)//不管反正广告局管不了我

1 Like

vscode支持oc代码提示老板多久安排一下?

高考完了安排上

试用试用去,谢谢! launchd debug 不了,是什么原因?

你手机装debugserver了么?
debugserver在你的PATH里面吗?

unc0ver 越狱,大部分deamon进程可以debug ,有debugserver,在PATH路径里的。调试launchd 一直不行。 你那边可以调试launchd ?

Test:~ root# debugserver 127.0.0.1:1237 -a launchd

debugserver-@(#)PROGRAM:LLDB PROJECT:lldb-900.3.86

for arm64.

Attaching to process launchd…

error: failed to attach to process named: “” (os/kern) invalid address

Exiting.

试试看apt.bingner.com的那个debugserver

不知为啥一双击图标就进入安全模式