Use of iOS multi-point connection, reverse protocol, and security

Source: Internet
Author: User
Tags dtls

Use of iOS multi-point connection, reverse protocol, and security
What is multi-point connection?
A multi-point connection simply means connecting devices to form a network. For details, refer:


Multi-point connections can be established based on the following two channels:


That is, Bluetooth and WiFi, and "Bluetooth-only devices" can communicate with "WiF-only devices". This is transparent and developers do not need to worry about it at all:


I personally feel that it is still powerful. So powerful, what can it do? MC only provides a data channel. Its specific usage depends on the business and imagination. The following lists some common uses: a device in the file transfer chat room is used as a data collection peripheral (for example: camera) to forward real-time data to another device...
SDK and version information for using multi-point connection APIs

 

MultipeerConnectivity. frameworkiOS 7.0OS X 10.10

 

We can see that MC-based communication can be achieved between computers and mobile phones. After learning about its capabilities and SDK information, let's take a look at the workflow: make the device discoverable ---> browse the device, establish a connection ---> transmit data. For more information, see resource reference and MCDemo. Here is just a code guide.
1. initialize MCPeerID and MCSession. MCPeerID is used to uniquely identify the device. MCSession is the basis of communication:
-(void)setupPeerAndSessionWithDisplayName:(NSString *)displayName{    _peerID = [[MCPeerID alloc] initWithDisplayName:displayName];        _session = [[MCSession alloc] initWithPeer:_peerID];    _session.delegate = self;}

2. Broadcast devices so that devices can be discovered:
-(void)advertiseSelf:(BOOL)shouldAdvertise{    if (shouldAdvertise) {        _advertiser = [[MCAdvertiserAssistant alloc] initWithServiceType:@chat-files                                                           discoveryInfo:nil                                                                 session:_session];        [_advertiser start];    }    else{        [_advertiser stop];        _advertiser = nil;    }}

3. Browse the devices in the LAN and establish a connection:
-(void)setupMCBrowser{    _browser = [[MCBrowserViewController alloc] initWithServiceType:@chat-files session:_session];}

After the MCBrowserViewController is instantiated, it will pop up directly. This class is responsible for finding the device and establishing a connection. Similar functions can be implemented through related interfaces for interface customization requirements.
4. Send a message:
-(void)sendMyMessage{    NSData *dataToSend = [_txtMessage.text dataUsingEncoding:NSUTF8StringEncoding];    NSArray *allPeers = _appDelegate.mcManager.session.connectedPeers;    NSError *error;        [_appDelegate.mcManager.session sendData:dataToSend                                     toPeers:allPeers                                    withMode:MCSessionSendDataReliable                                       error:&error];        if (error) {        NSLog(@%@, [error localizedDescription]);    }        [_tvChat setText:[_tvChat.text stringByAppendingString:[NSString stringWithFormat:@I wrote:%@, _txtMessage.text]]];    [_txtMessage setText:@];    [_txtMessage resignFirstResponder];}

When sending a message, there is an option: MCSessionSendDataReliable and MCSessionSendDataUnreliable. However, whether reliable or unreliable, data is transmitted over UDP.
5. receive messages:
-(void)session:(MCSession *)session didReceiveData:(NSData *)data fromPeer:(MCPeerID *)peerID{    NSDictionary *dict = @{@data: data,                           @peerID: peerID                           };        [[NSNotificationCenter defaultCenter] postNotificationName:@MCDidReceiveDataNotification                                                        object:nil                                                      userInfo:dict];}

Messages are received through the callback method of MCSession. The callback method of MCSession is very important. device status changes, message receiving, resource receiving, and stream receiving are all notified through this callback.

6. Send a resource. The resource can be a local URL or an Http link:
-(void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex{    if (buttonIndex != [[_appDelegate.mcManager.session connectedPeers] count]) {        NSString *filePath = [_documentsDirectory stringByAppendingPathComponent:_selectedFile];        NSString *modifiedName = [NSString stringWithFormat:@%@_%@, _appDelegate.mcManager.peerID.displayName, _selectedFile];        NSURL *resourceURL = [NSURL fileURLWithPath:filePath];                dispatch_async(dispatch_get_main_queue(), ^{            NSProgress *progress = [_appDelegate.mcManager.session sendResourceAtURL:resourceURL                                                                            withName:modifiedName                                                                              toPeer:[[_appDelegate.mcManager.session connectedPeers] objectAtIndex:buttonIndex]                                                               withCompletionHandler:^(NSError *error) {                                                                   if (error) {                                                                       NSLog(@Error: %@, [error localizedDescription]);                                                                   }                                                                                                                                      else{                                                                       UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@MCDemo                                                                                                                       message:@File was successfully sent.                                                                                                                      delegate:self                                                                                                             cancelButtonTitle:nil                                                                                                             otherButtonTitles:@Great!, nil];                                                                                                                                              [alert performSelectorOnMainThread:@selector(show) withObject:nil waitUntilDone:NO];                                                                                                                                              [_arrFiles replaceObjectAtIndex:_selectedRow withObject:_selectedFile];                                                                       [_tblFiles performSelectorOnMainThread:@selector(reloadData)                                                                                                   withObject:nil                                                                                                waitUntilDone:NO];                                                                   }                                                               }];                        //NSLog(@*** %f, progress.fractionCompleted);                        [progress addObserver:self                       forKeyPath:@fractionCompleted                          options:NSKeyValueObservingOptionNew                          context:nil];        });    }}

You can use NSProgress to query the status.
7. Receiving resources:
-(void)session:(MCSession *)session didStartReceivingResourceWithName:(NSString *)resourceName fromPeer:(MCPeerID *)peerID withProgress:(NSProgress *)progress{        NSDictionary *dict = @{@resourceName  :   resourceName,                           @peerID        :   peerID,                           @progress      :   progress                           };        [[NSNotificationCenter defaultCenter] postNotificationName:@MCDidStartReceivingResourceNotification                                                        object:nil                                                      userInfo:dict];            dispatch_async(dispatch_get_main_queue(), ^{        [progress addObserver:self                   forKeyPath:@fractionCompleted                      options:NSKeyValueObservingOptionNew                      context:nil];    });}


Protocol Inversion
During protocol analysis, we analyze the Protocol Based on WiFi, because it is easy to capture packets. The captured data packets include:


We can see that it is mainly based on the following protocols:


Bonjour refers to Hello in French, which is mainly used for service discovery. STUN is mainly used for port ing to facilitate direct connection between two devices. The remaining two protocols are unknown: TCP-based and UDP-based. Based on TCP, let's look at TCP Stream:


Note:


This is a handshake mechanism. First, the device ID is exchanged, and then information is exchanged based on Binary Plist. First, extract plist. When extracting plist, You need to refer to the starting and ending bytes in tcp stream. After plist is proposed, three plist values are exchanged:
Plist-1:


MCNearbyServiceInviteIDKey: MCEncryptionOption-> 1, MCEncryptionNone-> 0;
MCNearbyServiceMessageIDKey: No.
MCNearbyServiceRecipientPeerIDKey: the receiver's PeerID
MCNearbyServiceSenderPeerIDKey: the sender's PeerID

Plist-2:



MCNearbyServiceAcceptInviteKey: whether to receive connections
MCNearbyServiceConnectionDataKey

Plist-3:


MCNearbyServiceConnectionDataKey

The above is just about plist content, but in tcp stream we also see the device ID, how is the device ID generated? The following figure shows that the device ID is implemented in-[MCPeerIDInternal initWithIDString: pid64: displayName:]. The basic strategy is: IDString: Random, base36pid64: Random displayName: external input, such as: "Proteas-iPhone5s" between devices to exchange IDs need to be serialized, serialization method:-[MCPeerID serializedRepresentation] To sum up is: peerID = generate the first 9 bytes + displayName with The Decompilation Result Based on pid64:
void * -[MCPeerID initWithDisplayName:](void * self, void * _cmd, void * arg2) {    STK33 = r5;    STK35 = r7;    sp = sp - 0x28;    r5 = arg2;    arg_20 = self;    arg_24 = *0x568f0;    r6 = [[&arg_20 super] init];    if (r6 != 0x0) {            if ((r5 == 0x0) || ([r5 length] == 0x0)) {                    r0 = [r6 class];                    r0 = NSStringFromClass(r0);                    var_0 = r0;                    [NSException raise:*_NSInvalidArgumentException format:@Invalid displayName passed to %@];            }            else {                    if ([r5 lengthOfBytesUsingEncoding:0x4] >= 0x40) {                            r0 = [r6 class];                            r0 = NSStringFromClass(r0);                            var_0 = r0;                            [NSException raise:*_NSInvalidArgumentException format:@Invalid displayName passed to %@];                    }            }            arg_8 = r6;            arg_C = r5;            r8 = CFUUIDCreate(*_kCFAllocatorDefault);            CFUUIDGetUUIDBytes(&arg_10);            r11 = (arg_1C ^ arg_14) << 0x18 | (arg_1C ^ arg_14) & 0xff00 | 0xff00 & (arg_1C ^ arg_14) | arg_1C ^ arg_14;            r10 = 0xff00 & (arg_10 ^ arg_18) | ((arg_10 ^ arg_18) & 0xff00) << 0x8 | arg_10 ^ arg_18 | arg_10 ^ arg_18;            r5 = _makebase36string(r11, r10);            if (*_gVRTraceErrorLogLevel < 0x6) {                    asm{ strd       r4, r5, [sp] };                    VRTracePrint_();            }            else {                    if (*(int8_t *)_gVRTraceModuleFilterEnabled != 0x0) {                            asm{ strd       r4, r5, [sp] };                            VRTracePrint_();                    }            }            r4 = [NSString stringWithUTF8String:r5];            free(r5);            CFRelease(r8);            r0 = [MCPeerIDInternal alloc];            var_0 = r10;            arg_4 = arg_C;            r0 = [r0 initWithIDString:r4 pid64:r11 displayName:STK-1];            r6 = arg_8;            r6->_internal = r0;    }    r0 = r6;    Pop();    Pop();    Pop();    return r0;}[[MCPeerIDInternal alloc] initWithIDString:_makebase36string(...) pid64:r11 displayName:STK-1]

The previous plist contains Data Key, which is not described too much. Next let's take a look at the generation of Data Key:


When initializing a multi-point connection Session, we can specify the encryption method, which is an enumeration type: MCEncryptionOptional = 0
MCEncryptionRequired = 1
MCEncryptionNone = 2
It can be seen that the encryption method affects the Data Key, but it is time-consuming to analyze the Data Key completely by capturing packets, and there may be omissions. Through code inversion, we find the class responsible for Data Key generation:


This can be used as the starting point for Data Key analysis. If you need it, you can perform in-depth analysis.
We are talking about the TCP-based unknown protocol above. Next we will look at the UDP-based unknown protocol. UDP data stream:


A specific UDP packet:


It can be seen that it is encapsulated on DTLS. We only need to discard 0xd0 to allow Wireshark to perform identification and analysis. Here I need to talk about the specific tools and methods not published at the BH-US Conference, my approach is to write a Custom Protocol Dissector:
-- Apple Mutipeer Connectivity Custom DTLS Protocl-- cache globals to local for speed.local format = string.formatlocal tostring = tostringlocal tonumber = tonumberlocal sqrt = math.sqrtlocal pairs = pairs-- wireshark API globalslocal Pref = Preflocal Proto = Protolocal ProtoField = ProtoFieldlocal DissectorTable = DissectorTablelocal Dissector = Dissectorlocal ByteArray = ByteArraylocal PI_MALFORMED = PI_MALFORMEDlocal PI_ERROR = PI_ERROR-- dissectorslocal dtls_dissector = Dissector.get(dtls)apple_mcdtls_proto = Proto(apple_mcDTLS, Apple Multipeer Connectivity DTLS, Apple Multipeer Connectivity DTLS Protocol)function apple_mcdtls_proto.dissector(buffer, pinfo, tree)    local mctype = buffer(0, 1):uint()    if mctype == 208 then        pinfo.cols.protocol = AppleMCDTLS         pinfo.cols.info = Apple MC DTLS Payload Data         local subtree = tree:add(apple_mcdtls_proto, buffer(), Apple MC DTLS Protocol)        subtree:add(buffer(0, 1),Type:  .. buffer(0, 1):uint())        local size = buffer:len()         subtree:add(buffer(1, size - 1), Data:  .. tostring(buffer))        dtls_dissector:call(buffer(1):tvb(), pinfo, tree)    endendlocal function unregister_udp_port_range(start_port, end_port)if not start_port or start_port <= 0 or not end_port or end_port <= 0 thenreturnend  udp_port_table = DissectorTable.get(udp.port)  for port = start_port,end_port do    udp_port_table:remove(port, apple_mcdtls_proto)  endend local function register_udp_port_range(start_port, end_port)if not start_port or start_port <= 0 or not end_port or end_port <= 0 thenreturnendudp_port_table = DissectorTable.get(udp.port)for port = start_port,end_port doudp_port_table:add(port, apple_mcdtls_proto)endendregister_udp_port_range(16400, 16499)

After the custom protocol is used in Wireshark for processing:


After the protocol is identified here, we will not continue the analysis, but when evaluating the security, for example, after you call ssl on your phone, you can see the plaintext data in the Payload of DTLS.
Security Analysis
As mentioned above, security control is implemented when MCSession is initialized. MCEncryptionOptional is used by default. However, when either of them is MCEncryptionNone, the communication is not encrypted.


However, when both parties are MCEncryptionOptional, communication is insecure and man-in-the-middle attacks may occur:


The man-in-the-middle attack must first identify some TCP-based data packets, such as the light-colored part. The data packets are characteristic and therefore can be identified. However, the reason why the man-in-the-middle attack is not demonstrated is that the data in the plist file seems to be correlated. Simply changing 0 to 1 does not change false to true, which causes plist to be invalid, therefore, the man-in-the-middle attack may need to be intercepted and modified before being sent.

Currently, the entire communication protocol is not reversed. However, if you want to simulate some peripherals as MC devices, you need to reverse the entire protocol. MultipeerConnectivity links IOKit, so it may indirectly expose the IOKit attack surface.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.