def writeFileDescription(self, description: PlayerFileDescription, stream: BytesIO): path = description.path.encode() Uint32LE.pack(len(path), stream) stream.write(path) Uint8.pack(int(description.isDirectory), stream)
def write(self, pdu): """ Write a negotiation request. :param pdu: the request PDU. :type pdu: NegotiationRequestPDU :return: str """ stream = BytesIO() if pdu.cookie is not None: stream.write(pdu.cookie + b"\r\n") if pdu.flags is not None and pdu.requestedProtocols is not None: Uint8.pack(NegotiationType.TYPE_RDP_NEG_REQ, stream) Uint8.pack(pdu.flags, stream) Uint16LE.pack(8, stream) Uint32LE.pack(pdu.requestedProtocols, stream) if pdu.correlationFlags is not None and pdu.correlationID is not None: Uint8.pack(NegotiationType.TYPE_RDP_CORRELATION_INFO, stream) Uint8.pack(pdu.correlationFlags, stream) Uint16LE.pack(36, stream) stream.write(pdu.correlationID) stream.write(b"\x00" * 16) return stream.getvalue()
def write(self, pdu): """ :type pdu: VirtualChannelPDU :return: A LIST of VirtualChannelPDUs as raw bytes. The first one has the CHANNEL_FLAG_FIRST set and the last one has the CHANNEL_FLAG_LAST set. """ rawPacketList = [] length = pdu.length dataStream = BytesIO(pdu.payload) while length > 0: stream = BytesIO() Uint32LE.pack(pdu.length, stream) flags = pdu.flags & 0b11111111111111111111111111111100 if len(rawPacketList) == 0: # Means it's the first packet. flags |= VirtualChannelPDUFlag.CHANNEL_FLAG_FIRST if length <= self.MAX_CHUNK_SIZE: # Means it's the last packet. flags |= VirtualChannelPDUFlag.CHANNEL_FLAG_LAST Uint32LE.pack(flags, stream) toWrite = self.MAX_CHUNK_SIZE if length >= self.MAX_CHUNK_SIZE else length stream.write(dataStream.read(toWrite)) rawPacketList.append(stream.getvalue()) length -= toWrite return rawPacketList
def writeHeader(self, stream, pdu): """ Write the PDU header. :type stream: BytesIO :type pdu: SecurityPDU """ Uint32LE.pack(pdu.header, stream)
def writeFileDownloadRequest(self, pdu: PlayerFileDownloadRequestPDU, stream: BytesIO): path = pdu.path.encode() Uint32LE.pack(pdu.deviceID, stream) Uint32LE.pack(len(path), stream) stream.write(path)
def macData(macKey, data): """ Generate an unsalted signature. See: http://msdn.microsoft.com/en-us/library/cc241995.aspx :param macKey: signing key. :type macKey: bytes :param data: data to sign. :type data: bytes :return: str """ sha1Digest = hashlib.sha1() md5Digest = hashlib.md5() dataLength = ByteStream() Uint32LE.pack(len(data), dataLength) sha1Digest.update(macKey) sha1Digest.update(b"\x36" * 40) sha1Digest.update(dataLength.getvalue()) sha1Digest.update(data) sha1Sig = sha1Digest.digest() md5Digest.update(macKey) md5Digest.update(b"\x5c" * 48) md5Digest.update(sha1Sig) return md5Digest.digest()
def macSaltedData(macKey, data, encryptionCount): """ Generate a salted signature. See: https://msdn.microsoft.com/en-us/library/cc240789.aspx :param macKey: signing key. :type macKey: bytes :param data: data to sign. :type data: bytes :param encryptionCount: the number of encrypted packets so far. :type encryptionCount: int :return: str """ sha1Digest = hashlib.sha1() md5Digest = hashlib.md5() dataLengthS = ByteStream() Uint32LE.pack(len(data), dataLengthS) encryptionCountS = ByteStream() Uint32LE.pack(encryptionCount, encryptionCountS) sha1Digest.update(macKey) sha1Digest.update(b"\x36" * 40) sha1Digest.update(dataLengthS.getvalue()) sha1Digest.update(data) sha1Digest.update(encryptionCountS.getvalue()) sha1Sig = sha1Digest.digest() md5Digest.update(macKey) md5Digest.update(b"\x5c" * 48) md5Digest.update(sha1Sig) return md5Digest.digest()
def write(self, pdu: VirtualChannelPDU) -> List[bytes]: rawPacketList = [] payloadStream = BytesIO(pdu.payload) lengthRemaining = len(pdu.payload) while lengthRemaining > 0: chunkSize = min(lengthRemaining, self.MAX_CHUNK_SIZE) chunk = payloadStream.read(chunkSize) flags = pdu.flags & ~(VirtualChannelPDUFlag.CHANNEL_FLAG_FIRST | VirtualChannelPDUFlag.CHANNEL_FLAG_LAST) if len(rawPacketList) == 0: # Means it's the first packet. flags |= VirtualChannelPDUFlag.CHANNEL_FLAG_FIRST if lengthRemaining <= self.MAX_CHUNK_SIZE: # Means it's the last packet. flags |= VirtualChannelPDUFlag.CHANNEL_FLAG_LAST outputStream = BytesIO() Uint32LE.pack(len(pdu.payload), outputStream) Uint32LE.pack(flags, outputStream) outputStream.write(chunk) rawPacketList.append(outputStream.getvalue()) lengthRemaining -= chunkSize return rawPacketList
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 writeFormatDataRequest(self, stream, pdu): """ Write the FormatDataRequestPDU starting at dataLen. Assumes LongFormatNames. :type stream: BytesIO :type pdu: FormatDataRequestPDU """ Uint32LE.pack(4, stream) # datalen Uint32LE.pack(pdu.requestedFormatId, stream)
def writeFormatDataResponse(self, stream, pdu): """ Write the FormatDataResponsePDU starting at dataLen. :type stream: BytesIO :type pdu: FormatDataResponsePDU """ Uint32LE.pack(len(pdu.requestedFormatData), stream) stream.write(pdu.requestedFormatData)
def writeDirectoryListingRequest(self, pdu: PlayerDirectoryListingRequestPDU, stream: BytesIO): path = pdu.path.encode() Uint32LE.pack(pdu.deviceID, stream) Uint32LE.pack(len(path), stream) stream.write(path)
def writeDirectoryListingResponse(self, pdu: PlayerDirectoryListingResponsePDU, stream: BytesIO): Uint32LE.pack(pdu.deviceID, stream) Uint32LE.pack(len(pdu.fileDescriptions), stream) for description in pdu.fileDescriptions: self.writeFileDescription(description, stream)
def write(self, pdu): """ Encode a Client Info PDU to bytes. :param pdu: the Client Info PDU. :type pdu: ClientInfoPDU :return: str """ 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 writeClientNetworkData(self, stream: BytesIO, network: ClientNetworkData): stream.write(Uint32LE.pack(len(network.channelDefinitions))) for channel in network.channelDefinitions: if len(channel.name) > 8: raise ParsingError("Channel name must have 8 characters maximum") stream.write(channel.name.encode().ljust(8, b"\x00")[: 8]) stream.write(Uint32LE.pack(channel.options))
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 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 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 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 writeServerCertificate(self, certificate: ProprietaryCertificate) -> bytes: stream = BytesIO() if certificate.type == ServerCertificateType.PROPRIETARY: Uint32LE.pack(ServerCertificateType.PROPRIETARY, stream) self.writeProprietaryCertificate(stream, certificate) else: raise NotImplementedError("Unhandled certificate type") return stream.getvalue()
def writeServerSecurityData(self, stream: BytesIO, data: ServerSecurityData): stream.write(Uint32LE.pack(data.encryptionMethod)) stream.write(Uint32LE.pack(data.encryptionLevel)) if data.serverRandom is not None: serverCertificate = self.writeServerCertificate(data.serverCertificate) stream.write(Uint32LE.pack(len(data.serverRandom))) stream.write(Uint32LE.pack(len(serverCertificate))) stream.write(data.serverRandom) stream.write(serverCertificate)
def writeOffscreenCacheCapability(self, capability: OffscreenBitmapCacheCapability, stream: BytesIO): substream = BytesIO() Uint16LE.pack(capability.capabilityType, stream) Uint32LE.pack(capability.offscreenSupportLevel, substream) Uint16LE.pack(capability.offscreenCacheSize, substream) Uint16LE.pack(capability.offscreenCacheEntries, substream) Uint16LE.pack(len(substream.getvalue()) + 4, stream) stream.write(substream.getvalue())
def writeDeviceIORequest(self, pdu: DeviceIORequestPDU, stream: BytesIO): Uint32LE.pack(pdu.deviceId, stream) Uint32LE.pack(pdu.fileId, stream) Uint32LE.pack(pdu.completionId, stream) Uint32LE.pack(pdu.majorFunction, stream) Uint32LE.pack(pdu.minorFunction, stream) if pdu.majorFunction in self.ioRequestWriters.keys(): self.ioRequestWriters[pdu.majorFunction](pdu, stream) else: stream.write(pdu.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 writeDirectoryControlResponse(self, pdu: Union[DeviceDirectoryControlResponsePDU, DeviceQueryDirectoryResponsePDU], stream: BytesIO): if not hasattr(pdu, "minorFunction") or pdu.minorFunction == MinorFunction.IRP_MN_NOTIFY_CHANGE_DIRECTORY: stream.write(pdu.payload) return substream = BytesIO() self.fileInformationWriters[pdu.informationClass](pdu.fileInformation, substream) Uint32LE.pack(len(substream.getvalue()), stream) stream.write(substream.getvalue()) stream.write(pdu.endByte)
def writeSecurityExchange(self, pdu): """ Encode a RDPSecurityExchangePDU to bytes. :type pdu: SecurityExchangePDU :return: str """ stream = BytesIO() Uint32LE.pack(SecurityFlags.SEC_EXCHANGE_PKT | SecurityFlags.SEC_LICENSE_ENCRYPT_SC, stream) Uint32LE.pack(len(pdu.clientRandom), stream) stream.write(pdu.clientRandom) 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 writeServerCoreData(self, stream, data): """ :type stream: BytesIO :type data: ServerCoreData """ stream.write(Uint32LE.pack(data.version)) if data.clientRequestedProtocols is not None: stream.write(Uint32LE.pack(data.clientRequestedProtocols)) if data.earlyCapabilityFlags is not None: stream.write(Uint32LE.pack(data.earlyCapabilityFlags))
def writeServerCoreData(self, stream: BytesIO, data: ServerCoreData): stream.write(Uint32LE.pack(data.version)) requestedProtocols = data.clientRequestedProtocols if requestedProtocols is None: requestedProtocols = 0 stream.write(Uint32LE.pack(requestedProtocols)) if data.earlyCapabilityFlags is not None: stream.write(Uint32LE.pack(data.earlyCapabilityFlags))
def writeProprietaryCertificate(self, stream: BytesIO, cert: ProprietaryCertificate): keyBytes = self.writePublicKey(cert.publicKey) Uint32LE.pack(cert.signatureAlgorithmID, stream) Uint32LE.pack(cert.keyAlgorithmID, stream) Uint16LE.pack(cert.publicKeyType, stream) Uint16LE.pack(len(keyBytes), stream) stream.write(keyBytes) Uint16LE.pack(cert.signatureType, stream) Uint16LE.pack(len(cert.signature) + 8, stream) stream.write(cert.signature) stream.write(b"\x00" * 8)