iOS Tweak修改系统行为(classdump-dyld)

一、Tweak修改系统行为

有一个需求是去掉手机桌面的红点显示。首先必须清楚手机桌面也是一款App SpringBoard

zaizai:~ root# ps -A | grep SpringBoard
26075 ??         2:14.28 /System/Library/CoreServices/SpringBoard.app/SpringBoard
26859 ttys000    0:00.01 grep SpringBoard

直接拷贝SpringBoard

scp -P 12345  root@localhost:/System/Library/CoreServices/SpringBoard.app/SpringBoard ./

查看加密信息:

otool -l SpringBoard  | grep crypt

这个时候回发现SpringBoard根本没有相关加密字段,也就是它本身是没有加壳的。

这里手动拷贝是因为frida无法导出。dump.py -l根本找不到到SpringBoard应用,通过cycript找到bundleId砸壳dump.py com.apple.springboard也无效。
那么我们可以直接dump出它的头文件:

class-dump -H SpringBoard -o ./Headers
2021-05-31 19:44:08.473 class-dump[28776:9098728] Unknown load command: 0x00000032

发现直接报错Unknown load command: 0x00000032github上下载class-dump源码编译最新代码生成class-dump工具class-dump

编译源码的过程中发现Use of undeclared identifier 'PLATFORM_IOSMAC'

class-dump源码编译

查看对应宏定义用PLATFORM_MACCATALYST替换PLATFORM_IOSMAC成功。

虽然解决了报错问题,但是只生成了一个CDStructures.h文件:

image.png

难道springboard全部改为了swift实现?

image.png

查看了下SpringBoard发现只有75KB。这就有意思了,说明新版本SpringBoard只是一个壳真正的实现肯定不在SpringBoard .app中。

只好查看下MachO文件了,果然有一个SpringBoard私有库:

image.png

在手机上进入/System/Library/PrivateFrameworks/目录果然有SpringBoard.framework

zaizai:/System/Library/PrivateFrameworks root# AXSpringBoardServerInstance.framework/
SpringBoard.framework/
SpringBoardFoundation.framework/
SpringBoardHome.framework/
SpringBoardServices.framework/
SpringBoardUI.framework/
SpringBoardUIServices.framework/

拷贝这个私有库:

scp -r -P 12345  root@localhost:/System/Library/PrivateFrameworks/SpringBoard.framework ./

但是结果却是让人失望的,在SpringBoard.framework中并没有相关的MachO文件,唯一有点关联的就是有个SBRendererService.xpc文件:

image.png

查看对应的MachO

image.png

这个在上面搜索SpringBoard.framework的时候就已经见到了,继续导出SpringBoardFoundation.framework查看仍然没有什么有用的信息,随后将上面列出的所有framework尝试都没有找到有用的信息。

直接用Xcode附加SpringBoard

image.png

发现红点显示逻辑的视图是SBIconBadgeView

⚠️Reveal查看不了SpringBoard,在设置中根本就没有SpringBoard选项。
cycriptLLDB可以。

这个时候查看image list发现了加载了Xcode中的库:

/Users/zaizai/Library/Developer/Xcode/iOS DeviceSupport/14.0 (18A373)/Symbols/System/Library/PrivateFrameworks/SpringBoard.framework/SpringBoard 
image.png

这个大小看起来有点靠谱,并且没有加密相关字段。
查看MachO文件:

image.png

这里明确了SpringBoard依赖库的关系。尝试class-dump报错:

class-dump[44486:9544743] Error: Cannot find offset for address 0x201d7915448 in dataOffsetForAddress:

难道所有实现都是swift实现了?创建Tweak工程,尝试Hook SBIconBadgeView的实现:

%hook SBIconBadgeView
  - (id)init{
      return nil;
  }
%end

直接在init的时候返回nil。这个时候Hook是成功的红点直接全部消失了。

image.png

这里其实就已经实现了隐藏系统角标的问题。

二、dump头文件

虽然上面已经处理完隐藏逻辑了,但是并不严谨。如果有更复杂的功能需要处理那么导出头文件是个重要的步骤。

2.1 方式一 dsc_extractor(可以略过这个,这里只是为了做记录)

既然上面都获取不到那么就要换个思路了,系统动态库都在共享缓存中,那么导出共享缓存中的动态库是不是就能class-dump了?

拷贝共享缓存
启动本机的Mach-O文件的时候/System/Library/PrivateFrameworks相应的库文件全部转移到了 /System/Library/Caches/com.apple.dyld/dyld_shared_cache_arm64。那么直接拷贝共享缓存文件:

scp  -P 12345  root@localhost:/System/Library/Caches/com.apple.dyld/dyld_shared_cache_arm64 ./

解析共享缓存文件
在苹果dyld源码中有一个launch-cache/shared-cache(不同版本可能不太相同)文件夹可以用来解析动态库共享缓存。编译比较麻烦我这里直接用别人编译好的dsc_extractor文件。编译好的dsc_extractor

使用:

./dsc_extractor dyld_shared_cache_arm64 frameworks

这个时候就成功导出了共享缓存库。

生成dsc_extractor可执行文件步骤:
(1).下载对应版本的MachO源码 dyld源码
(2).修改代码,将 dsc_extractor.cpp 最后一个 #if 条件编译宏, 将 #if 0 改为 #if 1 (第653行)。这个是苹果的测试宏。
(4).编译 ``dsc_extractor,clang++ -o dsc_extractor dsc_extractor.cpp dsc_iterator.cpp
(5).编译成功之后会得到 dsc_extractor 这个文件,chmod +x dsc_extractor添加执行权限

dyld版本获取

#import <mach-o/dyld.h>

void printDyldVersion() {
    int32_t version = NSVersionOfRunTimeLibrary("dyld");
    NSLog(@"origin dyld version: %d",version);
    if ( version != 0xFFFFFFFF ) {
        printf("conventversion: (compatibility version %u.%u.%u, current version %u.%u.%u)\n",
           (version >> 16),
           (version >> 8) & 0xff,
           (version) & 0xff,
           (version >> 16),
           (version >> 8) & 0xff,
           (version) & 0xff);
    }
}

class-dump需要的framework
这个时候仍然和从Xcode导出来的库报同样的错误。查资料说是只适用于iOS12之前的版本。

2.2 方式二 RuntimeBrowser(可以略过这个,这里只是为了做记录)

无意间搜到到别人分享的RuntimeBrowserRuntimeBrowser
这个工具支持iOSmacOS下载源码后需要我们自己编译build到手机上。在尝试的过程中遇到的问题比较多,并且在源码中过滤了我需要的库:

image.png

所以就不过多研究这个库了。安装好后在iOS下如下:
RuntimeBrowser

对于某些库是能直接在手机端浏览头文件的。貌似也是iOS12支持的比较好。

2.3 方式三 classdump-dyld(推荐)

上面自己没有能够成功class-dump springboard库的头文件,那么尝试搜下看有没有其他人在iOS14上成功恢复。找到了iOS14runtime头文件

在别人分享出来的Headers文件中发现了以下信息:

/*
* This header is generated by classdump-dyld 1.0
* on Thursday, September 24, 2020 at 12:37:36 AM British Summer Time
* Operating System: Version 14.0 (Build 18A373)
* Image Source: /System/Library/PrivateFrameworks/SpringBoardHome.framework/SpringBoardHome
* classdump-dyld is licensed under GPLv3, Copyright © 2013-2016 by Elias Limneos.
*/

看到是通过classdump-dyld生成的头文件classdump-dyld

2.3.1 安装

cydia中直接搜索classdump-dyld插件进行安装。

classdump-dyld插件

2.3.2 classdump-dyld API

#cycript -p SpringBoard

@import net.limneos.classdumpdyld;

classdumpdyld.dumpClass(SpringBoard);
@"Wrote file /tmp/SpringBoard.h"

classdumpdyld.dumpBundle([NSBundle mainBundle]);
@"Wrote all headers to /tmp/SpringBoard"

// Dump any bundle other than the main bundle 
classdumpdyld.dumpBundle([NSBundle bundleWithIdentifier:@"com.apple.UIKit"]);
@"Wrote all headers to /tmp/UIKit"

// Dump any image loaded in the process using any class name it contains
classdumpdyld.dumpBundleForClass(CallBarControllerModern);
@"Wrote all headers to /tmp/CallBar7"
  1. 进入手机端cycript环境。
  2. import classdumpdyld
  3. 调用classdumpdyld导出头文件:
    • classdumpdyld.dumpClass(xxx):导出某个类的头文件
    • classdumpdyld.dumpBundle(xxx):导出某个库的头文件
    • classdumpdyld.dumpBundleForClass(xxx):根据库中的某个类导出整个库,适用于我们并不清楚类属于哪个库的情况。

2.3.3 classdump-dyld 使用

通过SBIconBadgeView导出整个库的头文件:

cycript -p SpringBoard
@import net.limneos.classdumpdyld;
cy# classdumpdyld.dumpBundleForClass(SBIconBadgeView);
@"Wrote all headers to /tmp/SpringBoardHome"

可以确定SBIconBadgeViewSpringBoardHome.framework中,从手机端拷贝文件:

scp -r  -P 12345  root@localhost:/tmp/SpringBoardHome/  ./SpringBoardHome_Headers/

这个时候就正常dump出头文件可以分析了。

image.png

三、Monkey写Tweak

3.1 创建工程

除了通过theostweak工程,也可以通过Monkey来写。
创建Monkey Tweak工程Logos Tweak

image.png

3.2 工程配置

配置要附加的进程Package->Library->MobileSubstrate->DynamicLibraries->***.plist

image.png

其中的Bundles就是要附加的进程,直接在这里配置就好了。

配置.xm文件的type:

image.png

直接将Hook代码拷贝过来:

image.png

签名信息配置:


image.png

3.3 编译安装配置

image.png
  • MonkeyDevBuildPackageOnAnyBuild: 每次build都生成deb包。
  • MonkeyDevClearUiCacheOnInstall:安装的时候清除缓存。
  • MonkeyDevCopyOnBuild:build时将deb包拷贝到设备的/var/root/MonkeyDevBuilds/目录。
  • MonkeyDevDeviceIP:目标设备的ip地址,默认USB连接,localhost
  • MonkeyDevDevicePassword:目标设备的ssh登录密码,默认为空使用免密码登录。
  • MonkeyDevDevicePort:目标设备的端口,默认22。和自己的映射端口相关,这里设置为12345
  • MonkeyDevInstallOnAnyBuild:每次编译安装,一般设置为NO。安装时设置为YES
  • MonkeyDevInstallOnProfiling:点击Profile才将deb安装到设备。

这个是command + i ?但是这个工程是灰色不能点击,暂时不清楚这个怎么操作。

  • MonkeyDevkillProcessOnInstall:安装插件后要杀掉的进程。
  • MonkeyDevPath:MonkeyDev安装路径。
  • MonkeyDevTheosPath:theos安装路径。

一般情况可以把MonkeyDevDeviceIPMonkeyDevDevicePort设置在.zshrc中。

export MonkeyDevDeviceIP=localhost
export MonkeyDevDevicePort=12345

MonkeyDev配置

3.4 安装运行

配置MonkeyDevInstallOnAnyBuildYES,然后command + b安装。
这个时候就和直接使用Tweak效果相同了。

错误处理
1.building for iOS, but linking in .tbd file (/opt/theos/vendor/lib/CydiaSubstrate.framework/CydiaSubstrate.tbd) built for iOS Simulator, file '/opt/theos/vendor/lib/CydiaSubstrate.framework/CydiaSubstrate.tbd' for architecture arm64

image.png

删除CydiaSubstrate.tbdi386x86_64两项。

四、Tweak原理

4.1 分析Tweak工程

创建新的Tweak工程后目录结构如下:

image.png

编译make后多了一个.theos文件夹:

image.png

其中存放.dylib文件。外层的.dylibFat类型的,是其它单一架构的合集。

打包make package后会生成packages文件夹,里面存放.deb文件:

image.png

并且.theos文件夹下也有一个packages,这个文件夹中是一个记录build号的文件:
image.png

image.png

  • .deb可以理解为类似.ipa.deb通过cydia下发安装插件。.ipa通过AppStore下发安装App
  • .ipa安装的是.app.deb安装的是.dylib

安装好的.dylib/Library/MobileSubstrate/DynamicLibraries目录中:

image.png

除了.dylib文件外,还有一个对应的.plist。这个plist记录了要附加的进程bundleid

4.2 验证

那么要注入动态库有两种方式:LC_LOAD_DYLIB写入MachODYLD_INSERT_LIBRARIES注入。
如果是LC_LOAD_DYLIB那么MachO中肯定有对应的记录。

由于SpringBoard不好查看,直接Monkey重签名微信,然后 Tweak Logos工程附加重签名的微信分析。
MonkeyBadgeHidden代码如下:

#import <UIKit/UIKit.h>

%hook UIView

+ (void)load {
    NSLog(@"\n\n\n UIView 🍉🍉🍉🍉🍉🍉🍉🍉\n\n\n");
    NSLog(@"\n\n\n UIView 🍉🍉🍉🍉🍉🍉🍉🍉\n\n\n");
    NSLog(@"\n\n\n UIView 🍉🍉🍉🍉🍉🍉🍉🍉\n\n\n");
}

%end

Monkey附加工程中如下:

%hook UIViewController

+ (void)load {
    NSLog(@"\n\n\n UIViewController 🍉🍉🍉🍉🍉🍉🍉🍉\n\n\n");
    NSLog(@"\n\n\n UIViewController 🍉🍉🍉🍉🍉🍉🍉🍉\n\n\n");
    NSLog(@"\n\n\n UIViewController 🍉🍉🍉🍉🍉🍉🍉🍉\n\n\n");
}

%end

image.png

确认 LC_LOAD_DYLIB只有libMonkeyDemoDylib.dylib

配置DYLD_PRINT_LIBRARIES打印下加载的库:

image.png

找到libMonkeyDemoDylib.dylibMonkeyBadgeHidden.dylib

dyld: loaded: <E2661470-9027-3E13-B71E-433B032D4A7E> /private/var/containers/Bundle/Application/B54EACB0-2790-42F4-A1F8-246116BC14BF/MonkeyDemo.app/Frameworks/libMonkeyDemoDylib.dylib

dyld: loaded: <DDC6FCBA-BD5C-3A2B-AE59-BED0B7A67135> /Library/MobileSubstrate/DynamicLibraries/MonkeyBadgeHidden.dylib

在这里也可以看到libMonkeyDemoDylib.dylib是从AppFrameworks中加载的,MonkeyBadgeHidden.dylib是从MobileSubstrate中加载的。

image list查看,MonkeyBadgeHidden插件如下:

[681] 48733794-72F0-3137-AFBE-704DA9B60E0D 0x0000000114ee4000 /Library/MobileSubstrate/DynamicLibraries/MonkeyBadgeHidden.dylib 
      /System/Volumes/Data/Users/zaizai/Library/Developer/Xcode/DerivedData/MonkeyBadgeHidden-ajtwpltzqpaxyldhfqsxakdgneuo/Build/Products/Debug-iphoneos/MonkeyBadgeHidden.dylib.dSYM/Contents/Resources/DWARF/MonkeyBadgeHidden.dylib(0x0000000114ee4000)

libMonkeyDemoDylib动态库如下:

[105] 67B122C5-FD9E-3C6A-AB0F-2A0287A6DCDD 0x000000010dfc0000 /Users/zaizai/Library/Developer/Xcode/DerivedData/MonkeyDemo-ezelbbqeimtnqtbanmlksmtowvin/Build/Products/Debug-iphoneos/MonkeyDemo.app/Frameworks/libMonkeyDemoDylib.dylib 

这就可以看出MonkeyBadgeHidden.dylib是从/Library/MobileSubstrate/DynamicLibraries/MonkeyBadgeHidden.dylib拷贝的,而libMonkeyDemoDylib并不需要拷贝。

总结

  • class-dump导出头文件
    • class-dump -H MachO文件 -o 头文件路径
  • classdump-dyld导出系统库头文件
    • 手机端需要安装classdump-dyld插件

    • 进入cycript环境导入classdumpdyld

    • 调用classdumpdyld导出头文件

      • classdumpdyld.dumpClass(xxx):导出某个类的头文件
      • classdumpdyld.dumpBundle(xxx):导出某个库的头文件

      主程序通过[NSBundle mainBundle]导出。
      其它通过identifier [NSBundle bundleWithIdentifier:@"com.apple.UIKit"]导出。

      • classdumpdyld.dumpBundleForClass(xxx):根据库中的某个类导出整个库的头文件

参考:
https://www.reddit.com/r/jailbreakdevelopers/comments/e6cjxx/ios_13_springboard_headers/f9qgkhr/
https://github.com/nst/RuntimeBrowser

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,294评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,493评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,790评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,595评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,718评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,906评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,053评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,797评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,250评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,570评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,711评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,388评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,018评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,796评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,023评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,461评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,595评论 2 350