def handle(self, data, addr): """ Handle incoming smartglass packets Args: data (bytes): Raw packet addr (str): IP address of sender Returns: None """ try: host, _ = addr if self.crypto: msg = packer.unpack(data, self.crypto) else: msg = packer.unpack(data) if msg.header.pkt_type == PacketType.DiscoveryResponse: log.debug("Received DiscoverResponse from %s", host, extra={'_msg': msg}) self._discovered[host] = msg self.on_discover(host, msg) elif msg.header.pkt_type == PacketType.ConnectResponse: log.debug("Received ConnectResponse from %s", host, extra={'_msg': msg}) if 'connect' in self._pending: self._set_result('connect', msg) elif msg.header.pkt_type == PacketType.Message: channel = self._chl_mgr.get_channel(msg.header.channel_id) log.debug("Received %s message on ServiceChannel %s from %s", msg.header.flags.msg_type.name, channel.name, host, extra={'_msg': msg}) seq_num = msg.header.sequence_number self._seq_mgr.add_received(seq_num) if msg.header.flags.need_ack: self.ack([msg.header.sequence_number], [], ServiceChannel.Core) self._on_message(msg, channel) self._seq_mgr.low_watermark = seq_num else: self._on_unk(msg) except Exception as e: log.exception("Exception in CoreProtocol datagram handler")
def parse(pcap_filepath, crypto): width = shutil.get_terminal_size().columns col_width = width // 2 - 3 wrapper = textwrap.TextWrapper(col_width, replace_whitespace=False) for packet, is_client, ts in packet_filter(pcap_filepath): try: msg = packer.unpack(packet, crypto) except Exception as e: print("Error: {}".format(e)) continue msg_type = msg.header.pkt_type type_str = msg_type.name if msg_type == PacketType.Message: type_str = msg.header.flags.msg_type.name direction = '>' if is_client else '<' print(' {} '.format(type_str).center(width, direction)) lines = str(msg).split('\n') for line in lines: line = wrapper.wrap(line) for i in line: if is_client: print('{0: <{1}}'.format(i, col_width), '│') else: print(' ' * col_width, '│', '{0}'.format(i, col_width))
def test_channel_manager(packets, crypto): from xbox.sg.enum import ServiceChannel from xbox.sg.packer import unpack start_channel_resp = unpack(packets['start_channel_response'], crypto) mgr = ChannelManager() request_id = 0 while request_id != start_channel_resp.protected_payload.channel_request_id: request_id = mgr.get_next_request_id(ServiceChannel.SystemInputTVRemote) service_channel = mgr.handle_channel_start_response(start_channel_resp) assert service_channel == ServiceChannel.SystemInputTVRemote # Deleting channel references mgr.reset() with pytest.raises(ChannelError): mgr.get_channel(123) with pytest.raises(ChannelError): mgr.get_channel_id(ServiceChannel.SystemInputTVRemote) with pytest.raises(ChannelError): mgr.handle_channel_start_response(start_channel_resp) assert mgr.get_channel(0) == ServiceChannel.Core assert mgr.get_channel(0x1000000000000000) == ServiceChannel.Ack assert mgr.get_channel_id(ServiceChannel.Core) == 0 assert mgr.get_channel_id(ServiceChannel.Ack) == 0x1000000000000000
def test_fragment_manager_fragment_messages(packets, crypto): from xbox.sg.packer import unpack fragments = [ unpack(packets['fragment_media_state_0'], crypto), unpack(packets['fragment_media_state_1'], crypto), unpack(packets['fragment_media_state_2'], crypto) ] mgr = FragmentManager() assert mgr.reassemble_message(fragments.pop()) is None assert mgr.reassemble_message(fragments.pop()) is None msg = mgr.reassemble_message(fragments.pop()) assert msg is not None assert msg.aum_id == 'Microsoft.BlurayPlayer_8wekyb3d8bbwe!Xbox.BlurayPlayer.Application' assert msg.max_seek == 50460000 assert len(msg.asset_id) == 2184
def packets(): secret = unhexlify( '82bba514e6d19521114940bd65121af234c53654a8e67add7710b3725db44f77' '30ed8e3da7015a09fe0f08e9bef3853c0506327eb77c9951769d923d863a2f5e') sg_crypto = Crypto.from_shared_secret(secret) # Who cares about RAM anyway? data = {} data_path = os.path.join(os.path.dirname(__file__), 'data', 'packets') for f in os.listdir(data_path): with open(os.path.join(data_path, f), 'rb') as fh: data[f] = packer.unpack(fh.read(), sg_crypto) return data
def parse(pcap_filepath, crypto): width = shutil.get_terminal_size().columns col_width = width // 2 - 3 wrapper = textwrap.TextWrapper(col_width, replace_whitespace=False) for packet, is_client, ts in packet_filter(pcap_filepath): try: msg = packer.unpack(packet, crypto) except Exception as e: print("Error: {}".format(e)) continue msg_type = msg.header.pkt_type type_str = msg_type.name if msg_type == PacketType.Message: type_str = msg.header.flags.msg_type.name if msg_type != PacketType.Message or msg.header.flags.msg_type != MessageType.AuxilaryStream: continue def un(d): return hexlify(d).decode('utf-8') if msg.protected_payload.connection_info_flag == 1: info = msg.protected_payload.connection_info print('Crypto Key: %s' % un(info.crypto_key)) print('Client IV: %s' % un(info.client_iv)) print('Server IV: %s' % un(info.server_iv)) print('Sign Hash: %s' % un(info.sign_hash)) direction = '>' if is_client else '<' print(' {} '.format(type_str).center(width, direction)) lines = str(msg).split('\n') for line in lines: line = wrapper.wrap(line) for i in line: if is_client: print('{0: <{1}}'.format(i, col_width), '│') else: print(' ' * col_width, '│', '{0}'.format(i, col_width))
def test_init_from_message(packets, crypto, uuid_dummy): msg = packer.unpack(packets['discovery_response'], crypto) c = console.Console.from_message('10.0.0.23', msg) assert c.address == '10.0.0.23' assert c.flags == enum.PrimaryDeviceFlag.AllowAuthenticatedUsers assert c.name == 'XboxOne' assert c.uuid == uuid_dummy assert c.liveid == 'FFFFFFFFFFF' assert c._public_key is not None assert c._crypto is not None assert c.device_status == enum.DeviceStatus.Available assert c.connection_state == enum.ConnectionState.Disconnected assert c.pairing_state == enum.PairedIdentityState.NotPaired assert c.paired is False assert c.available is True assert c.connected is False assert c.authenticated_users_allowed is True assert c.anonymous_connection_allowed is False assert c.console_users_allowed is False assert c.is_certificate_pending is False
def datagram_received(self, data: bytes, addr: str) -> None: """ Handle incoming smartglass packets Args: data: Raw packet addr: IP address of sender Returns: None """ try: host, _ = addr if self.crypto: msg = packer.unpack(data, self.crypto) else: msg = packer.unpack(data) if msg.header.pkt_type == PacketType.DiscoveryResponse: LOGGER.debug(f"Received DiscoverResponse from {host}", extra={'_msg': msg}) self._discovered[host] = msg self.on_discover(host, msg) elif msg.header.pkt_type == PacketType.ConnectResponse: LOGGER.debug(f"Received ConnectResponse from {host}", extra={'_msg': msg}) if 'connect' in self._pending: self._set_result('connect', msg) elif msg.header.pkt_type == PacketType.Message: channel = self._chl_mgr.get_channel(msg.header.channel_id) message_info = msg.header.flags.msg_type.name if msg.header.flags.is_fragment: message_info = 'MessageFragment ({0})'.format(message_info) LOGGER.debug( "Received %s message on ServiceChannel %s from %s", message_info, channel.name, host, extra={'_msg': msg}) seq_num = msg.header.sequence_number self._seq_mgr.add_received(seq_num) if msg.header.flags.need_ack: asyncio.create_task( self.ack([msg.header.sequence_number], [], ServiceChannel.Core)) self._seq_mgr.low_watermark = seq_num if msg.header.flags.is_fragment: sequence_begin = msg.protected_payload.sequence_begin sequence_end = msg.protected_payload.sequence_end fragment_payload = self._frg_mgr.reassemble_message(msg) if not fragment_payload: return msg(protected_payload=fragment_payload) LOGGER.debug("Assembled {0} (Seq {1}:{2})".format( message_info, sequence_begin, sequence_end), extra={'_msg': msg}) self._on_message(msg, channel) else: self._on_unk(msg) except Exception: LOGGER.exception("Exception in CoreProtocol datagram handler")
def _unpack(data, crypto): return packer.unpack(data, crypto)
def decrypted_packets(packets, crypto): return {k: packer.unpack(v, crypto) for k, v in packets.items()}