经过之前的分享,相信大家已经掌握了用户级的插件开发。勤奋好学的你是否对系统级的插件也有着浓厚的性趣,本篇文章将和大家一起学习如何分析并编写一款系统级的插件。
一、目标一步步分析并编写一个短信自动转发的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提供的守护进程,常见的进程配置文件有:
名称 描述更多服务请参考https://www.theiphonewiki.com/wiki/Services
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="+861812186xxxx", userDataPreferred=1, userDefaultVoice=1> msgID:0x80000010]根据日志信息可看出,该方法里除了msgID,并没有包含我们需要的短信及发件人相关信息。那我们继续按日志的顺序往下看,-[SMSServiceSession _convertCTMessageToDictionary:requiresUpload:] 这函数看着比较亲切。trace该函数得到日志如下:
-[SMSServiceSession _convertCTMessageToDictionary:<[CTMessageAddress: 189xxxxxx/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 = "+86181xxxxxx"; g = "00ECAC3B-0790-8674-CAD5-58DD07F4DEBA"; h = 189xxxxxx; 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 总结本篇文章主要对短信转发器的核心方法进行了分析及试验,拿到短信内容后,具体的转发逻辑请自行实现。