前语

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


一、目标

一步步剖析并编写一个短信自动转发的deb插件

二、东西

  • mac体系
  • 已越狱iOS设备:脱壳及frida调试
  • IDA Pro:静态剖析
  • 测试设备:iphone6-ios12.5.5

三、过程

1、看护进程

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

相应的配置目录:

  • /Library/LaunchAgents:管理员操控特定用户的署理
  • /Library/LaunchDaemons:管理员供给的体系级看护进程(cydia、filza、frida等就在这)
  • /System/Library/LaunchDaemons:iOS供给的默许看护进程

本文的目的首要短信,所以关注的重点在iOS供给的看护进程,常见的进程配置文件有:

名称 描绘
com.apple.apsd 推送服务
com.apple.biometrickitd.pearl 人脸解锁
com.apple.cloudd iCloud
com.apple.icloud.findmydeviced 查找我的iPhone
com.apple.imagent 即时消息署理 (iMessage)

更多服务请参阅www.theiphonewiki.com/wiki/Servic…

2、定位要害函数

在iPhone中运用文件管理东西检查/System/Library/LaunchDaemons/com.apple.imagent文件要害信息如下:

<?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>EnvironmentVariables</key>
  <dict>
    <key>NSRunningFromLaunchd</key>
    <string>1</string>
  </dict>
  <key>ProgramArguments</key>
  <array>
    <string>/System/Library/PrivateFrameworks/IMCore.framework/imagent.app/imagent</string>
  </array>
  <key>RunAtLoad</key>
  <true/>
</dict>
</plist>

ProgramArguments所对应的途径,便是该进程履行的二进制文件。履行frida-trace -U -m "*[IM* *]" imagent -o a.log后,当手机收到短信后的日志如下:

-[SMSServiceSession smsMessageReceived:0x10524abc0 msgID:0x80000006]
-[SMSServiceSession _processSMSorMMSMessageReceivedWithContext:0x10524abc0 messageID:0x80000006]
+[IMMetricsCollector sharedInstance]
-[IMMetricsCollector trackEvent:0x1d02ab1e8]
-[SMSServiceSession _convertCTMessageToDictionary:0x109a0e510 requiresUpload:0x16f832c2f]
-[IMMetricsCollector _trackEvent:0x1d02ab1e8]
-[SMSServiceSession _fixIncomingDate:0xd13d420d70d597e6]
-[SMSServiceSession shouldFixIncomingDate]
-[SMSServiceSession _myCTPhoneNumber]
+[IMCTSubscriptionUtilities sharedInstance]
-[IMCTSubscriptionUtilities deviceSupportsMultipleSubscriptions]
+[IMCTSubscriptionUtilities sharedInstance]
-[IMCTSubscriptionUtilities deviceSupportsMultipleSubscriptions]
+[IMCTSMSUtilities IMMMSEmailAddressToMatchForPhoneNumber:0x100830240 simID:0x0]
+[IMCTSubscriptionUtilities sharedInstance]
-[IMCTSubscriptionUtilities deviceSupportsMultipleSubscriptions]
-[SMSServiceSession _convertCTMessagePartToDictionary:0x109a28610]
-[SMSServiceSession _shouldUploadToMMCS:0x10524aca0]
-[SMSServiceSession _receivedSMSDictionary:0x10524aca0 requiresUpload:0x0 isBeingReplayed:0x0]
-[SMSServiceSession _processReceivedDictionary:0x10524aca0 storageContext:0x0]
+[IMMessageNotificationTimeManager sharedInstance]
-[IMMessageNotificationTimeManager acquireAssertionToUnsuspendProcess]
+[IMLockdownManager sharedInstance]
-[IMLockdownManager isInternalInstall]
-[IMLockdownManager _calculateInstallType]
-[IMMessageItem initWithSender:0x100890210 time:0x1008831d0 body:0x10083ba80 attributes:0x0 fileTransferGUIDs:0x1007081d0 flags:0x1 error:0x0 guid:0x10524acc0]
-[IMMessageItem initWithSender:0x100890210 time:0x1008831d0 body:0x10083ba80 attributes:0x0 fileTransferGUIDs:0x1007081d0 flags:0x1 error:0x0 guid:0x10524acc0 type:0x0]
-[IMMessageItem initWithSenderInfo:0x10085c330 time:0x1008831d0 timeRead:0x0 timeDelivered:0x0 timePlayed:0x0 subject:0x0 body:0x10083ba80 bodyData:0x0 attributes:0x0 fileTransferGUIDs:0x1007081d0 flags:0x1 guid:0x10524acc0 messageID:0x0 account:0x0 accountID:0x0 service:0x0 handle:0x0 roomName:0x0 unformattedID:0x0 countryCode:0x0 expireState:0x0 balloonBundleID:0x0 payloadData:0x0 expressiveSendStyleID:0x0 timeExpressiveSendPlayed:0x0 bizIntent:0x0 locale:0x0 errorType:0x0 type:0x0]
-[IMItem initWithSenderInfo:0x10085c330 time:0x1008831d0 guid:0x10524acc0 messageID:0x0 account:0x0 accountID:0x0 service:0x0 handle:0x0 roomName:0x0 unformattedID:0x0 countryCode:0x0 type:0x0]
-[IMItem setSenderInfo:0x10085c330]

根据日志可看出要害函数-[SMSServiceSession smsMessageReceived:0x10524abc0 msgID:0x80000006], 运用命令frida-trace -U -m "-[SMSServiceSession smsMessageReceived:msgID:]" imagent盯梢该函数,js代码如下:

{
 onEnter(log, args, state) {
  log(`-[SMSServiceSession smsMessageReceived:${ObjC.Object(args[2])} msgID:${args[3]}]`);
  },
 onLeave(log, retval, state) {
  }
}

当手机收到短信时,对应日志输出如下:

-[SMSServiceSession smsMessageReceived:<CTXPCServiceSubscriptionContext 0x10bfd1240 slotID=CTSubscriptionSlotOne, uuid=00000000-0000-0000-0000-000000000001, labelID="90D990CE-3484-4310-9F39-49A66EB80541", label="USER_LABEL_PRIMARY", phoneNumber="+8618121861895", userDataPreferred=1, userDefaultVoice=1> msgID:0x80000010]

根据日志信息可看出,该办法里除了msgID,并没有包含咱们需要的短信及发件人相关信息。那咱们继续按日志的顺序往下看,-[SMSServiceSession _convertCTMessageToDictionary:requiresUpload:] 这函数看着比较亲热。trace该函数得到日志如下:

-[SMSServiceSession _convertCTMessageToDictionary:<[CTMessageAddress: 18980003726/TYPE=PLMN]
  [Recipients: (
)]
  [Items: (
   "<CTMessagePart: 0x10be7f340>"
)]
  [Raw Headers: (null)]
  [Date: 2023-07-30 14:43:23 +0000]
  [message ID: -2147483630]
  [message Type: 1]
  [service center: (null)]
  [Content-type: (null)]
  [Content-type params: {
}]
  [replace message: 0]
 requiresUpload:0x16edaec2f]
-[SMSServiceSession _convertCTMessageToDictionary:requiresUpload:]={
   co = "+8618121861895";
   g = "00ECAC3B-0790-8674-CAD5-58DD07F4DEBA";
   h = 18980003726;
   k =   (
         {
       data = <e58fa6>;
       type = "text/plain";
     }
   );
   l = 0;
   m = sms;
   n = 460;
   re =   (
   );
   sV = 1;
   w = "2023-07-30 14:43:25 +0000";
}}=

从日志可以看出。该办法便是咱们要hook办法,收件人:co,发件人:h,短信内容:k

3、编写deb插件

具体的创立流程请参阅之前的文章,源码如下:

#import <Foundation/Foundation.h>
#import "CaptainHook/CaptainHook.h"
​
@interface SMSServiceSession
​
@end@interface IMDService
​
-(void)loadServiceBundle;
@property (nonatomic,retain,readonly) NSBundle * bundle;
​
@end
​
CHDeclareClass(SMSServiceSession); // declare class
CHOptimizedMethod2(self, id, SMSServiceSession, _convertCTMessageToDictionary, NSDictionary *, arg1, requiresUpload, BOOL*, arg2) {
  id result = CHSuper2(SMSServiceSession, _convertCTMessageToDictionary, arg1, requiresUpload, arg2);
  
  @try {
    NSString *from = result[@"h"];
    NSString *to = result[@"co"];
    NSArray *msgList = result[@"k"];
    if (msgList.count > 0) {
      NSData *data = msgList[0][@"data"];
      NSString *content = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
      NSLog(@"witwit =from %@=to %@=content %@=",from, to, content);
     } else {
      NSLog(@"witwit =sms为空=");
     }
   } @catch (NSException *exception) {
    NSLog(@"witwit =SMSServiceSession _convertCTMessageToDictionary=err=%@=", exception);
​
   } @finally {
    
   }
  
  return result;
}
​
CHDeclareClass(IMDService)
CHOptimizedMethod0(self, void, IMDService, loadServiceBundle) {
​
  CHSuper0(IMDService, loadServiceBundle);
  NSString *bundleId = [[self bundle] bundleIdentifier];
  NSLog(@"witwit =IMDService loadServiceBundle=%@=", bundleId);
  
  if ([bundleId isEqualToString:@"com.apple.imservice.sms"]) {
    CHLoadLateClass(SMSServiceSession);
    CHHook2(SMSServiceSession, _convertCTMessageToDictionary, requiresUpload);
   }
}
​
​
CHConstructor // code block that runs immediately upon load
{
  @autoreleasepool
  {
    NSLog(@"witwit SMSForward load success");
​
    CHLoadLateClass(IMDService);
    CHHook0(IMDService, loadServiceBundle);
   }
}

info.plist文件配置如下:

<?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>Filter</key>
  <dict>
    <key>Bundles</key>
    <array>
      <string>com.apple.imagent</string>
    </array>
  </dict>
</dict>
</plist>

注:插件装置完成后。请重启imagent:

launchctl unload /System/Library/LaunchDaemons/com.apple.imagent.plist
launchctl load /System/Library/LaunchDaemons/com.apple.imagent.plist

总结

本篇文章首要对短信转发器的核心办法进行了剖析及试验,拿到短信内容后,具体的转发逻辑请自行实现。

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

【iOS逆向与安全】sms短信转发插件开发

【iOS逆向与安全】sms短信转发插件开发