3

我正在为越狱设备构建,我想阻止传入的消息。我正在尝试挂钩 _ingestIncomingCTMessage,但它没有结果(它似乎不适用于 ios6)。我还能如何在 ios6 中阻止短信?

4

3 回答 3

9

Found much better and simpler way. Just as I thought com.apple.imagent daemon is very important and it's him who is handling kCTMessageReceivedNotification. This is why we get empty message object when handling kCTMessageReceivedNotification yourself - com.apple.imagent is removing it from CTMessageCenter.

We need to hook just two methods but finding and hooking them is quite tricky. Both methods are hooked in com.apple.imagent daemon.

First, SMSServiceSession -(void)_processReceivedMessage:(CTMessage*)msg. This is where incoming message is being initially processed, saved to the SMS database and passed to all other iOS components. Problem is there is no information about this API anywhere. com.apple.imagent appears to be not using it if you disassemble it. It's because it's being loaded manually at runtime.

When com.apple.imagent is started he's loading several plugins. The one that we need is located in /System/Library/Messages/PlugIns/SMS.imservice/ - this is where SMSServiceSession is implemented. You will not find binary in there because just like all the frameworks it's compiled into /System/Library/Caches/com.apple.dyld/dyld_shared_cache_armv7. IDA recognizes this file and let's you choose which binary inside of it you want to disassemble.

To delete incoming message and prevent any notifications about it you need to call [[CTMessageCenter sharedMessageCenter] acknowledgeIncomingMessageWithId:[msg messageId]] and return from _processReceivedMessage: without calling original implementation. Calling CTMessageCenter method is important because it queues incoming messages.

Now we need to find a way to know whenSMS.imservice plugin is being actually loaded. Initially imagent only creates NSBundle objects without loading any code. So you can't hook any methods because classes are not yet loaded from the plugins. To solve this we can hook IMDService -(void)loadServiceBundle method from private IMDaemonCore.framework. Call original implementation and you can hook methods inside the plugin. To determine which plugin is being loaded you can check bundle identifier in IMDService -(NSBundle*)bundle.

This method works only with SMS and MMS messages. iMessages are processed in similar way but with different plugin - /System/Library/Messages/PlugIns/iMessage.imservice. Hooking MessageServiceSession -(void)_handler:(id) incomingMessage:(id) encryptionType:(id) messageID:(id) fromIdentifier:(id) fromToken:(id) timeStamp:(id) storageContext:(id) allowRetry:(char) completionBlock:(id) should do the trick.

UPDATE

Works on iOS 7

UPDATE 2

On iOS 8 everything works the same way except you need to hook different SMSServiceSession method - -(void)_processReceivedDictionary:(NSDictionary*)msg. Dictionary will contain all SMS message contents.

If you don't want to rewrite everything for iOS 8 you can reuse your old code. Incoming SMS notification is handled by hidden non-exported C callback function - you can't hook it. First, it calls SMSServiceSession -(id)_convertCTMessageToDictionary:(CTMessage*)msg requiresUpload:(BOOL*)upload to convert SMS message object to dictionary. Then it calls SMSServiceSession -(void)_processReceivedDictionary:(NSDictionary*)msg to process message. Finally, it calls SMSServiceSession -(BOOL)relayDictionaryToPeers:(NSDictionary*)msg requiresUpload:(BOOL)upload to notify all other iOS components about incoming message.

To block SMS you need to hook _convertCTMessageToDictionary where you can use the same code you used on previous iOS versions. You also need to hook both _processReceivedDictionary and relayDictionaryToPeers to actually block incoming message. Just return from them without calling original implementation. You can set some global variable in _convertCTMessageToDictionary and check and reset it in other methods. It's perfectly safe to do it that way - these methods are called one after another synchronously. That C callback function is the only places where these methods are called.

于 2013-09-20T11:21:32.537 回答
5

这是相当棘手的。苹果在这方面做出了重大改变。在 iOS 5 上这很容易,但在 iOS 6 上我还没有找到简单的方法来做到这一点。首先,您需要使用 CTTelephonyCenter 观察 __kIMChatItemsDidChangeNotification 通知。我是在 SpringBoard 中注入的 dylib 中进行的。不确定,但这可能很重要。

CTTelephonyCenterAddObserver(CTTelephonyCenterGetDefault(), NULL, Callback, NULL, NULL, CFNotificationSuspensionBehaviourHold);

void Callback(CFNotificationCenterRef, void*, NSString* notification, const void*, NSDictionary* userInfo)
{
    if (![notification isEqualToString:@"__kIMChatItemsDidChangeNotification"])
    {
        return;
    }

    for (IMChatItem* chatItem in userInfo[@"__kIMChatItemsKey"])
    {
        IMMessage* msg = [chatItem message];//Incoming message object
        NSString* text = [[msg text] string];//message text
        NSString* sender = [[msg sender] ID];//message sender

        [[IMDMessageStore sharedInstance] performBlock:^{
            IMDChatRecordDeleteChatForGUID([NSString stringWithFormat:@"SMS;-;%@", sender]);
        }];
    }
}

最后一点非常重要。您不能只删除消息。您需要在特定的内部线程上执行此操作,否则会出现错误。这就是我使用IMDMessageStore. 它的performBlock:方法在这个特殊线程上执行块。 IMDChatRecordDeleteChatForGUID函数可以在 IMDPersistence.framework 中找到。它会删除具有特定 GUID 的整个消息树(聊天/对话)。我找不到检索此 GUID 的方法,因此我使用 SMS sqlite 数据库中的 GUID 作为示例手动构建它。

要仅删除一条消息,您可以使用IMDMessageRecordDeleteMessagesForGUIDs([NSArray arrayWithObject:[msg guid]]);

IMChatItem并且IMMessage可以在IMCore.framework. IMDMessageStoreIMDaemonCore.framework.

这是容易的部分。现在,当您收到消息并以这种方式阻止它时,您会看到它仍然显示在 MobileSMS 应用程序中,您仍然可能会收到公告通知,您仍然会收到徽章告诉您有未读消息。但是如果您打开 SMS sqlite 数据库,您会看到该消息确实已被删除。阻止这些并不是那么容易。

  1. 公告。在 SpringBoard 中,您需要挂钩BBServer方法publishBulletin:destinations:alwaysOnLockScreen:。第一个参数是 BBBulletin 对象。如果它是传入的消息公告,它的section属性等于com.apple.MobileSMS。要阻止公告,只需从此方法返回,不要调用原始实现。
  2. MobileSMS 应用程序徽章。当有传入的 SMS 时,SpringBoard 中会加载 ChatKit.serviceBundle。您需要在MessagesBadgeController-_madridChatRegistered:_madridUnreadCountChanged:. 他们的第一个参数是NSNotification具有包含对象的object属性的IMChat对象。同样,只需从这些方法返回以防止徽章更改。
  3. 手机短信应用。为了阻止它显示已删除的消息,我使用了很多方法。我只会给你一个清单: SMSApplication _receivedMessage:, CKTranscriptController _messageReceived:, CKConversationList _handleRegistryDidRegisterChatNotification:, _handleRegistryDidLoadChatNotification:, hasActiveConversations, unreadCount. CKConversationController _chatParticipantsChangedNotification:, updateConversationList,CKMessagesController showConversation:animate:forceToTranscript:

关于 ChatKit.serviceBundle。要挂钩它的类,您需要等待 SpringBoard 实际加载它。这是在SBPluginManager loadPluginBundle:. 捆绑标识符应等于com.apple.SMSPlugin. 只有这样你才能挂钩方法。

而已。相当多的工作,但它工作完美 - 没有收到消息的迹象,即使消息到达时您在 MobileSMS 应用程序中也是如此。

我确信有更简单的方法可以做到这一点。有 com.apple.imagent 守护进程向各种 iOS 组件发送通知。它在 iOS 6 消息系统中非常重要。开始的好地方。

于 2013-05-08T21:59:19.843 回答
1

我有更好的解决方案来阻止所有 SMS 消息

%hook CKConversationListController

- (void)viewDidLoad
{
    %orig;

    CKConversationList *list = MSHookIvar<CKConversationList *>(self, "_conversationList");

    if ([list count]) {
        [deleteAll release];
    }
}

%new
- (void)deleteAll:(id)sender {

    CKConversationList *list = MSHookIvar<CKConversationList *>(self, "_conversationList");
    UITableView *messages = MSHookIvar<UITableView *>(self, "_table");

    for (unsigned int i = 0; i < [[list conversations] count]; i++) {
        [list deleteConversationAtIndex:i];
    }

    [messages reloadData];
}
%end
于 2013-07-04T10:47:59.097 回答