Ejemplo n.º 1
0
class FastPathOutputParser(Parser):
    def __init__(self):
        super().__init__()
        self.bitmapParser = BitmapParser()

    def getEventLength(self, event: FastPathOutputEvent) -> int:
        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, FastPathOutputEvent):
            length = len(event.payload) + 3
            if event.compressionFlags is not None:
                length += 1
            return length

        return size

    def isCompressed(self, header: int) -> bool:
        return (
            header >> 6
        ) & FastPathOutputCompressionType.FASTPATH_OUTPUT_COMPRESSION_USED != 0

    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 parseBitmapEventRaw(self, stream: BytesIO, header: int,
                            compressionFlags: int,
                            size: int) -> FastPathBitmapEvent:
        return FastPathBitmapEvent(header, compressionFlags, [],
                                   stream.read(size))

    def parseBitmapEvent(
            self,
            fastPathBitmapEvent: FastPathOutputEvent) -> FastPathBitmapEvent:
        rawBitmapUpdateData = fastPathBitmapEvent.payload
        stream = BytesIO(rawBitmapUpdateData)
        updateType = Uint16LE.unpack(stream.read(2))
        bitmapData = self.bitmapParser.parseBitmapUpdateData(stream.read())

        return FastPathBitmapEvent(fastPathBitmapEvent.header,
                                   fastPathBitmapEvent.compressionFlags,
                                   bitmapData, rawBitmapUpdateData)

    def writeBitmapEvent(self, stream: BytesIO, event: FastPathBitmapEvent):
        stream.write(event.payload)

    def parseOrdersEvent(self, stream: BytesIO, header: int,
                         compressionFlags: int,
                         size: int) -> FastPathOrdersEvent:
        orderCount = Uint16LE.unpack(stream)
        orderData = stream.read(size - 2)

        assert len(orderData) == size - 2

        ordersEvent = FastPathOrdersEvent(header, compressionFlags, orderCount,
                                          orderData)
        controlFlags = Uint8.unpack(orderData[0])

        if controlFlags & (DrawingOrderControlFlags.TS_SECONDARY | DrawingOrderControlFlags.TS_STANDARD)\
                == (DrawingOrderControlFlags.TS_SECONDARY | DrawingOrderControlFlags.TS_STANDARD):
            ordersEvent.secondaryDrawingOrders = self.parseSecondaryDrawingOrder(
                orderData)
        elif controlFlags & DrawingOrderControlFlags.TS_SECONDARY:
            pass

        return ordersEvent

    def parseSecondaryDrawingOrder(self,
                                   orderData: bytes) -> SecondaryDrawingOrder:
        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 writeOrdersEvent(self, stream, event):
        Uint16LE.pack(event.orderCount, stream)
        stream.write(event.orderData)

    def write(self, event: FastPathOutputEvent) -> bytes:

        stream = BytesIO()
        Uint8.pack(event.header, stream)

        if event.compressionFlags is not None:
            Uint8.pack(event.compressionFlags if event.compressionFlags else 0,
                       stream)

        updateStream = BytesIO()

        if isinstance(event, FastPathBitmapEvent):
            self.writeBitmapEvent(updateStream, event)
        elif isinstance(event, FastPathOrdersEvent):
            self.writeOrdersEvent(updateStream, event)
        else:
            # Means it's simply a FastPathOutputUpdateEvent, this needs to be the last elif.
            updateStream.write(event.payload)

        updateData = updateStream.getvalue()
        Uint16LE.pack(len(updateData), stream)
        stream.write(updateData)
        return stream.getvalue()
Ejemplo n.º 2
0
 def __init__(self):
     super().__init__()
     self.bitmapParser = BitmapParser()
Ejemplo n.º 3
0
class FastPathOutputParser(Parser):
    def __init__(self):
        super().__init__()
        self.bitmapParser = BitmapParser()

    def getEventLength(self, event: FastPathOutputEvent) -> int:
        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 += len(event.payload)
        elif isinstance(event, FastPathBitmapEvent):
            size += len(event.payload)
        elif isinstance(event, FastPathOutputEvent):
            length = len(event.payload) + 3
            if event.compressionFlags is not None:
                length += 1
            return length

        return size

    def isCompressed(self, header: int) -> bool:
        return (
            header >> 6
        ) & FastPathOutputCompressionType.FASTPATH_OUTPUT_COMPRESSION_USED != 0

    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 parseBitmapEventRaw(self, stream: BytesIO, header: int, compressionFlags: int, size: int) \
            -> FastPathBitmapEvent:
        return FastPathBitmapEvent(header, compressionFlags, [],
                                   stream.read(size))

    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 writeBitmapEvent(self, stream: BytesIO, event: FastPathBitmapEvent):
        stream.write(event.payload)

    def parseOrdersEvent(self, stream: BytesIO, header: int,
                         compressionFlags: int,
                         size: int) -> FastPathOrdersEvent:
        """
        Parse the order events from a TS_FP_UPDATE_ORDERS.
        This is specified in MS-RDPEGDI.
        """
        payload = stream.read(size)
        assert len(payload) == size

        orders = FastPathOrdersEvent(header, compressionFlags, payload)
        return orders

    def writeOrdersEvent(self, stream, event):
        # Just write the saved raw bytes as-is.
        stream.write(event.payload)

    def write(self, event: FastPathOutputEvent) -> bytes:

        stream = BytesIO()
        Uint8.pack(event.header, stream)

        if event.compressionFlags is not None:
            Uint8.pack(event.compressionFlags if event.compressionFlags else 0,
                       stream)

        updateStream = BytesIO()

        if isinstance(event, FastPathBitmapEvent):
            self.writeBitmapEvent(updateStream, event)
        elif isinstance(event, FastPathOrdersEvent):
            self.writeOrdersEvent(updateStream, event)
        else:
            # Means it's simply a FastPathOutputUpdateEvent, this needs to be the last elif.
            updateStream.write(event.payload)

        updateData = updateStream.getvalue()
        Uint16LE.pack(len(updateData), stream)
        stream.write(updateData)
        return stream.getvalue()