From 9b99365f80aaecd3282166bfdf3d80269756633f Mon Sep 17 00:00:00 2001 From: speyrefitte Date: Tue, 19 May 2015 16:42:22 +0200 Subject: [PATCH 1/4] fix bug on lwin key activation --- bin/rdpy-rdpmitm.py | 9 +++++---- rdpy/protocol/rdp/rdp.py | 32 +++++++++++++++++++++----------- rdpy/protocol/rdp/sec.py | 2 +- 3 files changed, 27 insertions(+), 16 deletions(-) diff --git a/bin/rdpy-rdpmitm.py b/bin/rdpy-rdpmitm.py index 801817e..3601179 100755 --- a/bin/rdpy-rdpmitm.py +++ b/bin/rdpy-rdpmitm.py @@ -92,16 +92,17 @@ class ProxyServer(rdp.RDPServerObserver): return self._client._controller.close() - def onKeyEventScancode(self, code, isPressed): + def onKeyEventScancode(self, code, isPressed, isExtended): """ @summary: Event call when a keyboard event is catch in scan code format - @param code: {int} scan code of key - @param isPressed: {bool} True if key is down + @param code: {integer} scan code of key + @param isPressed: {boolean} True if key is down + @param isExtended: {boolean} True if a special key @see: rdp.RDPServerObserver.onKeyEventScancode """ if self._client is None: return - self._client._controller.sendKeyEventScancode(code, isPressed) + self._client._controller.sendKeyEventScancode(code, isPressed, isExtended) self._rss.keyScancode(code, isPressed) def onKeyEventUnicode(self, code, isPressed): diff --git a/rdpy/protocol/rdp/rdp.py b/rdpy/protocol/rdp/rdp.py index ba3c4ba..5ac6fc5 100644 --- a/rdpy/protocol/rdp/rdp.py +++ b/rdpy/protocol/rdp/rdp.py @@ -100,7 +100,7 @@ class RDPClientController(pdu.layer.PDUClientListener): def setUsername(self, username): """ @summary: Set the username for session - @param username: username of session + @param username: {string} username of session """ #username in PDU info packet self._secLayer._info.userName.value = username @@ -109,7 +109,7 @@ class RDPClientController(pdu.layer.PDUClientListener): def setPassword(self, password): """ @summary: Set password for session - @param password: password of session + @param password: {string} password of session """ self.setAutologon() self._secLayer._info.password.value = password @@ -117,7 +117,7 @@ class RDPClientController(pdu.layer.PDUClientListener): def setDomain(self, domain): """ @summary: Set the windows domain of session - @param domain: domain of session + @param domain: {string} domain of session """ self._secLayer._info.domain.value = domain @@ -127,6 +127,13 @@ class RDPClientController(pdu.layer.PDUClientListener): """ self._secLayer._info.flag |= sec.InfoFlag.INFO_AUTOLOGON + def setAlternateShell(self, appName): + """ + @summary: set application name of app which start at the begining of session + @param appName: {string} application name + """ + self._secLayer._info.alternateShell.value = appName + def setKeyboardLayout(self, layout): """ @summary: keyboard layout @@ -269,11 +276,12 @@ class RDPClientController(pdu.layer.PDUClientListener): except InvalidValue: log.info("try send wheel event with incorrect position") - def sendKeyEventScancode(self, code, isPressed): + def sendKeyEventScancode(self, code, isPressed, extended = False): """ @summary: Send a scan code to RDP stack @param code: scan code @param isPressed: True if key is pressed and false if it's released + @param extended: {boolean} extended scancode like ctr or win button """ if not self._isReady: return @@ -281,11 +289,12 @@ class RDPClientController(pdu.layer.PDUClientListener): try: event = pdu.data.ScancodeKeyEvent() event.keyCode.value = code - if isPressed: - event.keyboardFlags.value |= pdu.data.KeyboardFlag.KBDFLAGS_DOWN - else: + if not isPressed: event.keyboardFlags.value |= pdu.data.KeyboardFlag.KBDFLAGS_RELEASE + if extended: + event.keyboardFlags.value |= pdu.data.KeyboardFlag.KBDFLAGS_EXTENDED + #send event self._pduLayer.sendInputEvents([event]) @@ -478,7 +487,7 @@ class RDPServerController(pdu.layer.PDUServerListener): for event in slowPathInputEvents: #scan code if event.messageType.value == pdu.data.InputMessageType.INPUT_EVENT_SCANCODE: - observer.onKeyEventScancode(event.slowPathInputData.keyCode.value, not (event.slowPathInputData.keyboardFlags.value & pdu.data.KeyboardFlag.KBDFLAGS_RELEASE)) + observer.onKeyEventScancode(event.slowPathInputData.keyCode.value, not (event.slowPathInputData.keyboardFlags.value & pdu.data.KeyboardFlag.KBDFLAGS_RELEASE), bool(event.slowPathInputData.keyboardFlags.value & pdu.data.KeyboardFlag.KBDFLAGS_EXTENDED)) #unicode elif event.messageType.value == pdu.data.InputMessageType.INPUT_EVENT_UNICODE: observer.onKeyEventUnicode(event.slowPathInputData.unicode.value, not (event.slowPathInputData.keyboardFlags.value & pdu.data.KeyboardFlag.KBDFLAGS_RELEASE)) @@ -652,11 +661,12 @@ class RDPServerObserver(object): """ raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "onClose", "RDPClientObserver")) - def onKeyEventScancode(self, code, isPressed): + def onKeyEventScancode(self, code, isPressed, isExtended): """ @summary: Event call when a keyboard event is catch in scan code format - @param code: scan code of key - @param isPressed: True if key is down + @param code: {integer} scan code of key + @param isPressed: {boolean} True if key is down + @param isExtended: {boolean} True if a special key """ raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "onKeyEventScanCode", "RDPServerObserver")) diff --git a/rdpy/protocol/rdp/sec.py b/rdpy/protocol/rdp/sec.py index 9462715..7a49b5a 100644 --- a/rdpy/protocol/rdp/sec.py +++ b/rdpy/protocol/rdp/sec.py @@ -323,7 +323,7 @@ class RDPInfo(CompositeType): #code page self.codePage = UInt32Le() #support flag - self.flag = UInt32Le(InfoFlag.INFO_MOUSE | InfoFlag.INFO_UNICODE | InfoFlag.INFO_LOGONNOTIFY | InfoFlag.INFO_LOGONERRORS | InfoFlag.INFO_DISABLECTRLALTDEL) + self.flag = UInt32Le(InfoFlag.INFO_MOUSE | InfoFlag.INFO_UNICODE | InfoFlag.INFO_LOGONNOTIFY | InfoFlag.INFO_LOGONERRORS | InfoFlag.INFO_DISABLECTRLALTDEL | InfoFlag.INFO_ENABLEWINDOWSKEY) self.cbDomain = UInt16Le(lambda:sizeof(self.domain) - 2) self.cbUserName = UInt16Le(lambda:sizeof(self.userName) - 2) self.cbPassword = UInt16Le(lambda:sizeof(self.password) - 2) From 11d66a48188e49bb442cfc50a67c3c2f29b717d9 Mon Sep 17 00:00:00 2001 From: speyrefitte Date: Tue, 19 May 2015 17:53:15 +0200 Subject: [PATCH 2/4] add onSessionReady event -> user session is ready --- README.md | 5 +++++ bin/rdpy-rdpmitm.py | 7 +++++++ bin/rdpy-rdpscreenshot.py | 7 +++++++ rdpy/protocol/rdp/pdu/data.py | 16 ++++++++++++++-- rdpy/protocol/rdp/pdu/layer.py | 10 ++++++++++ rdpy/protocol/rdp/rdp.py | 15 +++++++++++++++ rdpy/ui/qt4.py | 27 ++++++++++++--------------- 7 files changed, 70 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index 10599be..f8ecdb4 100644 --- a/README.md +++ b/README.md @@ -181,6 +181,11 @@ class MyRDPFactory(rdp.ClientFactory): @param isCompress: use RLE compression @param data: bitmap data """ + + def onSessionReady(self): + """ + @summary: Windows session is ready + """ def onClose(self): """ diff --git a/bin/rdpy-rdpmitm.py b/bin/rdpy-rdpmitm.py index 3601179..b568b7f 100755 --- a/bin/rdpy-rdpmitm.py +++ b/bin/rdpy-rdpmitm.py @@ -179,6 +179,13 @@ class ProxyClient(rdp.RDPClientObserver): #maybe color depth change self._server._controller.setColorDepth(self._controller.getColorDepth()) + def onSessionReady(self): + """ + @summary: Windows session is ready + @see: rdp.RDPClientObserver.onSessionReady + """ + pass + def onClose(self): """ @summary: Event inform that stack is close diff --git a/bin/rdpy-rdpscreenshot.py b/bin/rdpy-rdpscreenshot.py index 7ca58a7..4b87755 100755 --- a/bin/rdpy-rdpscreenshot.py +++ b/bin/rdpy-rdpscreenshot.py @@ -136,6 +136,13 @@ class RDPScreenShotFactory(rdp.ClientFactory): """ log.info("connected %s"%addr) + def onSessionReady(self): + """ + @summary: Windows session is ready + @see: rdp.RDPClientObserver.onSessionReady + """ + pass + def onClose(self): """ @summary: callback use when RDP stack is closed diff --git a/rdpy/protocol/rdp/pdu/data.py b/rdpy/protocol/rdp/pdu/data.py index f527c0a..84a19b8 100644 --- a/rdpy/protocol/rdp/pdu/data.py +++ b/rdpy/protocol/rdp/pdu/data.py @@ -542,7 +542,7 @@ class DataPDU(CompositeType): """ @summary: Create object in accordance self.shareDataHeader.pduType2 value """ - for c in [UpdateDataPDU, SynchronizeDataPDU, ControlDataPDU, ErrorInfoDataPDU, FontListDataPDU, FontMapDataPDU, PersistentListPDU, ClientInputEventPDU, ShutdownDeniedPDU, ShutdownRequestPDU, SupressOutputDataPDU]: + for c in [UpdateDataPDU, SynchronizeDataPDU, ControlDataPDU, ErrorInfoDataPDU, FontListDataPDU, FontMapDataPDU, PersistentListPDU, ClientInputEventPDU, ShutdownDeniedPDU, ShutdownRequestPDU, SupressOutputDataPDU, SaveSessionInfoPDU]: if self.shareDataHeader.pduType2.value == c._PDUTYPE2_: return c() log.debug("unknown PDU data type : %s"%hex(self.shareDataHeader.pduType2.value)) @@ -771,7 +771,19 @@ class UpdateDataPDU(CompositeType): raise InvalidExpectedDataException("Try to send an invalid data update PDU") self.updateData = updateData - + +class SaveSessionInfoPDU(CompositeType): + """ + @see: https://msdn.microsoft.com/en-us/library/cc240636.aspx + """ + _PDUTYPE2_ = PDUType2.PDUTYPE2_SAVE_SESSION_INFO + + def __init__(self, readLen = None): + CompositeType.__init__(self, readLen = readLen) + self.infoType = UInt32Le() + #TODO parse info data + self.infoData = String() + class FastPathUpdatePDU(CompositeType): """ @summary: Fast path update PDU packet diff --git a/rdpy/protocol/rdp/pdu/layer.py b/rdpy/protocol/rdp/pdu/layer.py index 271a7d3..f326701 100644 --- a/rdpy/protocol/rdp/pdu/layer.py +++ b/rdpy/protocol/rdp/pdu/layer.py @@ -39,6 +39,13 @@ class PDUClientListener(object): """ raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "onReady", "PDUClientListener")) + def onSessionReady(self): + """ + @summary: Event call when Windows session is ready + """ + raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "onSessionReady", "PDUClientListener")) + + def onUpdate(self, rectangles): """ @summary: call when a bitmap data is received from update PDU @@ -298,6 +305,9 @@ class Client(PDULayer): elif dataPDU.shareDataHeader.pduType2.value == data.PDUType2.PDUTYPE2_SHUTDOWN_DENIED: #may be an event to ask to user self._transport.close() + elif dataPDU.shareDataHeader.pduType2.value == data.PDUType2.PDUTYPE2_SAVE_SESSION_INFO: + #handle session event + self._listener.onSessionReady() elif dataPDU.shareDataHeader.pduType2.value == data.PDUType2.PDUTYPE2_UPDATE: self.readUpdateDataPDU(dataPDU.pduData) diff --git a/rdpy/protocol/rdp/rdp.py b/rdpy/protocol/rdp/rdp.py index 5ac6fc5..4f38fd6 100644 --- a/rdpy/protocol/rdp/rdp.py +++ b/rdpy/protocol/rdp/rdp.py @@ -199,6 +199,15 @@ class RDPClientController(pdu.layer.PDUClientListener): for observer in self._clientObserver: observer.onReady() + def onSessionReady(self): + """ + @summary: Call when Windows session is ready (connected) + """ + self._isReady = True + #signal all listener + for observer in self._clientObserver: + observer.onSessionReady() + def onClose(self): """ @summary: Event call when RDP stack is closed @@ -616,6 +625,12 @@ class RDPClientObserver(object): """ raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "onReady", "RDPClientObserver")) + def onSessionReady(self): + """ + @summary: Windows session is ready + """ + raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "onSessionReady", "RDPClientObserver")) + def onClose(self): """ @summary: Stack is closes diff --git a/rdpy/ui/qt4.py b/rdpy/ui/qt4.py index 59723a6..5f17155 100644 --- a/rdpy/ui/qt4.py +++ b/rdpy/ui/qt4.py @@ -311,12 +311,21 @@ class RDPClientQt(RDPClientObserver, QAdaptor): def onReady(self): """ @summary: Call when stack is ready + @see: rdp.RDPClientObserver.onReady """ #do something maybe a loader + + def onSessionReady(self): + """ + @summary: Windows session is ready + @see: rdp.RDPClientObserver.onSessionReady + """ + pass def onClose(self): """ @summary: Call when stack is close + @see: rdp.RDPClientObserver.onClose """ #do something maybe a message @@ -336,12 +345,6 @@ class QRemoteDesktop(QtGui.QWidget): self._adaptor = adaptor #set correct size self.resize(width, height) - #refresh stack of image - #because we can update image only in paint - #event function. When protocol receive image - #we will stock into refresh list - #and in paint event paint list of all refresh images - self._refresh = [] #bind mouse event self.setMouseTracking(True) #buffer image @@ -354,8 +357,9 @@ class QRemoteDesktop(QtGui.QWidget): @param y: y position of new image @param qimage: new QImage """ - #save in refresh list (order is important) - self._refresh.append((x, y, qimage, width, height)) + #fill buffer image + with QtGui.QPainter(self._buffer) as qp: + qp.drawImage(x, y, qimage, 0, 0, width, height) #force update self.update() @@ -373,16 +377,9 @@ class QRemoteDesktop(QtGui.QWidget): @summary: Call when Qt renderer engine estimate that is needed @param e: QEvent """ - #fill buffer image - with QtGui.QPainter(self._buffer) as qp: - #draw image - for (x, y, image, width, height) in self._refresh: - qp.drawImage(x, y, image, 0, 0, width, height) #draw in widget with QtGui.QPainter(self) as qp: qp.drawImage(0, 0, self._buffer) - - self._refresh = [] def mouseMoveEvent(self, event): """ From 763ed2e3ee9306cc12a40b8aa6d602c1c720afc6 Mon Sep 17 00:00:00 2001 From: speyrefitte Date: Wed, 20 May 2015 17:51:43 +0200 Subject: [PATCH 3/4] fix major bug on update handle --- bin/rdpy-rdpclient.py | 4 +-- rdpy/core/type.py | 2 +- rdpy/protocol/rdp/pdu/data.py | 64 ++++++++++++++++++---------------- rdpy/protocol/rdp/pdu/layer.py | 35 ++++++++++--------- rdpy/ui/qt4.py | 5 ++- 5 files changed, 60 insertions(+), 50 deletions(-) diff --git a/bin/rdpy-rdpclient.py b/bin/rdpy-rdpclient.py index 937b968..660bfa4 100755 --- a/bin/rdpy-rdpclient.py +++ b/bin/rdpy-rdpclient.py @@ -172,7 +172,7 @@ class RDPClientQtFactory(rdp.ClientFactory): connector.connect() return - QtGui.QMessageBox.warning(self._w, "Warning", "Lost connection : %s"%reason) + log.info("Lost connection : %s"%reason) reactor.stop() app.exit() @@ -182,7 +182,7 @@ class RDPClientQtFactory(rdp.ClientFactory): @param connector: twisted connector use for rdp connection (use reconnect to restart connection) @param reason: str use to advertise reason of lost connection """ - QtGui.QMessageBox.warning(self._w, "Warning", "Connection failed : %s"%reason) + log.info("Connection failed : %s"%reason) reactor.stop() app.exit() diff --git a/rdpy/core/type.py b/rdpy/core/type.py index 804ca5d..260c672 100644 --- a/rdpy/core/type.py +++ b/rdpy/core/type.py @@ -477,7 +477,7 @@ class CompositeType(Type): raise e if not self._readLen is None and readLen < self._readLen.value: - log.debug("Still have correct data in packet %s, read it as padding"%self.__class__) + log.debug("Still have correct data in packet %s, read %s bytes as padding"%(self.__class__, self._readLen.value - readLen)) s.read(self._readLen.value - readLen) def __write__(self, s): diff --git a/rdpy/protocol/rdp/pdu/data.py b/rdpy/protocol/rdp/pdu/data.py index 84a19b8..e7caf36 100644 --- a/rdpy/protocol/rdp/pdu/data.py +++ b/rdpy/protocol/rdp/pdu/data.py @@ -413,8 +413,6 @@ class ErrorInfo(object): ERRINFO_VCDATATOOLONG : "The size of a received Virtual Channel PDU (section 2.2.6.1) exceeds the chunking size specified in the Virtual Channel Capability Set (section 2.2.7.1.10).", } - - class ShareControlHeader(CompositeType): """ @summary: PDU share control header @@ -461,10 +459,10 @@ class PDU(CompositeType): """ for c in [DemandActivePDU, ConfirmActivePDU, DataPDU, DeactiveAllPDU]: if self.shareControlHeader.pduType.value == c._PDUTYPE_: - return c() + return c(readLen = CallableValue(self.shareControlHeader.totalLength.value - sizeof(self.shareControlHeader))) log.debug("unknown PDU type : %s"%hex(self.shareControlHeader.pduType.value)) #read entire packet - return String() + return String(readLen = CallableValue(self.shareControlHeader.totalLength.value - sizeof(self.shareControlHeader))) if pduMessage is None: pduMessage = FactoryType(PDUMessageFactory) @@ -481,8 +479,8 @@ class DemandActivePDU(CompositeType): #may declare the PDU type _PDUTYPE_ = PDUType.PDUTYPE_DEMANDACTIVEPDU - def __init__(self): - CompositeType.__init__(self) + def __init__(self, readLen = None): + CompositeType.__init__(self, readLen = readLen) self.shareId = UInt32Le() self.lengthSourceDescriptor = UInt16Le(lambda:sizeof(self.sourceDescriptor)) self.lengthCombinedCapabilities = UInt16Le(lambda:(sizeof(self.numberCapabilities) + sizeof(self.pad2Octets) + sizeof(self.capabilitySets))) @@ -500,8 +498,8 @@ class ConfirmActivePDU(CompositeType): #may declare the PDU type _PDUTYPE_ = PDUType.PDUTYPE_CONFIRMACTIVEPDU - def __init__(self): - CompositeType.__init__(self) + def __init__(self, readLen = None): + CompositeType.__init__(self, readLen = readLen) self.shareId = UInt32Le() self.originatorId = UInt16Le(0x03EA, constant = True) self.lengthSourceDescriptor = UInt16Le(lambda:sizeof(self.sourceDescriptor)) @@ -519,10 +517,10 @@ class DeactiveAllPDU(CompositeType): #may declare the PDU type _PDUTYPE_ = PDUType.PDUTYPE_DEACTIVATEALLPDU - def __init__(self): + def __init__(self, readLen = None): #in old version this packet is empty i don't know #and not specified - CompositeType.__init__(self, optional = True) + CompositeType.__init__(self, optional = True, readLen = readLen) self.shareId = UInt32Le() self.lengthSourceDescriptor = UInt16Le(lambda:sizeof(self.sourceDescriptor)) self.sourceDescriptor = String("rdpy", readLen = self.lengthSourceDescriptor) @@ -534,8 +532,8 @@ class DataPDU(CompositeType): #may declare the PDU type _PDUTYPE_ = PDUType.PDUTYPE_DATAPDU - def __init__(self, pduData = None, shareId = 0): - CompositeType.__init__(self) + def __init__(self, pduData = None, shareId = 0, readLen = None): + CompositeType.__init__(self, readLen = readLen) self.shareDataHeader = ShareDataHeader(lambda:sizeof(self), lambda:self.pduData.__class__._PDUTYPE2_, shareId) def PDUDataFactory(): @@ -544,9 +542,9 @@ class DataPDU(CompositeType): """ for c in [UpdateDataPDU, SynchronizeDataPDU, ControlDataPDU, ErrorInfoDataPDU, FontListDataPDU, FontMapDataPDU, PersistentListPDU, ClientInputEventPDU, ShutdownDeniedPDU, ShutdownRequestPDU, SupressOutputDataPDU, SaveSessionInfoPDU]: if self.shareDataHeader.pduType2.value == c._PDUTYPE2_: - return c() + return c(readLen = CallableValue(self.shareDataHeader.uncompressedLength.value - 18)) log.debug("unknown PDU data type : %s"%hex(self.shareDataHeader.pduType2.value)) - return String() + return String(readLen = CallableValue(self.shareDataHeader.uncompressedLength.value - 18)) if pduData is None: pduData = FactoryType(PDUDataFactory) @@ -655,8 +653,8 @@ class PersistentListPDU(CompositeType): """ _PDUTYPE2_ = PDUType2.PDUTYPE2_BITMAPCACHE_PERSISTENT_LIST - def __init__(self, userId = 0, shareId = 0): - CompositeType.__init__(self) + def __init__(self, userId = 0, shareId = 0, readLen = None): + CompositeType.__init__(self, readLen = readLen) self.numEntriesCache0 = UInt16Le() self.numEntriesCache1 = UInt16Le() self.numEntriesCache2 = UInt16Le() @@ -679,8 +677,8 @@ class ClientInputEventPDU(CompositeType): """ _PDUTYPE2_ = PDUType2.PDUTYPE2_INPUT - def __init__(self): - CompositeType.__init__(self) + def __init__(self, readLen = None): + CompositeType.__init__(self, readLen = readLen) self.numEvents = UInt16Le(lambda:len(self.slowPathInputEvents._array)) self.pad2Octets = UInt16Le() self.slowPathInputEvents = ArrayType(SlowPathInputEvent, readLen = self.numEvents) @@ -691,8 +689,8 @@ class ShutdownRequestPDU(CompositeType): client -> server """ _PDUTYPE2_ = PDUType2.PDUTYPE2_SHUTDOWN_REQUEST - def __init__(self): - CompositeType.__init__(self) + def __init__(self, readLen = None): + CompositeType.__init__(self, readLen = readLen) class ShutdownDeniedPDU(CompositeType): """ @@ -700,8 +698,8 @@ class ShutdownDeniedPDU(CompositeType): server -> client """ _PDUTYPE2_ = PDUType2.PDUTYPE2_SHUTDOWN_DENIED - def __init__(self): - CompositeType.__init__(self) + def __init__(self, readLen = None): + CompositeType.__init__(self, readLen = readLen) class InclusiveRectangle(CompositeType): """ @@ -761,9 +759,15 @@ class UpdateDataPDU(CompositeType): """ for c in [BitmapUpdateDataPDU]: if self.updateType.value == c._UPDATE_TYPE_: - return c() + if not readLen is None: + return c(readLen = CallableValue(readLen.value - 2)) + else: + return c() log.debug("unknown PDU update data type : %s"%hex(self.updateType.value)) - return String() + if not readLen is None: + return String(readLen = CallableValue(readLen.value - 2)) + else: + return String() if updateData is None: updateData = FactoryType(UpdateDataFactory, conditional = lambda:(self.updateType.value != UpdateType.UPDATETYPE_SYNCHRONIZE)) @@ -801,9 +805,9 @@ class FastPathUpdatePDU(CompositeType): """ for c in [FastPathBitmapUpdateDataPDU]: if (self.updateHeader.value & 0xf) == c._FASTPATH_UPDATE_TYPE_: - return c() + return c(readLen = self.size) log.debug("unknown Fast Path PDU update data type : %s"%hex(self.updateHeader.value & 0xf)) - return String() + return String(readLen = self.size) if updateData is None: updateData = FactoryType(UpdateDataFactory) @@ -833,8 +837,8 @@ class OrderUpdateDataPDU(CompositeType): @see: http://msdn.microsoft.com/en-us/library/cc241571.aspx @todo: not implemented yet but need it """ - def __init__(self): - CompositeType.__init__(self) + def __init__(self, readLen = None): + CompositeType.__init__(self, readLen = readLen) self.pad2OctetsA = UInt16Le() self.numberOrders = UInt16Le(lambda:len(self.orderData._array)) self.pad2OctetsB = UInt16Le() @@ -894,8 +898,8 @@ class FastPathBitmapUpdateDataPDU(CompositeType): """ _FASTPATH_UPDATE_TYPE_ = FastPathUpdateType.FASTPATH_UPDATETYPE_BITMAP - def __init__(self): - CompositeType.__init__(self) + def __init__(self, readLen = None): + CompositeType.__init__(self, readLen = readLen) self.header = UInt16Le(FastPathUpdateType.FASTPATH_UPDATETYPE_BITMAP, constant = True) self.numberRectangles = UInt16Le(lambda:len(self.rectangles._array)) self.rectangles = ArrayType(BitmapData, readLen = self.numberRectangles) diff --git a/rdpy/protocol/rdp/pdu/layer.py b/rdpy/protocol/rdp/pdu/layer.py index f326701..dcf68e9 100644 --- a/rdpy/protocol/rdp/pdu/layer.py +++ b/rdpy/protocol/rdp/pdu/layer.py @@ -25,6 +25,7 @@ In this layer are managed all mains bitmap update orders end user inputs from rdpy.core.layer import LayerAutomata from rdpy.core.error import CallPureVirtualFuntion +from rdpy.core.type import ArrayType import rdpy.core.log as log import rdpy.protocol.rdp.tpkt as tpkt import data, caps @@ -266,15 +267,16 @@ class Client(PDULayer): @summary: Main receive function after connection sequence @param s: Stream from transport layer """ - pdu = data.PDU() - s.readType(pdu) - if pdu.shareControlHeader.pduType.value == data.PDUType.PDUTYPE_DATAPDU: - self.readDataPDU(pdu.pduMessage) - elif pdu.shareControlHeader.pduType.value == data.PDUType.PDUTYPE_DEACTIVATEALLPDU: - #use in deactivation-reactivation sequence - #next state is either a capabilities re exchange or disconnection - #http://msdn.microsoft.com/en-us/library/cc240454.aspx - self.setNextState(self.recvDemandActivePDU) + pdus = ArrayType(data.PDU) + s.readType(pdus) + for pdu in pdus: + if pdu.shareControlHeader.pduType.value == data.PDUType.PDUTYPE_DATAPDU: + self.readDataPDU(pdu.pduMessage) + elif pdu.shareControlHeader.pduType.value == data.PDUType.PDUTYPE_DEACTIVATEALLPDU: + #use in deactivation-reactivation sequence + #next state is either a capabilities re exchange or disconnection + #http://msdn.microsoft.com/en-us/library/cc240454.aspx + self.setNextState(self.recvDemandActivePDU) def recvFastPath(self, secFlag, fastPathS): """ @@ -283,11 +285,12 @@ class Client(PDULayer): @param fastPathS: {Stream} that contain fast path data @param secFlag: {SecFlags} """ - fastPathPDU = data.FastPathUpdatePDU() - fastPathS.readType(fastPathPDU) - if fastPathPDU.updateHeader.value == data.FastPathUpdateType.FASTPATH_UPDATETYPE_BITMAP: - self._listener.onUpdate(fastPathPDU.updateData.rectangles._array) - + updates = ArrayType(data.FastPathUpdatePDU) + fastPathS.readType(updates) + for update in updates: + if update.updateHeader.value == data.FastPathUpdateType.FASTPATH_UPDATETYPE_BITMAP: + self._listener.onUpdate(update.updateData.rectangles._array) + def readDataPDU(self, dataPDU): """ @summary: read a data PDU object @@ -329,8 +332,8 @@ class Client(PDULayer): generalCapability.osMajorType.value = caps.MajorType.OSMAJORTYPE_WINDOWS generalCapability.osMinorType.value = caps.MinorType.OSMINORTYPE_WINDOWS_NT generalCapability.extraFlags.value = caps.GeneralExtraFlag.LONG_CREDENTIALS_SUPPORTED | caps.GeneralExtraFlag.NO_BITMAP_COMPRESSION_HDR | caps.GeneralExtraFlag.ENC_SALTED_CHECKSUM - if not self._fastPathSender is None: - generalCapability.extraFlags.value |= caps.GeneralExtraFlag.FASTPATH_OUTPUT_SUPPORTED + #if not self._fastPathSender is None: + # generalCapability.extraFlags.value |= caps.GeneralExtraFlag.FASTPATH_OUTPUT_SUPPORTED #init bitmap capability bitmapCapability = self._clientCapabilities[caps.CapsType.CAPSTYPE_BITMAP].capability diff --git a/rdpy/ui/qt4.py b/rdpy/ui/qt4.py index 5f17155..63a3b14 100644 --- a/rdpy/ui/qt4.py +++ b/rdpy/ui/qt4.py @@ -241,6 +241,7 @@ class RDPClientQt(RDPClientObserver, QAdaptor): self._widget = QRemoteDesktop(width, height, self) #set widget screen to RDP stack controller.setScreen(width, height) + self._i = 0 def getWidget(self): """ @@ -303,7 +304,9 @@ class RDPClientQt(RDPClientObserver, QAdaptor): @param isCompress: {bool} use RLE compression @param data: {str} bitmap data """ - image = RDPBitmapToQtImage(width, height, bitsPerPixel, isCompress, data); + image = RDPBitmapToQtImage(width, height, bitsPerPixel, isCompress, data) + image.save("/tmp/%s.png"%self._i) + self._i += 1 #if image need to be cut #For bit alignement server may send more than image pixel self._widget.notifyImage(destLeft, destTop, image, destRight - destLeft + 1, destBottom - destTop + 1) From a23ae25a1fd1fa8372e67b83f389ce6900818f32 Mon Sep 17 00:00:00 2001 From: speyrefitte Date: Thu, 21 May 2015 10:29:32 +0200 Subject: [PATCH 4/4] fix issue on unhandle upadte --- bin/rdpy-rdphoneypot.py | 2 +- rdpy/protocol/rdp/lic.py | 2 +- rdpy/protocol/rdp/pdu/data.py | 43 +++++++++++++++++++++++----------- rdpy/protocol/rdp/pdu/layer.py | 4 ++-- rdpy/ui/qt4.py | 3 --- setup.py | 2 +- 6 files changed, 34 insertions(+), 22 deletions(-) diff --git a/bin/rdpy-rdphoneypot.py b/bin/rdpy-rdphoneypot.py index 3f1e898..3ceb42a 100755 --- a/bin/rdpy-rdphoneypot.py +++ b/bin/rdpy-rdphoneypot.py @@ -70,7 +70,7 @@ class HoneyPotServer(rdp.RDPServerObserver): def onClose(self): """ HoneyPot """ - def onKeyEventScancode(self, code, isPressed): + def onKeyEventScancode(self, code, isPressed, isExtended): """ HoneyPot """ def onKeyEventUnicode(self, code, isPressed): diff --git a/rdpy/protocol/rdp/lic.py b/rdpy/protocol/rdp/lic.py index 3acdb74..f22f4d4 100644 --- a/rdpy/protocol/rdp/lic.py +++ b/rdpy/protocol/rdp/lic.py @@ -234,7 +234,7 @@ class LicPacket(CompositeType): if self.bMsgtype.value == c._MESSAGE_TYPE_: return c(readLen = self.wMsgSize - 4) log.debug("unknown license message : %s"%self.bMsgtype.value) - return String() + return String(readLen = self.wMsgSize - 4) if message is None: message = FactoryType(LicensingMessageFactory) diff --git a/rdpy/protocol/rdp/pdu/data.py b/rdpy/protocol/rdp/pdu/data.py index e7caf36..385ae63 100644 --- a/rdpy/protocol/rdp/pdu/data.py +++ b/rdpy/protocol/rdp/pdu/data.py @@ -202,6 +202,16 @@ class Display(object): SUPPRESS_DISPLAY_UPDATES = 0x00 ALLOW_DISPLAY_UPDATES = 0x01 +class ToogleFlag(object): + """ + @summary: Use to known state of keyboard + @see: https://msdn.microsoft.com/en-us/library/cc240588.aspx + """ + TS_SYNC_SCROLL_LOCK = 0x00000001 + TS_SYNC_NUM_LOCK = 0x00000002 + TS_SYNC_CAPS_LOCK = 0x00000004 + TS_SYNC_KANA_LOCK = 0x00000008 + class ErrorInfo(object): """ @summary: Error code use in Error info PDU @@ -542,9 +552,9 @@ class DataPDU(CompositeType): """ for c in [UpdateDataPDU, SynchronizeDataPDU, ControlDataPDU, ErrorInfoDataPDU, FontListDataPDU, FontMapDataPDU, PersistentListPDU, ClientInputEventPDU, ShutdownDeniedPDU, ShutdownRequestPDU, SupressOutputDataPDU, SaveSessionInfoPDU]: if self.shareDataHeader.pduType2.value == c._PDUTYPE2_: - return c(readLen = CallableValue(self.shareDataHeader.uncompressedLength.value - 18)) + return c(readLen = CallableValue(readLen.value - sizeof(self.shareDataHeader))) log.debug("unknown PDU data type : %s"%hex(self.shareDataHeader.pduType2.value)) - return String(readLen = CallableValue(self.shareDataHeader.uncompressedLength.value - 18)) + return String(readLen = CallableValue(readLen.value - sizeof(self.shareDataHeader))) if pduData is None: pduData = FactoryType(PDUDataFactory) @@ -759,15 +769,9 @@ class UpdateDataPDU(CompositeType): """ for c in [BitmapUpdateDataPDU]: if self.updateType.value == c._UPDATE_TYPE_: - if not readLen is None: - return c(readLen = CallableValue(readLen.value - 2)) - else: - return c() + return c(readLen = CallableValue(readLen.value - 2)) log.debug("unknown PDU update data type : %s"%hex(self.updateType.value)) - if not readLen is None: - return String(readLen = CallableValue(readLen.value - 2)) - else: - return String() + return String(readLen = CallableValue(readLen.value - 2)) if updateData is None: updateData = FactoryType(UpdateDataFactory, conditional = lambda:(self.updateType.value != UpdateType.UPDATETYPE_SYNCHRONIZE)) @@ -915,11 +919,10 @@ class SlowPathInputEvent(CompositeType): self.messageType = UInt16Le(lambda:self.slowPathInputData.__class__._INPUT_MESSAGE_TYPE_) def SlowPathInputDataFactory(): - for c in [PointerEvent, ScancodeKeyEvent, UnicodeKeyEvent]: + for c in [PointerEvent, ScancodeKeyEvent, UnicodeKeyEvent, SynchronizeEvent]: if self.messageType.value == c._INPUT_MESSAGE_TYPE_: return c() - log.debug("unknown slow path input : %s"%hex(self.messageType.value)) - return String() + raise InvalidExpectedDataException("unknown slow path input : %s"%hex(self.messageType.value)) if messageData is None: messageData = FactoryType(SlowPathInputDataFactory) @@ -927,7 +930,19 @@ class SlowPathInputEvent(CompositeType): raise InvalidExpectedDataException("try to send an invalid Slow Path Input Event") self.slowPathInputData = messageData - + +class SynchronizeEvent(CompositeType): + """ + @summary: Synchronize keyboard + @see: https://msdn.microsoft.com/en-us/library/cc240588.aspx + """ + _INPUT_MESSAGE_TYPE_ = InputMessageType.INPUT_EVENT_SYNC + + def __init__(self): + CompositeType.__init__(self) + self.pad2Octets = UInt16Le() + self.toggleFlags = UInt32Le() + class PointerEvent(CompositeType): """ @summary: Event use to communicate mouse position diff --git a/rdpy/protocol/rdp/pdu/layer.py b/rdpy/protocol/rdp/pdu/layer.py index dcf68e9..aebcd15 100644 --- a/rdpy/protocol/rdp/pdu/layer.py +++ b/rdpy/protocol/rdp/pdu/layer.py @@ -332,8 +332,8 @@ class Client(PDULayer): generalCapability.osMajorType.value = caps.MajorType.OSMAJORTYPE_WINDOWS generalCapability.osMinorType.value = caps.MinorType.OSMINORTYPE_WINDOWS_NT generalCapability.extraFlags.value = caps.GeneralExtraFlag.LONG_CREDENTIALS_SUPPORTED | caps.GeneralExtraFlag.NO_BITMAP_COMPRESSION_HDR | caps.GeneralExtraFlag.ENC_SALTED_CHECKSUM - #if not self._fastPathSender is None: - # generalCapability.extraFlags.value |= caps.GeneralExtraFlag.FASTPATH_OUTPUT_SUPPORTED + if not self._fastPathSender is None: + generalCapability.extraFlags.value |= caps.GeneralExtraFlag.FASTPATH_OUTPUT_SUPPORTED #init bitmap capability bitmapCapability = self._clientCapabilities[caps.CapsType.CAPSTYPE_BITMAP].capability diff --git a/rdpy/ui/qt4.py b/rdpy/ui/qt4.py index 63a3b14..237f974 100644 --- a/rdpy/ui/qt4.py +++ b/rdpy/ui/qt4.py @@ -241,7 +241,6 @@ class RDPClientQt(RDPClientObserver, QAdaptor): self._widget = QRemoteDesktop(width, height, self) #set widget screen to RDP stack controller.setScreen(width, height) - self._i = 0 def getWidget(self): """ @@ -305,8 +304,6 @@ class RDPClientQt(RDPClientObserver, QAdaptor): @param data: {str} bitmap data """ image = RDPBitmapToQtImage(width, height, bitsPerPixel, isCompress, data) - image.save("/tmp/%s.png"%self._i) - self._i += 1 #if image need to be cut #For bit alignement server may send more than image pixel self._widget.notifyImage(destLeft, destTop, image, destRight - destLeft + 1, destBottom - destTop + 1) diff --git a/setup.py b/setup.py index e8a1bee..d3136f2 100644 --- a/setup.py +++ b/setup.py @@ -4,7 +4,7 @@ import setuptools from distutils.core import setup, Extension setup(name='rdpy', - version='1.3.1', + version='1.3.2', description='Remote Desktop Protocol in Python', long_description=""" RDPY is a pure Python implementation of the Microsoft RDP (Remote Desktop Protocol) protocol (Client and Server side). RDPY is built over the event driven network engine Twisted.