【问题标题】:Block sms on ios6在 ios6 上阻止短信
【发布时间】:2013-04-19 15:29:43
【问题描述】:

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

【问题讨论】:

  • 一个天真的问题:为什么要阻止传入的短信?
  • @AlexWien 我想它可能对很多调整有用,因为它允许您根据发件人/内容有条件地阻止文本。您可以使文本触发 Activator 操作或查询设备以获取信息,而稍后该文本在线程中不可见。

标签: ios ios6 jailbreak


【解决方案1】:

找到了更好更简单的方法。正如我认为com.apple.imagent 守护进程非常重要,而处理kCTMessageReceivedNotification 的是他。这就是为什么我们在自己处理 kCTMessageReceivedNotification 时得到空消息对象的原因 - com.apple.imagent 正在从 CTMessageCenter 中删除它。

我们只需要挂钩两个方法,但是找到并挂钩它们是相当棘手的。这两种方法都被com.apple.imagent daemon 挂钩。

首先,SMSServiceSession -(void)_processReceivedMessage:(CTMessage*)msg。这是最初处理传入消息、保存到 SMS 数据库并传递给所有其他 iOS 组件的地方。问题是在任何地方都没有关于这个 API 的信息。 com.apple.imagent 如果你拆开它,它似乎没有使用它。这是因为它是在运行时手动加载的。

com.apple.imagent 启动时,他正在加载几个插件。我们需要的位于/System/Library/Messages/PlugIns/SMS.imservice/ - 这是实现SMSServiceSession 的地方。你不会在那里找到二进制文件,因为就像所有框架一样,它被编译成/System/Library/Caches/com.apple.dyld/dyld_shared_cache_armv7。 IDA 识别出这个文件,让我们选择要反汇编其中的哪个二进制文件。

要删除传入消息并阻止任何有关它的通知,您需要调用[[CTMessageCenter sharedMessageCenter] acknowledgeIncomingMessageWithId:[msg messageId]] 并从_processReceivedMessage: 返回而不调用原始实现。调用CTMessageCenter 方法很重要,因为它将传入消息排队。

现在我们需要找到一种方法来知道SMS.imservice 插件何时被实际加载。最初 imagent 只创建 NSBundle 对象而不加载任何代码。因此,您不能挂钩任何方法,因为尚未从插件加载类。为了解决这个问题,我们可以从私有IMDaemonCore.framework 中挂钩IMDService -(void)loadServiceBundle 方法。调用原始实现,您可以挂钩插件内部的方法。要确定正在加载哪个插件,您可以检查 IMDService -(NSBundle*)bundle 中的包标识符。

此方法仅适用于 SMS 和 MMS 消息。 iMessage 以类似的方式处理,但使用不同的插件 - /System/Library/Messages/PlugIns/iMessage.imservice。挂钩 MessageServiceSession -(void)_handler:(id) incomingMessage:(id) encryptionType:(id) messageID:(id) fromIdentifier:(id) fromToken:(id) timeStamp:(id) storageContext:(id) allowRetry:(char) completionBlock:(id) 应该可以解决问题。

更新

适用于 iOS 7

更新 2

在 iOS 8 上,除了你需要挂钩不同的 SMSServiceSession 方法 - -(void)_processReceivedDictionary:(NSDictionary*)msg 之外,一切都以相同的方式工作。字典将包含所有 SMS 消息内容。

如果您不想为 iOS 8 重写所有内容,您可以重用旧代码。传入的 SMS 通知由隐藏的非导出 C 回调函数处理 - 你不能挂钩它。首先,它调用SMSServiceSession -(id)_convertCTMessageToDictionary:(CTMessage*)msg requiresUpload:(BOOL*)upload 将SMS 消息对象转换为字典。然后它调用SMSServiceSession -(void)_processReceivedDictionary:(NSDictionary*)msg 来处理消息。最后,它调用SMSServiceSession -(BOOL)relayDictionaryToPeers:(NSDictionary*)msg requiresUpload:(BOOL)upload 通知所有其他iOS 组件收到的消息。

要阻止短信,您需要挂钩_convertCTMessageToDictionary,您可以在其中使用与之前 iOS 版本相同的代码。您还需要同时挂钩 _processReceivedDictionaryrelayDictionaryToPeers 以实际阻止传入消息。只需从他们那里返回而不调用原始实现。您可以在_convertCTMessageToDictionary 中设置一些全局变量,并在其他方法中检查和重置它。这样做是非常安全的——这些方法被一个接一个地同步调用。那个 C 回调函数是调用这些方法的唯一地方。

【讨论】:

  • 对不起,如果太天真,但%hook SMSServiceSession -(void)_processReceivedMessage:(id)msg{ %log; %orig; } 什么都不做。在我的.plist 文件中尝试了Bundles = ("com.apple.imagent",)Executables = ( "imagent" )。我应该试试别的吗?
  • SMS.imservice(SMSServiceSession 在其中)正在手动加载到 imagent 中,它在编译时没有链接,因此您不能随时挂钩方法。 Theos 在 dylib 构造函数中挂钩方法,但此时 SMS.imservice 未加载。这就是为什么我们需要loadServiceBundle - 这是插件实际加载到 imagent 的地方。只有这样你才能钩住_processReceivedMessage。在那之前它是不存在的。我认为您需要为此手动使用 MobileSubstrate API。
  • 我花了很长时间才理解 Logos 的调整!我想现在开始使用 MobileSubstrate API 会非常困难……!
  • 您是否也设法阻止传出消息?能够在 Messages.app 中不显示消息的情况下发送消息?
  • @AlexandreBlin,看看我的回答stackoverflow.com/questions/15872553/…
【解决方案2】:

这很棘手。苹果在这方面做出了重大改变。在 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]]);

IMChatItemIMMessage 可以在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. 手机短信应用。为了阻止它显示已删除的消息,我 hook了很多方法。我只给你一个清单: SMSApplication _receivedMessage:CKTranscriptController _messageReceived:CKConversationList _handleRegistryDidRegisterChatNotification:, _handleRegistryDidLoadChatNotification:, hasActiveConversations, unreadCountCKConversationController _chatParticipantsChangedNotification:, updateConversationList, CKMessagesController showConversation:animate:forceToTranscript:

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

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

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

【讨论】:

  • 我找不到函数:IMDPersistence.framework 中的 IMDChatRecordDeleteChatForGUID
  • @user1561904,它就在那里,试着调用它。请记住,C 函数以前导下划线导出。例如,在 IDA 中,您会看到 _IMDChatRecordDeleteChatForGUID 函数,而不是 IMDChatRecordDeleteChatForGUID。
  • 我的问题是消息仍然显示在收件箱中,但是当触摸阅读它时,它消失了
  • 我认为这是因为 com.apple.imagent 认为有消息并告诉该消息应用程序。但是,当您阅读消息并且消息应用程序尝试实际从数据库中读取它时,它已经消失了,因为这条消息已从 SMS.db 中删除正如我在您的问题中所说,尝试杀死 imagent。它将重新加载 SMS.db 内容,收件箱将为空。这个有效,我昨天试过了。就个人而言,我不喜欢杀死进程,所以我使用 MobileSMS 方法来阻止它显示已删除的消息。阅读我的答案,它都在那里并且经过多次测试。
  • "这是在'SBPluginManager loadPluginBundle:'中完成的。包标识符应该等于com.apple.SMSPlugin。只有这样你才能挂钩方法"
【解决方案3】:

我有一个更好的解决方案来阻止所有 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

【讨论】:

  • 这不会阻止任何东西。公告未被阻止。 MobileSMS 徽章未被阻止。此代码唯一的作用就是在您启动 MobileSMS 后删除所有内容。此外,如果您在收到短信后启动它,您仍然会看到这条短信。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-20
  • 2012-03-23
相关资源
最近更新 更多