在ios6上阻止短信

我正在build设一个监狱设备,我想阻止传入的消息。 我试图钩_ingestIncomingCTMessage,但它没有结果(它似乎不工作在iOS 6)。 我还可以阻止ios6中的短信?

这是相当棘手的。 苹果在这方面做了重大的改变。 在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:方法在这个特殊的线程上执行block。 IMDChatRecordDeleteChatForGUID函数可以在IMDPersistence.framework中find。 它用特定的GUID删除整个消息树(聊天/会话)。 我找不到一种方法来检索这个GUID,所以我使用SMS sqlite数据库中的GUID手动构build它作为示例。

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

IMChatItemIMMessage可以在IMCore.frameworkfind。 IMDMessageStoreIMDaemonCore.framework

这很容易。 现在,当你收到消息并以这种方式阻止时,你会看到它仍然显示在MobileSMS应用程序中,你仍然可能会得到bullein通知,你仍然可以获得标志,告诉你有未读消息。 但是,如果你打开SMS sqlite数据库,你会看到这个消息确实被删除。 阻止这些并不那么容易。

  1. Bullein。 在SpringBoard中,您需要挂接BBServer方法publishBulletin:destinations:alwaysOnLockScreen: 第一个参数是BBBulletin对象。 如果它是传入的消息公告,它的section属性等于com.apple.MobileSMS 。 要阻止公告只是从这个方法返回,不要调用原来的实现。
  2. MobileSMS应用徽章。 有传入短信的时候在SpringBoard中加载了ChatKit.serviceBundle。 您需要在_madridChatRegistered:挂钩两个方法 – _madridChatRegistered:_madridUnreadCountChanged: 他们的第一个参数是带有包含IMChat对象的object属性的IMChat对象。 再次,从这些方法返回以防止徽章更改。
  3. MobileSMS应用程序。 要阻止它显示已经删除的消息,我挂钩了很多方法。 我将给你的清单: SMSApplication _receivedMessage:CKTranscriptController _messageReceived:CKConversationList _handleRegistryDidRegisterChatNotification:, _handleRegistryDidLoadChatNotification:, hasActiveConversations, unreadCount CKTranscriptController _messageReceived:CKConversationList _handleRegistryDidRegisterChatNotification:, _handleRegistryDidLoadChatNotification:, hasActiveConversations, unreadCountCKConversationController _chatParticipantsChangedNotification:, updateConversationListCKMessagesController showConversation:animate:forceToTranscript:

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

而已。 相当多的工作,但它的工作完美 – 没有传入消息的迹象,即使你在消息到达时在MobileSMS应用程序。

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

find了更好更简单的方法。 就像我以为com.apple.imagent守护进程是非常重要的,他正在处理kCTMessageReceivedNotification 。 这就是为什么我们自己处理kCTMessageReceivedNotification时候会得到空的消息对象kCTMessageReceivedNotification是从CTMessageCenter删除它。

我们只需要钩住两个方法,但是find并钩住它们是相当棘手的。 这两个方法都挂在com.apple.imagent守护进程中。

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

com.apple.imagent启动时,他正在加载几个插件。 我们需要的是位于/System/Library/Messages/PlugIns/SMS.imservice/ – 这是SMSServiceSession实现的地方。 你不会在那里find二进制文件,因为就像所有的框架被编译到/System/Library/Caches/com.apple.dyld/dyld_shared_cache_armv7 。 IDA认识到这个文件,让我们select你想拆解哪个二进制文件。

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

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

此方法仅适用于SMS和MMS消息。 iMessages以类似的方式进行处理,但使用不同的插件 – /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)应该做的伎俩。

UPDATE

适用于iOS 7

更新2

在iOS 8上,除了你需要挂接不同的SMSServiceSession方法以外,一切都以同样的方式工作 – -(void)_processReceivedDictionary:(NSDictionary*)msg 。 词典将包含所有的短信内容。

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

要阻止SMS,您需要挂钩_convertCTMessageToDictionary ,您可以使用您在以前iOS版本中使用的相同代码。 您还需要挂钩_processReceivedDictionaryrelayDictionaryToPeers来实际阻止传入的消息。 只需从原来的实现中返回即可。 您可以在_convertCTMessageToDictionary设置一些全局variables,并在其他方法中检查并重置它。 这样做是完全安全的 – 这些方法是一个接一个地同步调用的。 Ccallback函数是这些方法被调用的唯一地方。

我有一个更好的解决scheme来阻止所有的短信

 %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