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 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 writeMultiFragmentUpdateCapability( self, capability: MultifragmentUpdateCapability, stream: BytesIO): substream = BytesIO() Uint16LE.pack(capability.capabilityType, stream) Uint32LE.pack(capability.maxRequestSize, substream) Uint16LE.pack(len(substream.getvalue()) + 4, stream) stream.write(substream.getvalue())
def writeSurfaceCommandsCapability(self, capability: SurfaceCommandsCapability, stream: BytesIO): substream = BytesIO() Uint16LE.pack(capability.capabilityType, stream) Uint32LE.pack(capability.cmdFlags, substream) Uint32LE.pack(capability.reserved, substream) Uint16LE.pack(len(substream.getvalue()) + 4, stream) stream.write(substream.getvalue())
def write(self, pdu: ClientInfoPDU) -> bytes: """ Encode a Client Info PDU to bytes. :param pdu: the Client Info PDU. """ stream = BytesIO() stream.write(Uint32LE.pack(pdu.codePage)) stream.write(Uint32LE.pack(pdu.flags)) isUnicode = pdu.flags & ClientInfoFlags.INFO_UNICODE != 0 hasNullBytes = pdu.codePage == 1252 or isUnicode nullByteCount = 1 if hasNullBytes else 0 unicodeMultiplier = 2 if isUnicode else 0 domain = pdu.domain + "\x00" * nullByteCount username = pdu.username + "\x00" * nullByteCount password = pdu.password + "\x00" * nullByteCount alternateShell = pdu.alternateShell + "\x00" * nullByteCount workingDir = pdu.workingDir + "\x00" * nullByteCount if isUnicode: domain = encodeUTF16LE(domain) username = encodeUTF16LE(username) password = encodeUTF16LE(password) alternateShell = encodeUTF16LE(alternateShell) workingDir = encodeUTF16LE(workingDir) else: domain = domain.encode() username = username.encode() password = password.encode() alternateShell = alternateShell.encode() workingDir = workingDir.encode() domainLength = len(domain) - nullByteCount * unicodeMultiplier usernameLength = len(username) - nullByteCount * unicodeMultiplier passwordLength = len(password) - nullByteCount * unicodeMultiplier alternateShellLength = len( alternateShell) - nullByteCount * unicodeMultiplier workingDirLength = len(workingDir) - nullByteCount * unicodeMultiplier stream.write(Uint16LE.pack(domainLength)) stream.write(Uint16LE.pack(usernameLength)) stream.write(Uint16LE.pack(passwordLength)) stream.write(Uint16LE.pack(alternateShellLength)) stream.write(Uint16LE.pack(workingDirLength)) stream.write(domain) stream.write(username) stream.write(password) stream.write(alternateShell) stream.write(workingDir) if pdu.extraInfo is not None: extraInfoBytes = self.writeExtraInfo(pdu.extraInfo) stream.write(extraInfoBytes) return stream.getvalue()
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 writeServerNetworkData(self, stream: BytesIO, data: ServerNetworkData): """ https://msdn.microsoft.com/en-us/library/cc240522.aspx """ stream.write(Uint16LE.pack(data.mcsChannelID)) stream.write(Uint16LE.pack(len(data.channels))) for channel in data.channels: stream.write(Uint16LE.pack(channel)) if len(data.channels) % 2 != 0: stream.write(Uint16LE.pack(0)) # Write 2 empty bytes so we keep a multiple of 4.
def write(self, pdu: PlayerMessagePDU) -> bytes: stream = BytesIO() # 18 bytes of header + the payload Uint64LE.pack(len(pdu.payload) + 18, stream) Uint16LE.pack(pdu.header, stream) Uint64LE.pack(pdu.timestamp, stream) stream.write(pdu.payload) return stream.getvalue()
def writeColorEvent(self, stream, event): Uint16LE.pack(event.cacheIndex, stream) Uint32LE.pack(event.hotSpot, stream) Uint16LE.pack(event.width, stream) Uint16LE.pack(event.height, stream) Uint16LE.pack(len(event.andMask), stream) Uint16LE.pack(len(event.xorMask), stream) stream.write(event.xorMask) stream.write(event.andMask) stream.write(b"\x00")
def parseCapability(self, stream: BytesIO) -> DeviceRedirectionCapability: capabilityType = RDPDRCapabilityType(Uint16LE.unpack(stream)) capabilityLength = Uint16LE.unpack(stream) version = Uint32LE.unpack(stream) payload = stream.read(capabilityLength - 8) if capabilityType in self.capabilityParsers: return self.capabilityParsers[capabilityType](version, payload) else: return DeviceRedirectionCapability(capabilityType, version, payload)
def write(self, input): stream = BytesIO() Uint32LE.pack(input.eventTime, stream) Uint16LE.pack(input.messageType, stream) if input.messageType not in self.writers: raise WritingError("Invalid input message type") self.writers[input.messageType](stream, input) return stream.getvalue()
def parseLicenseBlob(self, stream): """ Parse the provided byte stream and return the corresponding RDPLicenseBinaryBlob :type stream: BytesIO :return: RDPLicenseBinaryBlob """ type = LicenseBinaryBlobType(Uint16LE.unpack(stream)) length = Uint16LE.unpack(stream) data = stream.read(length) return LicenseBinaryBlob(type, data)
def writePointerCapability(self, capability: PointerCapability, stream: BytesIO): substream = BytesIO() Uint16LE.pack(capability.capabilityType, stream) Uint16LE.pack(capability.colorPointerFlag, substream) Uint16LE.pack(capability.colorPointerCacheSize, substream) Uint16LE.pack(capability.pointerCacheSize, substream) Uint16LE.pack(len(substream.getvalue()) + 4, stream) stream.write(substream.getvalue())
def writeErrorAlert(self, stream, pdu): """ Writes LicenceErrorAlertPDU-specific fields to stream :type stream: BytesIO :type pdu: LicenseErrorAlertPDU """ stream.write(Uint32LE.pack(pdu.errorCode)) stream.write(Uint32LE.pack(pdu.stateTransition)) stream.write(Uint16LE.pack(pdu.blob.type)) stream.write(Uint16LE.pack(0))
def writeSingleCapability(self, capability: DeviceRedirectionCapability, stream: BytesIO): Uint16LE.pack(capability.capabilityType, stream) substream = BytesIO() if isinstance(capability, DeviceRedirectionGeneralCapability): self.writeGeneralCapability(capability, substream) else: substream.write(capability.payload) Uint16LE.pack(len(substream.getvalue()) + 8, stream) Uint32LE.pack(capability.version, stream) stream.write(substream.getvalue())
def write(self, event): stream = BytesIO() Uint16LE.pack(event.messageType, stream) stream.write(b"\x00" * 2) if event.messageType not in self.writers: raise ParsingError("Trying to write invalid pointer event type") self.writers[event.messageType](stream, event) return stream.getvalue()
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(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
def parsePointerCapability(self, data: bytes) -> PointerCapability: """ https://msdn.microsoft.com/en-us/library/cc240562.aspx :param data: Raw data starting after lengthCapability """ stream = BytesIO(data) colorPointerFlag = Uint16LE.unpack(stream) colorPointerCacheSize = Uint16LE.unpack(stream) pointerCacheSize = Uint16LE.unpack(stream) return PointerCapability(colorPointerFlag, colorPointerCacheSize, pointerCacheSize)
def parse(s: BytesIO) -> 'GdiPlusCacheNext': self = GdiPlusCacheNext() self.flags = Uint8.unpack(s) self.cacheType = Uint16LE.unpack(s) self.cacheIdx = Uint16LE.unpack(s) cbSize = Uint16LE.unpack(s) self.data = s.read(cbSize) return self
def parseCapabilitySets(self, capabilitySetsRaw, numberCapabilities): stream = BytesIO(capabilitySetsRaw) capabilitySets = {} # Do minimum parsing for every capability for i in range(numberCapabilities): capabilitySetType = Uint16LE.unpack(stream.read(2)) lengthCapability = Uint16LE.unpack(stream.read(2)) capabilityData = stream.read(lengthCapability - 4) capability = Capability(capabilitySetType, capabilityData) capabilitySets[CapabilityType(capabilitySetType)] = capability # Fully parse the General capability set capabilitySets[CapabilityType.CAPSTYPE_GENERAL] = \ self.parseGeneralCapability(capabilitySets[CapabilityType.CAPSTYPE_GENERAL].rawData) # Fully parse the Glyph cache capability set if CapabilityType.CAPSTYPE_GLYPHCACHE in capabilitySets: capabilitySets[CapabilityType.CAPSTYPE_GLYPHCACHE] = \ self.parseGlyphCacheCapability(capabilitySets[CapabilityType.CAPSTYPE_GLYPHCACHE].rawData) # If present, fully parse the offscreen cache capability set if CapabilityType.CAPSTYPE_OFFSCREENCACHE in capabilitySets: capabilitySets[CapabilityType.CAPSTYPE_OFFSCREENCACHE] = \ self.parseOffscreenCacheCapability(capabilitySets[CapabilityType.CAPSTYPE_OFFSCREENCACHE].rawData) # If present, fully parse the surface commands cache capability set if CapabilityType.CAPSETTYPE_SURFACE_COMMANDS in capabilitySets: capabilitySets[CapabilityType.CAPSETTYPE_SURFACE_COMMANDS] = \ self.parseSurfaceCommandsCapability(capabilitySets[CapabilityType.CAPSETTYPE_SURFACE_COMMANDS].rawData) # Fully parse the Bitmap capability set capabilitySets[CapabilityType.CAPSTYPE_BITMAP] = \ self.parseBitmapCapability(capabilitySets[CapabilityType.CAPSTYPE_BITMAP].rawData) # Fully parse the Order capability set capabilitySets[ CapabilityType.CAPSTYPE_ORDER] = self.parseOrderCapability( capabilitySets[CapabilityType.CAPSTYPE_ORDER].rawData) # Fully parse the VirtualChannel capability set if CapabilityType.CAPSTYPE_VIRTUALCHANNEL in capabilitySets: capabilitySets[ CapabilityType. CAPSTYPE_VIRTUALCHANNEL] = self.parseVirtualChannelCapability( capabilitySets[ CapabilityType.CAPSTYPE_VIRTUALCHANNEL].rawData) # Fully parse the Pointer capability set if CapabilityType.CAPSTYPE_POINTER in capabilitySets: capabilitySets[ CapabilityType.CAPSTYPE_POINTER] = self.parsePointerCapability( capabilitySets[CapabilityType.CAPSTYPE_POINTER].rawData) return capabilitySets
def write(self, pdu: DeviceRedirectionPDU) -> bytes: stream = BytesIO() Uint16LE.pack(pdu.component, stream) Uint16LE.pack(pdu.packetID, stream) if pdu.component == DeviceRedirectionComponent.RDPDR_CTYP_CORE and pdu.packetID in self.writers.keys(): self.writers[pdu.packetID](pdu, stream) else: stream.write(pdu.payload) return stream.getvalue()
def writeVirtualChannelCapability(self, capability: VirtualChannelCapability, stream: BytesIO): substream = BytesIO() Uint16LE.pack(capability.capabilityType, stream) Uint32LE.pack(capability.flags, substream) if capability.vcChunkSize is not None: Uint32LE.pack(capability.vcChunkSize, substream) Uint16LE.pack(len(substream.getvalue()) + 4, stream) stream.write(substream.getvalue())
def parseBitmapEvent( self, fastPathBitmapEvent: FastPathOutputEvent) -> FastPathBitmapEvent: rawBitmapUpdateData = fastPathBitmapEvent.payload stream = BytesIO(rawBitmapUpdateData) Uint16LE.unpack(stream.read(2)) # updateType (unused) bitmapData = self.bitmapParser.parseBitmapUpdateData(stream.read()) return FastPathBitmapEvent(fastPathBitmapEvent.header, fastPathBitmapEvent.compressionFlags, bitmapData, rawBitmapUpdateData)
def parseSingleCapability(self, stream: BytesIO) -> Tuple[CapabilityType, DeviceRedirectionCapability]: """ https://msdn.microsoft.com/en-us/library/cc241325.aspx """ capabilityType = CapabilityType(Uint16LE.unpack(stream)) capabilityLength = Uint16LE.unpack(stream) version = Uint32LE.unpack(stream) payload = stream.read(capabilityLength - 8) if capabilityType == CapabilityType.CAP_GENERAL_TYPE: return capabilityType, self.parseGeneralCapability(version, payload) else: return capabilityType, DeviceRedirectionCapability(capabilityType, version, payload=payload)
def writeGeneralCapability(self, capability: DeviceRedirectionGeneralCapability, stream: BytesIO): Uint32LE.pack(capability.osType, stream) Uint32LE.pack(capability.osVersion, stream) Uint16LE.pack(capability.protocolMajorVersion, stream) Uint16LE.pack(capability.protocolMinorVersion, stream) Uint32LE.pack(capability.ioCode1, stream) Uint32LE.pack(capability.ioCode2, stream) Uint32LE.pack(capability.extendedPDU, stream) Uint32LE.pack(capability.extraFlags1, stream) Uint32LE.pack(capability.extraFlags2, stream) if capability.version == GeneralCapabilityVersion.GENERAL_CAPABILITY_VERSION_02: Uint32LE.pack(capability.specialTypeDeviceCap, stream)
def parseDemandActive(self, stream: BytesIO, header): shareID = Uint32LE.unpack(stream) lengthSourceDescriptor = Uint16LE.unpack(stream) lengthCombinedCapabilities = Uint16LE.unpack(stream) sourceDescriptor = stream.read(lengthSourceDescriptor) numberCapabilities = Uint16LE.unpack(stream) pad2Octets = stream.read(2) capabilitySets = stream.read(lengthCombinedCapabilities - 4) sessionID = Uint32LE.unpack(stream) parsedCapabilitySets = self.parseCapabilitySets(capabilitySets, numberCapabilities) return DemandActivePDU(header, shareID, sourceDescriptor, numberCapabilities, capabilitySets, sessionID, parsedCapabilitySets)
def writeStructure(self, stream: BytesIO, data: typing.Union[ClientCoreData, ClientNetworkData, ClientSecurityData, ClientClusterData]): if data.header not in self.writers: raise UnknownPDUTypeError("Trying to write unknown Client Data structure %s" % data.header, data.header) substream = BytesIO() self.writers[data.header](substream, data) substream = substream.getvalue() stream.write(Uint16LE.pack(data.header)) stream.write(Uint16LE.pack(len(substream) + 4)) stream.write(substream)
def parseColorEvent(self, stream): cacheIndex = Uint16LE.unpack(stream) hotSpot = Uint32LE.unpack(stream) width = Uint16LE.unpack(stream) height = Uint16LE.unpack(stream) andMaskLength = Uint16LE.unpack(stream) xorMaskLength = Uint16LE.unpack(stream) xorMask = stream.read(xorMaskLength) andMask = stream.read(andMaskLength) stream.read(1) return PointerColorEvent(cacheIndex, hotSpot, width, height, andMask, xorMask)
def writeCapability(self, capability: DeviceRedirectionCapability, stream: BytesIO): Uint16LE.pack(capability.capabilityType, stream) substream = BytesIO() if capability.capabilityType in self.capabilityWriters: self.capabilityWriters[capability.capabilityType](capability, substream) else: substream.write(capability.payload) Uint16LE.pack(len(substream.getvalue()) + 8, stream) Uint32LE.pack(capability.version, stream) stream.write(substream.getvalue())