diff --git a/bin/rdpy-rdpmitm.py b/bin/rdpy-rdpmitm.py
index 188fce9..5371172 100755
--- a/bin/rdpy-rdpmitm.py
+++ b/bin/rdpy-rdpmitm.py
@@ -21,20 +21,20 @@
"""
RDP proxy with Man in the middle capabilities
Save bitmap in file and keylogging
- ---------------------------
+ ----------------------------
Client RDP -> | ProxyServer | ProxyClient | -> Server RDP
- ---------------------------
- | Save Session |
- --------------
+ ----------------------------
+ | Record Session |
+ -----------------
"""
-import sys, os, getopt, json
+import sys, os, getopt, time
-from rdpy.core import log, error
+from rdpy.core import log, error, type, rsr
from rdpy.protocol.rdp import rdp
from twisted.internet import reactor
-log._LOG_LEVEL = log.Level.DEBUG
+log._LOG_LEVEL = log.Level.INFO
class ProxyServer(rdp.RDPServerObserver):
"""
@@ -161,6 +161,7 @@ class ProxyClient(rdp.RDPClientObserver):
rdp.RDPClientObserver.__init__(self, controller)
self._server = server
self._connected = False
+ self._rsr = rsr.createRecorder("/tmp/toto")
def onReady(self):
"""
@@ -199,6 +200,17 @@ class ProxyClient(rdp.RDPClientObserver):
@param data: bitmap data
@see: rdp.RDPClientObserver.onUpdate
"""
+ e = rsr.UpdateEvent()
+ e.destLeft.value = destLeft
+ e.destTop.value = destTop
+ e.destRight.value = destRight
+ e.destBottom.value = destBottom
+ e.width.value = width
+ e.height.value = height
+ e.bpp.value = bitsPerPixel
+ e.format.value = rsr.UpdateFormat.BMP if isCompress else rsr.UpdateFormat.RAW
+ e.data.value = data
+ self._rsr.add(e)
self._server._controller.sendUpdate(destLeft, destTop, destRight, destBottom, width, height, bitsPerPixel, isCompress, data)
class ProxyClientFactory(rdp.ClientFactory):
@@ -237,6 +249,7 @@ class ProxyClientFactory(rdp.ClientFactory):
controller.setUsername(self._username)
controller.setPassword(self._password)
controller.setSecurityLevel(self._security)
+ controller.setPerformanceSession()
return ProxyClient(controller, self._server)
def help():
diff --git a/bin/rdpy-rdpshare.py b/bin/rdpy-rdpshare.py
index 4f228ba..d9e9851 100755
--- a/bin/rdpy-rdpshare.py
+++ b/bin/rdpy-rdpshare.py
@@ -30,7 +30,7 @@ Client RDP -> | ProxyServer | ProxyClient | -> Server RDP
Shadow client ------------|
"""
-import sys, os, getopt, json
+import sys, os, getopt
from rdpy.core import log, error
from rdpy.protocol.rdp import rdp
@@ -241,6 +241,7 @@ class ProxyClientFactory(rdp.ClientFactory):
controller.setDomain(self._domain)
controller.setUsername(self._username)
controller.setPassword(self._password)
+ controller.setPerformanceSession()
return ProxyClient(controller, self._server)
class Shadow(rdp.RDPServerObserver):
diff --git a/bin/rdpy-rsrplayer.py b/bin/rdpy-rsrplayer.py
new file mode 100755
index 0000000..f53a0f6
--- /dev/null
+++ b/bin/rdpy-rsrplayer.py
@@ -0,0 +1,93 @@
+#!/usr/bin/python
+#
+# Copyright (c) 2014 Sylvain Peyrefitte
+#
+# This file is part of rdpy.
+#
+# rdpy is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+#
+"""
+rsr file player
+"""
+
+import sys, os, getopt, socket
+
+from PyQt4 import QtGui, QtCore
+
+from rdpy.core import log, rsr
+from rdpy.ui.qt4 import RDPBitmapToQtImage
+log._LOG_LEVEL = log.Level.INFO
+
+class QRsrPlayer(QtGui.QWidget):
+ def __init__(self):
+ self._refresh = []
+ #buffer image
+ self._buffer = QtGui.QImage(width, height, QtGui.QImage.Format_RGB32)
+ self._f = rsr.createReader("/tmp/toto")
+ self._nextEvent = self._f.next()
+
+ def next(self):
+ #if self._nextEvent.type.value = rsr.EventType.UPDATE:
+ # self.notifyImage(self._nextEvent.event., y, RDPBitmapToQtImage(width, height, bitsPerPixel, isCompress, data), width, height)
+ self._nextEvent = self._f.next()
+ QtCore.QTimer.singleShot(0,)
+
+ def notifyImage(self, x, y, qimage, width, height):
+ """
+ @summary: Function call from QAdaptor
+ @param x: x position of new image
+ @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))
+ #force update
+ self.update()
+
+ def paintEvent(self, e):
+ """
+ @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 help():
+ print "Usage: rdpy-rsrplayer [options] ip[:port]"
+
+if __name__ == '__main__':
+
+ #default script argument
+
+ try:
+ opts, args = getopt.getopt(sys.argv[1:], "h")
+ except getopt.GetoptError:
+ help()
+ for opt, arg in opts:
+ if opt == "-h":
+ help()
+ sys.exit()
+
+ filepath = args[0]
+ #create application
+ app = QtGui.QApplication(sys.argv)
+ app.exec_()
\ No newline at end of file
diff --git a/rdpy/core/rsr.py b/rdpy/core/rsr.py
new file mode 100644
index 0000000..06143ac
--- /dev/null
+++ b/rdpy/core/rsr.py
@@ -0,0 +1,106 @@
+#
+# Copyright (c) 2014-2015 Sylvain Peyrefitte
+#
+# This file is part of rdpy.
+#
+# rdpy is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+#
+
+"""
+Remote Session Recorder File format
+Private protocol format to save events
+"""
+
+from rdpy.core.type import CompositeType, FactoryType, UInt8, UInt16Le, UInt32Le, String, sizeof, Stream
+from rdpy.core import log, error
+import time
+
+class EventType(object):
+ UPDATE = 0x00000001
+
+class UpdateFormat(object):
+ RAW = 0x01
+ BMP = 0x02
+
+class Event(CompositeType):
+ """
+ @summary: A recorded event
+ """
+ def __init__(self, event = None):
+ CompositeType.__init__(self)
+ self.type = UInt16Le(lambda:event.__class__._TYPE_)
+ self.timestamp = UInt32Le()
+ self.length = UInt32Le(lambda:(sizeof(self) - 12))
+
+ def EventFactory():
+ """
+ @summary: Closure for event factory
+ """
+ for c in [UpdateEvent]:
+ if self.type.value == c._TYPE_:
+ return c(readLen = self.length)
+ log.debug("unknown event type : %s"%hex(self.type.value))
+ #read entire packet
+ return String(readLen = self.length - 4)
+
+ if event is None:
+ event = FactoryType(EventFactory)
+ elif not "_TYPE_" in event.__class__.__dict__:
+ raise error.InvalidExpectedDataException("Try to send an invalid event block")
+
+ self.event = event
+
+class UpdateEvent(CompositeType):
+ _TYPE_ = EventType.UPDATE
+ def __init__(self, readLen = None):
+ CompositeType.__init__(self, readLen = readLen)
+ self.destLeft = UInt16Le()
+ self.destTop = UInt16Le()
+ self.destRight = UInt16Le()
+ self.destBottom = UInt16Le()
+ self.width = UInt16Le()
+ self.height = UInt16Le()
+ self.bpp = UInt8()
+ self.format = UInt8()
+ self.length = UInt32Le(lambda:sizeof(self.data))
+ self.data = String(readLen = self.length)
+
+class FileRecorder(object):
+ def __init__(self, f):
+ self._file = f
+ self._createTime = int(time.time() * 1000)
+
+ def add(self, event):
+ e = Event(event)
+ e.timestamp.value = int(time.time() * 1000) - self._createTime
+
+ s = Stream()
+ s.writeType(e)
+
+ self._file.write(s.getvalue())
+
+class FileReader(object):
+ def __init__(self, f):
+ self._s = Stream(f)
+
+ def next(self):
+ e = Event()
+ self._s.readType(e)
+ return e
+
+def createRecorder(path):
+ return FileRecorder(open(path, "wb"))
+
+def createReader(path):
+ return FileReader(open(path, "rb"))
\ No newline at end of file
diff --git a/rdpy/ui/qt4.py b/rdpy/ui/qt4.py
index 4cdac0b..f3297f3 100644
--- a/rdpy/ui/qt4.py
+++ b/rdpy/ui/qt4.py
@@ -185,7 +185,7 @@ class RFBClientQt(RFBClientObserver, QAdaptor):
#do something maybe a message
pass
-def RDPBitmapToQtImage(destLeft, width, height, bitsPerPixel, isCompress, data):
+def RDPBitmapToQtImage(width, height, bitsPerPixel, isCompress, data):
"""
@summary: Bitmap transformation to Qt object
@param width: width of bitmap
@@ -309,7 +309,7 @@ class RDPClientQt(RDPClientObserver, QAdaptor):
@param isCompress: use RLE compression
@param data: bitmap data
"""
- image = RDPBitmapToQtImage(destLeft, width, height, bitsPerPixel, isCompress, data);
+ image = RDPBitmapToQtImage(width, height, bitsPerPixel, isCompress, data);
#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)