Hacking in MFMessageComposeViewController

I know that this is prohibited in real applications in the interests of user privacy and security. But for pure academic purpose, I'm trying to send a message without presenting the MessageComposer user interface.

MFMessageComposeViewController *picker = [[MFMessageComposeViewController alloc] init]; if([MFMessageComposeViewController canSendText]) { picker.recipients = [NSArray arrayWithObject:@"1234"]; picker.body = @"Hello"; [picker performSelector:@selector(smsComposeControllerSendStarted:) withObject:[UIButton buttonWithType:UIButtonTypeCustom]]; } 

As a result, nothing happens. Even the exception is a failure on the console. I also do not see the message in the SMS application. The person to whom I sent the message also did not receive it.

Here you can find a list of iVars and the MFMessageComposeViewController methods.

https://github.com/nst/iOS-Runtime-Headers/blob/master/Frameworks/MessageUI.framework/MFMessageComposeViewController.h

And I wrote a quick code to check if these are really the elements present in the MFMessageComposeViewController.

 uint varCount = 0; Class cls= [MFMessageComposeViewController class]; Ivar *vars = class_copyIvarList(cls, &varCount); for (uint i = 0; i < varCount; i++) { Ivar var = vars[i]; const char* name = ivar_getName(var); const char* typeEncoding = ivar_getTypeEncoding(var); printf("iVar%i------------> %s\n",i+1,name); } free(vars); Method *imps = class_copyMethodList(cls, &varCount); for (uint i = 0; i < varCount; i++) { SEL sel = method_getName(imps[i]); printf("Method%i------------> %s\n",i+1,[(NSStringFromSelector(sel)) UTF8String]); } 

He produces the following conclusion:

 iVar1------------> _messageComposeDelegate iVar2------------> _recipients iVar3------------> _body iVar4------------> _subject iVar5------------> _mutableAttachmentURLs iVar6------------> _currentAttachedVideoCount iVar7------------> _currentAttachedAudioCount iVar8------------> _currentAttachedImageCount iVar9------------> _temporaryAttachmentURLs iVar10------------> _attachments Method1------------> disableUserAttachments Method2------------> setCurrentAttachedVideoCount: Method3------------> setCurrentAttachedAudioCount: Method4------------> setCurrentAttachedImageCount: Method5------------> _MIMETypeForURL: Method6------------> _isVideoMIMEType: Method7------------> _isAudioMIMEType: Method8------------> _isImageMIMEType: Method9------------> mutableAttachmentURLs Method10------------> _contentTypeForMIMEType: Method11------------> _updateAttachmentCountForAttachmentURL: Method12------------> _buildAttachmentInfoForAttachmentURL:andAlternameFilename: Method13------------> temporaryAttachmentURLs Method14------------> canAddAttachmentURL: Method15------------> addAttachmentData:withAlternateFilename: Method16------------> _setCanEditRecipients: Method17------------> messageComposeDelegate Method18------------> setMutableAttachmentURLs: Method19------------> currentAttachedVideoCount Method20------------> currentAttachedAudioCount Method21------------> currentAttachedImageCount Method22------------> setTemporaryAttachmentURLs: Method23------------> dealloc Method24------------> viewWillAppear: Method25------------> initWithNibName:bundle: Method26------------> automaticallyForwardAppearanceAndRotationMethodsToChildViewControllers Method27------------> setModalPresentationStyle: Method28------------> body Method29------------> setSubject: Method30------------> subject Method31------------> setMessageComposeDelegate: Method32------------> setBody: Method33------------> addAttachmentURL:withAlternateFilename: Method34------------> addAttachmentData:typeIdentifier:filename: Method35------------> attachmentURLs Method36------------> attachments Method37------------> recipients Method38------------> smsComposeControllerCancelled: Method39------------> smsComposeControllerSendStarted: Method40------------> setRecipients: 

It seems to me that the smsComposeControllerSendStarted: method can be more a delegate than an actual function that starts sending messages. In the above list of methods, none of the method signatures comes close to sendMessage: or something similar to a function that actually sends a message.

My questions:

1) This is all really MFMessageComposeViewController located under the hood. Or does it have clusters of classes that are not available through runtime functions?

2) How to find out the actual messageSend method and its implementation class?

We will be very grateful for any ideas.

Thanks.

+6
source share
1 answer

Inside MFMessageComposeViewController , MFMessageComposeViewController used as the actual user interface from the private ChatKit.framework , which uses a whole group of other classes ( CKSMSComposeQueuingRemoteViewControllerProxy , CKSMSComposeRemoteViewController , CKSMSComposeViewServiceController ), including the XPCProxy<CKSMSCompose> interface.

UPDATE 1

After reading the quellish comment, I found this http://oleb.net/blog/2012/10/remote-view-controllers-in-ios-6/ It looks like MFMessageComposeViewController and similar classes start another process for their own purposes. These processes are XPC services that implement certain protocols through which your application communicates with them. These processes are signed with all necessary rights. Probably /Applications/MessagesViewService.app/MessagesViewService is what actually sends SMS messages. This binary is signed with com.apple.messages.composeclient , which is required to send messages with this code, which I found in ChatKit.framework. I think there is a way to contact this XPC service manually to send SMS, but it will be difficult. Not something you could do by cheating with a dump class and similar simple tools that don't really give you much information.

UPDATE 2

I managed to figure it out. I selected all helper classes, all interface elements that do not actually interact with the XPC service. What is left is enough to display the SMS view controller and send some methods to the XPC service without any action.

When we show the composition of SMS, the iOS user interface really starts the process /Applications/MessagesViewService.app/MessagesViewService . This is an XPC service. You can try to kill it while your application displays it - you will get a black screen, which means that it is correct.

CKSMSComposeRemoteViewController is a view controller that displays the SMS user interface. This is a subclass of the _UIRemoteViewController class. Basically, it manages the connection between our application and the actual user interface that runs inside the XPC service in another process. This is how I get an instance inside my method -(void)viewDidLoad

 _UIAsyncInvocation* cancelationInvocation = [CKSMSComposeRemoveViewController requestViewController:@"CKSMSComposeViewServiceController" fromServiceWithBundleIdentifier:@"com.apple.mobilesms.compose" connectionHandler: ^(CKSMSComposeRemoteViewController* obj, NSError* error){ smsViewController = obj; [smsViewController setDelegate:self]; smsViewControllerProxy = [smsViewController serviceViewControllerProxy]; }]; 

smsViewController is an instance of a remote view controller. smsViewControllerProxy is an XPCProxy<CKSMSCompose> instance that implements a call to the CKSMSComposeViewServiceProtocol protocol - the method will be redirected to the XPC service. XPCProxy does not implement these methods. It implements the forwardInvocation: method to forward calls to the XPC connection.

_UIAsyncInvocation , looking at the name ivar cancelationInvocation , is used to cancel XPC messages. It is called only in the CKSMSComposeController viewServiceDidTerminateWithError: method.

This is how I show the controller:

 [self presentViewController:smsViewController animated:YES completion:NULL]; 

You probably noticed [smsViewController setDelegate:self] . The delegate must implement the CKSMSComposeRemoteViewControllerDelegate protocol or application crashes with an exception (unrecognized selector). Here is what I implemented:

 -(void)smsComposeControllerAppeared { } -(void)smsComposeControllerCancelled { } -(void)smsComposeControllerDataInserted { } 

This is enough to go.

And here is how we can send a message to the remote view controller:

 [smsViewControllerProxy insertTextPart:@"Some text"]; 

Paste the text into the SMS text box and call the smsComposeControllerDataInserted delegate method.

Given all this, I no longer think that we can send SMS messages without an interface. The actual user interface works in a different process, we do not control it. We can set some fields, but it is. I was hoping there was a way, but it’s true, not surprisingly, that we cannot. Remote views were introduced in iOS 6 to solve this security problem - on iOS 5 there was a way to send SMS without user permission, and some AppStore applications did this. So Apple came in handy.

UPDATE 3

I was able to send XPC messages sent while interacting with the SMS user interface. A few words about the format of magazines. The first line - the message was intercepted. This is either the name of the function or the Incoming event , which means its incoming message from the service. Connection name is just the name of the XPC connection. Message - the contents of the XPC message dictionary. Message data - some XPC messages contain binary data with the keys "d" β†’ "r". This is a serialized list of binary properties that cannot be deserialized using NSPropertyListSerialization - in some new format. Instead, you need to use NSXPCDecoder -(id)_initWithRootXPCObject:(xpc_object_t) from Foundation.framework . And now the dumps:

Presented SMS user interface http://pastebin.com/NVEpujSh

SMS user interface after clicking the "Send" button http://pastebin.com/BYXd2djF

There are messages sent and received during editing SMS fields, but they correspond only to user interface events. For example, who will be the first responder that actually does not say anything about what is happening in the SMS user interface.

+4
source

All Articles