我正在构建一个破牢的设备,我想阻止传入的消息。 我正在尝试挂钩_ingestIncomingCTMessage,但它没有结果(它似乎不适用于ios6)。我怎样才能阻止ios6中的短信?
答案 0 :(得分:9)
找到更好,更简单的方法。正如我认为com.apple.imagent
守护进程非常重要,并且正在处理kCTMessageReceivedNotification
的是他。这就是我们自己处理kCTMessageReceivedNotification
时获取空消息对象的原因 - com.apple.imagent
将其从CTMessageCenter
中删除。
我们需要挂钩两个方法,但找到并挂钩它们非常棘手。这两种方法都挂在com.apple.imagent
守护进程中。
首先,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
个对象而不加载任何代码。因此,您无法挂钩任何方法,因为类尚未从插件加载。要解决此问题,我们可以将IMDService -(void)loadServiceBundle
方法与私有IMDaemonCore.framework
挂钩。调用原始实现,您可以在插件中挂钩方法。要确定加载哪个插件,您可以在IMDService -(NSBundle*)bundle
中检查包标识符。
此方法仅适用于短信和彩信。 iMessages以类似的方式处理,但使用不同的插件 - /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版本相同的代码。您还需要挂钩_processReceivedDictionary
和relayDictionaryToPeers
以实际阻止传入的消息。只需从它们返回而不调用原始实现。您可以在_convertCTMessageToDictionary
中设置一些全局变量,并在其他方法中检查并重置它。这样做是非常安全的 - 这些方法是一个接一个地同步调用的。那个C回调函数是调用这些方法的唯一地方。
答案 1 :(得分:5)
这非常棘手。 Apple在这方面做出了重大改变。这在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
。 IMDMessageStore
位于IMDaemonCore.framework
。
这很容易。现在,当您收到消息并以此方式阻止它时,您将看到它仍然显示在MobileSMS应用程序中,您仍然可能会收到bullein通知,您仍然会获得徽章,告诉您有未读消息。但是,如果您打开SMS sqlite数据库,您将看到该消息确实被删除。阻止这些并不容易。
BBServer
方法publishBulletin:destinations:alwaysOnLockScreen:
。第一个参数是BBBulletin对象。如果是传入消息公告,则section
属性等于com.apple.MobileSMS
。要阻止公告,只需从此方法返回,不要调用原始实现。 MessagesBadgeController
- _madridChatRegistered:
和_madridUnreadCountChanged:
中挂钩两个方法。他们的第一个参数是NSNotification
对象,其object
属性包含IMChat
个对象。再次,只需从这些方法返回以防止徽章更改。SMSApplication _receivedMessage:
,CKTranscriptController
_messageReceived:
,CKConversationList _handleRegistryDidRegisterChatNotification:, _handleRegistryDidLoadChatNotification:, hasActiveConversations, unreadCount
。 CKConversationController
_chatParticipantsChangedNotification:, updateConversationList
,CKMessagesController showConversation:animate:forceToTranscript:
关于ChatKit.serviceBundle。要挂钩它的类,你需要等待SpringBoard实际加载它。这是在SBPluginManager loadPluginBundle:
中完成的。 Bundle标识符应该等于com.apple.SMSPlugin
。只有这样你才能挂钩方法。
就是这样。相当多的工作,但它工作得很好 - 没有传入消息的迹象,即使你在消息到达时在MobileSMS应用程序中。
我确信有更简单的方法可以做到这一点。 com.apple.imagent守护程序向各种iOS组件发送通知。这在iOS 6消息传递系统中非常重要。开始的好地方。
答案 2 :(得分:1)
我有一个更好的解决方案来阻止所有短信
%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