iOS多点连接的使用、协议逆向、安全性
参考资源
-
WWDC-2013-Session-708
-
BlackHat-US-2014-“It Just (Net)works”
-
Understanding Multipeer Connectivity Framework in iOS 7 - Part 1 & 2
-
MCDemo.zip: https://dl.dropboxusercontent.com/u/2857188/MCDemo.zip
什么是多点连接?
- 传文件
- 聊天室
- 一台设备作为数据采集外设(比如:摄像头),将实时数据导到另一台设备上
- 网络数据转发
- ...
多点连接 API 的使用
SDK及版本信息
- MultipeerConnectivity.framework
- iOS 7.0
- OS X 10.10
-(void)setupPeerAndSessionWithDisplayName:(NSString *)displayName{ _peerID = [[MCPeerID alloc] initWithDisplayName:displayName]; _session = [[MCSession alloc] initWithPeer:_peerID]; _session.delegate = self; }
2、广播设备,使设备可以被发现:
-(void)advertiseSelf:(BOOL)shouldAdvertise{ if (shouldAdvertise) { _advertiser = [[MCAdvertiserAssistant alloc] initWithServiceType:@"chat-files" discoveryInfo:nil session:_session]; [_advertiser start]; } else{ [_advertiser stop]; _advertiser = nil; } }
3、浏览“局域网”中的设备,并建立连接:
-(void)setupMCBrowser{ _browser = [[MCBrowserViewController alloc] initWithServiceType:@"chat-files" session:_session]; }
-(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:\n%@\n\n", _txtMessage.text]]]; [_txtMessage setText:@""]; [_txtMessage resignFirstResponder]; }
发送消息时有个选项:MCSessionSendDataReliable,MCSessionSendDataUnreliable
-(void)session:(MCSession *)session didReceiveData:(NSData *)data fromPeer:(MCPeerID *)peerID{ NSDictionary *dict = @{@"data": data, @"peerID": peerID }; [[NSNotificationCenter defaultCenter] postNotificationName:@"MCDidReceiveDataNotification" object:nil userInfo:dict]; }
消息的接收是通过 MCSession 的回调方法进行的。
6、发送资源,资源可以是本地的URL,也可以是 Http 链接:
-(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]; }); } }
可以通过 NSProgress查询相关状态。
-(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]; }); }
协议逆向
MCNearbyServiceMessageIDKey:序号
MCNearbyServiceRecipientPeerIDKey:接收者的PeerID
MCNearbyServiceSenderPeerIDKey:发送者的PeerID
MCNearbyServiceConnectionDataKey
- IDString: 随机,base36
- pid64:随机
- displayName:外部传入,如:”Proteas-iPhone5s”
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]
- MCEncryptionOptional = 0
- MCEncryptionRequired = 1
- MCEncryptionNone = 2
-- Apple Mutipeer Connectivity Custom DTLS Protocl -- cache globals to local for speed. local format = string.format local tostring = tostring local tonumber = tonumber local sqrt = math.sqrt local pairs = pairs -- wireshark API globals local Pref = Pref local Proto = Proto local ProtoField = ProtoField local DissectorTable = DissectorTable local Dissector = Dissector local ByteArray = ByteArray local PI_MALFORMED = PI_MALFORMED local PI_ERROR = PI_ERROR -- dissectors local 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) end end local 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 then return end udp_port_table = DissectorTable.get("udp.port") for port = start_port,end_port do udp_port_table:remove(port, apple_mcdtls_proto) end end 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 then return end udp_port_table = DissectorTable.get("udp.port") for port = start_port,end_port do udp_port_table:add(port, apple_mcdtls_proto) end end register_udp_port_range(16400, 16499)
在 Wireshark 中使用自定义协议进行处理后:
安全性分析
其他
- 目前没有逆向出整个通信协议,但是如果想将一些外设模拟成 MC 设备,需要进一步逆向出整个协议。
- MultipeerConnectivity 链接了 IOKit,因此可能间接得暴露出 IOKit 的攻击面。
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。