前言
iOS越獄為用戶打開了無限的可能性,其中之一是便是開發(fā)系統(tǒng)級插件,為了確保應(yīng)用程序一直保持在前臺,即使在意外情況下也是如此。
本文將向您展示如何輕松編寫這樣的插件,讓我們開始探索iOS系統(tǒng)插件的世界吧!
一、目標(biāo)
學(xué)會創(chuàng)建功能強(qiáng)大的iOS系統(tǒng)插件。
二、開發(fā)環(huán)境和工具清單
- mac系統(tǒng)
- frida:動態(tài)調(diào)試
- 已越獄iOS設(shè)備(iOS12.5.5):動態(tài)調(diào)試及插件測試
三、步驟
1、定位關(guān)鍵函數(shù)
SpringBoard是iOS系統(tǒng)非常重要的一個(gè)系統(tǒng)應(yīng)用程序,它為用戶提供了訪問和管理應(yīng)用程序的主要方式,同時(shí)也是用戶與設(shè)備交互的一個(gè)重要界面。咱們今天的調(diào)試目標(biāo)就是它。
使用frida-trace動態(tài)調(diào)試地,如何給定關(guān)鍵詞來縮小函數(shù)范圍,我在這有幾點(diǎn)經(jīng)驗(yàn):
根據(jù)類的前綴來減少不相關(guān)的類:
如果你要跟蹤的庫為CoreFoundation.framework。那對應(yīng)的trace為
frida-trace -UF -m "*[CF* *]"
同樣,如果你要跟蹤的庫為AVFoundation.framework。那對應(yīng)的trace為
frida-trace -UF -m "*[AV* *]"
這種命名約定的背后是,iOS系統(tǒng)庫中的類名通常采用庫名的首字母縮寫加上具體類名的形式,以確保類名的唯一性和可讀性。例如,MapKit.framework中的類MKMapView.h、CoreLocation.framework中的類CLLocationManager.h、以及AVFoundation.framework中的類AVCaptureSession.h都遵循了這一約定。
為什么UIKit.framework里的是UILabel.h,而不是UIKLabel.h呢?因?yàn)檫@貨出現(xiàn)得太早了,當(dāng)時(shí)的命名規(guī)范還未形成。
為什么Foundation.framework里的是NSString.h,而不是FString.h呢?這貨也一樣,太早了,命名不規(guī)范。NS的全稱是NeXTStep框架,也就是Objective-c語言早期的實(shí)現(xiàn)之一,更多信息請google。
根據(jù)你的目標(biāo)來限定關(guān)鍵詞,如你想要跟蹤的功能和定位有關(guān)系。那你可以嘗試trace
"*[*Location* *]"
或"*[* *Location*]"
?;蛘吣阋櫟暮桶l(fā)送消息有關(guān)系。那你可以嘗試trace"*[* *sendMsg*]"
或"*[* *sendMsg]"
。注:在這需要注意字母的大小寫。比如Location,這個(gè)L有可能是寫,這種情況你可以這樣trace"*[* ocation*]"
,不寫這個(gè)L就好了嘛。
那試想一下。我們今天的插件是不是和應(yīng)用有關(guān)系,那它的關(guān)鍵詞是不是就應(yīng)該是Application或App。還有狀態(tài)有關(guān)系。應(yīng)用的切換,就在在各種狀態(tài)之前變化,那這關(guān)鍵詞是不是就是State或state。根據(jù)經(jīng)驗(yàn)的第一條。咱們目標(biāo)應(yīng)用SpringBoard,那類名的前綴是不是應(yīng)該是SB。
連上你的手機(jī),并啟動任意程序。在終端執(zhí)行frida-trace -U -m "*[SB* *]" -o a.log SpringBoard
,然而,以SB開頭的類太多了,這命令trace了3萬多個(gè)函數(shù),范圍太廣,手機(jī)直接卡死了…
重新越獄調(diào)整命令為frida-trace -U -m "*[SB*pp* *]" -o a.log SpringBoard
,將應(yīng)用切換到后臺,獲取到關(guān)鍵日志如下:
......
......
......
......
......
......
仍然太多了,你也可以一點(diǎn)點(diǎn)分析,看看哪些函數(shù)可疑,然后再跟蹤。
再調(diào)試trace命令,加上statefrida-trace -U -m "*[SB*pp* *tate*]" -o a.log SpringBoard
,將應(yīng)用切換到后臺,獲取到的部分關(guān)鍵日志如下:
-[SBMainDisplayWorkspaceAppInteractionEventSource layoutStateTransitionCoordinator:0x283547690 transitionDidEndWithTransitionContext:0x28275c900]
-[SBAppToAppWorkspaceTransaction shouldPerformToAppStateCleanupOnCompletion]
-[SBToAppsWorkspaceTransaction performToAppStateCleanup]
-[SBWorkspaceApplicationSceneTransitionContext layoutState]
-[SBWorkspaceApplicationSceneTransitionContext previousLayoutState]
-[SBApplication _noteProcess:0x109b51300 didChangeToState:0x283be0880]
-[SBApplication _updateProcess:<FBApplicationProcess: 0x109b51300; Cydia (com.saurik.Cydia); pid: 20212> withState:<FBProcessState: 0x283be0880; pid: 20212; taskState: Running; visibility: Background>]
-[SBApplication _internalProcessState]
-[SBApplicationProcessState taskState]
-[SBApplication _internalProcessState]
-[SBApplicationProcessState _initWithProcess:0x109b51300 stateSnapshot:0x283be0880]
-[SBApplication _setInternalProcessState:0x283bf8f40]
-[SBApplicationProcessState taskState]
-[SBApplicationProcessState taskState]
-[SBApplicationAutoLaunchService _applicationProcessStateDidChange:0x2835676f0]
-[SBApplication processState]
-[SBApplicationProcessState taskState]
-[SBApplication _noteProcess:0x109b51300 didChangeToState:0x283b07b20]
-[SBApplication _updateProcess:<FBApplicationProcess: 0x109b51300; Cydia (com.saurik.Cydia); pid: 20212> withState:<FBProcessState: 0x283b07b20; pid: 20212; taskState: Suspended; visibility: Background>]
-[SBApplication _internalProcessState]
-[SBApplicationProcessState taskState]
-[SBApplication _internalProcessState]
-[SBApplicationProcessState _initWithProcess:0x109b51300 stateSnapshot:0x283b07b20]
-[SBApplication _setInternalProcessState:0x283b98ea0]
-[SBApplicationProcessState taskState]
-[SBApplicationProcessState taskState]
-[SBApplicationAutoLaunchService _applicationProcessStateDidChange:0x283544690]
-[SBApplication processState]
-[SBApplication _internalProcessState]
從以上信息我們提取出關(guān)鍵類為SBApplication
,可疑函數(shù)-[SBApplication _noteProcess:0x109b51300 didChangeToState:0x283b07b20]
,跟蹤該類frida-trace -U -m "-[SBApplication _noteProcess:didChangeToState:]" -o a.log SpringBoard
,js代碼如下:
{
onEnter(log, args, state) {
log(`-[SBApplication _noteProcess:${ObjC.Object(args[2])} didChangeToState:${ObjC.Object(args[3])}]`);
},
onLeave(log, retval, state) {
}
}
應(yīng)用切到后臺,獲取到日志如下:
-[SBApplication _noteProcess:<FBApplicationProcess: 0x113b1e540; Cydia (com.saurik.Cydia); pid: 20869> didChangeToState:<FBProcessState: 0x283bd71e0; pid: 20869; taskState: Running; visibility: Background>]
-[SBApplication _noteProcess:<FBApplicationProcess: 0x113b1e540; Cydia (com.saurik.Cydia); pid: 20869> didChangeToState:<FBProcessState: 0x283b82660; pid: 20869; taskState: Suspended; visibility: Background>]
根據(jù)日志信息,可以看出。第一個(gè)參數(shù)里包含了我們當(dāng)前的應(yīng)用信息。第二個(gè)參數(shù)則是應(yīng)用的狀態(tài)。Running、Suspended、Not Running。
至此,目標(biāo)函數(shù)已找到。
注:目標(biāo)函數(shù)不止這一個(gè),只要你通過你自己的關(guān)鍵詞定位,嘗試,也許是找到的其他函數(shù)。只要應(yīng)用的狀態(tài)正確且唯一,都可以使用。比如我之前調(diào)試過程中找到的函數(shù)是[SBMainWorkspace process:stateDidChangeFromState:toState:]
,也是可以用的。
2、編寫插件代碼
使用Xcode的MonkeyDev插件的Logos Tweak來創(chuàng)建插件工程:
應(yīng)用狀態(tài)hook代碼如下:
%hook SBMainWorkspace
-(void)process:(id)arg1 stateDidChangeFromState:(id)arg2 toState:(id)arg3{
%orig;
// arg1的類型為:FBApplicationProcess,獲取包名的方法名為bundleIdentifier
// arg3的類型為:FBProcessState,獲取到狀態(tài)的方法名為taskState
// 在這查找類對應(yīng)的頭文件:https://developer.limneos.net/index.php
NSString *bundleID = [arg1 valueForKey:@"bundleIdentifier"];
BOOL isValid = [AppAngel validBundleID:bundleID];
int toState = [[arg3 valueForKey:@"taskState"] intValue]; // 調(diào)試可得:2運(yùn)行,3后臺,1殺死
NSLog(@"witwit =%@=%@=", bundleID, arg3);
NSLog(@"witwit hook=%d=%d=", isValid, toState);
if (isValid {
if (toState == 3) {
[AppAngel launchApp:bundleID];
} else if (toState == 1) {
[AppAngel performSelector:@selector(launchApp:) withObject:bundleID afterDelay:1];
}
}
}
%end
由于插件開啟后,目標(biāo)應(yīng)用無法切換到后臺,這時(shí)你想關(guān)閉插件咋辦?于是有了關(guān)閉快捷鍵音量-或電源鍵,相關(guān)hook代碼如下:
%hook VolumeControl
-(void)increaseVolume {
NSTimeInterval nowtime = [[NSDate date] timeIntervalSince1970];
NSLog(@"witwit iosother increaseVolume");
if (nowtime - g_volume_up_time < 1) {
g_volume_up_count += 1;
if (g_volume_up_count >= 2) {
g_volume_up_count = 0;
[AppAngel enablePlugins:YES];
}
} else {
g_volume_up_count = 0;
}
%orig;
g_volume_up_time = nowtime;
}
-(void)decreaseVolume {
NSTimeInterval nowtime = [[NSDate date] timeIntervalSince1970];
NSLog(@"witwit iosother decreaseVolume");
if (nowtime - g_volume_down_time < 1) {
g_volume_down_count += 1;
if (g_volume_down_count >= 2) {
g_volume_down_count = 0;
[AppAngel enablePlugins:NO];
}
} else {
g_volume_down_count = 0;
}
%orig;
g_volume_down_time = nowtime;
}
// 在使用音量鍵開啟或關(guān)閉插件的toast在iOS12系統(tǒng)中會和音量彈窗重疊,hook音量彈窗
- (BOOL)_HUDIsDisplayableForCategory:(NSString *)category {
if ([category isEqualToString:@"Audio/Video"]) {
return NO;
}
return %orig;
}
%end
電源鍵監(jiān)聽相關(guān)代碼如下:
// 注冊鎖屏通知
notify_register_dispatch("com.apple.springboard.lockstate", ¬ifyToken, dispatch_get_main_queue(), ^(int token) {
uint64_t state = 0;
notify_get_state(token, &state);
BOOL isScreenLocked = state == 1;
if (isScreenLocked) {
NSLog(@"witwit 鎖屏了");
if ( [AppAngel getPreferencesWithKey:@"HookEnable"]) {
[AppAngel enablePlugins:NO];
}
}
});
由于我們可以會對特定的App進(jìn)行配置。于是使用AppList插件來實(shí)現(xiàn)該界面:
相關(guān)源碼如下:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>entry</key>
<dict>
<key>bundle</key>
<string>AppList</string>
<key>cell</key>
<string>PSLinkCell</string>
<key>icon</key>
<string>/Library/PreferenceLoader/Preferences/AppAngelIcon.png</string>
<key>isController</key>
<string>1</string>
<key>label</key>
<string>應(yīng)用天使</string>
<key>ALSettingsPath</key>
<string>/var/mobile/Library/Preferences/com.witchan.AppAngel.plist</string>
<key>ALSettingsKeyPrefix</key>
<string>witwit-</string>
<key>ALChangeNotification</key>
<string>com.rpetrich.applist.sample.notification</string>
<key>ALAllowsSelection</key>
<string>1</string>
<key>ALSectionDescriptors</key>
<array>
<dict>
<key>items</key>
<array>
<dict>
<key>text</key>
<string>關(guān)于我</string>
<key>action</key>
<string>launchURL</string>
<key>url</key>
<string>https://mp.weixin.qq.com/s/WERMNPzW6WV5YGFthVqCRg</string>
</dict>
</array>
</dict>
<dict>
<key>footer-title</key>
<string>連按音量+鍵開啟插件,連按音量-或電源鍵停止插件 </string>
<key>items</key>
<array>
<dict>
<key>cell-class-name</key>
<string>ALSwitchCell</string>
<key>default</key>
<string>NO</string>
<key>ALSettingsKey</key>
<string>witwit-HookEnable</string>
<key>text</key>
<string>插件開關(guān)</string>
</dict>
</array>
</dict>
<dict>
<key>title</key>
<string>用戶應(yīng)用</string>
<key>predicate</key>
<string>isSystemApplication = FALSE</string>
<key>cell-class-name</key>
<string>ALSwitchCell</string>
<key>icon-size</key>
<string>29</string>
<key>suppress-hidden-apps</key>
<string>1</string>
</dict>
<dict>
<key>title</key>
<string>系統(tǒng)應(yīng)用</string>
<key>predicate</key>
<string>isSystemApplication = TRUE</string>
<key>cell-class-name</key>
<string>ALSwitchCell</string>
<key>icon-size</key>
<string>29</string>
<key>suppress-hidden-apps</key>
<string>1</string>
</dict>
</array>
</dict>
</dict>
</plist>
總結(jié)
本文主要系統(tǒng)插件的實(shí)現(xiàn)過程進(jìn)行了分析及試驗(yàn),插件名叫【應(yīng)用天使】已在iOS12和15系統(tǒng)上測試并通過,已上傳到bigboss源。需要的同學(xué)請可下載使用,當(dāng)你在使用中遇到任何問題也可向我反饋。如需要插件完整源碼,請公眾號回復(fù)【應(yīng)用天使】即可獲取完整代碼。
注:在iOS15系統(tǒng)中,bigboss源的AppList插件不支持,請從https://repo.palera.in/源里下載并安裝AppList,或者自行下載支持iOS15的AppList。文章來源:http://www.zghlxwxcb.cn/news/detail-770310.html
提示:閱讀此文檔的過程中遇到任何問題,請關(guān)住工眾好【
移動端Android和iOS開發(fā)技術(shù)分享
】或+99 君羊【812546729
】文章來源地址http://www.zghlxwxcb.cn/news/detail-770310.html
到了這里,關(guān)于【iOS逆向與安全】編寫一個(gè)使應(yīng)用保持前臺運(yùn)行的系統(tǒng)插件的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!