add first step of rsr support

This commit is contained in:
speyrefitte
2015-01-07 18:32:16 +01:00
parent 522eda39e8
commit 9a4f5f254c
5 changed files with 223 additions and 10 deletions

View File

@@ -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():

View File

@@ -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):

93
bin/rdpy-rsrplayer.py Executable file
View File

@@ -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 <http://www.gnu.org/licenses/>.
#
"""
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_()

106
rdpy/core/rsr.py Normal file
View File

@@ -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 <http://www.gnu.org/licenses/>.
#
"""
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"))

View File

@@ -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)