コード例 #1
0
    def onSlowPathPDU(self, pdu: PlayerPDU):
        parser = SlowPathParser()
        pdu = parser.parse(pdu.payload)

        if isinstance(pdu, ConfirmActivePDU):
            bitmapCapability = pdu.parsedCapabilitySets[
                CapabilityType.CAPSTYPE_BITMAP]
            self.viewer.resize(bitmapCapability.desktopWidth,
                               bitmapCapability.desktopHeight)
        elif isinstance(
                pdu, UpdatePDU
        ) and pdu.updateType == SlowPathUpdateType.SLOWPATH_UPDATETYPE_BITMAP:
            updates = BitmapParser().parseBitmapUpdateData(pdu.updateData)

            for bitmap in updates:
                self.handleBitmap(bitmap)
        elif isinstance(pdu, InputPDU):
            for event in pdu.events:
                if isinstance(event, MouseEvent):
                    self.onMousePosition(event.x, event.y)
                elif isinstance(event, KeyboardEvent):
                    self.onScanCode(
                        event.keyCode,
                        event.flags & KeyboardFlag.KBDFLAGS_DOWN == 0,
                        event.flags & KeyboardFlag.KBDFLAGS_EXTENDED != 0)
コード例 #2
0
    def onSlowPathPDU(self, pdu: PlayerPDU):
        parser = SlowPathParser()
        pdu = parser.parse(pdu.payload)

        if isinstance(pdu, ConfirmActivePDU):
            self.onCapabilities(pdu.parsedCapabilitySets)

        elif isinstance(pdu, UpdatePDU):
            self.onSlowPathUpdate(pdu)

        elif isinstance(pdu, InputPDU):
            for event in pdu.events:
                if isinstance(event, MouseEvent):
                    self.onMousePosition(event.x, event.y)
                elif isinstance(event, KeyboardEvent):
                    self.onScanCode(
                        event.keyCode,
                        event.flags & KeyboardFlag.KBDFLAGS_DOWN == 0,
                        event.flags & KeyboardFlag.KBDFLAGS_EXTENDED != 0)
コード例 #3
0
class HeadlessEventHandler(Observer):
    """
    Handle events from a replay file without rendering to a surface.

    This event handler does not require any graphical dependencies.
    """
    def __init__(self, output: TextIOBase = stdout):
        super().__init__()
        self.output = output

        self.shiftPressed = False
        self.capsLockOn = False
        self.buffer = b""

        # Instantiate parsers.
        self.slowpath = SlowPathParser()
        # self.fastpath = FastPathOutputParser()
        self.clipboard = ClipboardParser()

        self.handlers = {
            PlayerPDUType.CLIENT_DATA: self.onClientData,
            PlayerPDUType.CLIENT_INFO: self.onClientInfo,
            PlayerPDUType.CONNECTION_CLOSE: self.onConnectionClose,
            PlayerPDUType.CLIPBOARD_DATA: self.onClipboardData,
            PlayerPDUType.SLOW_PATH_PDU: self.onSlowPathPDU,
            PlayerPDUType.FAST_PATH_INPUT: self.onFastPathInput,
            PlayerPDUType.DEVICE_MAPPING: self.onDeviceMapping,
        }

    def writeText(self, text: str):
        self.output.write(text.rstrip("\x00"))

    def writeSeparator(self):
        self.output.write("\n--------------------\n")

    def onPDUReceived(self, pdu: PlayerPDU, isMainThread=False):
        log.debug("Received %(pdu)s", {"pdu": pdu})
        if pdu.header in self.handlers:
            self.handlers[pdu.header](pdu)

    def onClientData(self, pdu: PlayerPDU):
        parser = ClientConnectionParser()
        clientDataPDU = parser.parse(pdu.payload)
        clientName = clientDataPDU.coreData.clientName.strip("\x00")

        self.writeSeparator()
        self.writeText(f"HOST: {clientName}\n")
        self.writeSeparator()

    def onClientInfo(self, pdu: PlayerPDU):
        parser = ClientInfoParser()
        clientInfoPDU = parser.parse(pdu.payload)

        self.writeSeparator()

        self.writeText("USERNAME: {}\nPASSWORD: {}\nDOMAIN: {}\n".format(
            clientInfoPDU.username.replace("\x00", ""),
            clientInfoPDU.password.replace("\x00", ""),
            clientInfoPDU.domain.replace("\x00", "")))

        self.writeSeparator()

    def onConnectionClose(self, _: PlayerPDU):
        self.writeText("\n<Connection closed>")

    def onClipboardData(self, pdu: PlayerPDU):
        parser = ClipboardParser()
        pdu = parser.parse(pdu.payload)

        if not isinstance(pdu, FormatDataResponsePDU):
            return

        clipboardData = decodeUTF16LE(pdu.requestedFormatData)

        self.writeSeparator()
        self.writeText(f"CLIPBOARD DATA: {clipboardData}")
        self.writeSeparator()

    def onSlowPathPDU(self, pdu: PlayerPDU):
        pdu = self.slowpath.parse(pdu.payload)

        if not isinstance(pdu, InputPDU):
            return
        for event in pdu.events:
            if isinstance(event, MouseEvent):
                self.onMousePosition(event.x, event.y)
            elif isinstance(event, KeyboardEvent):
                down = event.flags & KeyboardFlag.KBDFLAGS_DOWN == 0
                ext = event.flags & KeyboardFlag.KBDFLAGS_EXTENDED != 0
                self.onScanCode(event.keyCode, down, ext)

    def onFastPathInput(self, pdu: PlayerPDU):
        parser = BasicFastPathParser(ParserMode.SERVER)
        pdu = parser.parse(pdu.payload)

        for event in pdu.events:
            if isinstance(event, FastPathUnicodeEvent):
                if not event.released:
                    self.onUnicode(event)
            elif isinstance(event, FastPathMouseEvent):
                self.onMouse(event)
            elif isinstance(event, FastPathScanCodeEvent):
                ext = event.rawHeaderByte & KBDFLAGS_EXTENDED != 0
                self.onScanCode(event.scanCode, event.isReleased, ext)

    def onUnicode(self, event: FastPathUnicodeEvent):
        self.writeText(str(event.text))

    def onMouse(self, event: FastPathMouseEvent):
        if event.pointerFlags & PointerFlag.PTRFLAGS_DOWN:
            if event.pointerFlags & PointerFlag.PTRFLAGS_BUTTON1:
                button = 'Left'
            elif event.pointerFlags & PointerFlag.PTRFLAGS_BUTTON2:
                button = 'Right'
            elif event.pointerFlags & PointerFlag.PTRFLAGS_BUTTON3:
                button = 'Middle'
            else:
                button = 'Unknown'
            self.writeText(
                f'\n<Click ({button}) @ ({event.mouseX}, {event.mouseY})>')
        self.onMousePosition(event.mouseX, event.mouseY)

    def onMousePosition(self, x: int, y: int):
        pass

    def onScanCode(self, scanCode: int, isReleased: bool, isExtended: bool):
        keyName = getKeyName(scanCode, isExtended, self.shiftPressed,
                             self.capsLockOn)

        if len(keyName) == 1:
            if not isReleased:
                self.writeText(keyName)
        else:
            self.writeText(
                f"\n<{keyName} {'released' if isReleased else 'pressed'}>")

        # Handle shift.
        if scanCode in [0x2A, 0x36]:
            self.shiftPressed = not isReleased

        # Caps lock
        elif scanCode == 0x3A and not isReleased:
            self.capsLockOn = not self.capsLockOn

    def onDeviceMapping(self, pdu: PlayerDeviceMappingPDU):
        self.writeText(
            f"\n<{DeviceType.getPrettyName(pdu.deviceType)} mapped: {pdu.name}>"
        )
コード例 #4
0
ファイル: PlayerMessageHandler.py プロジェクト: rmdavy/pyrdp
class PlayerMessageHandler(PlayerMessageObserver):
    """
    Class to manage the display of the RDP player when reading events.
    """
    def __init__(self, viewer, text):
        super().__init__()
        self.viewer = viewer
        self.text = text
        self.writeInCaps = False

        self.inputParser = BasicFastPathParser(ParserMode.SERVER)
        self.outputParser = BasicFastPathParser(ParserMode.CLIENT)
        self.clientInfoParser = ClientInfoParser()
        self.dataParser = SlowPathParser()
        self.clipboardParser = ClipboardParser()
        self.outputEventParser = FastPathOutputParser()
        self.clientConnectionParser = ClientConnectionParser()

        self.buffer = b""

    def onConnectionClose(self, pdu: PlayerMessagePDU):
        self.text.moveCursor(QTextCursor.End)
        self.text.insertPlainText("\n<Connection closed>")

    def onOutput(self, pdu: PlayerMessagePDU):
        pdu = self.outputParser.parse(pdu.payload)

        for event in pdu.events:
            reassembledEvent = self.reassembleEvent(event)
            if reassembledEvent is not None:
                if isinstance(reassembledEvent, FastPathOrdersEvent):
                    log.debug("Not handling orders event, not coded :)")
                elif isinstance(reassembledEvent, FastPathBitmapEvent):
                    log.debug("Handling bitmap event %(arg1)s",
                              {"arg1": type(reassembledEvent)})
                    self.onBitmap(reassembledEvent)
                else:
                    log.debug("Can't handle output event: %(arg1)s",
                              {"arg1": type(reassembledEvent)})
            else:
                log.debug("Reassembling output event...")

    def onInput(self, pdu: PlayerMessagePDU):
        pdu = self.inputParser.parse(pdu.payload)

        for event in pdu.events:
            if isinstance(event, FastPathScanCodeEvent):
                log.debug("handling %(arg1)s", {"arg1": event})
                self.onScanCode(event.scancode, not event.isReleased)
            elif isinstance(event, FastPathMouseEvent):
                self.onMousePosition(event.mouseX, event.mouseY)
            else:
                log.debug("Can't handle input event: %(arg1)s",
                          {"arg1": event})

    def onScanCode(self, code: int, isPressed: bool):
        """
        Handle scan code.
        """
        log.debug("Reading scancode %(arg1)s", {"arg1": code})

        if code in [0x2A, 0x36]:
            self.text.moveCursor(QTextCursor.End)
            self.text.insertPlainText(
                "\n<LSHIFT PRESSED>" if isPressed else "\n<LSHIFT RELEASED>")
            self.writeInCaps = not self.writeInCaps
        elif code == 0x3A and isPressed:
            self.text.moveCursor(QTextCursor.End)
            self.text.insertPlainText("\n<CAPSLOCK>")
            self.writeInCaps = not self.writeInCaps
        elif isPressed:
            char = scancodeToChar(code)
            self.text.moveCursor(QTextCursor.End)
            self.text.insertPlainText(
                char if self.writeInCaps else char.lower())

    def onMousePosition(self, x: int, y: int):
        self.viewer.setMousePosition(x, y)

    def onBitmap(self, event: FastPathBitmapEvent):
        parsedEvent = self.outputEventParser.parseBitmapEvent(event)
        for bitmapData in parsedEvent.bitmapUpdateData:
            self.handleBitmap(bitmapData)

    def handleBitmap(self, bitmapData: BitmapUpdateData):
        image = RDPBitmapToQtImage(
            bitmapData.width, bitmapData.heigth, bitmapData.bitsPerPixel,
            bitmapData.flags & BitmapFlags.BITMAP_COMPRESSION != 0,
            bitmapData.bitmapData)
        self.viewer.notifyImage(bitmapData.destLeft, bitmapData.destTop, image,
                                bitmapData.destRight - bitmapData.destLeft + 1,
                                bitmapData.destBottom - bitmapData.destTop + 1)

    def onClientInfo(self, pdu: PlayerMessagePDU):
        clientInfoPDU = self.clientInfoParser.parse(pdu.payload)
        self.text.insertPlainText(
            "USERNAME: {}\nPASSWORD: {}\nDOMAIN: {}\n".format(
                clientInfoPDU.username.replace("\0", ""),
                clientInfoPDU.password.replace("\0", ""),
                clientInfoPDU.domain.replace("\0", "")))
        self.text.insertPlainText("--------------------\n")

    def onSlowPathPDU(self, pdu: PlayerMessagePDU):
        pdu = self.dataParser.parse(pdu.payload)

        if isinstance(pdu, ConfirmActivePDU):
            self.viewer.resize(
                pdu.parsedCapabilitySets[
                    CapabilityType.CAPSTYPE_BITMAP].desktopWidth,
                pdu.parsedCapabilitySets[
                    CapabilityType.CAPSTYPE_BITMAP].desktopHeight)
        elif isinstance(
                pdu, UpdatePDU
        ) and pdu.updateType == SlowPathUpdateType.SLOWPATH_UPDATETYPE_BITMAP:
            updates = BitmapParser().parseBitmapUpdateData(pdu.updateData)
            for bitmap in updates:
                self.handleBitmap(bitmap)
        elif isinstance(pdu, InputPDU):
            for event in pdu.events:
                if isinstance(event, MouseEvent):
                    self.onMousePosition(event.x, event.y)
                elif isinstance(event, KeyboardEvent):
                    self.onScanCode(
                        event.keyCode,
                        event.flags & KeyboardFlag.KBDFLAGS_DOWN != 0)

    def onClipboardData(self, pdu: PlayerMessagePDU):
        formatDataResponsePDU: FormatDataResponsePDU = self.clipboardParser.parse(
            pdu.payload)
        self.text.moveCursor(QTextCursor.End)
        self.text.insertPlainText("\n=============\n")
        self.text.insertPlainText("CLIPBOARD DATA: {}".format(
            decodeUTF16LE(formatDataResponsePDU.requestedFormatData)))
        self.text.insertPlainText("\n=============\n")

    def onClientData(self, pdu: PlayerMessagePDU):
        """
        Prints the clientName on the screen
        """
        clientDataPDU = self.clientConnectionParser.parse(pdu.payload)
        self.text.moveCursor(QTextCursor.End)
        self.text.insertPlainText("--------------------\n")
        self.text.insertPlainText(
            f"HOST: {clientDataPDU.coreData.clientName.strip(chr(0))}\n")

    def reassembleEvent(
        self, event: FastPathOutputEvent
    ) -> Optional[Union[FastPathBitmapEvent, FastPathOutputEvent]]:
        """
        Handles FastPath event reassembly as described in
        https://msdn.microsoft.com/en-us/library/cc240622.aspx
        :param event: A potentially segmented fastpath output event
        :return: a FastPathBitmapEvent if a complete PDU has been reassembled, otherwise None. If the event is not
        fragmented, returns the original event.
        """
        fragmentationFlag = FastPathFragmentation((event.header
                                                   & 0b00110000) >> 4)
        if fragmentationFlag == FastPathFragmentation.FASTPATH_FRAGMENT_SINGLE:
            return event
        elif fragmentationFlag == FastPathFragmentation.FASTPATH_FRAGMENT_FIRST:
            self.buffer = event.payload
        elif fragmentationFlag == FastPathFragmentation.FASTPATH_FRAGMENT_NEXT:
            self.buffer += event.payload
        elif fragmentationFlag == FastPathFragmentation.FASTPATH_FRAGMENT_LAST:
            self.buffer += event.payload
            event.payload = self.buffer
            return self.outputEventParser.parseBitmapEvent(event)

        return None