写点什么

【iOS 逆向与安全】系统推送服务 (APNS) 拦截

作者:小陈
  • 2023-01-16
    四川
  • 本文字数:9808 字

    阅读完需:约 32 分钟

前言

经过之前的分享,相信大家已经掌握了用户级的插件开发。勤奋好学的你是否对系统级的插件也有着浓厚的性趣,本篇文章将和大家一起学习如何分析并编写一款系统级的插件。



一、目标

一步步分析并编写一个拦截系统推送的 deb 插件

二、工具

  • mac 系统

  • 已越狱 iOS 设备:脱壳及 frida 调试

  • IDA Pro:静态分析

三、步骤

1、守护进程

​ 守护进程(daemon)是一类在后台运行的特殊进程,用于执行特定的系统任务。例如:推送服务、人脸解锁、iCloud、查找我的 iPhone、iMessage 等。


相应的配置目录:


  • /Library/LaunchAgents:管理员控制特定用户的代理

  • /Library/LaunchDaemons:管理员提供的系统级守护进程(cydia、filza、frida 等就在这)

  • /System/Library/LaunchDaemons:iOS 提供的默认守护进程


常见的进程配置文件有:



更多服务请参考https://www.theiphonewiki.com/wiki/Services

2、定位关键函数

使用命令frida-trace -U -m "*[UILabel setText:]" SpringBoard后,收到通知后的日志如下:


 66907 ms  -[UILabel setText:移动端小陈] 66907 ms  UILabel setText called from:0x1e54aa12c UserNotificationsUIKit!-[NCNotificationContentView setSecondaryText:]0x1e5475474 UserNotificationsUIKit!-[NCNotificationShortLookView setSecondaryText:]0x1e543bd1c UserNotificationsUIKit!-[NCNotificationViewController _updateWithProvidedStaticContent]0x1e54b68b4 UserNotificationsUIKit!-[NCNotificationShortLookViewController _updateWithProvidedStaticContent]0x1e543b6ec UserNotificationsUIKit!-[NCNotificationViewController setHasUpdatedContent]0x1e543c450 UserNotificationsUIKit!-[NCNotificationViewController viewDidLoad]0x1ea9fe224 UIKitCore!-[UIViewController loadViewIfRequired]0x1ea9fe628 UIKitCore!-[UIViewController view]0x1eaa15dd4 UIKitCore!-[UIViewController _setPresentationController:]0x1eaa0e1f4 UIKitCore!-[UIViewController _presentViewController:modalSourceViewController:presentationController:animationController:interactionController:completion:]0x1eaa0fccc UIKitCore!-[UIViewController _presentViewController:withAnimationController:completion:]0x1eaa123a8 UIKitCore!__63-[UIViewController _presentViewController:animated:completion:]_block_invoke0x1eaa128a4 UIKitCore!-[UIViewController _performCoordinatedPresentOrDismiss:animated:]0x1eaa12300 UIKitCore!-[UIViewController _presentViewController:animated:completion:]0x1eaa12560 UIKitCore!-[UIViewController presentViewController:animated:completion:]0x1010d78e0 /System/Library/CoreServices/SpringBoard.app/SpringBoard!-[SBNotificationBannerDestination _presentNotificationViewController:modal:forRequest:sourceAction:completion:]
复制代码


继续使用命令frida-trace -U -m "*[SBNotificationBannerDestination _presentNotificationViewController:modal:forRequest:sourceAction:completion:]" SpringBoard后,收到通知后的日志如下:


 13037 ms  -[SBNotificationBannerDestination _presentNotificationViewController:0x10286f400 modal:0x0 forRequest:0x2825bb2c0 sourceAction:0x0 completion:0x0] 13037 ms  SBNotificationBannerDestination called from:0x1013ba3e8 SpringBoard!0x4363e8 (0x1004363e8)0x1be00ca38 libdispatch.dylib!_dispatch_call_block_and_release0x1be00d7d4 libdispatch.dylib!_dispatch_client_callout0x1bdfbb008 libdispatch.dylib!_dispatch_main_queue_callback_4CF$VARIANT$mp0x1be560b20 CoreFoundation!__CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__0x1be55ba58 CoreFoundation!__CFRunLoopRun0x1be55afb4 CoreFoundation!CFRunLoopRunSpecific0x1c075d79c GraphicsServices!GSEventRunModal0x1eafa7c38 UIKitCore!UIApplicationMain0x1d4219a70 FrontBoard!FBSystemAppMain0x10116db98 SpringBoard!0x1e9b98 (0x1001e9b98)0x1be01e8e0 libdyld.dylib!start
复制代码


根据以上日志,只能看到上一层级的函数是一个地址。咱们先把/System/Library/CoreServices/目录的 SpringBoard.app 文件导出到电脑(可使用爱思或其他工具),再使用 IDA Pro 工具打开,搜索_presentNotificationViewController后,找到该函数:





一层层往上找,直到



继续使用命令frida-trace -U -m "*[SBNotificationBannerDestination *]" SpringBoard -o a.log后,获取到日志如下:



-[SBNotificationBannerDestination canReceiveNotificationRequest:<NCNotificationRequest: 0x2825a0e00; timestamp: 2023-01-12 11:55:55 +0000; sectionId: com.laiwang.DingTalk; threadId: 263527137:2653514294; notificationId: IM_2653514294_14628640765618; categoryId: category.message.reply.v2>]-[SBNotificationBannerDestination _isPresentingStickyBanner]-[SBNotificationBannerDestination presentedBanner]-[SBNotificationBannerDestination _isPresentingBanner]-[SBNotificationBannerDestination presentedBanner]-[SBNotificationBannerDestination _isPresentedBannerBeingDragged]-[SBNotificationBannerDestination _isPresentingBanner]-[SBNotificationBannerDestination presentedBanner]-[SBNotificationBannerDestination _isInSetupMode]-[SBNotificationBannerDestination setupManager]-[SBNotificationBannerDestination _isPendingBannerPresentation]-[SBNotificationBannerDestination bannerPresentationSemaphore]-[SBNotificationBannerDestination _canReceiveNotificationRequestIfLocked:0x2825a0e00]-[SBNotificationBannerDestination _isUILocked]-[SBNotificationBannerDestination lockScreenManager]-[SBNotificationBannerDestination identifier]-[SBNotificationBannerDestination _isPresentingStickyBanner]-[SBNotificationBannerDestination presentedBanner]-[SBNotificationBannerDestination _isPresentingBanner]-[SBNotificationBannerDestination presentedBanner]-[SBNotificationBannerDestination _isPresentedBannerBeingDragged]-[SBNotificationBannerDestination _isPresentingBanner]-[SBNotificationBannerDestination presentedBanner]-[SBNotificationBannerDestination _isInSetupMode]-[SBNotificationBannerDestination setupManager]-[SBNotificationBannerDestination _isPendingBannerPresentation]-[SBNotificationBannerDestination bannerPresentationSemaphore]-[SBNotificationBannerDestination identifier]-[SBNotificationBannerDestination postNotificationRequest:0x2825a0e00 forCoalescedNotification:0x281166e20]-[SBNotificationBannerDestination _postNotificationRequest:0x2825a0e00 forCoalescedNotification:0x281166e20 modal:0x0 sourceAction:0x0 completion:0x0]-[SBNotificationBannerDestination dndEventBehaviorResolutionService]-[SBNotificationBannerDestination _isBundleIdentifierBlockedForScreenTimeExpiration:0x28118dc80]-[SBNotificationBannerDestination _isPresentingBannerInLongLook]-[SBNotificationBannerDestination _isPresentingBanner]-[SBNotificationBannerDestination presentedBanner]-[SBNotificationBannerDestination setBannerPresentationSemaphore:0x283fc5450]-[SBNotificationBannerDestination _notificationViewControllerForRequest:0x2825a0e00]-[SBNotificationBannerDestination notificationViewController:0x11683d000 staticContentProviderForNotificationRequest:0x2825a0e00]-[SBNotificationBannerDestination _isContentSuppressedForNotificationRequest:0x2825a0e00]-[SBNotificationBannerDestination _isDeviceAuthenticated]-[SBNotificationBannerDestination notificationViewController:0x11683d000 auxiliaryOptionsContentProviderForNotificationRequest:0x2825a0e00 withLongLook:0x0]-[SBNotificationBannerDestination _notificationSectionSettingsForSectionIdentifier:0x28118dc80]-[SBNotificationBannerDestination delegate]-[SBNotificationBannerDestination shouldLoadAudioAccessoryViewForNotificationViewController:0x11683d000]-[SBNotificationBannerDestination notificationViewControllerIsReadyToBePresented:0x11683d000]-[SBNotificationBannerDestination bannerPresentationSemaphore]-[SBNotificationBannerDestination bannerPresentationSemaphore]-[SBNotificationBannerDestination _scheduleNotificationViewControllerPresentationBlock:0x16ee7a4b8]-[SBNotificationBannerDestination bannerPresentationSemaphore]-[SBNotificationBannerDestination setBannerPresentationSemaphore:0x0]-[SBNotificationBannerDestination _topPresentedViewController]-[SBNotificationBannerDestination _rootViewController]-[SBNotificationBannerDestination bannerWindow]
复制代码


根据日志可确定函数为-[SBNotificationBannerDestination _postNotificationRequest:0x2825a64c0 forCoalescedNotification:0x281166e20 modal:0x0 sourceAction:0x0 completion:0x0]


继续 trace 该函数后获取到日志如下:


-[SBNotificationBannerDestination _postNotificationRequest:0x2825a5ce0 forCoalescedNotification:0x281166e20 modal:0x0 sourceAction:0x0 completion:0x0]_postNotificationRequest called from:0x1010d681c /System/Library/CoreServices/SpringBoard.app/SpringBoard!-[SBNotificationBannerDestination postNotificationRequest:forCoalescedNotification:]0x1dae97d10 UserNotificationsKit!__78-[NCNotificationAlertQueue _postNotificationRequest:forCoalescedNotification:]_block_invoke0x1dae97fd0 UserNotificationsKit!-[NCNotificationAlertQueue _performDestinationOperationForRequest:block:]0x1dae97a4c UserNotificationsKit!-[NCNotificationAlertQueue _postNotificationRequest:forCoalescedNotification:]0x1dae95ed4 UserNotificationsKit!-[NCNotificationAlertQueue postNotificationRequest:forCoalescedNotification:]0x1daea36bc UserNotificationsKit!-[NCNotificationDispatcher postNotificationWithRequest:]0x1e54b0bcc UserNotificationsUIKit!-[NCBulletinNotificationSource observer:addBulletin:forFeed:playLightsAndSirens:withReply:]0x1cdffd760 BulletinBoard!__49-[BBObserver _queue_updateAddBulletin:withReply:]_block_invoke0x1be00ca38 libdispatch.dylib!_dispatch_call_block_and_release0x1be00d7d4 libdispatch.dylib!_dispatch_client_callout0x1bdfbb008 libdispatch.dylib!_dispatch_main_queue_callback_4CF$VARIANT$mp0x1be560b20 CoreFoundation!__CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__0x1be55ba58 CoreFoundation!__CFRunLoopRun0x1be55afb4 CoreFoundation!CFRunLoopRunSpecific0x1c075d79c GraphicsServices!GSEventRunModal0x1eafa7c38 UIKitCore!UIApplicationMain
复制代码


继续跟踪-[BBObserver _queue_updateAddBulletin:withReply:]方法后,获取到日志如下:


-[BBObserver _queue_updateAddBulletin:<BBBulletinAddUpdate: 0x281d2a440; Should Play Lights And Sirens: YES> withReply:<__NSMallocBlock__: 0x281290ed0>]-[BBObserver _queue_updateAddBulletin:<BBBulletinAddUpdate: 0x281d78ce0; Should Play Lights And Sirens: YES> withReply:<__NSMallocBlock__: 0x281397150>] BBObserver_queue_updateAddBulletin called from:0x1cdffd260 BulletinBoard!-[BBObserver _queue_updateBulletin:withReply:]0x1be00ca38 libdispatch.dylib!_dispatch_call_block_and_release0x1be00d7d4 libdispatch.dylib!_dispatch_client_callout0x1bdfb6324 libdispatch.dylib!_dispatch_lane_serial_drain$VARIANT$mp0x1bdfb6e74 libdispatch.dylib!_dispatch_lane_invoke$VARIANT$mp0x1bdfbf4ac libdispatch.dylib!_dispatch_workloop_worker_thread0x1be1ee114 libsystem_pthread.dylib!_pthread_wqthread
BBObserver_queue_updateAddBulletin called from:0x1cdffd260 BulletinBoard!-[BBObserver _queue_updateBulletin:withReply:]0x1be00ca38 libdispatch.dylib!_dispatch_call_block_and_release0x1be00d7d4 libdispatch.dylib!_dispatch_client_callout0x1bdfbb008 libdispatch.dylib!_dispatch_main_queue_callback_4CF$VARIANT$mp0x1be560b20 CoreFoundation!__CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__0x1be55ba58 CoreFoundation!__CFRunLoopRun0x1be55afb4 CoreFoundation!CFRunLoopRunSpecific0x1c075d79c GraphicsServices!GSEventRunModal0x1eafa7c38 UIKitCore!UIApplicationMain0x1d4219a70 FrontBoard!FBSystemAppMain0x10116db98 SpringBoard!0x1e9b98 (0x1001e9b98)0x1be01e8e0 libdyld.dylib!start
复制代码


最终,拿到关键函数-[BBObserver _queue_updateBulletin:withReply:],我们发现关键类 BBObserver 在 BulletinBoard 动态库里,根据 iphonedevwiki(原文地址:https://iphonedevwiki.net/index.php/BulletinBoard.framework),我们继续使用命令`frida-trace -U -m "*[BBBulletin init]" SpringBoard -o a.log`,收到通知后,获取到的日志如下:


-[BBBulletin init]BBBulletin  init called from:0x1e53f4748 UserNotificationsServer!-[UNSDefaultDataProvider _queue_bulletinForNotification:]0x1e53f7e70 UserNotificationsServer!-[UNSDefaultDataProvider _queue_addBulletinForNotification:]0x1e53f78cc UserNotificationsServer!-[UNSDefaultDataProvider _queue_notificationRepositoryDidPerformUpdates:]0x1be00ca38 libdispatch.dylib!_dispatch_call_block_and_release0x1be00d7d4 libdispatch.dylib!_dispatch_client_callout0x1bdfb6324 libdispatch.dylib!_dispatch_lane_serial_drain$VARIANT$mp0x1bdfb6e74 libdispatch.dylib!_dispatch_lane_invoke$VARIANT$mp0x1bdfbf4ac libdispatch.dylib!_dispatch_workloop_worker_thread0x1be1ee114 libsystem_pthread.dylib!_pthread_wqthread
复制代码


继续使用命令frida-trace -U -m "*[UNSDefaultDataProvider *]" SpringBoard -o a.log跟踪后,获取到日志如下:


-[UNSDefaultDataProvider notificationRepository:0x2833118f0 didPerformUpdates:0x283303840 forBundleIdentifier:0x2831142a0]UNSDefaultDataProvider  notificationRepository called from:0x1e53c52c0 UserNotificationsServer!-[UNSKeyedObservable _callOutQueue_notifyObserversKey:usingBlock:]0x1e53c5158 UserNotificationsServer!__52-[UNSKeyedObservable notifyObserversKey:usingBlock:]_block_invoke0x1be00ca38 libdispatch.dylib!_dispatch_call_block_and_release0x1be00d7d4 libdispatch.dylib!_dispatch_client_callout0x1bdfb6324 libdispatch.dylib!_dispatch_lane_serial_drain$VARIANT$mp0x1bdfb6e74 libdispatch.dylib!_dispatch_lane_invoke$VARIANT$mp0x1bdfbf4ac libdispatch.dylib!_dispatch_workloop_worker_thread0x1be1ee114 libsystem_pthread.dylib!_pthread_wqthread
-[UNSDefaultDataProvider _queue_notificationRepositoryDidPerformUpdates:0x283303840]-[UNSDefaultDataProvider _queue_addBulletinForNotification:0x13152f9f0]-[UNSDefaultDataProvider _categoryForIdentifier:0x283367ba0]-[UNSDefaultDataProvider sectionIdentifier]-[UNSDefaultDataProvider sectionIdentifier]-[UNSDefaultDataProvider _queue_bulletinForNotification:0x13152f9f0]-[UNSDefaultDataProvider sectionIdentifier]-[UNSDefaultDataProvider _defaultActionWithNotification:0x13152f9f0]-[UNSDefaultDataProvider _categoryForIdentifier:0x283367ba0]-[UNSDefaultDataProvider sectionIdentifier]-[UNSDefaultDataProvider _dismissActionForCategory:0x281ba68e0]-[UNSDefaultDataProvider _silenceActionForCategory:0x281ba68e0]-[UNSDefaultDataProvider _supplementaryActionsForForCategoryRecord:0x281ba68e0]-[UNSDefaultDataProvider _actionsFromActionRecords:0x283d74230]-[UNSDefaultDataProvider _actionFromActionRecord:0x2814d3d40]-[UNSDefaultDataProvider _pathForSoundName:0x98df68cf59d4b573]-[UNSDefaultDataProvider _isResourceValidForPath:0x280636140 withContainerPath:0x28042acb0]-[UNSDefaultDataProvider _isResourceValidForPath:0x280429790 withContainerPath:0x280a97300]-[UNSDefaultDataProvider _addAttachments:0x283d180f0 toBulletinRequest:0x131156390]
复制代码


根据日志,继续使用命令-[UNSDefaultDataProvider notificationRepository:didPerformUpdates:forBundleIdentifier:]


js 代码如下:


{  onEnter(log, args, state) {    var arg2 = new ObjC.Object(args[2]);    var arg3 = new ObjC.Object(args[3]);    var arg4 = new ObjC.Object(args[4]);    log(`-[UNSDefaultDataProvider notificationRepository:${arg2} didPerformUpdates:${arg3} forBundleIdentifier:${arg4}]`);
var array = arg3; var count = array.count().valueOf(); for (var i = 0; i !== count; i++) { var element = array.objectAtIndex_(i); var vs =element.$ivars for (var key in vs) { log("k:" + key + " v:" + vs[key]); } } }, onLeave(log, retval, state) { }}
复制代码


收到通知后,获取到的日志如下:


-[UNSDefaultDataProvider notificationRepository:<UNSNotificationRepository: 0x2833118f0> didPerformUpdates:(    "<UNSNotificationRecordAddUpdate: 0x283d703a0>") forBundleIdentifier:com.laiwang.DingTalk]k:isa v:UNSNotificationRecordAddUpdatek:_notificationRecord v:<UNSNotificationRecord: 0x131265a20> {    Date = 2023-01-15 05:14:42 +0000;    Identifier = IM_2653514294_14665184200561;    ThreadIdentifier = 263527137:2653514294;    CategoryIdentifier = category.message.reply.v2;    Badge = 7;    Body = 移动端小陈;    SummaryArgument = 0x0;    SummaryArgumentCount = 0;    ContentAvailable = 0;    MutableContent = 1;    Title = 小陈;    ToneAlertType = TLAlertTypeAppNotification;    ToneFileName = general.mp3;    DefaultDestinations = YES;    LockScreenDestination = YES;    NotificationCenterDestination = YES;    AlertDestination = YES;    CarPlayDestination = YES;    TriggerType = Push;    UserInfo = {        feedbackInfo = {            feedbackParam = kICibP7dH0S6Hh4A3zFVFg==&1673759682344&/gBKUiN/54;            feedbackUrl = https://pnsfeedback.dingtalk.com/apple;        }        ctag = 0;        content_type = 1;        nick_name = 小陈;        type = 1;        cid = 263527137:2653514294;        avatar = @lADPDhmOva64dWrNAtDNAtA;        orgId = 0;        aps = {            interruption-level = time-sensitive;            mutable-content = 1;            alert = {                title = 小陈;                body = 移动端小陈;            }            badge = 7;            category = category.message.reply;            sound = general.mp3;        }        openId = 2653514294;        msgId = 14665184200561;        sender_id = 263527137;    }}
复制代码


至此,方法-[UNSDefaultDataProvider notificationRepository:didPerformUpdates:forBundleIdentifier:]就是我们的目标函数,该方法位于 UserNotificationsServer.framework 私有库里,查了一圈资料,也没找着该库的相关说明。但从库名可以看出,该库是处理用户通知的服务。

3、编写 deb 插件

接下来,我们就编写 deb 插件,关键代码如下:


#if TARGET_OS_SIMULATOR#error Do not support the simulator, please use the real iPhone Device.#endif
#import "NSObject+YYModel.h"#import <Foundation/Foundation.h>#import "CaptainHook/CaptainHook.h"#include <notify.h> // not required; for examples only
@interface UNSDefaultDataProvider : NSObject
- (void)notificationRepository:(id)arg1 didPerformUpdates:(NSArray *)arg2 forBundleIdentifier:(NSString *)arg3;
@end

@class UNSDefaultDataProvider;
CHDeclareClass(UNSDefaultDataProvider); // declare class
CHOptimizedMethod3(self, void, UNSDefaultDataProvider, notificationRepository, id, arg1, didPerformUpdates, NSArray *, arg2, forBundleIdentifier, NSString *, arg3) { @try { for (id record in arg2) { NSLog(@"witchan =obj0=%@=", record);
if ([record isKindOfClass:NSClassFromString(@"UNSNotificationRecord")] || [record isKindOfClass:NSClassFromString(@"UNSNotificationRecordAddUpdate")]) { UNSNotificationRecord *obj = [record valueForKey:@"_notificationRecord"]; obj.body = @"我是移动端的小陈"; // 修改推送内容 NSLog(@"witchan =obj=%@=", obj); NSDictionary *content = [obj modelToJSONObject]; NSMutableDictionary *params = [NSMutableDictionary dictionary]; params[@"bundleid"] = arg3; params[@"content"] = content; NSLog(@"witchan =message=%@=", params); } } } @catch (NSException *exception) { NSLog(@"witchan =exception=%@=", exception); } @finally { CHSuper3(UNSDefaultDataProvider, notificationRepository, arg1, didPerformUpdates, arg2, forBundleIdentifier, arg3); // 如果不需要显示通知,注释此此行代码即可 }}
CHConstructor // code block that runs immediately upon load{ @autoreleasepool { CHLoadLateClass(UNSDefaultDataProvider); NSLog(@"witchan =load success="); CHHook3(UNSDefaultDataProvider, notificationRepository, didPerformUpdates, forBundleIdentifier); }}
复制代码


需要 hook 的应用为 springboard:




总结

以上就是如何一步步查找到推送的关键函数,并对该函数进行操作,实现一个系统级的 deb 插件的示例。希望能对你有所启发。在 iOS 系统中,SpringBoard 就是用户和 iOS 底层系统的桥梁,你可以在 SpringBoard 中,安装,卸载,使用其他 App,也可以系统进行人性化的可配置等,SpringBoard 之下,还有许多支撑整个系统私有库,这些库,有很多都是正向开发无法使用的,却一直在后台默默的运行着(LaunchDaemon)。如果你注意看守护进程那,是否有注意到一个 com.apple.apsd 的守护进程,这个进程也是处理推送的,你也可以用类似frida-trace -U -m "*[APS* *]" apsd的命令尝试去 trace 试一下。


提示:阅读此文档的过程中遇到任何问题,请关住工众好【*移动端Android和iOS开发技术分享】或+99 君羊【812546729*】



用户头像

小陈

关注

和昨天不一样 2019-03-12 加入

公众号:移动端Android和iOS开发技术分享

评论

发布
暂无评论
【iOS逆向与安全】系统推送服务(APNS)拦截_安卓_小陈_InfoQ写作社区