吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 5804|回复: 44
上一主题 下一主题
收起左侧

[iOS 原创] XCode调试越狱iOS上任意App和系统进程/查看界面元素

  [复制链接]
跳转到指定楼层
楼主
lichao890427 发表于 2023-7-15 13:04 回帖奖励
本帖最后由 lichao890427 于 2024-6-9 18:10 编辑

背景

  近一年没发过帖子了,近几年一直在iOS系统深耕,现在分享一个我去年的研究成果,项目地址[https://github.com/lich4/debugserver_azj]。
此项目为增强越狱环境下iOS上的调试器功能。主要为以下几点:

  1. 使XCode支持调试任意第三方签名的App或者进程,包括系统进程  
  2. 使XCode支持查看任意App界面布局
    笔者主要用的调试方式仍然是命令行远程调试,而图形化调试在某些情况下方便一些,如果开发了某些Tweak想要调试,使用XCode附加调试也能起到很好的效果

分析

笔者环境: XCode11.x + iOS12.x

  先从XCode入手研究XCode怎么实现调试的,可以看到设备在首次连接到Mac上时,会挂一个/Developer分区进去,debugserver就在其中,此debugserver用于XCode调试有自己开发着签名的App。而挂载的dmg其实在/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/DeviceSupport/12.5/DeveloperDiskImage.dmg
  而Cydia源里其实也提供debugserver,此debugserver可以用于命令行远程调试任意进程,实际上是加了root权限和额外的entitlemet。XCode控制debugserver是通过lockdownd来通信的,此系统进程提供了USB相关的各种功能,例如XCode安装调试,还有爱思助手的各种功能,都要走lockdownd(如果想改爱思助手显示的设备参数其实也是从这里改)。
  经过调试可以定位关键系统API为SMJobSubmit  

{
    EnvironmentVariables =     {
        "LOCKDOWN_MACH_SERVICE" = "lockdown.2144085414520.com.apple.debugserver";
    };
    KeepAlive = 0;
    Label = "lockdown.2144085414520.com.apple.debugserver";
    LaunchOnlyOnce = 1;
    MachServices =     {
        "lockdown.2144085414520.com.apple.debugserver" = 1;
    };
    POSIXSpawnType = Interactive;
    ProgramArguments =     (
        "/Developer/usr/bin/debugserver",
        "--lockdown",
        "--launch=frontboard"
    );
    RunAtLoad = 0;
    UserName = mobile;
}

  可以发现XCode使用了/Developer/usr/bin/debugserver。但由于debugserver缺少root权限以及entitlemet导致无法附加到系统进程,因此XCode正常情况无法调试系统进程和第三方App(MonkeyDev之类重打包不算)。那么直接换成Cydia源里的debugserver是否可行呢,经过笔者测试,那个debugserver也是无法使用的,因为苹果原生debugserver是支持--lockdown参数的,而Cydia源的却不支持,因此必须自行改版debugserver。这一步其实很简单,将Cydia源里的debugserver的entitlement,ldid签名到Developer的debugserver即可。
  下一步,想办法让lockdownd使用我们改版debugserver,最直接的想法是做个dmg,让lockdown挂上去,然而经过逆向和测试发现DeviceSupport下的有DeveloperDiskImage.dmg和DeveloperDiskImage.dmg.signature,后者用于文件校验,且用到RSA加密了,无解。因此笔者考虑使用tweak来改lockdownd

编码

  替换ProgramArguments中的debugserver为我们定制的debugserver即可

#include <dlfcn.h>
#include <time.h>
#import <Foundation/Foundation.h>

static void nouse(){}
static void* _SMJobSubmit = (void*)nouse;
static void* _CFPropertyListCreateData = (void*)nouse;
static int last_inst_time = 0;

%hookf(CFDataRef, _CFPropertyListCreateData, CFAllocatorRef allocator, CFPropertyListRef propertyList, CFPropertyListFormat format, CFOptionFlags options, CFErrorRef* error) {
    if (CFGetTypeID(propertyList) == CFDictionaryGetTypeID()) {
        NSDictionary* info = (__bridge NSDictionary*)propertyList;
        if (info[@"Service"] != nil && [info[@"Service"] isEqualToString:@"com.apple.mobile.installation_proxy"]) {
            last_inst_time = time(0);
        }
    }
    return %orig;
}

%hookf(Boolean, _SMJobSubmit, CFStringRef domain, CFDictionaryRef job, CFTypeID auth, CFErrorRef *outError) {
    NSMutableDictionary* mjob = [(__bridge NSDictionary*)job mutableCopy];
    if (job != nil && mjob[@"ProgramArguments"] != nil) {
        NSArray* argv = mjob[@"ProgramArguments"];
        NSString* full_cmd = [argv componentsJoinedByString:@" "];
        NSLog(@"debugserver_azj %@", full_cmd);
        NSString* path = argv.firstObject;
        if (time(0) - last_inst_time > 3) { // 防止影响Xcode安装调试普通App
            NSOperatingSystemVersion sysver = NSProcessInfo.processInfo.operatingSystemVersion;;
            int mv = sysver.majorVersion;
            if ([path isEqualToString:@"/Developer/usr/bin/debugserver"]) {
                NSMutableArray* margv = [argv mutableCopy];
                if (mv <= 8) {
                    // not implement
                } else if (mv == 9 || mv == 10) {
                    margv[0] = @"/usr/bin/debugserver_azj10";
                } else if (mv == 11 || mv == 12) {
                    margv[0] = @"/usr/bin/debugserver_azj12";
                } else if (mv == 13 || mv == 14) {
                    margv[0] = @"/usr/bin/debugserver_azj14";
                } else if (mv >= 15) { // XCode 12+ is need for iOS15  // not test on iOS16+
                    margv[0] = @"/usr/bin/debugserver_azj15"; 
                }
                mjob[@"UserName"] = @"root";
                mjob[@"ProgramArguments"] = margv;
            } else if ([path isEqualToString:@"/Developer/usr/libexec/gputoolsd"]) {
                NSMutableArray* margv = [argv mutableCopy];
                if (mv <= 8) {
                    // not implement
                } else if (mv == 9 || mv == 10) {
                    margv[0] = @"/usr/bin/gputoolsd_azj10";
                } else if (mv == 11 || mv == 12) {
                    margv[0] = @"/usr/bin/gputoolsd_azj12";
                } else if (mv == 13 || mv == 14) {
                    margv[0] = @"/usr/bin/gputoolsd_azj14";
                } else if (mv >= 15) { // not test on iOS16+
                    margv[0] = @"/usr/bin/gputoolsd_azj15"; 
                }
                mjob[@"UserName"] = @"root";
                mjob[@"ProgramArguments"] = margv;
            } 
            job = (__bridge_retained CFDictionaryRef)mjob;
        }      
    }
    return %orig;
}

%ctor {
    _SMJobSubmit = dlsym(RTLD_DEFAULT, "SMJobSubmit");
    _CFPropertyListCreateData = dlsym(RTLD_DEFAULT, "CFPropertyListCreateData");
}

使用

  附加已有进程不必赘述,直接选择"Attach to Process by PID or Name"即可,这里谈下启动附加。由于进程在启动以后,再附加调试可能错过启动时刻的执行逻辑,因此可以在进程启动前就选择"Attach to Process by PID or Name"并指定进程名,然后启动进程,这样能实现启动时附加(底层是通过debugserver的-waitfor实现)
  而获取界面元素则和正常开发相同,先暂停进程,然后选择"View Debugging" -> "Capture View Hierarchy"

注意

  本插件在iOS9/10/12/13/14/15 iPhone5s/6/6s/7/X上均做过测试,XCode11.7完美支持iOS9-14

  1. 安装完本插件需要重新插拔USB,以便注入到lockdownd生效。  
  2. 若App有反调试,需要先想办法去除反调试  
  3. 若调试老型号手机出现Jetsam相关错误,为调试时内存占用过大被系统kill,需要开发tweak使用memorystatus_control修改下进程权限。这种情况笔者在分析iOS10的SpringBoard界面元素时遇到过  
  4. 附加时间: iOS15 > iOS13/14 > iOS12 ... ;iOS15上附加进程速度会比较慢,笔者测附加Safari在2分钟左右  
  5. XCode12.x附加调试iOS15的SpringBoard会因为时间过长而导致桌面被系统kill,但XCode13.x却可以  
  6. 本插件只增强附加调试,会影响XCode调试普通App,所以代码中设置last_inst_time用于记录IPA安装时间避开XCode安装调试。(其实也可以在设置里增加开关来控制是否root身份启动debugserver不过那样更麻烦一些)。
  7. 亲测支持无根越狱(dopamine已测),arm64e架构,安装我提供的release里arm64e的deb即可

后记(2024年6月)

  之前遇到lldb卡几分钟的主要原因是DeviceSupport文件不正确导致lldb从内存读取符号,所以速度缓慢,需要先用高版本XCode生成正确的DeviceSupport再进行调试

免费评分

参与人数 8吾爱币 +7 热心值 +7 收起 理由
yp17792351859 + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
GKKK911 + 1 + 1 我很赞同!
wangxd + 1 + 1 谢谢@Thanks!
ASASASSSA + 1 + 1 鼓励转贴优秀软件安全工具和文档!
zhukun1980 + 1 用心讨论,共获提升!
gamingnow + 1 + 1 用心讨论,共获提升!
lalicorne + 1 我很赞同!
qwq5555 + 1 + 1 热心回复!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

来自 #
 楼主| lichao890427 发表于 2023-7-17 13:10 |楼主
卡卡超人 发表于 2023-7-16 18:22
造轮子之前至少应该先找找有没有现成的轮子
https://github.com/lemon4ex/XcodeRootDebug
https://iosre. ...

这个后来有朋友跟我说了,但是这是我一年前的研究成果,只不过现在才发布而已,算起来基本都是同时期。巧得很,我也是去年6月研究的这个
推荐
卡卡超人 发表于 2023-7-16 18:22
造轮子之前至少应该先找找有没有现成的轮子
https://github.com/lemon4ex/XcodeRootDebug
https://iosre.com/t/tweak-%E8%AE%A9-xcode-%E4%BD%BF%E7%94%A8-root-%E6%9D%83%E9%99%90%E8%B0%83%E8%AF%95ios%E8%AE%BE%E5%A4%87%E4%B8%8A%E7%9A%84%E4%BB%BB%E4%BD%95%E5%BA%94%E7%94%A8%E6%88%96%E8%BF%9B%E7%A8%8B/22194
沙发
anwen 发表于 2023-7-15 13:19

没研究过这些,不过看到使用标题中用到的很多分层的图,看样子很方便以后的一些调试啊~

3#
sxtyys 发表于 2023-7-15 14:00
谢谢分享,学习学习
4#
myloverycpp 发表于 2023-7-15 14:03
谢谢分享,还好有个iOS14,实践一下。
5#
qwq5555 发表于 2023-7-15 14:10
我感觉iOS越狱后也适合养老。
6#
帝巴必 发表于 2023-7-15 14:49
谢谢,研究下!收藏
7#
米斯特张 发表于 2023-7-15 17:36
qwq5555 发表于 2023-7-15 14:10
我感觉iOS越狱后也适合养老。

14.5.1养老中  哈哈哈
8#
夜色baby 发表于 2023-7-15 17:49
貌似不支持多巴胺无根越狱
9#
雾都孤尔 发表于 2023-7-15 17:53
学习下,感谢分享。
10#
陪你一起出发 发表于 2023-7-15 18:09
冒昧的问下,这个有什么用?
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-23 15:06

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表