add first step of rsr support
This commit is contained in:
@@ -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():
|
||||
|
||||
@@ -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
93
bin/rdpy-rsrplayer.py
Executable 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
106
rdpy/core/rsr.py
Normal 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"))
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user