def parseSecondaryDrawingOrder(self, orderData): stream = BytesIO(orderData) controlFlags = Uint8.unpack(stream.read(1)) orderLength = Uint16LE.unpack(stream.read(2)) extraFlags = Uint16LE.unpack(stream.read(2)) orderType = Uint8.unpack(stream.read(1)) return SecondaryDrawingOrder(controlFlags, orderLength, extraFlags, orderType)
def parse(self, data: bytes) -> NegotiationRequestPDU: """ Parse a negotiation request. :param data: the request data. """ cookie = None if b"\r\n" in data: cookie = data[: data.index(b"\r\n")] data = data[data.index(b"\r\n") + 2 :] stream = BytesIO(data) if len(data) >= 8: type = Uint8.unpack(stream) requestFlags = Uint8.unpack(stream) requestLength = Uint16LE.unpack(stream) requestedProtocols = Uint32LE.unpack(stream) correlationFlags = None correlationID = None if requestFlags & NegotiationRequestFlags.CORRELATION_INFO_PRESENT != 0 and len(data) >= 36: type = Uint8.unpack(stream) correlationFlags = Uint8.unpack(stream) correlationLength = Uint16LE.unpack(stream) correlationID = stream.read(16) stream.read(16) return NegotiationRequestPDU(cookie, requestFlags, requestedProtocols, correlationFlags, correlationID) else: return NegotiationRequestPDU(cookie, None, None, None, None)
def parse(self, data: bytes) -> X224PDU: """ Read the byte stream and return a corresponding X224PDU """ length = Uint8.unpack(data[0]) header = Uint8.unpack(data[1]) >> 4 if header in list(X224PDUType): header = X224PDUType(header) if length < 2: raise ParsingError( "Invalid X224 length indicator: indicator = %d, expected at least 2 bytes" % length) if len(data) < length: raise ParsingError( "Invalid X224 length indicator: indicator = %d, length = %d" % (length, len(data))) if header not in self.parsers: raise UnknownPDUTypeError( "Trying to parse unknown X224 PDU type: %s" % (header if header in X224PDUType else hex(header)), header) return self.parsers[header](data, length)
def parseBitmapCapability(self, data: bytes) -> BitmapCapability: """ https://msdn.microsoft.com/en-us/library/cc240554.aspx :param data: Raw data starting after lengthCapability """ stream = BytesIO(data) preferredBitsPerPixel = Uint16LE.unpack(stream.read(2)) receive1bitPerPixel = Uint16LE.unpack(stream.read(2)) receive4bitPerPixel = Uint16LE.unpack(stream.read(2)) receive8bitPerPixel = Uint16LE.unpack(stream.read(2)) desktopWidth = Uint16LE.unpack(stream.read(2)) desktopHeight = Uint16LE.unpack(stream.read(2)) stream.read(2) # pad2octets desktopResizeFlag = Uint16LE.unpack(stream.read(2)) bitmapCompressionFlag = Uint16LE.unpack(stream.read(2)) highColorFlags = Uint8.unpack(stream.read(1)) drawingFlags = Uint8.unpack(stream.read(1)) multipleRectangleSupport = Uint16LE.unpack(stream.read(2)) # ignoring pad2octetsB capability = BitmapCapability(preferredBitsPerPixel, receive1bitPerPixel, receive4bitPerPixel, receive8bitPerPixel, desktopWidth, desktopHeight, desktopResizeFlag, bitmapCompressionFlag, highColorFlags, drawingFlags, multipleRectangleSupport) capability.rawData = data return capability
def parse(self, data: bytes) -> FastPathOutputEvent: stream = BytesIO(data) header = Uint8.unpack(stream) compressionFlags = None if self.isCompressed(header): compressionFlags = Uint8.unpack(stream) size = Uint16LE.unpack(stream) eventType = header & 0xf fragmentation = header & 0b00110000 != 0 if fragmentation: log.debug( "Fragmentation is present in output fastpath event packets." " Not parsing it and saving to FastPathOutputUpdateEvent.") return FastPathOutputEvent(header, compressionFlags, payload=stream.read(size)) if eventType == FastPathOutputType.FASTPATH_UPDATETYPE_BITMAP: return self.parseBitmapEventRaw(stream, header, compressionFlags, size) elif eventType == FastPathOutputType.FASTPATH_UPDATETYPE_ORDERS: return self.parseOrdersEvent(stream, header, compressionFlags, size) read = stream.read(size) return FastPathOutputEvent(header, compressionFlags, read)
def parse(self, data: bytes) -> FastPathOutputEvent: """ Parse TS_FP_UPDATE. https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpbcgr/a1c4caa8-00ed-45bb-a06e-5177473766d3 """ stream = BytesIO(data) header = Uint8.unpack(stream) # https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpbcgr/a1c4caa8-00ed-45bb-a06e-5177473766d3 updateCode = header & 0xf # fragmentation = (header & 0b00110000) >> 4 compressionFlags = Uint8.unpack(stream) if self.isCompressed( header) else None size = Uint16LE.unpack(stream) # Dispatch to the appropriate sub-parser. if updateCode == FastPathOutputType.FASTPATH_UPDATETYPE_BITMAP: return self.parseBitmapEventRaw(stream, header, compressionFlags, size) elif updateCode == FastPathOutputType.FASTPATH_UPDATETYPE_ORDERS: return self.parseOrdersEvent(stream, header, compressionFlags, size) read = stream.read(size) return FastPathOutputEvent(header, compressionFlags, read)
def parseLength(self, stream: BytesIO) -> int: length = Uint8.unpack(stream) if length & 0x80 != 0: length = ((length & 0x7f) << 8) | Uint8.unpack(stream) return length
def parseShareDataHeader(self, stream: BytesIO, controlHeader: ShareControlHeader): shareID = Uint32LE.unpack(stream) stream.read(1) streamID = Uint8.unpack(stream) uncompressedLength = Uint16LE.unpack(stream) pduSubtype = Uint8.unpack(stream) compressedType = Uint8.unpack(stream) compressedLength = Uint16LE.unpack(stream) return ShareDataHeader(controlHeader.pduType, controlHeader.version, controlHeader.source, shareID, streamID, uncompressedLength, SlowPathDataType(pduSubtype), compressedType, compressedLength)
def parse(self, data: bytes) -> FastPathPDU: stream = BytesIO(data) header = Uint8.unpack(stream) eventCount = self.parseEventCount(header) pduLength = self.parseLength(stream) if eventCount == 0: eventCount = Uint8.unpack(stream) data = stream.read(pduLength - stream.tell()) events = self.parseEvents(data) return FastPathPDU(header, events)
def parse(self, data: bytes) -> TPKTPDU: """ Read the byte stream and return a TPKTPDU """ _version = Uint8.unpack(data[0:1]) _padding = Uint8.unpack(data[1:2]) length = Uint16BE.unpack(data[2:4]) payload = data[4:length] if len(payload) != length - 4: raise ParsingError("Payload is too short for TPKT length field") return TPKTPDU(payload)
def parseLengthWithSocket(self, socket): """ Same as parseLength, but with a network socket. :type socket: socket.socket """ data = socket.recv(1) length = Uint8.unpack(data) if length & 0x80 != 0: data2 = socket.recv(1) data += data2 length = ((length & 0x7f) << 8) | Uint8.unpack(data2) return data, length
def parse(self, data: bytes) -> NegotiationResponsePDU: """ Parse a negotiation response. :param data: the response data. """ stream = BytesIO(data) if len(data) == 8: type = Uint8.unpack(stream) flags = Uint8.unpack(stream) length = Uint16LE.unpack(stream) selectedProtocols = Uint32LE.unpack(stream) return NegotiationResponsePDU(type, flags, selectedProtocols) else: return NegotiationResponsePDU(None, None, None)
def parseConnectionPDU(self, data: bytes, length: int, name: str) -> Tuple[int, int, int, bytes]: """ Parse the provided data to extract common information contained in Connection Request, Connection Confirm and Disconnect Request PDUs. :param data: bytes to parse. :param length: Length of the Connection PDU. :param name: For debugging purposes: the name of the connection PDU (like "Connection Request"). :return: A tuple of the information we find in both connection PDUs: (source, destination, options, payload) """ if length < 6: raise ParsingError( "Invalid X244 %s length indicator: indicator = %d, expected at least 6 bytes" % (name, 6)) destination = Uint16BE.unpack(data[2:4]) source = Uint16BE.unpack(data[4:6]) options = Uint8.unpack(data[6]) payload = data[7:] if len(payload) != length - 6: raise ParsingError( "Invalid X224 %s payload length: expected = %d, length = %d" % (name, length - 6, len(payload))) return source, destination, options, payload
def getEventLength(self, event: FastPathOutputUpdateEvent): if isinstance(event, bytes): header = Uint8.unpack(event[0]) if self.isCompressed(header): return Uint16LE.unpack(event[2: 4]) + 4 else: return Uint16LE.unpack(event[1: 3]) + 3 size = 3 if self.isCompressed(event.header): size += 1 if isinstance(event, FastPathOrdersEvent): size += 2 + len(event.orderData) elif isinstance(event, FastPathBitmapEvent): size += len(event.payload) elif isinstance(event, FastPathOutputUpdateEvent): length = len(event.payload) + 3 if event.compressionFlags is not None: length += 1 return length return size
def parseDirectoryControlRequest(self, deviceID: int, fileID: int, completionID: int, minorFunction: int, stream: BytesIO) -> DeviceIORequestPDU: self.minorFunctionsForParsingResponse[completionID] = MinorFunction( minorFunction) if minorFunction == MinorFunction.IRP_MN_NOTIFY_CHANGE_DIRECTORY: return DeviceIORequestPDU(deviceID, fileID, completionID, MajorFunction.IRP_MJ_DIRECTORY_CONTROL, minorFunction, stream.read()) else: informationClass = FileSystemInformationClass( Uint32LE.unpack(stream)) initialQuery = Uint8.unpack(stream) pathLength = Uint32LE.unpack(stream) stream.read(23) path = stream.read(pathLength) path = decodeUTF16LE(path)[:-1] self.informationClassForParsingResponse[ completionID] = informationClass return DeviceQueryDirectoryRequestPDU(deviceID, fileID, completionID, informationClass, initialQuery, path)
def parseData(self, data, length): """ Parse a Data PDU from the raw bytes :type data: bytes :param length: The length in bytes of the Data PDU. :return: X224DataPDU """ if length != 2: raise ParsingError("Invalid X224 Data PDU length indicator: expected = 2, indicator = %d" % length) code = Uint8.unpack(data[1]) & 0xf sequence = Uint8.unpack(data[2]) payload = data[3 :] return X224DataPDU(code & 1 == 1, sequence & 0x80 == 0x80, payload)
def parse(self, data: bytes) -> MCSPDU: """ Parse raw data bytes into a MCSPDU :param data: raw bytes to parse """ stream = BytesIO(data) header = Uint8.unpack(stream.read(1)) if header == ber.Class.BER_CLASS_APPL | ber.PC.BER_CONSTRUCT | ber.Tag.BER_TAG_MASK: header = Uint8.unpack(stream.read(1)) else: header = header >> 2 if header not in self.parsers: raise UnknownPDUTypeError("Trying to parse unknown MCS PDU type %s" % header, header) return self.parsers[header](stream)
def parse(self, data): """ Read the provided byte stream and return the corresponding RDPLicensingPDU. :type data: bytes :return: RDPLicensingPDU """ stream = BytesIO(data) header = Uint8.unpack(stream) flags = Uint8.unpack(stream) size = Uint16LE.unpack(stream) if header not in self.parsers: raise UnknownPDUTypeError("Trying to parse unknown license PDU", header) return self.parsers[header](stream, flags)
def parseSuppressOutput(self, stream: BytesIO, header): allowDisplayUpdates = Uint8.unpack(stream) stream.read(3) left = Uint16LE.unpack(stream) top = Uint16LE.unpack(stream) right = Uint16LE.unpack(stream) bottom = Uint16LE.unpack(stream) return SuppressOutputPDU(header, allowDisplayUpdates, left, top, right, bottom)
def isCompletePDU(self, data: bytes) -> bool: if len(data) == 1: return False if Uint8.unpack(data[1]) & 0x80 != 0 and len(data) == 2: return False return len(data) >= self.getPDULength(data)
def isTPKTPDU(self, data): """ Check if the PDU in data is a TPKT PDU. :param data: the data. :type data: bytes :return: bool """ return Uint8.unpack(data[0]) == 3
def parse(self, data): stream = BytesIO(data) header = Uint32LE.unpack(stream) if header & SecurityFlags.SEC_EXCHANGE_PKT != 0: return self.parseSecurityExchange(stream, header) length = Uint16LE.unpack(stream) version = Uint8.unpack(stream) padLength = Uint8.unpack(stream) signature = stream.read(8) payload = stream.read() if header & SecurityFlags.SEC_ENCRYPT != 0: payload = self.crypter.decrypt(payload) self.crypter.addDecryption() return SecurityPDU(header, payload)
def readChannelId(self, stream: BytesIO, cbid: int): if cbid == CbId.ONE_BYTE: return Uint8.unpack(stream) elif cbid == CbId.TWO_BYTE: return Uint16LE.unpack(stream) elif cbid == CbId.FOUR_BYTES: return Uint16LE.unpack(stream) else: raise ValueError(f"Invalid channel id length: {cbid}")
def parse(self, data: bytes) -> FastPathPDU: stream = BytesIO(data) header = Uint8.unpack(stream) eventCount = self.parseEventCount(header) pduLength = self.parseLength(stream) _signature = stream.read(8) if eventCount == 0: eventCount = Uint8.unpack(stream) data = stream.read(pduLength - stream.tell()) if header & FastPathSecurityFlags.FASTPATH_OUTPUT_ENCRYPTED != 0: data = self.crypter.decrypt(data) self.crypter.addDecryption() events = self.parseEvents(data) return FastPathPDU(header, events)
def parseConnectionConfirm(self, data, length): """ Parse a ConnectionConfirm PDU from the raw bytes :type data: bytes :param length: The length in bytes of the Connection Confirm PDU. :return: X224ConnectionConfirmPDU """ credit = Uint8.unpack(data[1]) & 0xf destination, source, options, payload = self.parseConnectionPDU(data, length, "Connection Confirm") return X224ConnectionConfirmPDU(credit, destination, source, options, payload)
def recv(self, data: bytes): """ Parses data to make a RDPPlayerMessagePDU and calls the observer with it. """ stream = BytesIO(data) type = PlayerMessageType(Uint8.unpack(stream)) timestamp = Uint64LE.unpack(stream) payload = stream.read() pdu = PlayerMessagePDU(type, timestamp, payload) self.pduReceived(pdu, forward=False)
def parse(s: BytesIO) -> 'StreamBitmapNext': self = StreamBitmapNext() self.flags = Uint8.unpack(s) self.bitmapType = Uint16LE.unpack(s) blockSize = Uint16LE.unpack(s) self.data = s.read(blockSize) return self
def parse(self, data): stream = BytesIO(data) eventHeader = Uint8.unpack(stream.read(1)) eventCode = (eventHeader & 0b11100000) >> 5 eventFlags= eventHeader & 0b00011111 if eventCode == FastPathInputType.FASTPATH_INPUT_EVENT_SCANCODE: return self.parseScanCode(eventFlags, eventHeader, stream) elif eventCode == FastPathInputType.FASTPATH_INPUT_EVENT_MOUSE: return self.parseMouseEvent(data, eventHeader) return FastPathEventRaw(data)
def parse(s: BytesIO) -> 'StreamBitmapFirst': self = StreamBitmapFirst() self.flags = Uint8.unpack(s) self.bpp = Uint8.unpack(s) self.type = Uint16LE.unpack(s) self.width = Uint16LE.unpack(s) self.height = Uint16LE.unpack(s) self.totalSize = 0 if self.flags & STREAM_BITMAP_V2: self.totalSize = Uint32LE.unpack(s) else: self.totalSize = Uint16LE.unpack(s) blockSize = Uint16LE.unpack(s) self.data = s.read(blockSize) return self
def parse(s: BytesIO) -> 'GdiPlusCacheEnd': self = GdiPlusCacheEnd() self.flags = Uint8.unpack(s) self.cacheType = Uint16LE.unpack(s) self.cacheIndex = Uint16LE.unpack(s) cbSize = Uint16LE.unpack(s) self.totalSize = Uint32LE.unpack(s) self.data = s.read(cbSize) return self