关于ios:iOS逆向与安全系统推送服务APNS拦截

7次阅读

共计 17209 个字符,预计需要花费 44 分钟才能阅读完成。

前言

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

一、指标

一步步剖析并编写一个拦挡零碎推送的 deb 插件

二、工具

mac 零碎
已越狱 iOS 设施:脱壳及 frida 调试
IDA Pro:动态剖析

三、步骤

1、守护过程

守护过程 (daemon) 是一类在后盾运行的非凡过程,用于执行特定的零碎工作。例如:推送服务、人脸解锁、iCloud、查找我的 iPhone、iMessage 等。相应的配置目录:/Library/LaunchAgents:管理员管制特定用户的代理 /Library/LaunchDaemons:管理员提供的零碎级守护过程(cydia、filza、frida 等就在这)/System/Library/LaunchDaemons:iOS 提供的默认守护过程常见的过程配置文件有:

名称 形容
com.apple.apsd 推送服务
com.apple.biometrickitd.pearl 人脸解锁 com.apple.clouddiCloudcom.apple.icloud.findmydeviced 查找我的 iPhone
com.apple.imagent 即时消息代理 (iMessage)
更多服务请参考 https://www.theiphonewiki.com…

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_invoke
0x1eaa128a4 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_release
0x1be00d7d4 libdispatch.dylib!_dispatch_client_callout
0x1bdfbb008 libdispatch.dylib!_dispatch_main_queue_callback_4CF$VARIANT$mp
0x1be560b20 CoreFoundation!__CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__
0x1be55ba58 CoreFoundation!__CFRunLoopRun
0x1be55afb4 CoreFoundation!CFRunLoopRunSpecific
0x1c075d79c GraphicsServices!GSEventRunModal
0x1eafa7c38 UIKitCore!UIApplicationMain
0x1d4219a70 FrontBoard!FBSystemAppMain
0x10116db98 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_invoke
0x1dae97fd0 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_invoke
0x1be00ca38 libdispatch.dylib!_dispatch_call_block_and_release
0x1be00d7d4 libdispatch.dylib!_dispatch_client_callout
0x1bdfbb008 libdispatch.dylib!_dispatch_main_queue_callback_4CF$VARIANT$mp
0x1be560b20 CoreFoundation!__CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__
0x1be55ba58 CoreFoundation!__CFRunLoopRun
0x1be55afb4 CoreFoundation!CFRunLoopRunSpecific
0x1c075d79c GraphicsServices!GSEventRunModal
0x1eafa7c38 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_release
0x1be00d7d4 libdispatch.dylib!_dispatch_client_callout
0x1bdfb6324 libdispatch.dylib!_dispatch_lane_serial_drain$VARIANT$mp
0x1bdfb6e74 libdispatch.dylib!_dispatch_lane_invoke$VARIANT$mp
0x1bdfbf4ac libdispatch.dylib!_dispatch_workloop_worker_thread
0x1be1ee114 libsystem_pthread.dylib!_pthread_wqthread

 BBObserver_queue_updateAddBulletin called from:
0x1cdffd260 BulletinBoard!-[BBObserver _queue_updateBulletin:withReply:]
0x1be00ca38 libdispatch.dylib!_dispatch_call_block_and_release
0x1be00d7d4 libdispatch.dylib!_dispatch_client_callout
0x1bdfbb008 libdispatch.dylib!_dispatch_main_queue_callback_4CF$VARIANT$mp
0x1be560b20 CoreFoundation!__CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__
0x1be55ba58 CoreFoundation!__CFRunLoopRun
0x1be55afb4 CoreFoundation!CFRunLoopRunSpecific
0x1c075d79c GraphicsServices!GSEventRunModal
0x1eafa7c38 UIKitCore!UIApplicationMain
0x1d4219a70 FrontBoard!FBSystemAppMain
0x10116db98 SpringBoard!0x1e9b98 (0x1001e9b98)
0x1be01e8e0 libdyld.dylib!start

最终,拿到要害函数-[BBObserver _queue_updateBulletin:withReply:], 咱们发现要害类 BBObserver 在 BulletinBoard 动静库里,依据iphonedevwiki(原文地址:https://iphonedevwiki.net/ind…),咱们持续应用命令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_release
0x1be00d7d4 libdispatch.dylib!_dispatch_client_callout
0x1bdfb6324 libdispatch.dylib!_dispatch_lane_serial_drain$VARIANT$mp
0x1bdfb6e74 libdispatch.dylib!_dispatch_lane_invoke$VARIANT$mp
0x1bdfbf4ac libdispatch.dylib!_dispatch_workloop_worker_thread
0x1be1ee114 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_invoke
0x1be00ca38 libdispatch.dylib!_dispatch_call_block_and_release
0x1be00d7d4 libdispatch.dylib!_dispatch_client_callout
0x1bdfb6324 libdispatch.dylib!_dispatch_lane_serial_drain$VARIANT$mp
0x1bdfb6e74 libdispatch.dylib!_dispatch_lane_invoke$VARIANT$mp
0x1bdfbf4ac libdispatch.dylib!_dispatch_workloop_worker_thread
0x1be1ee114 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:UNSNotificationRecordAddUpdate
k:_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`*】

正文完
 0