iOS Tweak修改系統(tǒng)行為(classdump-dyld)

一、Tweak修改系統(tǒng)行為

有一個需求是去掉手機桌面的紅點顯示。首先必須清楚手機桌面也是一款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

這個時候回發(fā)現(xiàn)SpringBoard根本沒有相關(guān)加密字段,也就是它本身是沒有加殼的。

這里手動拷貝是因為frida無法導(dǎo)出。dump.py -l根本找不到到SpringBoard應(yīng)用,通過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

發(fā)現(xiàn)直接報錯Unknown load command: 0x00000032,github上下載class-dump源碼編譯最新代碼生成class-dump工具class-dump。

編譯源碼的過程中發(fā)現(xiàn)Use of undeclared identifier 'PLATFORM_IOSMAC'

class-dump源碼編譯

查看對應(yīng)宏定義用PLATFORM_MACCATALYST替換PLATFORM_IOSMAC成功。

雖然解決了報錯問題,但是只生成了一個CDStructures.h文件:

image.png

難道springboard全部改為了swift實現(xiàn)?

image.png

查看了下SpringBoard發(fā)現(xiàn)只有75KB。這就有意思了,說明新版本SpringBoard只是一個殼真正的實現(xiàn)肯定不在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 ./

但是結(jié)果卻是讓人失望的,在SpringBoard.framework中并沒有相關(guān)的MachO文件,唯一有點關(guān)聯(lián)的就是有個SBRendererService.xpc文件:

image.png

查看對應(yīng)的MachO

image.png

這個在上面搜索SpringBoard.framework的時候就已經(jīng)見到了,繼續(xù)導(dǎo)出SpringBoardFoundation.framework查看仍然沒有什么有用的信息,隨后將上面列出的所有framework嘗試都沒有找到有用的信息。

直接用Xcode附加SpringBoard

image.png

發(fā)現(xiàn)紅點顯示邏輯的視圖是SBIconBadgeView

??Reveal查看不了SpringBoard,在設(shè)置中根本就沒有SpringBoard選項。
cycriptLLDB可以。

這個時候查看image list發(fā)現(xiàn)了加載了Xcode中的庫:

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

這個大小看起來有點靠譜,并且沒有加密相關(guān)字段。
查看MachO文件:

image.png

這里明確了SpringBoard依賴庫的關(guān)系。嘗試class-dump報錯:

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

難道所有實現(xiàn)都是swift實現(xiàn)了?創(chuàng)建Tweak工程,嘗試Hook SBIconBadgeView的實現(xiàn):

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

直接在init的時候返回nil。這個時候Hook是成功的紅點直接全部消失了。

image.png

這里其實就已經(jīng)實現(xiàn)了隱藏系統(tǒng)角標(biāo)的問題。

二、dump頭文件

雖然上面已經(jīng)處理完隱藏邏輯了,但是并不嚴(yán)謹(jǐn)。如果有更復(fù)雜的功能需要處理那么導(dǎo)出頭文件是個重要的步驟。

2.1 方式一 dsc_extractor(可以略過這個,這里只是為了做記錄)

既然上面都獲取不到那么就要換個思路了,系統(tǒng)動態(tài)庫都在共享緩存中,那么導(dǎo)出共享緩存中的動態(tài)庫是不是就能class-dump了?

拷貝共享緩存
啟動本機的Mach-O文件的時候/System/Library/PrivateFrameworks相應(yīng)的庫文件全部轉(zhuǎn)移到了 /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(不同版本可能不太相同)文件夾可以用來解析動態(tài)庫共享緩存。編譯比較麻煩我這里直接用別人編譯好的dsc_extractor文件。編譯好的dsc_extractor

使用:

./dsc_extractor dyld_shared_cache_arm64 frameworks

這個時候就成功導(dǎo)出了共享緩存庫。

生成dsc_extractor可執(zhí)行文件步驟:
(1).下載對應(yīng)版本的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添加執(zhí)行權(quán)限

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導(dǎo)出來的庫報同樣的錯誤。查資料說是只適用于iOS12之前的版本。

2.2 方式二 RuntimeBrowser(可以略過這個,這里只是為了做記錄)

無意間搜到到別人分享的RuntimeBrowserRuntimeBrowser
這個工具支持iOSmacOS下載源碼后需要我們自己編譯build到手機上。在嘗試的過程中遇到的問題比較多,并且在源碼中過濾了我需要的庫:

image.png

所以就不過多研究這個庫了。安裝好后在iOS下如下:
RuntimeBrowser

對于某些庫是能直接在手機端瀏覽頭文件的。貌似也是iOS12支持的比較好。

2.3 方式三 classdump-dyld(推薦)

上面自己沒有能夠成功class-dump springboard庫的頭文件,那么嘗試搜下看有沒有其他人在iOS14上成功恢復(fù)。找到了iOS14runtime頭文件。

在別人分享出來的Headers文件中發(fā)現(xiàn)了以下信息:

/*
* 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環(huán)境。
  2. import classdumpdyld。
  3. 調(diào)用classdumpdyld導(dǎo)出頭文件:
    • classdumpdyld.dumpClass(xxx):導(dǎo)出某個類的頭文件
    • classdumpdyld.dumpBundle(xxx):導(dǎo)出某個庫的頭文件
    • classdumpdyld.dumpBundleForClass(xxx):根據(jù)庫中的某個類導(dǎo)出整個庫,適用于我們并不清楚類屬于哪個庫的情況。

2.3.3 classdump-dyld 使用

通過SBIconBadgeView導(dǎo)出整個庫的頭文件:

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 創(chuàng)建工程

除了通過theostweak工程,也可以通過Monkey來寫。
創(chuàng)建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包拷貝到設(shè)備的/var/root/MonkeyDevBuilds/目錄。
  • MonkeyDevDeviceIP:目標(biāo)設(shè)備的ip地址,默認(rèn)USB連接,localhost。
  • MonkeyDevDevicePassword:目標(biāo)設(shè)備的ssh登錄密碼,默認(rèn)為空使用免密碼登錄。
  • MonkeyDevDevicePort:目標(biāo)設(shè)備的端口,默認(rèn)22。和自己的映射端口相關(guān),這里設(shè)置為12345
  • MonkeyDevInstallOnAnyBuild:每次編譯安裝,一般設(shè)置為NO。安裝時設(shè)置為YES。
  • MonkeyDevInstallOnProfiling:點擊Profile才將deb安裝到設(shè)備。

這個是command + i ?但是這個工程是灰色不能點擊,暫時不清楚這個怎么操作。

  • MonkeyDevkillProcessOnInstall:安裝插件后要殺掉的進程。
  • MonkeyDevPath:MonkeyDev安裝路徑。
  • MonkeyDevTheosPath:theos安裝路徑。

一般情況可以把MonkeyDevDeviceIPMonkeyDevDevicePort設(shè)置在.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工程

創(chuàng)建新的Tweak工程后目錄結(jié)構(gòu)如下:

image.png

編譯make后多了一個.theos文件夾:

image.png

其中存放.dylib文件。外層的.dylibFat類型的,是其它單一架構(gòu)的合集。

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

image.png

并且.theos文件夾下也有一個packages,這個文件夾中是一個記錄build號的文件:
image.png

image.png

  • .deb可以理解為類似.ipa.deb通過cydia下發(fā)安裝插件。.ipa通過AppStore下發(fā)安裝App。
  • .ipa安裝的是.app.deb安裝的是.dylib。

安裝好的.dylib/Library/MobileSubstrate/DynamicLibraries目錄中:

image.png

除了.dylib文件外,還有一個對應(yīng)的.plist。這個plist記錄了要附加的進程bundleid。

4.2 驗證

那么要注入動態(tài)庫有兩種方式:LC_LOAD_DYLIB寫入MachODYLD_INSERT_LIBRARIES注入。
如果是LC_LOAD_DYLIB那么MachO中肯定有對應(yīng)的記錄。

由于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

確認(rèn) 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動態(tài)庫如下:

[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并不需要拷貝。

總結(jié)

  • class-dump導(dǎo)出頭文件
    • class-dump -H MachO文件 -o 頭文件路徑
  • classdump-dyld導(dǎo)出系統(tǒng)庫頭文件
    • 手機端需要安裝classdump-dyld插件

    • 進入cycript環(huán)境導(dǎo)入classdumpdyld

    • 調(diào)用classdumpdyld導(dǎo)出頭文件

      • classdumpdyld.dumpClass(xxx):導(dǎo)出某個類的頭文件
      • classdumpdyld.dumpBundle(xxx):導(dǎo)出某個庫的頭文件

      主程序通過[NSBundle mainBundle]導(dǎo)出。
      其它通過identifier [NSBundle bundleWithIdentifier:@"com.apple.UIKit"]導(dǎo)出。

      • classdumpdyld.dumpBundleForClass(xxx):根據(jù)庫中的某個類導(dǎo)出整個庫的頭文件

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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容