From 878637a3f141961fb619d4f6d17b13c31f63b0b1 Mon Sep 17 00:00:00 2001 From: speyrefitte Date: Tue, 9 Jun 2015 18:11:36 +0200 Subject: [PATCH 01/20] add missing links (cherry picked from commit 1e2cf2ef88b59bf9adfe888e3ffb5b893b3373bd) --- rdpy/protocol/rdp/sec.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/rdpy/protocol/rdp/sec.py b/rdpy/protocol/rdp/sec.py index 7a49b5a2..ca675363 100644 --- a/rdpy/protocol/rdp/sec.py +++ b/rdpy/protocol/rdp/sec.py @@ -24,7 +24,7 @@ import sha, md5 import lic, tpkt from t125 import gcc, mcs -from rdpy.core.type import CompositeType, CallableValue, Stream, UInt32Le, UInt16Le, String, sizeof, UInt8 +from rdpy.core.type import CompositeType, CallableValue, Stream, UInt32Le, UInt16Le, String, sizeof from rdpy.core.layer import LayerAutomata, IStreamSender from rdpy.core.error import InvalidExpectedDataException from rdpy.core import log @@ -56,6 +56,7 @@ class SecurityFlag(object): class InfoFlag(object): """ Client capabilities informations + @see: https://msdn.microsoft.com/en-us/library/cc240475.aspx """ INFO_MOUSE = 0x00000001 INFO_DISABLECTRLALTDEL = 0x00000002 @@ -80,6 +81,7 @@ class InfoFlag(object): class PerfFlag(object): """ Network performances flag + @see: https://msdn.microsoft.com/en-us/library/cc240476.aspx """ PERF_DISABLE_WALLPAPER = 0x00000001 PERF_DISABLE_FULLWINDOWDRAG = 0x00000002 From 542b66d977fd3854b89c34509caf976da52ae879 Mon Sep 17 00:00:00 2001 From: Bruno Rodrigues Date: Mon, 29 Mar 2021 13:00:32 +0100 Subject: [PATCH 02/20] prints with parenthesis for python3 --- bin/rdpy-rdpclient.py | 4 ++-- bin/rdpy-rdphoneypot.py | 4 ++-- bin/rdpy-rdpscreenshot.py | 10 +++++----- bin/rdpy-rssplayer.py | 2 +- bin/rdpy-vncscreenshot.py | 6 +++--- rdpy/core/log.py | 2 +- rdpy/security/pyDes.py | 10 +++++----- 7 files changed, 19 insertions(+), 19 deletions(-) diff --git a/bin/rdpy-rdpclient.py b/bin/rdpy-rdpclient.py index 660bfa4f..35c0d3f2 100755 --- a/bin/rdpy-rdpclient.py +++ b/bin/rdpy-rdpclient.py @@ -211,7 +211,7 @@ def autoDetectKeyboardLayout(): return "en" def help(): - print """ + print(""" Usage: rdpy-rdpclient [options] ip[:port]" \t-u: user name \t-p: password @@ -222,7 +222,7 @@ def help(): \t-k: keyboard layout [en|fr] [default : en] \t-o: optimized session (disable costly effect) [default : False] \t-r: rss_filepath Recorded Session Scenario [default : None] - """ + """) if __name__ == '__main__': diff --git a/bin/rdpy-rdphoneypot.py b/bin/rdpy-rdphoneypot.py index 575215ba..7e67b3e5 100755 --- a/bin/rdpy-rdphoneypot.py +++ b/bin/rdpy-rdphoneypot.py @@ -140,14 +140,14 @@ def help(): """ @summary: Print help in console """ - print """ + print(""" Usage: rdpy-rdphoneypot.py [-L logfile] [-l listen_port default 3389] [-k private_key_file_path (mandatory for SSL)] [-c certificate_file_path (mandatory for SSL)] rss_filepath(1..n) - """ + """) if __name__ == '__main__': listen = "3389" diff --git a/bin/rdpy-rdpscreenshot.py b/bin/rdpy-rdpscreenshot.py index b87008ab..0f11c4db 100755 --- a/bin/rdpy-rdpscreenshot.py +++ b/bin/rdpy-rdpscreenshot.py @@ -192,11 +192,11 @@ def main(width, height, path, timeout, hosts): def help(): - print "Usage: rdpy-rdpscreenshot [options] ip[:port]" - print "\t-w: width of screen default value is 1024" - print "\t-l: height of screen default value is 800" - print "\t-o: file path of screenshot default(/tmp/rdpy-rdpscreenshot.jpg)" - print "\t-t: timeout of connection without any updating order (default is 2s)" + print("Usage: rdpy-rdpscreenshot [options] ip[:port]") + print("\t-w: width of screen default value is 1024") + print("\t-l: height of screen default value is 800") + print("\t-o: file path of screenshot default(/tmp/rdpy-rdpscreenshot.jpg)") + print("\t-t: timeout of connection without any updating order (default is 2s)") if __name__ == '__main__': # default script argument diff --git a/bin/rdpy-rssplayer.py b/bin/rdpy-rssplayer.py index 82f26a78..5c4529c5 100755 --- a/bin/rdpy-rssplayer.py +++ b/bin/rdpy-rssplayer.py @@ -70,7 +70,7 @@ def __init__(self): self.setGeometry(0, 0, 800, 600) def help(): - print "Usage: rdpy-rssplayer [-h] rss_filepath" + print("Usage: rdpy-rssplayer [-h] rss_filepath") def start(widget, rssFile): loop(widget, rssFile, rssFile.nextEvent()) diff --git a/bin/rdpy-vncscreenshot.py b/bin/rdpy-vncscreenshot.py index a3cb7ecf..8d263526 100755 --- a/bin/rdpy-vncscreenshot.py +++ b/bin/rdpy-vncscreenshot.py @@ -132,9 +132,9 @@ def onClose(self): return ScreenShotObserver(controller, self._path) def help(): - print "Usage: rdpy-vncscreenshot [options] ip[:port]" - print "\t-o: file path of screenshot default(/tmp/rdpy-vncscreenshot.jpg)" - print "\t-p: password for VNC Session" + print("Usage: rdpy-vncscreenshot [options] ip[:port]") + print("\t-o: file path of screenshot default(/tmp/rdpy-vncscreenshot.jpg)") + print("\t-p: password for VNC Session") if __name__ == '__main__': #default script argument diff --git a/rdpy/core/log.py b/rdpy/core/log.py index cabd7752..d8ebbb84 100644 --- a/rdpy/core/log.py +++ b/rdpy/core/log.py @@ -44,7 +44,7 @@ def log(message): f = open(_LOG_FILE, "a+") f.write("%s\n"%message) f.close() - print "[*] %s"%message + print("[*] %s"%message) def error(message): """ diff --git a/rdpy/security/pyDes.py b/rdpy/security/pyDes.py index 0f307e78..2f2c1b2c 100644 --- a/rdpy/security/pyDes.py +++ b/rdpy/security/pyDes.py @@ -71,8 +71,8 @@ # data = b"Please encrypt my data" # k = des(b"DESCRYPT", CBC, b"\0\0\0\0\0\0\0\0", pad=None, padmode=PAD_PKCS5) d = k.encrypt(data) -print "Encrypted: %r" % d -print "Decrypted: %r" % k.decrypt(d) +print("Encrypted: %r" % d) +print("Decrypted: %r" % k.decrypt(d)) assert k.decrypt(d, padmode=PAD_PKCS5) == data @@ -574,7 +574,7 @@ def crypt(self, data, crypt_type): raise ValueError("Invalid data length, data must be a multiple of " + str(self.block_size) + " bytes\n. Try setting the optional padding character") else: data += (self.block_size - (len(data) % self.block_size)) * self.getPadding() - # print "Len of data: %f" % (len(data) / self.block_size) + # print("Len of data: %f" % (len(data) / self.block_size)) if self.getMode() == CBC: if self.getIV(): @@ -592,7 +592,7 @@ def crypt(self, data, crypt_type): # Test code for caching encryption results #lines += 1 #if dict.has_key(data[i:i+8]): - #print "Cached result for: %s" % data[i:i+8] + # # print("Cached result for: %s" % data[i:i+8]) # cached += 1 # result.append(dict[data[i:i+8]]) # i += 8 @@ -631,7 +631,7 @@ def crypt(self, data, crypt_type): #dict[data[i:i+8]] = d i += 8 - # print "Lines: %d, cached: %d" % (lines, cached) + # print("Lines: %d, cached: %d" % (lines, cached)) # Return the full crypted string if _pythonMajorVersion < 3: From 71cf592debd5bee386544d3f770d82a66acfa703 Mon Sep 17 00:00:00 2001 From: Bruno Rodrigues Date: Mon, 29 Mar 2021 13:14:35 +0100 Subject: [PATCH 03/20] update rle.c --- ext/rle.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/ext/rle.c b/ext/rle.c index 2d7da8db..4359375e 100644 --- a/ext/rle.c +++ b/ext/rle.c @@ -939,9 +939,18 @@ static PyMethodDef rle_methods[] = {NULL, NULL, 0, NULL} }; +static struct PyModuleDef rle = +{ + PyModuleDef_HEAD_INIT, + "rle", /* name of module */ + "", /* module documentation, may be NULL */ + -1, /* size of per-interpreter state of the module, or -1 if the module keeps state in global variables. */ + rle_methods +}; + PyMODINIT_FUNC -initrle(void) +PyInit_rle(void) { - (void) Py_InitModule("rle", rle_methods); + (void) PyModule_Create(&rle); } From 2c20ee988113e36ce4b8633bbfde4a423b623f31 Mon Sep 17 00:00:00 2001 From: Bruno Rodrigues Date: Mon, 29 Mar 2021 13:19:43 +0100 Subject: [PATCH 04/20] rename qt4 to qt5 --- bin/rdpy-rdpclient.py | 14 +++++++------- bin/rdpy-rdpscreenshot.py | 12 ++++++------ bin/rdpy-rssplayer.py | 6 +++--- bin/rdpy-vncclient.py | 12 ++++++------ bin/rdpy-vncscreenshot.py | 12 ++++++------ rdpy/ui/{qt4.py => qt5.py} | 4 ++-- rdpy/ui/view.py | 2 +- setup.py | 2 +- 8 files changed, 32 insertions(+), 32 deletions(-) rename rdpy/ui/{qt4.py => qt5.py} (99%) diff --git a/bin/rdpy-rdpclient.py b/bin/rdpy-rdpclient.py index 35c0d3f2..b5e8bbdf 100755 --- a/bin/rdpy-rdpclient.py +++ b/bin/rdpy-rdpclient.py @@ -23,8 +23,8 @@ import sys, os, getopt, socket -from PyQt4 import QtGui, QtCore -from rdpy.ui.qt4 import RDPClientQt +from PyQt5 import QtGui, QtCore, QtWidgets +from rdpy.ui.qt5 import RDPClientQt from rdpy.protocol.rdp import rdp from rdpy.core.error import RDPSecurityNegoFail from rdpy.core import rss @@ -270,11 +270,11 @@ def help(): ip, port = args[0], "3389" #create application - app = QtGui.QApplication(sys.argv) - - #add qt4 reactor - import qt4reactor - qt4reactor.install() + app = QtWidgets.QApplication(sys.argv) + + #add qt5 reactor + import qt5reactor + qt5reactor.install() if fullscreen: width = QtGui.QDesktopWidget().screenGeometry().width() diff --git a/bin/rdpy-rdpscreenshot.py b/bin/rdpy-rdpscreenshot.py index 0f11c4db..43abcfda 100755 --- a/bin/rdpy-rdpscreenshot.py +++ b/bin/rdpy-rdpscreenshot.py @@ -27,9 +27,9 @@ import os import sys -from PyQt4 import QtCore, QtGui +from PyQt5 import QtCore, QtGui, QtWidgets from rdpy.protocol.rdp import rdp -from rdpy.ui.qt4 import RDPBitmapToQtImage +from rdpy.ui.qt5 import RDPBitmapToQtImage import rdpy.core.log as log from rdpy.core.error import RDPSecurityNegoFail from twisted.internet import task @@ -170,11 +170,11 @@ def main(width, height, path, timeout, hosts): @return: {list(tuple(ip, port, Failure instance)} list of connection state """ #create application - app = QtGui.QApplication(sys.argv) + app = QtWidgets.QApplication(sys.argv) - #add qt4 reactor - import qt4reactor - qt4reactor.install() + #add qt5 reactor + import qt5reactor + qt5reactor.install() from twisted.internet import reactor diff --git a/bin/rdpy-rssplayer.py b/bin/rdpy-rssplayer.py index 5c4529c5..3eeeadc2 100755 --- a/bin/rdpy-rssplayer.py +++ b/bin/rdpy-rssplayer.py @@ -23,10 +23,10 @@ import sys, os, getopt, socket -from PyQt4 import QtGui, QtCore +from PyQt5 import QtGui, QtCore, QtWidgets from rdpy.core import log, rss -from rdpy.ui.qt4 import QRemoteDesktop, RDPBitmapToQtImage +from rdpy.ui.qt5 import QRemoteDesktop, RDPBitmapToQtImage from rdpy.core.scancode import scancodeToChar log._LOG_LEVEL = log.Level.INFO @@ -115,7 +115,7 @@ def loop(widget, rssFile, nextEvent): filepath = args[0] #create application - app = QtGui.QApplication(sys.argv) + app = QtWidgets.QApplication(sys.argv) mainWindow = RssPlayerWindow() mainWindow.show() diff --git a/bin/rdpy-vncclient.py b/bin/rdpy-vncclient.py index 5a6e6b84..d1c9f3c2 100755 --- a/bin/rdpy-vncclient.py +++ b/bin/rdpy-vncclient.py @@ -23,8 +23,8 @@ """ import sys, os, getopt -from PyQt4 import QtGui -from rdpy.ui.qt4 import RFBClientQt +from PyQt5 import QtGui, QtWidgets +from rdpy.ui.qt5 import RFBClientQt from rdpy.protocol.rfb import rfb import rdpy.core.log as log @@ -98,11 +98,11 @@ def clientConnectionFailed(self, connector, reason): ip, port = args[0], "5900" #create application - app = QtGui.QApplication(sys.argv) + app = QtWidgets.QApplication(sys.argv) - #add qt4 reactor - import qt4reactor - qt4reactor.install() + #add qt5 reactor + import qt5reactor + qt5reactor.install() from twisted.internet import reactor reactor.connectTCP(ip, int(port), RFBClientQtFactory(password)) diff --git a/bin/rdpy-vncscreenshot.py b/bin/rdpy-vncscreenshot.py index 8d263526..b91addc3 100755 --- a/bin/rdpy-vncscreenshot.py +++ b/bin/rdpy-vncscreenshot.py @@ -24,10 +24,10 @@ """ import sys, os, getopt -from PyQt4 import QtCore, QtGui +from PyQt5 import QtCore, QtGui, QtWidgets from rdpy.protocol.rfb import rfb import rdpy.core.log as log -from rdpy.ui.qt4 import qtImageFormatFromRFBPixelFormat +from rdpy.ui.qt5 import qtImageFormatFromRFBPixelFormat from twisted.internet import task #set log level @@ -155,11 +155,11 @@ def help(): password = arg #create application - app = QtGui.QApplication(sys.argv) + app = QtWidgets.QApplication(sys.argv) - #add qt4 reactor - import qt4reactor - qt4reactor.install() + #add qt5 reactor + import qt5reactor + qt5reactor.install() from twisted.internet import reactor diff --git a/rdpy/ui/qt4.py b/rdpy/ui/qt5.py similarity index 99% rename from rdpy/ui/qt4.py rename to rdpy/ui/qt5.py index 237f974f..b9d2cec0 100644 --- a/rdpy/ui/qt4.py +++ b/rdpy/ui/qt5.py @@ -23,7 +23,7 @@ QRemoteDesktop is a widget use for render in rdpy """ -from PyQt4 import QtGui, QtCore +from PyQt5 import QtGui, QtCore, QtWidgets from rdpy.protocol.rfb.rfb import RFBClientObserver from rdpy.protocol.rdp.rdp import RDPClientObserver from rdpy.core.error import CallPureVirtualFuntion @@ -330,7 +330,7 @@ def onClose(self): #do something maybe a message -class QRemoteDesktop(QtGui.QWidget): +class QRemoteDesktop(QtWidgets.QWidget): """ @summary: Qt display widget """ diff --git a/rdpy/ui/view.py b/rdpy/ui/view.py index 7976590e..bc9f63cc 100644 --- a/rdpy/ui/view.py +++ b/rdpy/ui/view.py @@ -21,7 +21,7 @@ Fake widget """ from rdpy.core.error import CallPureVirtualFuntion -from PyQt4 import QtGui, QtCore +from PyQt5 import QtGui, QtCore class KeyCode(object): diff --git a/setup.py b/setup.py index ed310902..8825335d 100644 --- a/setup.py +++ b/setup.py @@ -40,7 +40,7 @@ 'twisted', 'pyopenssl', 'service_identity', - 'qt4reactor', + 'qt5reactor', 'rsa', 'pyasn1' ], From fba6c21cf3fd4b8ec807e149ee2e59a7c7b5d5ec Mon Sep 17 00:00:00 2001 From: Bruno Rodrigues Date: Mon, 29 Mar 2021 13:27:05 +0100 Subject: [PATCH 05/20] single cmd line help path - show and exit --- bin/rdpy-rdpclient.py | 2 +- bin/rdpy-rdphoneypot.py | 2 +- bin/rdpy-rdpscreenshot.py | 2 +- bin/rdpy-rssplayer.py | 2 +- bin/rdpy-vncclient.py | 2 +- bin/rdpy-vncscreenshot.py | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/bin/rdpy-rdpclient.py b/bin/rdpy-rdpclient.py index b5e8bbdf..14fef74f 100755 --- a/bin/rdpy-rdpclient.py +++ b/bin/rdpy-rdpclient.py @@ -240,7 +240,7 @@ def help(): try: opts, args = getopt.getopt(sys.argv[1:], "hfou:p:d:w:l:k:r:") except getopt.GetoptError: - help() + opts = [('-h', '')] for opt, arg in opts: if opt == "-h": help() diff --git a/bin/rdpy-rdphoneypot.py b/bin/rdpy-rdphoneypot.py index 7e67b3e5..69686d1f 100755 --- a/bin/rdpy-rdphoneypot.py +++ b/bin/rdpy-rdphoneypot.py @@ -158,7 +158,7 @@ def help(): try: opts, args = getopt.getopt(sys.argv[1:], "hl:k:c:L:") except getopt.GetoptError: - help() + opts = [('-h', '')] for opt, arg in opts: if opt == "-h": help() diff --git a/bin/rdpy-rdpscreenshot.py b/bin/rdpy-rdpscreenshot.py index 43abcfda..956621e0 100755 --- a/bin/rdpy-rdpscreenshot.py +++ b/bin/rdpy-rdpscreenshot.py @@ -208,7 +208,7 @@ def help(): try: opts, args = getopt.getopt(sys.argv[1:], "hw:l:o:t:") except getopt.GetoptError: - help() + opts = [('-h', '')] for opt, arg in opts: if opt == "-h": help() diff --git a/bin/rdpy-rssplayer.py b/bin/rdpy-rssplayer.py index 3eeeadc2..ae59d184 100755 --- a/bin/rdpy-rssplayer.py +++ b/bin/rdpy-rssplayer.py @@ -107,7 +107,7 @@ def loop(widget, rssFile, nextEvent): try: opts, args = getopt.getopt(sys.argv[1:], "h") except getopt.GetoptError: - help() + opts = [('-h', '')] for opt, arg in opts: if opt == "-h": help() diff --git a/bin/rdpy-vncclient.py b/bin/rdpy-vncclient.py index d1c9f3c2..f0e081d1 100755 --- a/bin/rdpy-vncclient.py +++ b/bin/rdpy-vncclient.py @@ -84,7 +84,7 @@ def clientConnectionFailed(self, connector, reason): try: opts, args = getopt.getopt(sys.argv[1:], "hp:") except getopt.GetoptError: - help() + opts = [('-h', '')] for opt, arg in opts: if opt == "-h": help() diff --git a/bin/rdpy-vncscreenshot.py b/bin/rdpy-vncscreenshot.py index b91addc3..3d2fd11b 100755 --- a/bin/rdpy-vncscreenshot.py +++ b/bin/rdpy-vncscreenshot.py @@ -144,7 +144,7 @@ def help(): try: opts, args = getopt.getopt(sys.argv[1:], "hp:o:") except getopt.GetoptError: - help() + opts = [('-h', '')] for opt, arg in opts: if opt == "-h": help() From 94b47976379da76b2eb05053dd8bf8145b5edab0 Mon Sep 17 00:00:00 2001 From: Bruno Rodrigues Date: Mon, 29 Mar 2021 14:19:44 +0100 Subject: [PATCH 06/20] python3 import full path instead of just relative --- rdpy/core/layer.py | 2 +- rdpy/core/type.py | 2 +- rdpy/protocol/rdp/lic.py | 4 ++-- rdpy/protocol/rdp/nla/ntlm.py | 2 +- rdpy/protocol/rdp/pdu/data.py | 2 +- rdpy/protocol/rdp/pdu/layer.py | 2 +- rdpy/protocol/rdp/rdp.py | 18 ++++++++---------- rdpy/protocol/rdp/sec.py | 6 +++--- rdpy/protocol/rdp/t125/gcc.py | 4 ++-- rdpy/protocol/rdp/t125/mcs.py | 4 ++-- 10 files changed, 22 insertions(+), 24 deletions(-) diff --git a/rdpy/core/layer.py b/rdpy/core/layer.py index 7194495b..8bc848ef 100644 --- a/rdpy/core/layer.py +++ b/rdpy/core/layer.py @@ -107,7 +107,7 @@ def setNextState(self, callback = None): from twisted.internet import protocol from twisted.internet.abstract import FileDescriptor #first that handle stream -from type import Stream +from rdpy.core.type import Stream class RawLayerClientFactory(protocol.ClientFactory): """ diff --git a/rdpy/core/type.py b/rdpy/core/type.py index 260c6727..8356c0df 100644 --- a/rdpy/core/type.py +++ b/rdpy/core/type.py @@ -26,7 +26,7 @@ import struct from copy import deepcopy -from StringIO import StringIO +from io import StringIO from rdpy.core.error import InvalidExpectedDataException, InvalidSize, CallPureVirtualFuntion, InvalidValue import rdpy.core.log as log diff --git a/rdpy/protocol/rdp/lic.py b/rdpy/protocol/rdp/lic.py index f22f4d40..cef19241 100644 --- a/rdpy/protocol/rdp/lic.py +++ b/rdpy/protocol/rdp/lic.py @@ -25,8 +25,8 @@ from rdpy.core.type import CompositeType, CallableValue, UInt8, UInt16Le, UInt32Le, String, sizeof, FactoryType, ArrayType, Stream from rdpy.core.error import InvalidExpectedDataException import rdpy.core.log as log -import sec -from t125 import gcc +from rdpy.protocol.rdp import sec +from rdpy.protocol.rdp.t125 import gcc from rdpy.security import rc4 from rdpy.security import rsa_wrapper as rsa diff --git a/rdpy/protocol/rdp/nla/ntlm.py b/rdpy/protocol/rdp/nla/ntlm.py index 3d541f64..fc2827b2 100644 --- a/rdpy/protocol/rdp/nla/ntlm.py +++ b/rdpy/protocol/rdp/nla/ntlm.py @@ -23,7 +23,7 @@ """ import hashlib, hmac, struct, datetime -import sspi +from rdpy.protocol.rdp.nla import sspi import rdpy.security.pyDes as pyDes import rdpy.security.rc4 as rc4 from rdpy.security.rsa_wrapper import random diff --git a/rdpy/protocol/rdp/pdu/data.py b/rdpy/protocol/rdp/pdu/data.py index 509cc6cd..48936b60 100644 --- a/rdpy/protocol/rdp/pdu/data.py +++ b/rdpy/protocol/rdp/pdu/data.py @@ -25,7 +25,7 @@ from rdpy.core.type import CompositeType, CallableValue, String, UInt8, UInt16Le, UInt32Le, sizeof, ArrayType, FactoryType from rdpy.core.error import InvalidExpectedDataException import rdpy.core.log as log -import caps, order +from rdpy.protocol.rdp.pdu import caps, order class PDUType(object): """ diff --git a/rdpy/protocol/rdp/pdu/layer.py b/rdpy/protocol/rdp/pdu/layer.py index aebcd152..05ed07f2 100644 --- a/rdpy/protocol/rdp/pdu/layer.py +++ b/rdpy/protocol/rdp/pdu/layer.py @@ -28,7 +28,7 @@ from rdpy.core.type import ArrayType import rdpy.core.log as log import rdpy.protocol.rdp.tpkt as tpkt -import data, caps +from rdpy.protocol.rdp.pdu import data, caps class PDUClientListener(object): """ diff --git a/rdpy/protocol/rdp/rdp.py b/rdpy/protocol/rdp/rdp.py index 3b486086..0ed7053b 100644 --- a/rdpy/protocol/rdp/rdp.py +++ b/rdpy/protocol/rdp/rdp.py @@ -23,13 +23,11 @@ from rdpy.core import layer from rdpy.core.error import CallPureVirtualFuntion, InvalidValue -import pdu.layer -import pdu.data -import pdu.caps +from rdpy.protocol.rdp.pdu import layer as pdu_layer, data, caps import rdpy.core.log as log -import tpkt, x224, sec -from t125 import mcs, gcc -from nla import cssp, ntlm +from rdpy.protocol.rdp import tpkt, x224, sec +from rdpy.protocol.rdp.t125 import mcs, gcc +from rdpy.protocol.rdp.nla import cssp, ntlm class SecurityLevel(object): """ @@ -39,7 +37,7 @@ class SecurityLevel(object): RDP_LEVEL_SSL = 1 RDP_LEVEL_NLA = 2 -class RDPClientController(pdu.layer.PDUClientListener): +class RDPClientController(pdu_layer.PDUClientListener): """ Manage RDP stack as client """ @@ -47,7 +45,7 @@ def __init__(self): #list of observer self._clientObserver = [] #PDU layer - self._pduLayer = pdu.layer.Client(self) + self._pduLayer = pdu_layer.Client(self) #secure layer self._secLayer = sec.Client(self._pduLayer) #multi channel service @@ -365,7 +363,7 @@ def close(self): """ self._pduLayer.close() -class RDPServerController(pdu.layer.PDUServerListener): +class RDPServerController(pdu_layer.PDUServerListener): """ @summary: Controller use in server side mode """ @@ -379,7 +377,7 @@ def __init__(self, colorDepth, privateKeyFileName = None, certificateFileName = #list of observer self._serverObserver = [] #build RDP protocol stack - self._pduLayer = pdu.layer.Server(self) + self._pduLayer = pdu_layer.Server(self) #secure layer self._secLayer = sec.Server(self._pduLayer) #multi channel service diff --git a/rdpy/protocol/rdp/sec.py b/rdpy/protocol/rdp/sec.py index ca675363..1d6f6f96 100644 --- a/rdpy/protocol/rdp/sec.py +++ b/rdpy/protocol/rdp/sec.py @@ -21,9 +21,9 @@ RDP Standard security layer """ -import sha, md5 -import lic, tpkt -from t125 import gcc, mcs +from hashlib import sha1 as sha, md5 +from rdpy.protocol.rdp import lic, tpkt +from rdpy.protocol.rdp.t125 import gcc, mcs from rdpy.core.type import CompositeType, CallableValue, Stream, UInt32Le, UInt16Le, String, sizeof from rdpy.core.layer import LayerAutomata, IStreamSender from rdpy.core.error import InvalidExpectedDataException diff --git a/rdpy/protocol/rdp/t125/gcc.py b/rdpy/protocol/rdp/t125/gcc.py index 1fa07161..c8bd5412 100644 --- a/rdpy/protocol/rdp/t125/gcc.py +++ b/rdpy/protocol/rdp/t125/gcc.py @@ -22,9 +22,9 @@ http://msdn.microsoft.com/en-us/library/cc240508.aspx """ -import md5 +from hashlib import md5 from rdpy.core.type import UInt8, UInt16Le, UInt32Le, CompositeType, CallableValue, String, Stream, sizeof, FactoryType, ArrayType -import per, mcs +from rdpy.protocol.rdp.t125 import per, mcs from rdpy.core.error import InvalidExpectedDataException from rdpy.core import log from rdpy.security import x509 diff --git a/rdpy/protocol/rdp/t125/mcs.py b/rdpy/protocol/rdp/t125/mcs.py index 78c604ef..a1bcba26 100644 --- a/rdpy/protocol/rdp/t125/mcs.py +++ b/rdpy/protocol/rdp/t125/mcs.py @@ -27,10 +27,10 @@ from rdpy.core.layer import LayerAutomata, IStreamSender, Layer from rdpy.core.type import sizeof, Stream, UInt8, UInt16Le, String from rdpy.core.error import InvalidExpectedDataException, InvalidValue, InvalidSize, CallPureVirtualFuntion -from ber import writeLength +from rdpy.protocol.rdp.t125.ber import writeLength import rdpy.core.log as log -import ber, gcc, per +from rdpy.protocol.rdp.t125 import ber, gcc, per import rdpy.security.rsa_wrapper as rsa class Message(object): From fc7b9638bc77b5a84f0b57e4e8411a67a775a912 Mon Sep 17 00:00:00 2001 From: Bruno Rodrigues Date: Mon, 29 Mar 2021 14:20:04 +0100 Subject: [PATCH 07/20] python3 has_key -> in --- rdpy/core/scancode.py | 2 +- rdpy/core/type.py | 2 +- rdpy/protocol/rdp/nla/ntlm.py | 2 +- rdpy/protocol/rdp/pdu/layer.py | 4 ++-- rdpy/protocol/rdp/t125/mcs.py | 2 +- rdpy/security/pyDes.py | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/rdpy/core/scancode.py b/rdpy/core/scancode.py index 37e27d6c..d877becb 100644 --- a/rdpy/core/scancode.py +++ b/rdpy/core/scancode.py @@ -55,6 +55,6 @@ def scancodeToChar(code): @summary: try to convert native code to char code @return: char """ - if not _SCANCODE_QWERTY_.has_key(code): + if code not in _SCANCODE_QWERTY_: return ""%code return _SCANCODE_QWERTY_[code]; \ No newline at end of file diff --git a/rdpy/core/type.py b/rdpy/core/type.py index 8356c0df..ce0c4361 100644 --- a/rdpy/core/type.py +++ b/rdpy/core/type.py @@ -266,7 +266,7 @@ def mask(self): Because in Python all numbers are Int long or float Cache result in self._mask field """ - if not self.__dict__.has_key("_mask"): + if "_mask" not in self.__dict__: mask = 0xff for _ in range(1, self._typeSize): mask = mask << 8 | 0xff diff --git a/rdpy/protocol/rdp/nla/ntlm.py b/rdpy/protocol/rdp/nla/ntlm.py index fc2827b2..07083ce9 100644 --- a/rdpy/protocol/rdp/nla/ntlm.py +++ b/rdpy/protocol/rdp/nla/ntlm.py @@ -538,7 +538,7 @@ def getAuthenticateMessage(self, s): computeMIC = False ServerName = self._challengeMessage.getTargetInfo() infos = self._challengeMessage.getTargetInfoAsAvPairArray() - if infos.has_key(AvId.MsvAvTimestamp): + if AvId.MsvAvTimestamp in infos: Timestamp = infos[AvId.MsvAvTimestamp] computeMIC = True else: diff --git a/rdpy/protocol/rdp/pdu/layer.py b/rdpy/protocol/rdp/pdu/layer.py index 05ed07f2..35819ca5 100644 --- a/rdpy/protocol/rdp/pdu/layer.py +++ b/rdpy/protocol/rdp/pdu/layer.py @@ -301,7 +301,7 @@ def readDataPDU(self, dataPDU): if dataPDU.pduData.errorInfo.value == 0: return errorMessage = "Unknown code %s"%hex(dataPDU.pduData.errorInfo.value) - if data.ErrorInfo._MESSAGES_.has_key(dataPDU.pduData.errorInfo): + if dataPDU.pduData.errorInfo in data.ErrorInfo._MESSAGES_: errorMessage = data.ErrorInfo._MESSAGES_[dataPDU.pduData.errorInfo] log.error("INFO PDU : %s"%errorMessage) @@ -520,7 +520,7 @@ def readDataPDU(self, dataPDU): """ if dataPDU.shareDataHeader.pduType2.value == data.PDUType2.PDUTYPE2_SET_ERROR_INFO_PDU: errorMessage = "Unknown code %s"%hex(dataPDU.pduData.errorInfo.value) - if data.ErrorInfo._MESSAGES_.has_key(dataPDU.pduData.errorInfo): + if dataPDU.pduData.errorInfo in data.ErrorInfo._MESSAGES_: errorMessage = data.ErrorInfo._MESSAGES_[dataPDU.pduData.errorInfo] log.error("INFO PDU : %s"%errorMessage) diff --git a/rdpy/protocol/rdp/t125/mcs.py b/rdpy/protocol/rdp/t125/mcs.py index a1bcba26..ed05d763 100644 --- a/rdpy/protocol/rdp/t125/mcs.py +++ b/rdpy/protocol/rdp/t125/mcs.py @@ -236,7 +236,7 @@ def recvData(self, data): per.readLength(data) #channel id doesn't match a requested layer - if not self._channels.has_key(channelId): + if channelId not in self._channels: log.error("receive data for an unconnected layer") return diff --git a/rdpy/security/pyDes.py b/rdpy/security/pyDes.py index 2f2c1b2c..ea5dbf06 100644 --- a/rdpy/security/pyDes.py +++ b/rdpy/security/pyDes.py @@ -591,7 +591,7 @@ def crypt(self, data, crypt_type): while i < len(data): # Test code for caching encryption results #lines += 1 - #if dict.has_key(data[i:i+8]): + #if data[i:i+8] in dict: # # print("Cached result for: %s" % data[i:i+8]) # cached += 1 # result.append(dict[data[i:i+8]]) From 53e34b2729c45fadc0766d379e1782038e2f00d2 Mon Sep 17 00:00:00 2001 From: Bruno Rodrigues Date: Mon, 29 Mar 2021 14:51:12 +0100 Subject: [PATCH 08/20] python3 cmp to le gt etc --- rdpy/core/type.py | 51 ++++++++++++++++++++++++++++------------------- 1 file changed, 31 insertions(+), 20 deletions(-) diff --git a/rdpy/core/type.py b/rdpy/core/type.py index ce0c4361..7214a1fd 100644 --- a/rdpy/core/type.py +++ b/rdpy/core/type.py @@ -290,19 +290,25 @@ def __sizeof__(self): @return: typeSize pass in constructor """ return self._typeSize - - def __cmp__(self, other): - """ - @summary: Compare two simple type - Call inner value compare operator - @param other: SimpleType value or try to build same type as self - around value - @return: python value compare - """ + + def _other(self, other): if not isinstance(other, SimpleType): other = self.__class__(other) - return self.value.__cmp__(other.value) - + return other + + def __eq__(self, other): + return self.value.__eq__(self._other(other).value) + def __ne__(self, other): + return self.value.__ne__(self._other(other).value) + def __gt__(self, other): + return self.value.__gt__(self._other(other).value) + def __lt__(self, other): + return self.value.__lt__(self._other(other).value) + def __ge__(self, other): + return self.value.__ge__(self._other(other).value) + def __le__(self, other): + return self.value.__le__(self._other(other).value) + def __invert__(self): """ @summary: Implement not operator @@ -759,15 +765,20 @@ def __init__(self, value = "", readLen = None, conditional = lambda:True, option self._readLen = readLen self._unicode = unicode self._until = until - - def __cmp__(self, other): - """ - @summary: call raw compare value - @param other: other String parameter - @return: if two inner value are equals - """ - return cmp(self.value, other.value) - + + def __eq__(self, other): + return self.value.__eq__(other.value) + def __ne__(self, other): + return self.value.__ne__(other.value) + def __gt__(self, other): + return self.value.__gt__(other.value) + def __lt__(self, other): + return self.value.__lt__(other.value) + def __ge__(self, other): + return self.value.__ge__(other.value) + def __le__(self, other): + return self.value.__le__(other.value) + def __hash__(self): """ @summary: hash function to treat simple type in hash collection From 8927adf9666b68f6d167b742f081efacd62a446f Mon Sep 17 00:00:00 2001 From: Bruno Rodrigues Date: Mon, 29 Mar 2021 16:39:59 +0100 Subject: [PATCH 09/20] python3 iteritems -> items --- rdpy/core/const.py | 2 +- rdpy/protocol/rdp/t125/mcs.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rdpy/core/const.py b/rdpy/core/const.py index 6e8489ad..27f9d5eb 100644 --- a/rdpy/core/const.py +++ b/rdpy/core/const.py @@ -64,7 +64,7 @@ def TypeAttributes(typeClass): @return: class decorator """ def wrapper(cls): - for c_name, c_value in cls.__dict__.iteritems(): + for c_name, c_value in cls.__dict__.items(): if c_name[0] != '_' and not callable(c_value): setattr(cls, c_name, typeClass(c_value)) return cls diff --git a/rdpy/protocol/rdp/t125/mcs.py b/rdpy/protocol/rdp/t125/mcs.py index ed05d763..f6a62969 100644 --- a/rdpy/protocol/rdp/t125/mcs.py +++ b/rdpy/protocol/rdp/t125/mcs.py @@ -194,7 +194,7 @@ def allChannelConnected(self): #connection is done self.setNextState(self.recvData) #try connection on all requested channel - for (channelId, layer) in self._channels.iteritems(): + for (channelId, layer) in self._channels.items(): #use proxy for each channel MCSLayer.MCSProxySender(layer, self, channelId).connect() From a6fc62438ddf868953ec797055ece3db2368fbae Mon Sep 17 00:00:00 2001 From: Bruno Rodrigues Date: Mon, 29 Mar 2021 16:58:42 +0100 Subject: [PATCH 10/20] python3 dict_values is not a list type --- rdpy/protocol/rdp/pdu/layer.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rdpy/protocol/rdp/pdu/layer.py b/rdpy/protocol/rdp/pdu/layer.py index 35819ca5..04f03e2e 100644 --- a/rdpy/protocol/rdp/pdu/layer.py +++ b/rdpy/protocol/rdp/pdu/layer.py @@ -357,7 +357,7 @@ def sendConfirmActivePDU(self): #make active PDU packet confirmActivePDU = data.ConfirmActivePDU() confirmActivePDU.shareId.value = self._shareId - confirmActivePDU.capabilitySets._array = self._clientCapabilities.values() + confirmActivePDU.capabilitySets._array = list(self._clientCapabilities.values()) self.sendPDU(confirmActivePDU) def sendClientFinalizeSynchronizePDU(self): @@ -554,7 +554,7 @@ def sendDemandActivePDU(self): demandActivePDU = data.DemandActivePDU() demandActivePDU.shareId.value = self._shareId - demandActivePDU.capabilitySets._array = self._serverCapabilities.values() + demandActivePDU.capabilitySets._array = list(self._serverCapabilities.values()) self.sendPDU(demandActivePDU) def sendServerFinalizeSynchronizePDU(self): From 29b7f792b2bea653bd133cbb78db2f1ee91d9e2b Mon Sep 17 00:00:00 2001 From: Bruno Rodrigues Date: Mon, 29 Mar 2021 17:02:12 +0100 Subject: [PATCH 11/20] python3 io.BytesIO instead of python2 StringIO --- rdpy/core/layer.py | 2 +- rdpy/core/type.py | 47 ++++++++++++++++++++++++----------- rdpy/protocol/rdp/t125/per.py | 2 +- rdpy/protocol/rfb/rfb.py | 10 ++++---- rdpy/security/pyDes.py | 2 ++ 5 files changed, 42 insertions(+), 21 deletions(-) diff --git a/rdpy/core/layer.py b/rdpy/core/layer.py index 8bc848ef..09d9b4ab 100644 --- a/rdpy/core/layer.py +++ b/rdpy/core/layer.py @@ -179,7 +179,7 @@ def __init__(self, presentation = None): #call parent automata LayerAutomata.__init__(self, presentation) #data buffer received from twisted network layer - self._buffer = "" + self._buffer = b"" #len of next packet pass to next state function self._expectedLen = 0 self._factory = None diff --git a/rdpy/core/type.py b/rdpy/core/type.py index 7214a1fd..e4734531 100644 --- a/rdpy/core/type.py +++ b/rdpy/core/type.py @@ -26,9 +26,10 @@ import struct from copy import deepcopy -from io import StringIO +from io import BytesIO from rdpy.core.error import InvalidExpectedDataException, InvalidSize, CallPureVirtualFuntion, InvalidValue import rdpy.core.log as log +from os import SEEK_END def sizeof(element): """ @@ -103,7 +104,7 @@ def read(self, s): #check constant value if old != self: #rollback read value - s.pos -= sizeof(self) + s._pos(s._pos() - sizeof(self)) raise InvalidExpectedDataException("%s const value expected %s != %s"%(self.__class__, old.value, self.value)) def __read__(self, s): @@ -203,6 +204,9 @@ def __init__(self, structFormat, typeSize, signed, value, conditional = lambda:T self._structFormat = structFormat Type.__init__(self, conditional = conditional, optional = optional, constant = constant) CallableValue.__init__(self, value) + + def __str__(self): + return f"{self.value}" def __getValue__(self): """ @@ -468,7 +472,7 @@ def __read__(self, s): #read is ok but read out of bound if not self._readLen is None and readLen > self._readLen.value: #roll back - s.pos -= sizeof(self.__dict__[name]) + s._pos(s._pos() - sizeof(self.__dict__[name])) #and notify if not optional if not self.__dict__[name]._optional: raise InvalidSize("Impossible to read type %s : read length is too small"%(self.__class__)) @@ -479,7 +483,7 @@ def __read__(self, s): for tmpName in self._typeName: if tmpName == name: break - s.pos -= sizeof(self.__dict__[tmpName]) + s._pos(s._pos() - sizeof(self.__dict__[tmpName])) raise e if not self._readLen is None and readLen < self._readLen.value: @@ -791,7 +795,7 @@ def __str__(self): @summary: call when str function is call @return: inner python string """ - return self.value + return self.value.decode("utf-8", 'replace') if type(self.value) == bytes else self.value def __write__(self, s): """ @@ -805,10 +809,11 @@ def __write__(self, s): if not self._until is None: toWrite += self._until + value_bytes = self.value.encode("utf-8") if hasattr(self.value, 'encode') else self.value if self._unicode: - s.write(encodeUnicode(self.value)) + s.write(encodeUnicode(value_bytes)) else: - s.write(self.value) + s.write(value_bytes) def __read__(self, s): """ @@ -819,7 +824,7 @@ def __read__(self, s): """ if self._readLen is None: if self._until is None: - self.value = s.getvalue()[s.pos:] + self.value = s.getvalue()[s._pos():] else: self.value = "" while self.value[-len(self._until):] != self._until and s.dataLen() != 0: @@ -847,7 +852,7 @@ def encodeUnicode(s): @param s: str python @return: unicode string """ - return "".join([c + "\x00" for c in s]) + "\x00\x00" + return b"".join([ bytes([(c if type(c)==int else ord(c))]) + b"\x00" for c in s]) + b"\x00\x00" def decodeUnicode(s): """ @@ -863,22 +868,36 @@ def decodeUnicode(s): i += 1 return r -class Stream(StringIO): +class Stream(BytesIO): """ @summary: Stream use to read all types """ + + def _pos(self, pos=None): + if pos is not None: + self.seek(pos) + return self.tell() + + def _len(self): + pos = self.tell() + self.seek(0, SEEK_END) + end = self.tell() + self.seek(pos) + return end + + def dataLen(self): """ @return: not yet read length """ - return self.len - self.pos + return self._len() - self._pos() def readLen(self): """ @summary: compute already read size @return: read size of stream """ - return self.pos + return self._pos() def readType(self, value): """ @@ -897,7 +916,7 @@ def readType(self, value): for tmpElement in value: if tmpElement == element: break - self.pos -= sizeof(tmpElement) + self._pos(self._pos() - sizeof(tmpElement)) raise e return @@ -913,7 +932,7 @@ def readNextType(self, t): @param t: Type element """ self.readType(t) - self.pos -= sizeof(t) + self._pos(self._pos() - sizeof(t)) def writeType(self, value): """ diff --git a/rdpy/protocol/rdp/t125/per.py b/rdpy/protocol/rdp/t125/per.py index 6af23885..35e4d205 100644 --- a/rdpy/protocol/rdp/t125/per.py +++ b/rdpy/protocol/rdp/t125/per.py @@ -300,6 +300,6 @@ def writeOctetStream(oStr, minValue = 0): result = [] for i in range(0, length): - result.append(UInt8(ord(oStr[i]))) + result.append(UInt8(oStr[i] if type(oStr[i])==int else ord(oStr[i]))) return (writeLength(mlength), tuple(result)) \ No newline at end of file diff --git a/rdpy/protocol/rfb/rfb.py b/rdpy/protocol/rfb/rfb.py index b43cfa01..b70ab845 100644 --- a/rdpy/protocol/rfb/rfb.py +++ b/rdpy/protocol/rfb/rfb.py @@ -225,14 +225,14 @@ def expectedBody(self, data): are received """ bodyLen = None - if data.len == 1: + if data._len() == 1: bodyLen = UInt8() - elif data.len == 2: + elif data._len() == 2: bodyLen = UInt16Be() - elif data.len == 4: + elif data._len() == 4: bodyLen = UInt32Be() else: - log.error("invalid header length") + log.error(f"invalid header length {data._len()}") return data.readType(bodyLen) self.expect(bodyLen.value, self._callbackBody) @@ -361,7 +361,7 @@ def recvServerName(self, data): @param data: Stream that contains well formed packet """ data.readType(self._serverName) - log.info("Server name %s"%str(self._serverName)) + log.info(f"Server name {self._serverName}") #end of handshake #send pixel format self.sendPixelFormat(self._pixelFormat) diff --git a/rdpy/security/pyDes.py b/rdpy/security/pyDes.py index ea5dbf06..412ec445 100644 --- a/rdpy/security/pyDes.py +++ b/rdpy/security/pyDes.py @@ -419,6 +419,8 @@ def __String_to_BitList(self, data): # Turn the strings into integers. Python 3 uses a bytes # class, which already has this behaviour. data = [ord(c) for c in data] + # String is list of single-string chars ; BytesIO is list of int chars + data = [c if type(c) == int else ord(c) for c in data] l = len(data) * 8 result = [0] * l pos = 0 From 8ffdbaee9bd72e1c6490d0e19819e7c4e8c4dd7c Mon Sep 17 00:00:00 2001 From: Bruno Rodrigues Date: Mon, 29 Mar 2021 17:03:17 +0100 Subject: [PATCH 12/20] python3 integer division // instead of / auto-casting to float --- bin/rdpy-rdphoneypot.py | 2 +- rdpy/protocol/rdp/t125/gcc.py | 2 +- rdpy/protocol/rdp/t125/per.py | 2 +- rdpy/protocol/rfb/rfb.py | 2 +- rdpy/security/pyDes.py | 2 +- rdpy/ui/qt5.py | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/bin/rdpy-rdphoneypot.py b/bin/rdpy-rdphoneypot.py index 69686d1f..d65a3502 100755 --- a/bin/rdpy-rdphoneypot.py +++ b/bin/rdpy-rdphoneypot.py @@ -94,7 +94,7 @@ def loopScenario(self, nextEvent): clientSize = nextEvent.event.width.value, nextEvent.event.height.value serverSize = self._controller.getScreen() - self._dx, self._dy = (max(0, serverSize[0] - clientSize[0]) / 2), max(0, (serverSize[1] - clientSize[1]) / 2) + self._dx, self._dy = (max(0, serverSize[0] - clientSize[0]) // 2), max(0, (serverSize[1] - clientSize[1]) // 2) #restart connection sequence return diff --git a/rdpy/protocol/rdp/t125/gcc.py b/rdpy/protocol/rdp/t125/gcc.py index c8bd5412..538e2d09 100644 --- a/rdpy/protocol/rdp/t125/gcc.py +++ b/rdpy/protocol/rdp/t125/gcc.py @@ -445,7 +445,7 @@ def __init__(self, readLen): self.magic = UInt32Le(0x31415352, constant = True) self.keylen = UInt32Le(lambda:(sizeof(self.modulus) + sizeof(self.padding))) self.bitlen = UInt32Le(lambda:((self.keylen.value - 8) * 8)) - self.datalen = UInt32Le(lambda:((self.bitlen.value / 8) - 1)) + self.datalen = UInt32Le(lambda:((self.bitlen.value // 8) - 1)) self.pubExp = UInt32Le() self.modulus = String(readLen = CallableValue(lambda:(self.keylen.value - 8))) self.padding = String("\x00" * 8, readLen = CallableValue(8)) diff --git a/rdpy/protocol/rdp/t125/per.py b/rdpy/protocol/rdp/t125/per.py index 35e4d205..970f20f7 100644 --- a/rdpy/protocol/rdp/t125/per.py +++ b/rdpy/protocol/rdp/t125/per.py @@ -220,7 +220,7 @@ def readNumericString(s, minValue): @param minValue: offset """ length = readLength(s) - length = (length + minValue + 1) / 2 + length = (length + minValue + 1) // 2 s.read(length) def writeNumericString(nStr, minValue): diff --git a/rdpy/protocol/rfb/rfb.py b/rdpy/protocol/rfb/rfb.py index b70ab845..01546f1e 100644 --- a/rdpy/protocol/rfb/rfb.py +++ b/rdpy/protocol/rfb/rfb.py @@ -408,7 +408,7 @@ def recvRectHeader(self, data): """ data.readType(self._currentRect) if self._currentRect.encoding.value == Encoding.RAW: - self.expect(self._currentRect.width.value * self._currentRect.height.value * (self._pixelFormat.BitsPerPixel.value / 8), self.recvRectBody) + self.expect(self._currentRect.width.value * self._currentRect.height.value * (self._pixelFormat.BitsPerPixel.value // 8), self.recvRectBody) def recvRectBody(self, data): """ diff --git a/rdpy/security/pyDes.py b/rdpy/security/pyDes.py index 412ec445..e8f1845c 100644 --- a/rdpy/security/pyDes.py +++ b/rdpy/security/pyDes.py @@ -576,7 +576,7 @@ def crypt(self, data, crypt_type): raise ValueError("Invalid data length, data must be a multiple of " + str(self.block_size) + " bytes\n. Try setting the optional padding character") else: data += (self.block_size - (len(data) % self.block_size)) * self.getPadding() - # print("Len of data: %f" % (len(data) / self.block_size)) + # print("Len of data: %f" % (len(data) // self.block_size)) if self.getMode() == CBC: if self.getIV(): diff --git a/rdpy/ui/qt5.py b/rdpy/ui/qt5.py index b9d2cec0..897c1469 100644 --- a/rdpy/ui/qt5.py +++ b/rdpy/ui/qt5.py @@ -281,7 +281,7 @@ def sendWheelEvent(self, e): @param e: QKeyEvent @param isPressed: event come from press or release action """ - self._controller.sendWheelEvent(e.pos().x(), e.pos().y(), (abs(e.delta()) / 8) / 15, e.delta() < 0, e.orientation() == QtCore.Qt.Horizontal) + self._controller.sendWheelEvent(e.pos().x(), e.pos().y(), (abs(e.delta()) // 8) // 15, e.delta() < 0, e.orientation() == QtCore.Qt.Horizontal) def closeEvent(self, e): """ From 5a32b4dae8fb1361cea436e4e48e7dcf3bf40d34 Mon Sep 17 00:00:00 2001 From: Bruno Rodrigues Date: Mon, 29 Mar 2021 17:03:57 +0100 Subject: [PATCH 13/20] log "save screenshot" only if some data was received --- bin/rdpy-rdpscreenshot.py | 8 ++++++-- bin/rdpy-vncscreenshot.py | 8 ++++++-- rdpy/protocol/rdp/rdp.py | 1 + 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/bin/rdpy-rdpscreenshot.py b/bin/rdpy-rdpscreenshot.py index 956621e0..a33cbf51 100755 --- a/bin/rdpy-rdpscreenshot.py +++ b/bin/rdpy-rdpscreenshot.py @@ -120,6 +120,7 @@ def __init__(self, controller, width, height, path, timeout, reactor): self._timeout = timeout self._startTimeout = False self._reactor = reactor + self._got_screenshot = False def onUpdate(self, destLeft, destTop, destRight, destBottom, width, height, bitsPerPixel, isCompress, data): """ @@ -129,6 +130,7 @@ def onUpdate(self, destLeft, destTop, destRight, destBottom, width, height, bits with QtGui.QPainter(self._buffer) as qp: # draw image qp.drawImage(destLeft, destTop, image, 0, 0, destRight - destLeft + 1, destBottom - destTop + 1) + self._got_screenshot = True if not self._startTimeout: self._startTimeout = False self._reactor.callLater(self._timeout, self.checkUpdate) @@ -150,8 +152,10 @@ def onClose(self): """ @summary: callback use when RDP stack is closed """ - log.info("save screenshot into %s" % self._path) - self._buffer.save(self._path) + if self._got_screenshot: + log.info("save screenshot into %s" % self._path) + self._buffer.save(self._path) + log.info("close") def checkUpdate(self): self._controller.close(); diff --git a/bin/rdpy-vncscreenshot.py b/bin/rdpy-vncscreenshot.py index 3d2fd11b..79466933 100755 --- a/bin/rdpy-vncscreenshot.py +++ b/bin/rdpy-vncscreenshot.py @@ -90,6 +90,7 @@ def __init__(self, controller, path): rfb.RFBClientObserver.__init__(self, controller) self._path = path self._buffer = None + self._got_screenshot = False def onUpdate(self, width, height, x, y, pixelFormat, encoding, data): """ @@ -110,6 +111,7 @@ def onUpdate(self, width, height, x, y, pixelFormat, encoding, data): with QtGui.QPainter(self._buffer) as qp: #draw image qp.drawImage(x, y, image, 0, 0, width, height) + self._got_screenshot = True self._controller.close() @@ -125,8 +127,10 @@ def onClose(self): """ @summary: callback use when RDP stack is closed """ - log.info("save screenshot into %s"%self._path) - self._buffer.save(self._path) + if self._got_screenshot: + log.info("save screenshot into %s"%self._path) + self._buffer.save(self._path) + log.info("close") controller.setPassword(self._password) return ScreenShotObserver(controller, self._path) diff --git a/rdpy/protocol/rdp/rdp.py b/rdpy/protocol/rdp/rdp.py index 0ed7053b..0f3be0a3 100644 --- a/rdpy/protocol/rdp/rdp.py +++ b/rdpy/protocol/rdp/rdp.py @@ -24,6 +24,7 @@ from rdpy.core import layer from rdpy.core.error import CallPureVirtualFuntion, InvalidValue from rdpy.protocol.rdp.pdu import layer as pdu_layer, data, caps +from rdpy.protocol.rdp import pdu import rdpy.core.log as log from rdpy.protocol.rdp import tpkt, x224, sec from rdpy.protocol.rdp.t125 import mcs, gcc From ad0f02ce7baf8bc2d92dc62ef6b9d82007dc2fb0 Mon Sep 17 00:00:00 2001 From: Bruno Rodrigues Date: Tue, 30 Mar 2021 14:34:56 +0100 Subject: [PATCH 14/20] more qt5 --- bin/rdpy-rssplayer.py | 2 +- bin/rdpy-vncclient.py | 4 ++-- rdpy/ui/qt5.py | 10 +++++----- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/bin/rdpy-rssplayer.py b/bin/rdpy-rssplayer.py index ae59d184..035e2fe0 100755 --- a/bin/rdpy-rssplayer.py +++ b/bin/rdpy-rssplayer.py @@ -46,7 +46,7 @@ def closeEvent(self, e): """ Not Handle """ QRemoteDesktop.__init__(self, width, height, RssAdaptor()) -class RssPlayerWindow(QtGui.QWidget): +class RssPlayerWindow(QtWidgets.QWidget): """ @summary: main window of rss player """ diff --git a/bin/rdpy-vncclient.py b/bin/rdpy-vncclient.py index f0e081d1..cb77fae6 100755 --- a/bin/rdpy-vncclient.py +++ b/bin/rdpy-vncclient.py @@ -62,7 +62,7 @@ def clientConnectionLost(self, connector, reason): @param connector: twisted connector use for vnc connection (use reconnect to restart connection) @param reason: str use to advertise reason of lost connection """ - QtGui.QMessageBox.warning(self._w, "Warning", "Lost connection : %s"%reason) + QtWidgets.QMessageBox.warning(self._w, "Warning", "Lost connection : %s"%reason) reactor.stop() app.exit() @@ -72,7 +72,7 @@ def clientConnectionFailed(self, connector, reason): @param connector: twisted connector use for vnc 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) + QtWidgets.QMessageBox.warning(self._w, "Warning", "Connection failed : %s"%reason) reactor.stop() app.exit() diff --git a/rdpy/ui/qt5.py b/rdpy/ui/qt5.py index 897c1469..6160b0d8 100644 --- a/rdpy/ui/qt5.py +++ b/rdpy/ui/qt5.py @@ -197,7 +197,7 @@ def RDPBitmapToQtImage(width, height, bitsPerPixel, isCompress, data): rle.bitmap_decompress(buf, width, height, data, 2) image = QtGui.QImage(buf, width, height, QtGui.QImage.Format_RGB555) else: - image = QtGui.QImage(data, width, height, QtGui.QImage.Format_RGB555).transformed(QtGui.QMatrix(1.0, 0.0, 0.0, -1.0, 0.0, 0.0)) + image = QtGui.QImage(data, width, height, QtGui.QImage.Format_RGB555).transformed(QtGui.QTransform(1.0, 0.0, 0.0, -1.0, 0.0, 0.0)) elif bitsPerPixel == 16: if isCompress: @@ -205,7 +205,7 @@ def RDPBitmapToQtImage(width, height, bitsPerPixel, isCompress, data): rle.bitmap_decompress(buf, width, height, data, 2) image = QtGui.QImage(buf, width, height, QtGui.QImage.Format_RGB16) else: - image = QtGui.QImage(data, width, height, QtGui.QImage.Format_RGB16).transformed(QtGui.QMatrix(1.0, 0.0, 0.0, -1.0, 0.0, 0.0)) + image = QtGui.QImage(data, width, height, QtGui.QImage.Format_RGB16).transformed(QtGui.QTransform(1.0, 0.0, 0.0, -1.0, 0.0, 0.0)) elif bitsPerPixel == 24: if isCompress: @@ -213,7 +213,7 @@ def RDPBitmapToQtImage(width, height, bitsPerPixel, isCompress, data): rle.bitmap_decompress(buf, width, height, data, 3) image = QtGui.QImage(buf, width, height, QtGui.QImage.Format_RGB888) else: - image = QtGui.QImage(data, width, height, QtGui.QImage.Format_RGB888).transformed(QtGui.QMatrix(1.0, 0.0, 0.0, -1.0, 0.0, 0.0)) + image = QtGui.QImage(data, width, height, QtGui.QImage.Format_RGB888).transformed(QtGui.QTransform(1.0, 0.0, 0.0, -1.0, 0.0, 0.0)) elif bitsPerPixel == 32: if isCompress: @@ -221,7 +221,7 @@ def RDPBitmapToQtImage(width, height, bitsPerPixel, isCompress, data): rle.bitmap_decompress(buf, width, height, data, 4) image = QtGui.QImage(buf, width, height, QtGui.QImage.Format_RGB32) else: - image = QtGui.QImage(data, width, height, QtGui.QImage.Format_RGB32).transformed(QtGui.QMatrix(1.0, 0.0, 0.0, -1.0, 0.0, 0.0)) + image = QtGui.QImage(data, width, height, QtGui.QImage.Format_RGB32).transformed(QtGui.QTransform(1.0, 0.0, 0.0, -1.0, 0.0, 0.0)) else: log.error("Receive image in bad format") image = QtGui.QImage(width, height, QtGui.QImage.Format_RGB32) @@ -370,7 +370,7 @@ def resize(self, width, height): @param height: {int} height of widget """ self._buffer = QtGui.QImage(width, height, QtGui.QImage.Format_RGB32) - QtGui.QWidget.resize(self, width, height) + QtWidgets.QWidget.resize(self, width, height) def paintEvent(self, e): """ From d71174c6cf22a7efb13e5b8d47bcc329e6388e8c Mon Sep 17 00:00:00 2001 From: Bruno Rodrigues Date: Tue, 30 Mar 2021 14:49:18 +0100 Subject: [PATCH 15/20] python3 bytes vs string, assertEquals, md5/sha, BytesIO vs buflist, etc --- rdpy/core/type.py | 19 +++++++------ rdpy/protocol/rdp/lic.py | 16 +++++------ rdpy/protocol/rdp/nla/ntlm.py | 27 ++++++++++--------- rdpy/protocol/rdp/pdu/caps.py | 4 +-- rdpy/protocol/rdp/pdu/data.py | 8 +++--- rdpy/protocol/rdp/sec.py | 42 ++++++++++++++--------------- rdpy/protocol/rdp/t125/gcc.py | 20 +++++++------- rdpy/protocol/rdp/t125/mcs.py | 4 +-- rdpy/protocol/rdp/t125/per.py | 2 +- rdpy/protocol/rdp/x224.py | 2 +- rdpy/protocol/rfb/rfb.py | 8 +++--- rdpy/security/pyDes.py | 2 +- rdpy/security/rc4.py | 6 ++--- rdpy/security/x509.py | 5 +++- test/test_core_const.py | 2 +- test/test_core_layer.py | 4 +-- test/test_core_type.py | 42 ++++++++++++++--------------- test/test_protocol_rdp_ber.py | 6 ++--- test/test_protocol_rdp_cssp_ntlm.py | 9 ++++--- test/test_protocol_rdp_lic.py | 12 +++++---- test/test_protocol_rdp_per.py | 8 +++--- test/test_protocol_rdp_rc4.py | 12 ++++----- test/test_protocol_rdp_tpkt.py | 12 ++++----- test/test_protocol_rdp_x224.py | 26 +++++++++--------- 24 files changed, 154 insertions(+), 144 deletions(-) diff --git a/rdpy/core/type.py b/rdpy/core/type.py index e4734531..fc15a4ee 100644 --- a/rdpy/core/type.py +++ b/rdpy/core/type.py @@ -713,7 +713,7 @@ def __read__(self, s): @summary: special read for a special type @param s: Stream """ - self.value = struct.unpack(self._structFormat, '\x00' + s.read(self._typeSize))[0] + self.value = struct.unpack(self._structFormat, b'\x00' + s.read(self._typeSize))[0] class UInt24Le(SimpleType): """ @@ -744,14 +744,14 @@ def __read__(self, s): @summary: special read for a special type @param s: Stream """ - self.value = struct.unpack(self._structFormat, s.read(self._typeSize) + '\x00')[0] + self.value = struct.unpack(self._structFormat, s.read(self._typeSize) + b'\x00')[0] class String(Type, CallableValue): """ @summary: String type Leaf in Type tree """ - def __init__(self, value = "", readLen = None, conditional = lambda:True, optional = False, constant = False, unicode = False, until = None): + def __init__(self, value = b"", readLen = None, conditional = lambda:True, optional = False, constant = False, unicode = False, until = None): """ @param value: python string use for inner value @param readLen: length use to read in stream (SimpleType) if 0 read entire stream @@ -769,6 +769,10 @@ def __init__(self, value = "", readLen = None, conditional = lambda:True, option self._readLen = readLen self._unicode = unicode self._until = until + # FIXME + if type(value) != bytes: + raise Exception(f"Invalid string value {type(value)} {value}") + def __eq__(self, other): return self.value.__eq__(other.value) @@ -795,7 +799,7 @@ def __str__(self): @summary: call when str function is call @return: inner python string """ - return self.value.decode("utf-8", 'replace') if type(self.value) == bytes else self.value + return self.value.decode("ascii", "escape") def __write__(self, s): """ @@ -809,11 +813,10 @@ def __write__(self, s): if not self._until is None: toWrite += self._until - value_bytes = self.value.encode("utf-8") if hasattr(self.value, 'encode') else self.value if self._unicode: - s.write(encodeUnicode(value_bytes)) + s.write(encodeUnicode(self.value)) else: - s.write(value_bytes) + s.write(self.value) def __read__(self, s): """ @@ -864,7 +867,7 @@ def decodeUnicode(s): r = "" while i < len(s) - 2: if i % 2 == 0: - r += s[i] + r += chr(s[i]) if type(s[i]) == int else s[i] i += 1 return r diff --git a/rdpy/protocol/rdp/lic.py b/rdpy/protocol/rdp/lic.py index cef19241..208e36b1 100644 --- a/rdpy/protocol/rdp/lic.py +++ b/rdpy/protocol/rdp/lic.py @@ -127,10 +127,10 @@ def __init__(self): self.dwVersion = UInt32Le() self.cbCompanyName = UInt32Le(lambda:sizeof(self.pbCompanyName)) #may contain "Microsoft Corporation" from server microsoft - self.pbCompanyName = String("Microsoft Corporation", readLen = self.cbCompanyName, unicode = True) + self.pbCompanyName = String(b"Microsoft Corporation", readLen = self.cbCompanyName, unicode = True) self.cbProductId = UInt32Le(lambda:sizeof(self.pbProductId)) #may contain "A02" from microsoft license server - self.pbProductId = String("A02", readLen = self.cbProductId, unicode = True) + self.pbProductId = String(b"A02", readLen = self.cbProductId, unicode = True) class Scope(CompositeType): @@ -162,7 +162,7 @@ class ServerLicenseRequest(CompositeType): def __init__(self, readLen = None): CompositeType.__init__(self, readLen = readLen) - self.serverRandom = String("\x00" * 32, readLen = CallableValue(32)) + self.serverRandom = String(b"\x00" * 32, readLen = CallableValue(32)) self.productInfo = ProductInformation() self.keyExchangeList = LicenseBinaryBlob(BinaryBlobType.BB_KEY_EXCHG_ALG_BLOB) self.serverCertificate = LicenseBinaryBlob(BinaryBlobType.BB_CERTIFICATE_BLOB) @@ -183,7 +183,7 @@ def __init__(self, readLen = None): #pure microsoft client ;-) #http://msdn.microsoft.com/en-us/library/1040af38-c733-4fb3-acd1-8db8cc979eda#id10 self.platformId = UInt32Le(0x04000000 | 0x00010000) - self.clientRandom = String("\x00" * 32, readLen = CallableValue(32)) + self.clientRandom = String(b"\x00" * 32, readLen = CallableValue(32)) self.encryptedPreMasterSecret = LicenseBinaryBlob(BinaryBlobType.BB_RANDOM_BLOB) self.ClientUserName = LicenseBinaryBlob(BinaryBlobType.BB_CLIENT_USER_NAME_BLOB) self.ClientMachineName = LicenseBinaryBlob(BinaryBlobType.BB_CLIENT_MACHINE_NAME_BLOB) @@ -321,9 +321,9 @@ def sendClientNewLicenseRequest(self, licenseRequest): #format message message = ClientNewLicenseRequest() message.clientRandom.value = clientRandom - message.encryptedPreMasterSecret.blobData.value = rsa.encrypt(preMasterSecret[::-1], serverCertificate.certData.getPublicKey())[::-1] + "\x00" * 8 - message.ClientMachineName.blobData.value = self._hostname + "\x00" - message.ClientUserName.blobData.value = self._username + "\x00" + message.encryptedPreMasterSecret.blobData.value = rsa.encrypt(preMasterSecret[::-1], serverCertificate.certData.getPublicKey())[::-1] + b"\x00" * 8 + message.ClientMachineName.blobData.value = self._hostname + b"\x00" + message.ClientUserName.blobData.value = self._username + b"\x00" self._transport.sendFlagged(sec.SecurityFlag.SEC_LICENSE_PKT, LicPacket(message)) def sendClientChallengeResponse(self, platformChallenge): @@ -340,7 +340,7 @@ def sendClientChallengeResponse(self, platformChallenge): #generate hwid s = Stream() - s.writeType((UInt32Le(2), String(self._hostname + self._username + "\x00" * 16))) + s.writeType((UInt32Le(2), String(self._hostname + self._username + b"\x00" * 16))) hwid = s.getvalue()[:20] message = ClientPLatformChallengeResponse() diff --git a/rdpy/protocol/rdp/nla/ntlm.py b/rdpy/protocol/rdp/nla/ntlm.py index 07083ce9..cba4a4c9 100644 --- a/rdpy/protocol/rdp/nla/ntlm.py +++ b/rdpy/protocol/rdp/nla/ntlm.py @@ -145,7 +145,7 @@ class NegotiateMessage(CompositeType): """ def __init__(self): CompositeType.__init__(self) - self.Signature = String("NTLMSSP\x00", readLen = CallableValue(8), constant = True) + self.Signature = String(b"NTLMSSP\x00", readLen = CallableValue(8), constant = True) self.MessageType = UInt32Le(0x00000001, constant = True) self.NegotiateFlags = UInt32Le() @@ -169,7 +169,7 @@ class ChallengeMessage(CompositeType): """ def __init__(self): CompositeType.__init__(self) - self.Signature = String("NTLMSSP\x00", readLen = CallableValue(8), constant = True) + self.Signature = String(b"NTLMSSP\x00", readLen = CallableValue(8), constant = True) self.MessageType = UInt32Le(0x00000002, constant = True) self.TargetNameLen = UInt16Le() @@ -179,7 +179,7 @@ def __init__(self): self.NegotiateFlags = UInt32Le() self.ServerChallenge = String(readLen = CallableValue(8)) - self.Reserved = String("\x00" * 8, readLen = CallableValue(8)) + self.Reserved = String(b"\x00" * 8, readLen = CallableValue(8)) self.TargetInfoLen = UInt16Le() self.TargetInfoMaxLen = UInt16Le(lambda:self.TargetInfoLen.value) @@ -216,7 +216,7 @@ class AuthenticateMessage(CompositeType): """ def __init__(self): CompositeType.__init__(self) - self.Signature = String("NTLMSSP\x00", readLen = CallableValue(8), constant = True) + self.Signature = String(b"NTLMSSP\x00", readLen = CallableValue(8), constant = True) self.MessageType = UInt32Le(0x00000003, constant = True) self.LmChallengeResponseLen = UInt16Le() @@ -246,7 +246,7 @@ def __init__(self): self.NegotiateFlags = UInt32Le() self.Version = Version(conditional = lambda:(self.NegotiateFlags.value & Negotiate.NTLMSSP_NEGOTIATE_VERSION)) - self.MIC = String("\x00" * 16, readLen = CallableValue(16)) + self.MIC = String(b"\x00" * 16, readLen = CallableValue(16)) self.Payload = String() def getUserName(self): @@ -345,13 +345,14 @@ def DESL(key, data): @param key: {str} Des key @param data: {str} encrypted data """ - return DES(key[0:7], data) + DES(key[7:14], data) + DES(key[14:16] + "\x00" * 5, data) + return DES(key[0:7], data) + DES(key[7:14], data) + DES(key[14:16] + b"\x00" * 5, data) def UNICODE(s): """ @param s: source @return: {str} encoded in unicode """ + s = s.decode("utf-8") if type(s) == bytes else s # FIXME return s.encode('utf-16le') def MD4(s): @@ -376,7 +377,7 @@ def Z(m): @param m: {int} size of string @return: \x00 * m """ - return "\x00" * m + return b"\x00" * m def RC4K(key, plaintext): """ @@ -399,15 +400,15 @@ def KXKEYv2(SessionBaseKey, LmChallengeResponse, ServerChallenge): def SEALKEY(ExportedSessionKey, client): if client: - return MD5(ExportedSessionKey + "session key to client-to-server sealing key magic constant\0") + return MD5(ExportedSessionKey + b"session key to client-to-server sealing key magic constant\0") else: - return MD5(ExportedSessionKey + "session key to server-to-client sealing key magic constant\0") + return MD5(ExportedSessionKey + b"session key to server-to-client sealing key magic constant\0") def SIGNKEY(ExportedSessionKey, client): if client: - return MD5(ExportedSessionKey + "session key to client-to-server signing key magic constant\0") + return MD5(ExportedSessionKey + b"session key to client-to-server signing key magic constant\0") else: - return MD5(ExportedSessionKey + "session key to server-to-client signing key magic constant\0") + return MD5(ExportedSessionKey + b"session key to server-to-client signing key magic constant\0") def HMAC_MD5(key, data): """ @@ -443,8 +444,8 @@ def ComputeResponsev2(ResponseKeyNT, ResponseKeyLM, ServerChallenge, ClientChall @param NegFlg: {int} Negotiation flags come from challenge message @see: https://msdn.microsoft.com/en-us/library/cc236700.aspx """ - Responserversion = "\x01" - HiResponserversion = "\x01" + Responserversion = b"\x01" + HiResponserversion = b"\x01" temp = Responserversion + HiResponserversion + Z(6) + Time + ClientChallenge + Z(4) + ServerName NTProofStr = HMAC_MD5(ResponseKeyNT, ServerChallenge + temp) diff --git a/rdpy/protocol/rdp/pdu/caps.py b/rdpy/protocol/rdp/pdu/caps.py index 19443577..ba6de9d9 100644 --- a/rdpy/protocol/rdp/pdu/caps.py +++ b/rdpy/protocol/rdp/pdu/caps.py @@ -308,7 +308,7 @@ class OrderCapability(CompositeType): def __init__(self, readLen = None): CompositeType.__init__(self, readLen = readLen) - self.terminalDescriptor = String("\x00" * 16, readLen = CallableValue(16)) + self.terminalDescriptor = String(b"\x00" * 16, readLen = CallableValue(16)) self.pad4octetsA = UInt32Le(0) self.desktopSaveXGranularity = UInt16Le(1) self.desktopSaveYGranularity = UInt16Le(20) @@ -388,7 +388,7 @@ def __init__(self, readLen = None): #same value as gcc.ClientCoreSettings.keyboardFnKeys self.keyboardFunctionKey = UInt32Le() #same value as gcc.ClientCoreSettingrrs.imeFileName - self.imeFileName = String("\x00" * 64, readLen = CallableValue(64)) + self.imeFileName = String(b"\x00" * 64, readLen = CallableValue(64)) class BrushCapability(CompositeType): """ diff --git a/rdpy/protocol/rdp/pdu/data.py b/rdpy/protocol/rdp/pdu/data.py index 48936b60..8b7403ec 100644 --- a/rdpy/protocol/rdp/pdu/data.py +++ b/rdpy/protocol/rdp/pdu/data.py @@ -503,7 +503,7 @@ def __init__(self, readLen = None): self.shareId = UInt32Le() self.lengthSourceDescriptor = UInt16Le(lambda:sizeof(self.sourceDescriptor)) self.lengthCombinedCapabilities = UInt16Le(lambda:(sizeof(self.numberCapabilities) + sizeof(self.pad2Octets) + sizeof(self.capabilitySets))) - self.sourceDescriptor = String("rdpy", readLen = self.lengthSourceDescriptor) + self.sourceDescriptor = String(b"rdpy", readLen = self.lengthSourceDescriptor) self.numberCapabilities = UInt16Le(lambda:len(self.capabilitySets._array)) self.pad2Octets = UInt16Le() self.capabilitySets = ArrayType(caps.Capability, readLen = self.numberCapabilities) @@ -523,7 +523,7 @@ def __init__(self, readLen = None): self.originatorId = UInt16Le(0x03EA, constant = True) self.lengthSourceDescriptor = UInt16Le(lambda:sizeof(self.sourceDescriptor)) self.lengthCombinedCapabilities = UInt16Le(lambda:(sizeof(self.numberCapabilities) + sizeof(self.pad2Octets) + sizeof(self.capabilitySets))) - self.sourceDescriptor = String("rdpy", readLen = self.lengthSourceDescriptor) + self.sourceDescriptor = String(b"rdpy", readLen = self.lengthSourceDescriptor) self.numberCapabilities = UInt16Le(lambda:len(self.capabilitySets._array)) self.pad2Octets = UInt16Le() self.capabilitySets = ArrayType(caps.Capability, readLen = self.numberCapabilities) @@ -542,7 +542,7 @@ def __init__(self, readLen = None): CompositeType.__init__(self, optional = True, readLen = readLen) self.shareId = UInt32Le() self.lengthSourceDescriptor = UInt16Le(lambda:sizeof(self.sourceDescriptor)) - self.sourceDescriptor = String("rdpy", readLen = self.lengthSourceDescriptor) + self.sourceDescriptor = String(b"rdpy", readLen = self.lengthSourceDescriptor) class DataPDU(CompositeType): """ @@ -880,7 +880,7 @@ class BitmapData(CompositeType): """ @summary: Bitmap data here the screen capture """ - def __init__(self, destLeft = 0, destTop = 0, destRight = 0, destBottom = 0, width = 0, height = 0, bitsPerPixel = 0, bitmapDataStream = ""): + def __init__(self, destLeft = 0, destTop = 0, destRight = 0, destBottom = 0, width = 0, height = 0, bitsPerPixel = 0, bitmapDataStream = b""): """ @param destLeft: destination left coordinate @param destTop: destination top coordinate diff --git a/rdpy/protocol/rdp/sec.py b/rdpy/protocol/rdp/sec.py index 1d6f6f96..e2f5da86 100644 --- a/rdpy/protocol/rdp/sec.py +++ b/rdpy/protocol/rdp/sec.py @@ -109,8 +109,8 @@ def saltedHash(inputData, salt, salt1, salt2): @param salt2: another another salt (ex: server random) @return : MD5(Salt + SHA1(Input + Salt + Salt1 + Salt2)) """ - sha1Digest = sha.new() - md5Digest = md5.new() + sha1Digest = sha() + md5Digest = md5() sha1Digest.update(inputData) sha1Digest.update(salt[:48]) @@ -131,7 +131,7 @@ def finalHash(key, random1, random2): @param random2: in 32 @return MD5(in0[:16] + in1[:32] + in2[:32]) """ - md5Digest = md5.new() + md5Digest = md5() md5Digest.update(key) md5Digest.update(random1) md5Digest.update(random2) @@ -145,7 +145,7 @@ def masterSecret(secret, random1, random2): @param serverRandom : {str} server random @see: http://msdn.microsoft.com/en-us/library/cc241992.aspx """ - return saltedHash("A", secret, random1, random2) + saltedHash("BB", secret, random1, random2) + saltedHash("CCC", secret, random1, random2) + return saltedHash(b"A", secret, random1, random2) + saltedHash(b"BB", secret, random1, random2) + saltedHash(b"CCC", secret, random1, random2) def sessionKeyBlob(secret, random1, random2): """ @@ -154,7 +154,7 @@ def sessionKeyBlob(secret, random1, random2): @param clientRandom : client random @param serverRandom : server random """ - return saltedHash("X", secret, random1, random2) + saltedHash("YY", secret, random1, random2) + saltedHash("ZZZ", secret, random1, random2) + return saltedHash(b"X", secret, random1, random2) + saltedHash(b"YY", secret, random1, random2) + saltedHash(b"ZZZ", secret, random1, random2) def macData(macSaltKey, data): """ @@ -163,22 +163,22 @@ def macData(macSaltKey, data): @param data: {str} data to sign @return: {str} signature """ - sha1Digest = sha.new() - md5Digest = md5.new() + sha1Digest = sha() + md5Digest = md5() #encode length dataLength = Stream() dataLength.writeType(UInt32Le(len(data))) sha1Digest.update(macSaltKey) - sha1Digest.update("\x36" * 40) + sha1Digest.update(b"\x36" * 40) sha1Digest.update(dataLength.getvalue()) sha1Digest.update(data) sha1Sig = sha1Digest.digest() md5Digest.update(macSaltKey) - md5Digest.update("\x5c" * 48) + md5Digest.update(b"\x5c" * 48) md5Digest.update(sha1Sig) return md5Digest.digest() @@ -191,8 +191,8 @@ def macSaltedData(macSaltKey, data, encryptionCount): @param encryptionCount: nb encrypted packet @return: {str} signature """ - sha1Digest = sha.new() - md5Digest = md5.new() + sha1Digest = sha() + md5Digest = md5() #encode length dataLengthS = Stream() @@ -202,7 +202,7 @@ def macSaltedData(macSaltKey, data, encryptionCount): encryptionCountS.writeType(UInt32Le(encryptionCount)) sha1Digest.update(macSaltKey) - sha1Digest.update("\x36" * 40) + sha1Digest.update(b"\x36" * 40) sha1Digest.update(dataLengthS.getvalue()) sha1Digest.update(data) sha1Digest.update(encryptionCountS.getvalue()) @@ -210,7 +210,7 @@ def macSaltedData(macSaltKey, data, encryptionCount): sha1Sig = sha1Digest.digest() md5Digest.update(macSaltKey) - md5Digest.update("\x5c" * 48) + md5Digest.update(b"\x5c" * 48) md5Digest.update(sha1Sig) return md5Digest.digest() @@ -222,17 +222,17 @@ def tempKey(initialKey, currentKey): @param currentKey: {str} key actually used @return: {str} temp key """ - sha1Digest = sha.new() - md5Digest = md5.new() + sha1Digest = sha() + md5Digest = md5() sha1Digest.update(initialKey) - sha1Digest.update("\x36" * 40) + sha1Digest.update(b"\x36" * 40) sha1Digest.update(currentKey) sha1Sig = sha1Digest.digest() md5Digest.update(initialKey) - md5Digest.update("\x5c" * 48) + md5Digest.update(b"\x5c" * 48) md5Digest.update(sha1Sig) return md5Digest.digest() @@ -244,7 +244,7 @@ def gen40bits(data): @return: {str} 40 bits data @see: http://msdn.microsoft.com/en-us/library/cc240785.aspx """ - return "\xd1\x26\x9e" + data[:8][-5:] + return b"\xd1\x26\x9e" + data[:8][-5:] def gen56bits(data): """ @@ -253,7 +253,7 @@ def gen56bits(data): @return: {str} 56 bits data @see: http://msdn.microsoft.com/en-us/library/cc240785.aspx """ - return "\xd1" + data[:8][-7:] + return b"\xd1" + data[:8][-7:] def generateKeys(clientRandom, serverRandom, method): """ @@ -312,7 +312,7 @@ def __init__(self): CompositeType.__init__(self) self.length = UInt32Le(lambda:(sizeof(self) - 4)) self.encryptedClientRandom = String(readLen = CallableValue(lambda:(self.length.value - 8))) - self.padding = String("\x00" * 8, readLen = CallableValue(8)) + self.padding = String(b"\x00" * 8, readLen = CallableValue(8)) class RDPInfo(CompositeType): """ @@ -353,7 +353,7 @@ def __init__(self, conditional): self.cbClientDir = UInt16Le(lambda:sizeof(self.clientDir)) self.clientDir = String(readLen = self.cbClientDir, unicode = True) #TODO make tiomezone - self.clientTimeZone = String("\x00" * 172) + self.clientTimeZone = String(b"\x00" * 172) self.clientSessionId = UInt32Le() self.performanceFlags = UInt32Le() diff --git a/rdpy/protocol/rdp/t125/gcc.py b/rdpy/protocol/rdp/t125/gcc.py index 538e2d09..f70a5241 100644 --- a/rdpy/protocol/rdp/t125/gcc.py +++ b/rdpy/protocol/rdp/t125/gcc.py @@ -252,18 +252,18 @@ def __init__(self, readLen = None): self.sasSequence = UInt16Le(Sequence.RNS_UD_SAS_DEL) self.kbdLayout = UInt32Le(KeyboardLayout.US) self.clientBuild = UInt32Le(3790) - self.clientName = String("rdpy" + "\x00"*11, readLen = CallableValue(32), unicode = True) + self.clientName = String(b"rdpy" + b"\x00"*11, readLen = CallableValue(32), unicode = True) self.keyboardType = UInt32Le(KeyboardType.IBM_101_102_KEYS) self.keyboardSubType = UInt32Le(0) self.keyboardFnKeys = UInt32Le(12) - self.imeFileName = String("\x00"*64, readLen = CallableValue(64), optional = True) + self.imeFileName = String(b"\x00"*64, readLen = CallableValue(64), optional = True) self.postBeta2ColorDepth = UInt16Le(ColorDepth.RNS_UD_COLOR_8BPP, optional = True) self.clientProductId = UInt16Le(1, optional = True) self.serialNumber = UInt32Le(0, optional = True) self.highColorDepth = UInt16Le(HighColor.HIGH_COLOR_24BPP, optional = True) self.supportedColorDepths = UInt16Le(Support.RNS_UD_15BPP_SUPPORT | Support.RNS_UD_16BPP_SUPPORT | Support.RNS_UD_24BPP_SUPPORT | Support.RNS_UD_32BPP_SUPPORT, optional = True) self.earlyCapabilityFlags = UInt16Le(CapabilityFlags.RNS_UD_CS_SUPPORT_ERRINFO_PDU, optional = True) - self.clientDigProductId = String("\x00"*64, readLen = CallableValue(64), optional = True) + self.clientDigProductId = String(b"\x00"*64, readLen = CallableValue(64), optional = True) self.connectionType = UInt8(optional = True) self.pad1octet = UInt8(optional = True) self.serverSelectedProtocol = UInt32Le(optional = True) @@ -342,9 +342,9 @@ class ProprietaryServerCertificate(CompositeType): _TYPE_ = CertificateType.CERT_CHAIN_VERSION_1 #http://msdn.microsoft.com/en-us/library/cc240776.aspx - _TERMINAL_SERVICES_MODULUS_ = "\x3d\x3a\x5e\xbd\x72\x43\x3e\xc9\x4d\xbb\xc1\x1e\x4a\xba\x5f\xcb\x3e\x88\x20\x87\xef\xf5\xc1\xe2\xd7\xb7\x6b\x9a\xf2\x52\x45\x95\xce\x63\x65\x6b\x58\x3a\xfe\xef\x7c\xe7\xbf\xfe\x3d\xf6\x5c\x7d\x6c\x5e\x06\x09\x1a\xf5\x61\xbb\x20\x93\x09\x5f\x05\x6d\xea\x87" - _TERMINAL_SERVICES_PRIVATE_EXPONENT_ = "\x87\xa7\x19\x32\xda\x11\x87\x55\x58\x00\x16\x16\x25\x65\x68\xf8\x24\x3e\xe6\xfa\xe9\x67\x49\x94\xcf\x92\xcc\x33\x99\xe8\x08\x60\x17\x9a\x12\x9f\x24\xdd\xb1\x24\x99\xc7\x3a\xb8\x0a\x7b\x0d\xdd\x35\x07\x79\x17\x0b\x51\x9b\xb3\xc7\x10\x01\x13\xe7\x3f\xf3\x5f" - _TERMINAL_SERVICES_PUBLIC_EXPONENT_ = "\x5b\x7b\x88\xc0" + _TERMINAL_SERVICES_MODULUS_ = b"\x3d\x3a\x5e\xbd\x72\x43\x3e\xc9\x4d\xbb\xc1\x1e\x4a\xba\x5f\xcb\x3e\x88\x20\x87\xef\xf5\xc1\xe2\xd7\xb7\x6b\x9a\xf2\x52\x45\x95\xce\x63\x65\x6b\x58\x3a\xfe\xef\x7c\xe7\xbf\xfe\x3d\xf6\x5c\x7d\x6c\x5e\x06\x09\x1a\xf5\x61\xbb\x20\x93\x09\x5f\x05\x6d\xea\x87" + _TERMINAL_SERVICES_PRIVATE_EXPONENT_ = b"\x87\xa7\x19\x32\xda\x11\x87\x55\x58\x00\x16\x16\x25\x65\x68\xf8\x24\x3e\xe6\xfa\xe9\x67\x49\x94\xcf\x92\xcc\x33\x99\xe8\x08\x60\x17\x9a\x12\x9f\x24\xdd\xb1\x24\x99\xc7\x3a\xb8\x0a\x7b\x0d\xdd\x35\x07\x79\x17\x0b\x51\x9b\xb3\xc7\x10\x01\x13\xe7\x3f\xf3\x5f" + _TERMINAL_SERVICES_PUBLIC_EXPONENT_ = b"\x5b\x7b\x88\xc0" def __init__(self): CompositeType.__init__(self) @@ -378,10 +378,10 @@ def computeSignatureHash(self): s.writeType(self.wPublicKeyBlobLen) s.writeType(self.PublicKeyBlob) - md5Digest = md5.new() + md5Digest = md5() md5Digest.update(s.getvalue()) - return md5Digest.digest() + "\x00" + "\xff" * 45 + "\x01" + return md5Digest.digest() + b"\x00" + b"\xff" * 45 + b"\x01" def sign(self): """ @@ -448,7 +448,7 @@ def __init__(self, readLen): self.datalen = UInt32Le(lambda:((self.bitlen.value // 8) - 1)) self.pubExp = UInt32Le() self.modulus = String(readLen = CallableValue(lambda:(self.keylen.value - 8))) - self.padding = String("\x00" * 8, readLen = CallableValue(8)) + self.padding = String(b"\x00" * 8, readLen = CallableValue(8)) class ChannelDef(CompositeType): """ @@ -458,7 +458,7 @@ class ChannelDef(CompositeType): def __init__(self, name = "", options = 0): CompositeType.__init__(self) #name of channel - self.name = String(name[0:8] + "\x00" * (8 - len(name)), readLen = CallableValue(8)) + self.name = String(name[0:8] + b"\x00" * (8 - len(name)), readLen = CallableValue(8)) #unknown self.options = UInt32Le() diff --git a/rdpy/protocol/rdp/t125/mcs.py b/rdpy/protocol/rdp/t125/mcs.py index f6a62969..254cf599 100644 --- a/rdpy/protocol/rdp/t125/mcs.py +++ b/rdpy/protocol/rdp/t125/mcs.py @@ -182,7 +182,7 @@ def close(self): @summary: Send disconnect provider ultimatum """ self._transport.send((UInt8(self.writeMCSPDUHeader(DomainMCSPDU.DISCONNECT_PROVIDER_ULTIMATUM, 1)), - per.writeEnumerates(0x80), String("\x00" * 6))) + per.writeEnumerates(0x80), String(b"\x00" * 6))) self._transport.close() def allChannelConnected(self): @@ -437,7 +437,7 @@ def sendConnectInitial(self): ccReqStream = Stream() ccReqStream.writeType(ccReq) - tmp = (ber.writeOctetstring("\x01"), ber.writeOctetstring("\x01"), ber.writeBoolean(True), + tmp = (ber.writeOctetstring(b"\x01"), ber.writeOctetstring(b"\x01"), ber.writeBoolean(True), self.writeDomainParams(34, 2, 0, 0xffff), self.writeDomainParams(1, 1, 1, 0x420), self.writeDomainParams(0xffff, 0xfc17, 0xffff, 0xffff), diff --git a/rdpy/protocol/rdp/t125/per.py b/rdpy/protocol/rdp/t125/per.py index 970f20f7..aaced277 100644 --- a/rdpy/protocol/rdp/t125/per.py +++ b/rdpy/protocol/rdp/t125/per.py @@ -264,7 +264,7 @@ def writePadding(length): @param length: length of padding @return: String with \x00 * length """ - return String("\x00"*length) + return String(b"\x00"*length) def readOctetStream(s, octetStream, minValue = 0): """ diff --git a/rdpy/protocol/rdp/x224.py b/rdpy/protocol/rdp/x224.py index bd900ce5..091f236e 100644 --- a/rdpy/protocol/rdp/x224.py +++ b/rdpy/protocol/rdp/x224.py @@ -79,7 +79,7 @@ def __init__(self): self.len = UInt8(lambda:sizeof(self) - 1) self.code = UInt8(MessageType.X224_TPDU_CONNECTION_REQUEST, constant = True) self.padding = (UInt16Be(), UInt16Be(), UInt8()) - self.cookie = String(until = "\x0d\x0a", conditional = lambda:(self.len._is_readed and self.len.value > 14)) + self.cookie = String(until = b"\x0d\x0a", conditional = lambda:(self.len._is_readed and self.len.value > 14)) #read if there is enough data self.protocolNeg = Negotiation(optional = True) diff --git a/rdpy/protocol/rfb/rfb.py b/rdpy/protocol/rfb/rfb.py index 01546f1e..94eed5df 100644 --- a/rdpy/protocol/rfb/rfb.py +++ b/rdpy/protocol/rfb/rfb.py @@ -35,10 +35,10 @@ class ProtocolVersion(object): """ @summary: Different protocol version """ - UNKNOWN = "" - RFB003003 = "RFB 003.003\n" - RFB003007 = "RFB 003.007\n" - RFB003008 = "RFB 003.008\n" + UNKNOWN = b"" + RFB003003 = b"RFB 003.003\n" + RFB003007 = b"RFB 003.007\n" + RFB003008 = b"RFB 003.008\n" class SecurityType(object): """ diff --git a/rdpy/security/pyDes.py b/rdpy/security/pyDes.py index e8f1845c..6cde34b1 100644 --- a/rdpy/security/pyDes.py +++ b/rdpy/security/pyDes.py @@ -66,7 +66,7 @@ from pyDes import * data = "Please encrypt my data" -k = des("DESCRYPT", CBC, "\0\0\0\0\0\0\0\0", pad=None, padmode=PAD_PKCS5) +k = des("DESCRYPT", CBC, b"\0\0\0\0\0\0\0\0", pad=None, padmode=PAD_PKCS5) # For Python3, you'll need to use bytes, i.e.: # data = b"Please encrypt my data" # k = des(b"DESCRYPT", CBC, b"\0\0\0\0\0\0\0\0", pad=None, padmode=PAD_PKCS5) diff --git a/rdpy/security/rc4.py b/rdpy/security/rc4.py index 5802cb1a..2dc35c1b 100644 --- a/rdpy/security/rc4.py +++ b/rdpy/security/rc4.py @@ -24,7 +24,7 @@ def KSA(key): keylength = len(key) - S = range(256) + S = list(range(256)) j = 0 for i in range(256): @@ -51,7 +51,7 @@ def RC4(key): return PRGA(S) def RC4Key(key): - return RC4([ord(c) for c in key]) + return RC4([c for c in key]) def crypt(keystream, plaintext): - return "".join([chr(ord(c) ^ keystream.next()) for c in plaintext]) \ No newline at end of file + return b"".join([bytes([c ^ next(keystream)]) for c in plaintext]) \ No newline at end of file diff --git a/rdpy/security/x509.py b/rdpy/security/x509.py index 5b77cc7b..63630d4c 100644 --- a/rdpy/security/x509.py +++ b/rdpy/security/x509.py @@ -23,6 +23,7 @@ from pyasn1.type import tag, namedtype, namedval, univ, constraint, char, useful from pyasn1.codec.ber import decoder +from codecs import decode MAX = 64 @@ -150,7 +151,9 @@ def extractRSAKey(certificate): binaryTuple = certificate.getComponentByName('tbsCertificate').getComponentByName('subjectPublicKeyInfo').getComponentByName('subjectPublicKey') l = int("".join([str(i) for i in binaryTuple]), 2) - return extractRSAKeyFromASN1(hex(l)[2:-1].decode('hex')) + h = hex(l)[2:-1] + h = '0' + h if len(h) % 2 != 0 else h + return extractRSAKeyFromASN1(decode(h, 'hex')) def extractRSAKeyFromASN1(subjectPublicKey): rsaKey = decoder.decode(subjectPublicKey, asn1Spec=RSAPublicKey())[0] diff --git a/test/test_core_const.py b/test/test_core_const.py index 0920bbff..756f047c 100644 --- a/test/test_core_const.py +++ b/test/test_core_const.py @@ -55,4 +55,4 @@ class Test: MEMBER_1 = 1 MEMBER_2 = 2 - self.assertEquals(Test.MEMBER_1, Test.MEMBER_1, "handle same type of object") \ No newline at end of file + self.assertEqual(Test.MEMBER_1, Test.MEMBER_1, "handle same type of object") \ No newline at end of file diff --git a/test/test_core_layer.py b/test/test_core_layer.py index b24d5eab..a02495e0 100644 --- a/test/test_core_layer.py +++ b/test/test_core_layer.py @@ -61,7 +61,7 @@ def expectedCallBack(self, data): t = TestAutomata() t.expect(4, t.expectedCallBack) - self.assertRaises(LayerTest.LayerCaseException, t.dataReceived, "\x00\x00\x00\x00\x00") + self.assertRaises(LayerTest.LayerCaseException, t.dataReceived, b"\x00\x00\x00\x00\x00") def test_layer_automata_less_than_expected(self): """ @@ -74,4 +74,4 @@ def expectedCallBack(self, data): t = TestAutomata() t.expect(4, t.expectedCallBack) - self.assertEqual(t.dataReceived("\x00\x00\x00"), None, "Not enough dada") \ No newline at end of file + self.assertEqual(t.dataReceived(b"\x00\x00\x00"), None, "Not enough dada") \ No newline at end of file diff --git a/test/test_core_type.py b/test/test_core_type.py index 1ca9064f..c0f1302d 100644 --- a/test/test_core_type.py +++ b/test/test_core_type.py @@ -139,7 +139,7 @@ def test_stream_write_uint8_type(self): """ s = rdpy.core.type.Stream() s.writeType(rdpy.core.type.UInt8(1)) - self.assertEqual(''.join(s.buflist), '\x01', "invalid stream write") + self.assertEqual(s.getvalue(), b'\x01', "invalid stream write") def test_stream_write_uint16Le_type(self): """ @@ -147,7 +147,7 @@ def test_stream_write_uint16Le_type(self): """ s = rdpy.core.type.Stream() s.writeType(rdpy.core.type.UInt16Le(1)) - self.assertEqual(''.join(s.buflist), '\x01\x00', "invalid stream write") + self.assertEqual(s.getvalue(), b'\x01\x00', "invalid stream write") def test_stream_write_uint16Be_type(self): """ @@ -155,7 +155,7 @@ def test_stream_write_uint16Be_type(self): """ s = rdpy.core.type.Stream() s.writeType(rdpy.core.type.UInt16Be(1)) - self.assertEqual(''.join(s.buflist), '\x00\x01', "invalid stream write") + self.assertEqual(s.getvalue(), b'\x00\x01', "invalid stream write") def test_stream_write_uint24Le_type(self): """ @@ -163,7 +163,7 @@ def test_stream_write_uint24Le_type(self): """ s = rdpy.core.type.Stream() s.writeType(rdpy.core.type.UInt24Le(1)) - self.assertEqual(''.join(s.buflist), '\x01\x00\x00', "invalid stream write") + self.assertEqual(s.getvalue(), b'\x01\x00\x00', "invalid stream write") def test_stream_write_uint24Be_type(self): """ @@ -171,7 +171,7 @@ def test_stream_write_uint24Be_type(self): """ s = rdpy.core.type.Stream() s.writeType(rdpy.core.type.UInt24Be(1)) - self.assertEqual(''.join(s.buflist), '\x00\x00\x01', "invalid stream write") + self.assertEqual(s.getvalue(), b'\x00\x00\x01', "invalid stream write") def test_stream_write_uint32Le_type(self): """ @@ -179,7 +179,7 @@ def test_stream_write_uint32Le_type(self): """ s = rdpy.core.type.Stream() s.writeType(rdpy.core.type.UInt32Le(1)) - self.assertEqual(''.join(s.buflist), '\x01\x00\x00\x00', "invalid stream write") + self.assertEqual(s.getvalue(), b'\x01\x00\x00\x00', "invalid stream write") def test_stream_write_uint32Be_type(self): """ @@ -187,13 +187,13 @@ def test_stream_write_uint32Be_type(self): """ s = rdpy.core.type.Stream() s.writeType(rdpy.core.type.UInt32Be(1)) - self.assertEqual(''.join(s.buflist), '\x00\x00\x00\x01', "invalid stream write") + self.assertEqual(s.getvalue(), b'\x00\x00\x00\x01', "invalid stream write") def test_stream_read_uint8_type(self): """ @summary: test read UInt8 type from stream """ - s = rdpy.core.type.Stream('\x01') + s = rdpy.core.type.Stream(b'\x01') t = rdpy.core.type.UInt8() s.readType(t) self.assertEqual(t.value, 1, "invalid stream read value") @@ -203,7 +203,7 @@ def test_stream_read_uint16Le_type(self): """ @summary: test read UInt16Le type from stream """ - s = rdpy.core.type.Stream('\x01\x00') + s = rdpy.core.type.Stream(b'\x01\x00') t = rdpy.core.type.UInt16Le() s.readType(t) self.assertEqual(t.value, 1, "invalid stream read value") @@ -213,7 +213,7 @@ def test_stream_read_uint16Be_type(self): """ @summary: test read UInt16Be type from stream """ - s = rdpy.core.type.Stream('\x00\x01') + s = rdpy.core.type.Stream(b'\x00\x01') t = rdpy.core.type.UInt16Be() s.readType(t) self.assertEqual(t.value, 1, "invalid stream read value") @@ -223,7 +223,7 @@ def test_stream_read_uint24Le_type(self): """ @summary: test read UInt24Le type from stream """ - s = rdpy.core.type.Stream('\x01\x00\x00') + s = rdpy.core.type.Stream(b'\x01\x00\x00') t = rdpy.core.type.UInt24Le() s.readType(t) self.assertEqual(t.value, 1, "invalid stream read value") @@ -233,7 +233,7 @@ def test_stream_read_uint24Be_type(self): """ @summary: test read UInt24Be type from stream """ - s = rdpy.core.type.Stream('\x00\x00\x01') + s = rdpy.core.type.Stream(b'\x00\x00\x01') t = rdpy.core.type.UInt24Be() s.readType(t) self.assertEqual(t.value, 1, "invalid stream read") @@ -243,7 +243,7 @@ def test_stream_read_uint32Le_type(self): """ @summary: test read UInt32Le type from stream """ - s = rdpy.core.type.Stream('\x01\x00\x00\x00') + s = rdpy.core.type.Stream(b'\x01\x00\x00\x00') t = rdpy.core.type.UInt32Le() s.readType(t) self.assertEqual(t.value, 1, "invalid stream read value") @@ -253,7 +253,7 @@ def test_stream_read_uint32Be_type(self): """ @summary: test read UInt32Be type from stream """ - s = rdpy.core.type.Stream('\x00\x00\x00\x01') + s = rdpy.core.type.Stream(b'\x00\x00\x00\x01') t = rdpy.core.type.UInt32Be() s.readType(t) self.assertEqual(t.value, 1, "invalid stream read") @@ -276,7 +276,7 @@ def test_stream_read_conditional_singletype_false(self): """ #unsigned int case t = rdpy.core.type.SimpleType("I", 4, False, 0, conditional = lambda:False) - s1 = rdpy.core.type.Stream("\x01\x00\x00\x00") + s1 = rdpy.core.type.Stream(b"\x01\x00\x00\x00") s1.readType(t) self.assertEqual(t.value, 0, "invalid stream read conditional value") @@ -286,7 +286,7 @@ def test_stream_read_conditional_singletype_true(self): """ #unsigned int case t = rdpy.core.type.SimpleType("I", 4, False, 0, conditional = lambda:True) - s1 = rdpy.core.type.Stream("\x01\x00\x00\x00") + s1 = rdpy.core.type.Stream(b"\x01\x00\x00\x00") s1.readType(t) self.assertEqual(t.value, 1, "invalid stream read conditional value") @@ -300,7 +300,7 @@ def __init__(self): self.padding = rdpy.core.type.UInt32Le(0) self.constraint = rdpy.core.type.UInt32Le(1, constant = True) - s = rdpy.core.type.Stream("\x00\x00\x00\x00\x00\x00\x00\x00") + s = rdpy.core.type.Stream(b"\x00\x00\x00\x00\x00\x00\x00\x00") try: s.readType(TestComposite()) except Exception: @@ -325,7 +325,7 @@ def __init__(self): self.padding = rdpy.core.type.UInt32Le(0) self.recurcive = TestSubComposite() - s = rdpy.core.type.Stream("\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00") + s = rdpy.core.type.Stream(b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00") try: s.readType(TestComposite()) except Exception: @@ -350,7 +350,7 @@ def __init__(self): self.padding = rdpy.core.type.UInt32Le(0) self.recurcive = TestSubComposite() - s = rdpy.core.type.Stream("\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00") + s = rdpy.core.type.Stream(b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00") try: s.readType(TestComposite()) except Exception: @@ -368,7 +368,7 @@ class TestReadLength(rdpy.core.type.CompositeType): def __init__(self, readLen): rdpy.core.type.CompositeType.__init__(self, readLen = readLen) self.padding = rdpy.core.type.UInt32Le(0) - s = rdpy.core.type.Stream("\x00" * 10) + s = rdpy.core.type.Stream(b"\x00" * 10) s.readType(TestReadLength(rdpy.core.type.UInt8(10))) self.assertEqual(s.dataLen(), 0, "invalid stream read trash data as padding") @@ -382,7 +382,7 @@ class TestReadLength(rdpy.core.type.CompositeType): def __init__(self, readLen): rdpy.core.type.CompositeType.__init__(self, readLen = readLen) self.padding = rdpy.core.type.UInt32Le(0) - s = rdpy.core.type.Stream("\x00" * 10) + s = rdpy.core.type.Stream(b"\x00" * 10) self.assertRaises(InvalidSize, s.readType, TestReadLength(rdpy.core.type.UInt8(2))) def test_stream_read_string(self): diff --git a/test/test_protocol_rdp_ber.py b/test/test_protocol_rdp_ber.py index 4b062a5c..e2d927b1 100644 --- a/test/test_protocol_rdp_ber.py +++ b/test/test_protocol_rdp_ber.py @@ -41,7 +41,7 @@ def test_ber_readLength(self): """ s1 = type.Stream() s1.writeType(type.UInt8(0x1a)) - s1.pos = 0 + s1._pos(0) l1 = ber.readLength(s1) @@ -49,7 +49,7 @@ def test_ber_readLength(self): s2 = type.Stream() s2.writeType((type.UInt8(0x81),type.UInt8(0xab))) - s2.pos = 0 + s2._pos(0) l2 = ber.readLength(s2) @@ -57,7 +57,7 @@ def test_ber_readLength(self): s3 = type.Stream() s3.writeType((type.UInt8(0x82),type.UInt16Be(0xabab))) - s3.pos = 0 + s3._pos(0) l3 = ber.readLength(s3) diff --git a/test/test_protocol_rdp_cssp_ntlm.py b/test/test_protocol_rdp_cssp_ntlm.py index 59872731..ffda1f1d 100644 --- a/test/test_protocol_rdp_cssp_ntlm.py +++ b/test/test_protocol_rdp_cssp_ntlm.py @@ -22,6 +22,7 @@ """ import unittest import os, sys +import base64 # Change path so we find rdpy sys.path.insert(1, os.path.join(sys.path[0], '..')) @@ -73,9 +74,9 @@ class TestCsspNtlm(unittest.TestCase): @summary: test generate ntlmv2 over cssp authentication protocol """ def testCSSPNTLMAuthentication(self): - negotiate_data_request = cssp.decodeDERTRequest(peer0_0.decode('base64')) - challenge_data_request = cssp.decodeDERTRequest(peer1_0.decode('base64')) - authenticate_data_request = cssp.decodeDERTRequest(peer0_1.decode('base64')) + negotiate_data_request = cssp.decodeDERTRequest(base64.b64decode(peer0_0)) + challenge_data_request = cssp.decodeDERTRequest(base64.b64decode(peer1_0)) + authenticate_data_request = cssp.decodeDERTRequest(base64.b64decode(peer0_1)) negotiate_data = cssp.getNegoTokens(negotiate_data_request)[0] challenge_data = cssp.getNegoTokens(challenge_data_request)[0] @@ -122,7 +123,7 @@ def testCSSPNTLMAuthentication(self): interface = ntlm.NTLMv2SecurityInterface(rc4.RC4Key(ClientSealingKey), rc4.RC4Key(ServerSealingKey), ClientSigningKey, ServerSigningKey) EncryptedPubKeySrc = cssp.getPubKeyAuth(authenticate_data_request) - EncryptedPubKeyDst = interface.GSS_WrapEx(pubKeyHex.decode('base64')) + EncryptedPubKeyDst = interface.GSS_WrapEx(base64.b64decode(pubKeyHex)) self.assertTrue(EncryptedPubKeySrc == EncryptedPubKeyDst, "Public key must be equals") \ No newline at end of file diff --git a/test/test_protocol_rdp_lic.py b/test/test_protocol_rdp_lic.py index 9627d801..a05d1f01 100644 --- a/test/test_protocol_rdp_lic.py +++ b/test/test_protocol_rdp_lic.py @@ -28,9 +28,10 @@ import unittest from rdpy.protocol.rdp import lic, sec import rdpy.core.type as type +import base64 #dump of server request -SERVERREQUEST = """ +SERVERREQUEST = b""" AQNfCBkr6c1CVLRPx7PPYVgzW5uMQ1pSvtzs9XlTt74jwjslAAAGACwAAABNAGkAYwByAG8AcwBv AGYAdAAgAEMAbwByAHAAbwByAGEAdABpAG8AbgAAAAgAAABBADAAMgAAAA0ABAABAAAAAwDZBwIA AAACAAAAWAMAADCCA1QwggJAoAMCAQICCAGemF/kFo3QMAkGBSsOAwIdBQAwODE2MBUGA1UEBx4O @@ -93,7 +94,7 @@ def test_valid_client_licensing_error_message(self): s = type.Stream() s.writeType(lic.createValidClientLicensingErrorMessage()) #reinit position - s.pos = 0 + s._pos(0) self.assertTrue(l.recv(s), "Manager can retrieve valid case") @@ -106,7 +107,7 @@ def sendFlagged(self, flag, message): return s = type.Stream() s.writeType(message) - s.pos = 0 + s._pos(0) s.readType(lic.LicPacket(lic.ClientNewLicenseRequest())) self._state = True def getGCCServerSettings(self): @@ -124,6 +125,7 @@ def __init__(self): t = Transport() l = lic.LicenseManager(t) - s = type.Stream(SERVERREQUEST.decode("base64")) + s = type.Stream(base64.b64decode(SERVERREQUEST)) - self.assertFalse(l.recv(s) and t._state, "Bad message after license request") \ No newline at end of file + # FIXME + # self.assertFalse(l.recv(s) and t._state, "Bad message after license request") \ No newline at end of file diff --git a/test/test_protocol_rdp_per.py b/test/test_protocol_rdp_per.py index ad3f7a00..ecd787c4 100644 --- a/test/test_protocol_rdp_per.py +++ b/test/test_protocol_rdp_per.py @@ -41,7 +41,7 @@ def test_per_readLength(self): """ s1 = type.Stream() s1.writeType(type.UInt8(0x1a)) - s1.pos = 0 + s1._pos(0) l1 = per.readLength(s1) @@ -49,7 +49,7 @@ def test_per_readLength(self): s2 = type.Stream() s2.writeType(type.UInt16Be(0x1abc | 0x8000)) - s2.pos = 0 + s2._pos(0) l2 = per.readLength(s2) @@ -79,7 +79,7 @@ def test_per_readInteger(self): v = t(3) s = type.Stream() s.writeType((per.writeLength(type.sizeof(v)), v)) - s.pos = 0 + s._pos(0) self.assertTrue(per.readInteger(s) == 3, "invalid readLength for type %s"%t) @@ -87,7 +87,7 @@ def test_per_readInteger(self): for l in [0, 3, 5]: s = type.Stream() s.writeType(per.writeLength(l)) - s.pos = 0 + s._pos(0) self.assertRaises(error.InvalidValue, per.readInteger, s) diff --git a/test/test_protocol_rdp_rc4.py b/test/test_protocol_rdp_rc4.py index 68063463..a6c9f293 100644 --- a/test/test_protocol_rdp_rc4.py +++ b/test/test_protocol_rdp_rc4.py @@ -36,13 +36,13 @@ class RC4Test(unittest.TestCase): """ def test_rc4_key_plaintext(self): - self.assertEqual("\xBB\xF3\x16\xE8\xD9\x40\xAF\x0A\xD3", rc4.crypt(rc4.RC4Key("Key"), "Plaintext"), "RC4 bad crypt") - self.assertEqual("Plaintext", rc4.crypt(rc4.RC4Key("Key"), "\xBB\xF3\x16\xE8\xD9\x40\xAF\x0A\xD3"), "RC4 bad crypt") + self.assertEqual(b"\xBB\xF3\x16\xE8\xD9\x40\xAF\x0A\xD3", rc4.crypt(rc4.RC4Key(b"Key"), b"Plaintext"), "RC4 bad crypt") + self.assertEqual(b"Plaintext", rc4.crypt(rc4.RC4Key(b"Key"), b"\xBB\xF3\x16\xE8\xD9\x40\xAF\x0A\xD3"), "RC4 bad crypt") def test_rc4_wiki_pedia(self): - self.assertEqual("\x10\x21\xBF\x04\x20", rc4.crypt(rc4.RC4Key("Wiki"), "pedia"), "RC4 bad crypt") - self.assertEqual("pedia", rc4.crypt(rc4.RC4Key("Wiki"), "\x10\x21\xBF\x04\x20"), "RC4 bad crypt") + self.assertEqual(b"\x10\x21\xBF\x04\x20", rc4.crypt(rc4.RC4Key(b"Wiki"), b"pedia"), "RC4 bad crypt") + self.assertEqual(b"pedia", rc4.crypt(rc4.RC4Key(b"Wiki"), b"\x10\x21\xBF\x04\x20"), "RC4 bad crypt") def test_rc4_secret_attack_at_down(self): - self.assertEqual("\x45\xA0\x1F\x64\x5F\xC3\x5B\x38\x35\x52\x54\x4B\x9B\xF5", rc4.crypt(rc4.RC4Key("Secret"), "Attack at dawn"), "RC4 bad crypt") - self.assertEqual("Attack at dawn", rc4.crypt(rc4.RC4Key("Secret"), "\x45\xA0\x1F\x64\x5F\xC3\x5B\x38\x35\x52\x54\x4B\x9B\xF5"), "RC4 bad crypt") + self.assertEqual(b"\x45\xA0\x1F\x64\x5F\xC3\x5B\x38\x35\x52\x54\x4B\x9B\xF5", rc4.crypt(rc4.RC4Key(b"Secret"), b"Attack at dawn"), "RC4 bad crypt") + self.assertEqual(b"Attack at dawn", rc4.crypt(rc4.RC4Key(b"Secret"), b"\x45\xA0\x1F\x64\x5F\xC3\x5B\x38\x35\x52\x54\x4B\x9B\xF5"), "RC4 bad crypt") diff --git a/test/test_protocol_rdp_tpkt.py b/test/test_protocol_rdp_tpkt.py index 9e277921..5fb36aeb 100644 --- a/test/test_protocol_rdp_tpkt.py +++ b/test/test_protocol_rdp_tpkt.py @@ -60,10 +60,10 @@ class Presentation(object): def connect(self): pass def recv(self, data): - data.readType(type.String("test_tpkt_layer_recv", constant = True)) + data.readType(type.String(b"test_tpkt_layer_recv", constant = True)) raise TPKTTest.TPKT_PASS() - message = type.String("test_tpkt_layer_recv") + message = type.String(b"test_tpkt_layer_recv") s = type.Stream() s.writeType((type.UInt8(tpkt.Action.FASTPATH_ACTION_X224), type.UInt8(), type.UInt16Be(type.sizeof(message) + 4), message)) @@ -80,10 +80,10 @@ class FastPathLayer(tpkt.IFastPathListener): def setFastPathSender(self, fastPathSender): pass def recvFastPath(self, secFlag, fastPathS): - fastPathS.readType(type.String("test_tpkt_layer_recv_fastpath", constant = True)) + fastPathS.readType(type.String(b"test_tpkt_layer_recv_fastpath", constant = True)) raise TPKTTest.TPKT_PASS() - message = type.String("test_tpkt_layer_recv_fastpath") + message = type.String(b"test_tpkt_layer_recv_fastpath") s = type.Stream() s.writeType((type.UInt8(tpkt.Action.FASTPATH_ACTION_FASTPATH), type.UInt8(type.sizeof(message) + 2), message)) @@ -101,10 +101,10 @@ class FastPathLayer(tpkt.IFastPathListener): def setFastPathSender(self, fastPathSender): pass def recvFastPath(self, secflag, fastPathS): - fastPathS.readType(type.String("test_tpkt_layer_recv_fastpath_ext_length", constant = True)) + fastPathS.readType(type.String(b"test_tpkt_layer_recv_fastpath_ext_length", constant = True)) raise TPKTTest.TPKT_PASS() - message = type.String("test_tpkt_layer_recv_fastpath_ext_length") + message = type.String(b"test_tpkt_layer_recv_fastpath_ext_length") s = type.Stream() s.writeType((type.UInt8(tpkt.Action.FASTPATH_ACTION_FASTPATH), type.UInt16Be((type.sizeof(message) + 3) | 0x8000), message)) diff --git a/test/test_protocol_rdp_x224.py b/test/test_protocol_rdp_x224.py index e396e06f..2d62c81a 100644 --- a/test/test_protocol_rdp_x224.py +++ b/test/test_protocol_rdp_x224.py @@ -53,14 +53,14 @@ def test_x224_layer_recvData(self): """ class Presentation(object): def recv(self, data): - data.readType(type.String('test_x224_layer_recvData', constant = True)) + data.readType(type.String(b'test_x224_layer_recvData', constant = True)) raise X224Test.X224_PASS() layer = x224.X224Layer(Presentation()) s = type.Stream() - s.writeType((x224.X224DataHeader(), type.String('test_x224_layer_recvData'))) + s.writeType((x224.X224DataHeader(), type.String(b'test_x224_layer_recvData'))) #reinit position - s.pos = 0 + s._pos(0) self.assertRaises(X224Test.X224_PASS, layer.recvData, s) @@ -72,15 +72,15 @@ class Transport(object): def send(self, data): s = type.Stream() s.writeType(data) - s.pos = 0 + s._pos(0) s.readType(x224.X224DataHeader()) - s.readType(type.String('test_x224_layer_send', constant = True)) + s.readType(type.String(b'test_x224_layer_send', constant = True)) raise X224Test.X224_PASS() layer = x224.X224Layer(None) layer._transport = Transport() - self.assertRaises(X224Test.X224_PASS, layer.send, type.String('test_x224_layer_send')) + self.assertRaises(X224Test.X224_PASS, layer.send, type.String(b'test_x224_layer_send')) def test_x224_client_connect(self): """ @@ -90,7 +90,7 @@ class Transport(object): def send(self, data): s = type.Stream() s.writeType(data) - s.pos = 0 + s._pos(0) t = x224.ClientConnectionRequestPDU() s.readType(t) @@ -105,7 +105,7 @@ def nextAutomata(data): layer.recvConnectionConfirm = nextAutomata layer.connect() - self.assertRaises(X224Test.X224_PASS, layer.recv, type.String('\x01\x02')) + self.assertRaises(X224Test.X224_PASS, layer.recv, type.String(b'\x01\x02')) def test_x224_client_recvConnectionConfirm_negotiation_failure(self): """ @@ -116,7 +116,7 @@ def test_x224_client_recvConnectionConfirm_negotiation_failure(self): message.protocolNeg.code.value = x224.NegociationType.TYPE_RDP_NEG_FAILURE s = type.Stream() s.writeType(message) - s.pos = 0 + s._pos(0) layer = x224.Client(None) self.assertRaises(error.RDPSecurityNegoFail, layer.recvConnectionConfirm, s) @@ -146,7 +146,7 @@ def recvData(data): s = type.Stream() s.writeType(message) - s.pos = 0 + s._pos(0) layer = x224.Client(Presentation()) layer._transport = Transport() layer.recvData = recvData @@ -155,7 +155,7 @@ def recvData(data): self.assertTrue(tls_begin, "TLS is not started") self.assertTrue(presentation_connect, "connect event is not forwarded") - self.assertRaises(X224Test.X224_PASS, layer.recv, type.String('\x01\x02')) + self.assertRaises(X224Test.X224_PASS, layer.recv, type.String(b'\x01\x02')) def test_x224_server_recvConnectionRequest_client_accept_ssl(self): """ @@ -176,7 +176,7 @@ def close(self): message.protocolNeg.selectedProtocol.value = x224.Protocols.PROTOCOL_HYBRID s = type.Stream() s.writeType(message) - s.pos = 0 + s._pos(0) layer = x224.Server(None, "key", "cert", True) layer._transport = Transport() @@ -218,7 +218,7 @@ def connect(self): message.protocolNeg.selectedProtocol.value = x224.Protocols.PROTOCOL_SSL | x224.Protocols.PROTOCOL_RDP s = type.Stream() s.writeType(message) - s.pos = 0 + s._pos(0) layer = x224.Server(Presentation(), "key", "cert") layer._transport = Transport() From c333389c3bc66b75926d6a3afa9fc807a8b4a286 Mon Sep 17 00:00:00 2001 From: Bruno Rodrigues Date: Tue, 30 Mar 2021 14:53:54 +0100 Subject: [PATCH 16/20] update readme and travis --- .travis.yml | 10 +++++----- README.md | 23 ++++++++++------------- 2 files changed, 15 insertions(+), 18 deletions(-) diff --git a/.travis.yml b/.travis.yml index e3494681..f1f7122b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,13 +1,13 @@ language: python python: - - 2.7 + - 3.8 before_install: - - sudo apt-get install python-qt4 - - ln -s /usr/lib/python2.7/dist-packages/PyQt4/ $VIRTUAL_ENV/lib/python2.7/site-packages/ - - ln -s /usr/lib/python2.7/dist-packages/sip.so $VIRTUAL_ENV/lib/python2.7/site-packages/ - - pip install qt4reactor pyopenssl twisted service_identity rsa pyasn1 + - sudo apt-get install python-qt5 + - ln -s /usr/lib/python3.8/dist-packages/PyQt5/ $VIRTUAL_ENV/lib/python3.8/site-packages/ + - ln -s /usr/lib/python3.8/dist-packages/sip.so $VIRTUAL_ENV/lib/python3.8/site-packages/ + - pip install qt5reactor pyopenssl twisted service_identity rsa pyasn1 install: - python setup.py install diff --git a/README.md b/README.md index dd6543ed..559be7a3 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ RDPY is fully implemented in python, except the bitmap decompression algorithm w ### Dependencies -Dependencies are only needed for pyqt4 binaries : +Dependencies are only needed for pyqt5 binaries : * rdpy-rdpclient * rdpy-rdpscreenshot * rdpy-vncclient @@ -30,7 +30,7 @@ Dependencies are only needed for pyqt4 binaries : Example for Debian based systems : ``` -sudo apt-get install python-qt4 +sudo apt-get install python-qt5 ``` #### OS X @@ -41,16 +41,13 @@ $ brew install qt sip pyqt #### Windows -x86 | x86_64 -----|------- -[PyQt4](http://sourceforge.net/projects/pyqt/files/PyQt4/PyQt-4.11.3/PyQt4-4.11.3-gpl-Py2.7-Qt4.8.6-x32.exe) | [PyQt4](http://sourceforge.net/projects/pyqt/files/PyQt4/PyQt-4.11.3/PyQt4-4.11.3-gpl-Py2.7-Qt4.8.6-x64.exe/download) -[PyWin32](http://sourceforge.net/projects/pywin32/files/pywin32/Build%20218/pywin32-218.win32-py2.7.exe/download) | [PyWin32](http://sourceforge.net/projects/pywin32/files/pywin32/Build%20218/pywin32-218.win-amd64-py2.7.exe/download) +… FIXME … ### Build ``` $ git clone https://github.com/citronneur/rdpy.git rdpy -$ pip install twisted pyopenssl qt4reactor service_identity rsa pyasn1 +$ pip install twisted pyopenssl qt5reactor service_identity rsa pyasn1 $ python rdpy/setup.py install ``` @@ -59,10 +56,10 @@ Or use PIP: $ pip install rdpy ``` -For virtualenv, you will need to link the qt4 library to it: +For virtualenv, you will need to link the qt5 library to it: ``` -$ ln -s /usr/lib/python2.7/dist-packages/PyQt4/ $VIRTUAL_ENV/lib/python2.7/site-packages/ -$ ln -s /usr/lib/python2.7/dist-packages/sip.so $VIRTUAL_ENV/lib/python2.7/site-packages/ +$ ln -s /usr/lib/python3.8/dist-packages/PyQt5/ $VIRTUAL_ENV/lib/python3.8/site-packages/ +$ ln -s /usr/lib/python3.8/dist-packages/sip.so $VIRTUAL_ENV/lib/python3.8/site-packages/ ``` ## RDPY Binaries @@ -71,7 +68,7 @@ RDPY comes with some very useful binaries. These binaries are linux and windows ### rdpy-rdpclient -rdpy-rdpclient is a simple RDP Qt4 client. +rdpy-rdpclient is a simple RDP Qt5 client. ``` $ rdpy-rdpclient.py [-u username] [-p password] [-d domain] [-r rss_ouput_file] [...] XXX.XXX.XXX.XXX[:3389] @@ -81,7 +78,7 @@ You can use rdpy-rdpclient in a Recorder Session Scenario, used in rdpy-rdphoney ### rdpy-vncclient -rdpy-vncclient is a simple VNC Qt4 client . +rdpy-vncclient is a simple VNC Qt5 client . ``` $ rdpy-vncclient.py [-p password] XXX.XXX.XXX.XXX[:5900] @@ -136,7 +133,7 @@ $ rdpy-rssplayer.py rss_file_path ## RDPY Qt Widget -RDPY can also be used as Qt widget through rdpy.ui.qt4.QRemoteDesktop class. It can be embedded in your own Qt application. qt4reactor must be used in your app for Twisted and Qt to work together. For more details, see sources of rdpy-rdpclient. +RDPY can also be used as Qt widget through rdpy.ui.qt5.QRemoteDesktop class. It can be embedded in your own Qt application. qt5reactor must be used in your app for Twisted and Qt to work together. For more details, see sources of rdpy-rdpclient. ## RDPY library From 9e46190ad9c942893600629ebca30db9a0af19f7 Mon Sep 17 00:00:00 2001 From: Bruno Rodrigues Date: Fri, 14 May 2021 11:57:12 +0100 Subject: [PATCH 17/20] no message --- bin/rdpy-rdpclient.py | 12 ++++++++++-- bin/rdpy-rdpscreenshot.py | 16 ++++++++++++---- bin/rdpy-vncclient.py | 15 ++++++++++++--- bin/rdpy-vncscreenshot.py | 13 +++++++++++-- rdpy/protocol/rdp/lic.py | 4 ++-- rdpy/protocol/rdp/rdp.py | 10 +++++++++- rdpy/protocol/rdp/t125/per.py | 2 +- test/test_protocol_rdp_lic.py | 3 +-- 8 files changed, 58 insertions(+), 17 deletions(-) diff --git a/bin/rdpy-rdpclient.py b/bin/rdpy-rdpclient.py index 14fef74f..eaa4020f 100755 --- a/bin/rdpy-rdpclient.py +++ b/bin/rdpy-rdpclient.py @@ -32,6 +32,12 @@ import rdpy.core.log as log log._LOG_LEVEL = log.Level.INFO +def stop(reactor): + try: + reactor.stop() + except Exception as e: + log.warning(f"Error stopping reactor: {e}") + class RDPClientQtRecorder(RDPClientQt): """ @@ -173,7 +179,8 @@ def clientConnectionLost(self, connector, reason): return log.info("Lost connection : %s"%reason) - reactor.stop() + # reactor.stop() + stop(reactor) app.exit() def clientConnectionFailed(self, connector, reason): @@ -183,7 +190,8 @@ def clientConnectionFailed(self, connector, reason): @param reason: str use to advertise reason of lost connection """ log.info("Connection failed : %s"%reason) - reactor.stop() + # reactor.stop() + stop(reactor) app.exit() def autoDetectKeyboardLayout(): diff --git a/bin/rdpy-rdpscreenshot.py b/bin/rdpy-rdpscreenshot.py index a33cbf51..241a1e5a 100755 --- a/bin/rdpy-rdpscreenshot.py +++ b/bin/rdpy-rdpscreenshot.py @@ -37,6 +37,12 @@ # set log level log._LOG_LEVEL = log.Level.INFO +def stop(reactor): + try: + reactor.stop() + except Exception as e: + log.warning(f"Error stopping reactor: {e}") + class RDPScreenShotFactory(rdp.ClientFactory): """ @@ -79,7 +85,8 @@ def clientConnectionLost(self, connector, reason): RDPScreenShotFactory.__STATE__.append((connector.host, connector.port, reason)) RDPScreenShotFactory.__INSTANCE__ -= 1 if(RDPScreenShotFactory.__INSTANCE__ == 0): - self._reactor.stop() + #self._reactor.stop() + stop(self._reactor) self._app.exit() def clientConnectionFailed(self, connector, reason): @@ -92,7 +99,8 @@ def clientConnectionFailed(self, connector, reason): RDPScreenShotFactory.__STATE__.append((connector.host, connector.port, reason)) RDPScreenShotFactory.__INSTANCE__ -= 1 if(RDPScreenShotFactory.__INSTANCE__ == 0): - self._reactor.stop() + #self._reactor.stop() + stop(self._reactor) self._app.exit() def buildObserver(self, controller, addr): @@ -158,9 +166,9 @@ def onClose(self): log.info("close") def checkUpdate(self): - self._controller.close(); + self._controller.close() - controller.setScreen(self._width, self._height); + controller.setScreen(self._width, self._height) controller.setSecurityLevel(self._security) return ScreenShotObserver(controller, self._width, self._height, self._path, self._timeout, self._reactor) diff --git a/bin/rdpy-vncclient.py b/bin/rdpy-vncclient.py index cb77fae6..a08bdea9 100755 --- a/bin/rdpy-vncclient.py +++ b/bin/rdpy-vncclient.py @@ -29,7 +29,14 @@ import rdpy.core.log as log log._LOG_LEVEL = log.Level.INFO - + +def stop(reactor): + try: + reactor.stop() + except Exception as e: + log.warning(f"Error stopping reactor: {e}") + + class RFBClientQtFactory(rfb.ClientFactory): """ @summary: Factory create a VNC GUI client @@ -63,7 +70,8 @@ def clientConnectionLost(self, connector, reason): @param reason: str use to advertise reason of lost connection """ QtWidgets.QMessageBox.warning(self._w, "Warning", "Lost connection : %s"%reason) - reactor.stop() + # reactor.stop() + stop(reactor) app.exit() def clientConnectionFailed(self, connector, reason): @@ -73,7 +81,8 @@ def clientConnectionFailed(self, connector, reason): @param reason: str use to advertise reason of lost connection """ QtWidgets.QMessageBox.warning(self._w, "Warning", "Connection failed : %s"%reason) - reactor.stop() + # reactor.stop() + stop(reactor) app.exit() if __name__ == '__main__': diff --git a/bin/rdpy-vncscreenshot.py b/bin/rdpy-vncscreenshot.py index 79466933..78941c3a 100755 --- a/bin/rdpy-vncscreenshot.py +++ b/bin/rdpy-vncscreenshot.py @@ -33,6 +33,13 @@ #set log level log._LOG_LEVEL = log.Level.INFO +def stop(reactor): + try: + reactor.stop() + except Exception as e: + log.warning(f"Error stopping reactor: {e}") + + class RFBScreenShotFactory(rfb.ClientFactory): """ @summary: Factory for screenshot exemple @@ -56,7 +63,8 @@ def clientConnectionLost(self, connector, reason): log.info("connection lost : %s"%reason) RFBScreenShotFactory.__INSTANCE__ -= 1 if(RFBScreenShotFactory.__INSTANCE__ == 0): - reactor.stop() + # reactor.stop() + stop(reactor) app.exit() def clientConnectionFailed(self, connector, reason): @@ -68,7 +76,8 @@ def clientConnectionFailed(self, connector, reason): log.info("connection failed : %s"%reason) RFBScreenShotFactory.__INSTANCE__ -= 1 if(RFBScreenShotFactory.__INSTANCE__ == 0): - reactor.stop() + # reactor.stop() + stop(reactor) app.exit() diff --git a/rdpy/protocol/rdp/lic.py b/rdpy/protocol/rdp/lic.py index 208e36b1..2f91e790 100644 --- a/rdpy/protocol/rdp/lic.py +++ b/rdpy/protocol/rdp/lic.py @@ -263,8 +263,8 @@ def __init__(self, transport): @param transport: layer use to send packet """ self._transport = transport - self._username = "" - self._hostname = "" + self._username = b"" + self._hostname = b"" def recv(self, s): """ diff --git a/rdpy/protocol/rdp/rdp.py b/rdpy/protocol/rdp/rdp.py index 0f3be0a3..2419a2c6 100644 --- a/rdpy/protocol/rdp/rdp.py +++ b/rdpy/protocol/rdp/rdp.py @@ -38,6 +38,10 @@ class SecurityLevel(object): RDP_LEVEL_SSL = 1 RDP_LEVEL_NLA = 2 +def b(value): + return value.encode('ascii') if type(value) == str else value + + class RDPClientController(pdu_layer.PDUClientListener): """ Manage RDP stack as client @@ -102,6 +106,7 @@ def setUsername(self, username): @param username: {string} username of session """ #username in PDU info packet + username = b(username) self._secLayer._info.userName.value = username self._secLayer._licenceManager._username = username @@ -110,6 +115,7 @@ def setPassword(self, password): @summary: Set password for session @param password: {string} password of session """ + password = b(password) self.setAutologon() self._secLayer._info.password.value = password @@ -118,6 +124,7 @@ def setDomain(self, domain): @summary: Set the windows domain of session @param domain: {string} domain of session """ + domain = b(domain) self._secLayer._info.domain.value = domain def setAutologon(self): @@ -147,7 +154,8 @@ def setHostname(self, hostname): """ @summary: set hostname of machine """ - self._mcsLayer._clientSettings.CS_CORE.clientName.value = hostname[:15] + "\x00" * (15 - len(hostname)) + hostname = b(hostname) + self._mcsLayer._clientSettings.CS_CORE.clientName.value = hostname[:15] + b"\x00" * (15 - len(hostname)) self._secLayer._licenceManager._hostname = hostname def setSecurityLevel(self, level): diff --git a/rdpy/protocol/rdp/t125/per.py b/rdpy/protocol/rdp/t125/per.py index aaced277..db8fc044 100644 --- a/rdpy/protocol/rdp/t125/per.py +++ b/rdpy/protocol/rdp/t125/per.py @@ -276,7 +276,7 @@ def readOctetStream(s, octetStream, minValue = 0): """ size = readLength(s) + minValue if size != len(octetStream): - raise InvalidValue("incompatible size %d != %d"(len(octetStream), size)) + raise InvalidValue("incompatible size %d != %d"%(len(octetStream), size)) for i in range(0, size): c = UInt8() s.readType(c) diff --git a/test/test_protocol_rdp_lic.py b/test/test_protocol_rdp_lic.py index a05d1f01..c5d54239 100644 --- a/test/test_protocol_rdp_lic.py +++ b/test/test_protocol_rdp_lic.py @@ -127,5 +127,4 @@ def __init__(self): s = type.Stream(base64.b64decode(SERVERREQUEST)) - # FIXME - # self.assertFalse(l.recv(s) and t._state, "Bad message after license request") \ No newline at end of file + self.assertFalse(l.recv(s) and t._state, "Bad message after license request") \ No newline at end of file From 97f2683e5b051429e9d74e550820433bde458177 Mon Sep 17 00:00:00 2001 From: Bruno Rodrigues Date: Fri, 14 May 2021 20:09:25 +0100 Subject: [PATCH 18/20] debug --- .gitignore | 1 + bin/rdpy-rdpscreenshot.py | 17 +++++++++++++++++ rdpy/core/layer.py | 5 +++++ rdpy/core/type.py | 6 +++++- rdpy/protocol/rdp/nla/ntlm.py | 2 +- rdpy/security/x509.py | 16 +++++++++++++--- 6 files changed, 42 insertions(+), 5 deletions(-) diff --git a/.gitignore b/.gitignore index 56750d33..1189fe6a 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,4 @@ README.md~ dist/* build/* rdpy.egg-info/* +rdpy-*.* diff --git a/bin/rdpy-rdpscreenshot.py b/bin/rdpy-rdpscreenshot.py index 241a1e5a..c8c9543f 100755 --- a/bin/rdpy-rdpscreenshot.py +++ b/bin/rdpy-rdpscreenshot.py @@ -34,6 +34,8 @@ from rdpy.core.error import RDPSecurityNegoFail from twisted.internet import task +from rdpy.core.layer import RawLayer + # set log level log._LOG_LEVEL = log.Level.INFO @@ -196,6 +198,21 @@ def main(width, height, path, timeout, hosts): else: ip, port = host, "3389" + # FIXME + out_file = path + "%s.bin" % ip + if os.path.exists(out_file): + os.unlink(out_file) + def hack(data): + #print(f"FOOBAR data {data}") + # only first line + if os.path.exists(out_file): + return + out= open(out_file, "ab") + out.write(data) + # out.write(b"\n") + out.close() + RawLayer.__hack__ = hack + reactor.connectTCP(ip, int(port), RDPScreenShotFactory(reactor, app, width, height, path + "%s.jpg" % ip, timeout)) reactor.runReturn() diff --git a/rdpy/core/layer.py b/rdpy/core/layer.py index 09d9b4ab..3d6cb3fb 100644 --- a/rdpy/core/layer.py +++ b/rdpy/core/layer.py @@ -199,6 +199,11 @@ def dataReceived(self, data): """ #add in buffer self._buffer += data + + if hasattr(self, '__hack__'): + RawLayer.__hack__(data) + # print(f"dataReceived {data}") + #while buffer have expected size call local callback while self._expectedLen > 0 and len(self._buffer) >= self._expectedLen: #expected data is first expected bytes diff --git a/rdpy/core/type.py b/rdpy/core/type.py index fc15a4ee..a5539814 100644 --- a/rdpy/core/type.py +++ b/rdpy/core/type.py @@ -817,7 +817,9 @@ def __write__(self, s): s.write(encodeUnicode(self.value)) else: s.write(self.value) - + + # print(f"String write unicode={self._unicode} {self.value}") # FIXME + def __read__(self, s): """ @summary: Read readLen bytes as string @@ -837,6 +839,8 @@ def __read__(self, s): if self._unicode: self.value = decodeUnicode(self.value) + + # print(f"String read unicode={self._unicode} {self.value}") # FIXME def __sizeof__(self): """ diff --git a/rdpy/protocol/rdp/nla/ntlm.py b/rdpy/protocol/rdp/nla/ntlm.py index cba4a4c9..14921096 100644 --- a/rdpy/protocol/rdp/nla/ntlm.py +++ b/rdpy/protocol/rdp/nla/ntlm.py @@ -352,7 +352,7 @@ def UNICODE(s): @param s: source @return: {str} encoded in unicode """ - s = s.decode("utf-8") if type(s) == bytes else s # FIXME + s = s.decode("utf-8") if type(s) == bytes else s return s.encode('utf-16le') def MD4(s): diff --git a/rdpy/security/x509.py b/rdpy/security/x509.py index 63630d4c..4e36b845 100644 --- a/rdpy/security/x509.py +++ b/rdpy/security/x509.py @@ -150,10 +150,20 @@ def extractRSAKey(certificate): #http://www.alvestrand.no/objectid/1.2.840.113549.1.1.1.html binaryTuple = certificate.getComponentByName('tbsCertificate').getComponentByName('subjectPublicKeyInfo').getComponentByName('subjectPublicKey') + print(f"rsa binaryTuple {len(binaryTuple)} {binaryTuple}") + l = "".join([str(i) for i in binaryTuple]) + print(f"rsa l {len(l)} {l}") l = int("".join([str(i) for i in binaryTuple]), 2) - h = hex(l)[2:-1] - h = '0' + h if len(h) % 2 != 0 else h - return extractRSAKeyFromASN1(decode(h, 'hex')) + print(f"rsa l {len(str(l))} {l}") + h = hex(l) + print(f"rsa h {len(h)} {h}") + #h = hex(l)[2:-1] + h = hex(l)[2:] + print(f"rsa h {len(h)} {h}") + #h = '0' + h if len(h) % 2 != 0 else h + decoded_hex = decode(h, 'hex') + print(f"rsa binaryTuple {len(binaryTuple)} {binaryTuple} l {l} h {len(h)} {h} decoded_hex={decoded_hex}") + return extractRSAKeyFromASN1(decoded_hex) def extractRSAKeyFromASN1(subjectPublicKey): rsaKey = decoder.decode(subjectPublicKey, asn1Spec=RSAPublicKey())[0] From bc8e231d80ec1d22d716505642a70379f2fe37e1 Mon Sep 17 00:00:00 2001 From: Bruno Rodrigues Date: Tue, 18 May 2021 16:33:47 +0100 Subject: [PATCH 19/20] no message --- .gitignore | 4 +++- bin/rdpy-rdpscreenshot.py | 18 +++++++++++++++--- bin/rdpy-vncscreenshot.py | 32 +++++++++++++++++++++++++++++--- setup.py | 2 +- 4 files changed, 48 insertions(+), 8 deletions(-) diff --git a/.gitignore b/.gitignore index 1189fe6a..b5f971a1 100644 --- a/.gitignore +++ b/.gitignore @@ -7,4 +7,6 @@ README.md~ dist/* build/* rdpy.egg-info/* -rdpy-*.* +# version +rdpy-*.*.* +temp diff --git a/bin/rdpy-rdpscreenshot.py b/bin/rdpy-rdpscreenshot.py index c8c9543f..d8e15907 100755 --- a/bin/rdpy-rdpscreenshot.py +++ b/bin/rdpy-rdpscreenshot.py @@ -41,6 +41,9 @@ def stop(reactor): try: + # https://stackoverflow.com/a/13538248 + reactor.removeAll() + reactor.iterate() reactor.stop() except Exception as e: log.warning(f"Error stopping reactor: {e}") @@ -77,13 +80,15 @@ def clientConnectionLost(self, connector, reason): @param connector: twisted connector use for rdp connection (use reconnect to restart connection) @param reason: str use to advertise reason of lost connection """ - if reason.type == RDPSecurityNegoFail and self._security != "rdp": + if reason.type == RDPSecurityNegoFail and self._security != rdp.SecurityLevel.RDP_LEVEL_RDP: log.info("due to RDPSecurityNegoFail try standard security layer") self._security = rdp.SecurityLevel.RDP_LEVEL_RDP connector.connect() return - log.info("connection lost : %s" % reason) + if "Connection was closed cleanly" not in f"{reason}": + log.info("connection lost : %s" % reason) + RDPScreenShotFactory.__STATE__.append((connector.host, connector.port, reason)) RDPScreenShotFactory.__INSTANCE__ -= 1 if(RDPScreenShotFactory.__INSTANCE__ == 0): @@ -192,6 +197,10 @@ def main(width, height, path, timeout, hosts): from twisted.internet import reactor + # FIXME + if len(hosts) != 1: + raise Exception(f"Only one host supported, got {hosts}") + for host in hosts: if ':' in host: ip, port = host.split(':') @@ -202,8 +211,9 @@ def main(width, height, path, timeout, hosts): out_file = path + "%s.bin" % ip if os.path.exists(out_file): os.unlink(out_file) + print(f"[*] INFO: out_file={out_file}") def hack(data): - #print(f"FOOBAR data {data}") + # print(f"FOOBAR data {data}") # only first line if os.path.exists(out_file): return @@ -251,4 +261,6 @@ def help(): elif opt == "-t": timeout = float(arg) + # print(f"opts={opts} args={args}") + main(width, height, path, timeout, args) diff --git a/bin/rdpy-vncscreenshot.py b/bin/rdpy-vncscreenshot.py index 78941c3a..74acbc6e 100755 --- a/bin/rdpy-vncscreenshot.py +++ b/bin/rdpy-vncscreenshot.py @@ -30,11 +30,16 @@ from rdpy.ui.qt5 import qtImageFormatFromRFBPixelFormat from twisted.internet import task +from rdpy.core.layer import RawLayer + #set log level log._LOG_LEVEL = log.Level.INFO def stop(reactor): try: + # https://stackoverflow.com/a/13538248 + reactor.removeAll() + reactor.iterate() reactor.stop() except Exception as e: log.warning(f"Error stopping reactor: {e}") @@ -60,7 +65,8 @@ def clientConnectionLost(self, connector, reason): @param connector: twisted connector use for rfb connection (use reconnect to restart connection) @param reason: str use to advertise reason of lost connection """ - log.info("connection lost : %s"%reason) + if "Connection was closed cleanly" not in f"{reason}": + log.info("connection lost : %s"%reason) RFBScreenShotFactory.__INSTANCE__ -= 1 if(RFBScreenShotFactory.__INSTANCE__ == 0): # reactor.stop() @@ -118,7 +124,7 @@ def onUpdate(self, width, height, x, y, pixelFormat, encoding, data): return image = QtGui.QImage(data, width, height, imageFormat) with QtGui.QPainter(self._buffer) as qp: - #draw image + #draw image qp.drawImage(x, y, image, 0, 0, width, height) self._got_screenshot = True @@ -175,13 +181,33 @@ def help(): qt5reactor.install() from twisted.internet import reactor + + # FIXME + if len(args) != 1: + raise Exception(f"Only one host supported, got {args}") for arg in args: if ':' in arg: ip, port = arg.split(':') else: ip, port = arg, "5900" - + + # FIXME + out_file = path + "%s.bin" % ip + if os.path.exists(out_file): + os.unlink(out_file) + print(f"[*] INFO: out_file={out_file}") + def hack(data): + # print(f"FOOBAR data {data}") + # only first line + if os.path.exists(out_file): + return + out= open(out_file, "ab") + out.write(data) + # out.write(b"\n") + out.close() + RawLayer.__hack__ = hack + reactor.connectTCP(ip, int(port), RFBScreenShotFactory(password, path + "%s.jpg"%ip)) diff --git a/setup.py b/setup.py index 8825335d..e686f5a9 100644 --- a/setup.py +++ b/setup.py @@ -4,7 +4,7 @@ from distutils.core import setup, Extension setup(name='rdpy', - version='1.3.2', + version='1.3.3-bs1', 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. From 1665aedefa7f0c2aeea42fce8321322390ef6e76 Mon Sep 17 00:00:00 2001 From: Bruno Rodrigues Date: Fri, 11 Jun 2021 10:41:11 +0100 Subject: [PATCH 20/20] no message --- bin/rdpy-rdpscreenshot.py | 7 ++++--- bin/rdpy-vncscreenshot.py | 40 ++++++++++++++++++++++++++++----------- setup.py | 2 +- 3 files changed, 34 insertions(+), 15 deletions(-) diff --git a/bin/rdpy-rdpscreenshot.py b/bin/rdpy-rdpscreenshot.py index d8e15907..3290420f 100755 --- a/bin/rdpy-rdpscreenshot.py +++ b/bin/rdpy-rdpscreenshot.py @@ -143,9 +143,10 @@ def onUpdate(self, destLeft, destTop, destRight, destBottom, width, height, bits """ image = RDPBitmapToQtImage(width, height, bitsPerPixel, isCompress, data); with QtGui.QPainter(self._buffer) as qp: - # draw image + # draw image qp.drawImage(destLeft, destTop, image, 0, 0, destRight - destLeft + 1, destBottom - destTop + 1) - self._got_screenshot = True + log.info(f"incoming frame pos={destLeft},{destTop} size={destRight - destLeft + 1},{destBottom - destTop + 1}") + self._got_screenshot = True if not self._startTimeout: self._startTimeout = False self._reactor.callLater(self._timeout, self.checkUpdate) @@ -242,7 +243,7 @@ def help(): width = 1024 height = 800 path = "/tmp/" - timeout = 5.0 + timeout = 2.0 try: opts, args = getopt.getopt(sys.argv[1:], "hw:l:o:t:") diff --git a/bin/rdpy-vncscreenshot.py b/bin/rdpy-vncscreenshot.py index 74acbc6e..5d566ab3 100755 --- a/bin/rdpy-vncscreenshot.py +++ b/bin/rdpy-vncscreenshot.py @@ -50,13 +50,15 @@ class RFBScreenShotFactory(rfb.ClientFactory): @summary: Factory for screenshot exemple """ __INSTANCE__ = 0 - def __init__(self, password, path): + def __init__(self, reactor, password, path, timeout): """ @param password: password for VNC authentication @param path: path of output screenshot """ RFBScreenShotFactory.__INSTANCE__ += 1 + self._reactor = reactor self._path = path + self._timeout = timeout self._password = password def clientConnectionLost(self, connector, reason): @@ -97,7 +99,7 @@ class ScreenShotObserver(rfb.RFBClientObserver): """ @summary: observer that connect, cache every image received and save at deconnection """ - def __init__(self, controller, path): + def __init__(self, controller, path, timeout, reactor): """ @param controller: RFBClientController @param path: path of output screenshot @@ -105,6 +107,9 @@ def __init__(self, controller, path): rfb.RFBClientObserver.__init__(self, controller) self._path = path self._buffer = None + self._timeout = timeout + self._reactor = reactor + self._startTimeout = False self._got_screenshot = False def onUpdate(self, width, height, x, y, pixelFormat, encoding, data): @@ -126,17 +131,23 @@ def onUpdate(self, width, height, x, y, pixelFormat, encoding, data): with QtGui.QPainter(self._buffer) as qp: #draw image qp.drawImage(x, y, image, 0, 0, width, height) - self._got_screenshot = True - - self._controller.close() - + log.info(f"incoming frame pos={x},{y} size={width},{height}") + self._got_screenshot = True + self.mouseEvent(1, 1, 1) + self.keyEvent(True, 27) # escape key + + if not self._startTimeout: + self._startTimeout = False + self._reactor.callLater(self._timeout, self.checkUpdate) + def onReady(self): """ @summary: callback use when RDP stack is connected (just before received bitmap) """ log.info("connected %s"%addr) - width, height = self._controller.getScreen() - self._buffer = QtGui.QImage(width, height, QtGui.QImage.Format_RGB32) + self._width, self._height = self._controller.getScreen() + log.info(f"ready size={self._width},{self._height}") + self._buffer = QtGui.QImage(self._width, self._height, QtGui.QImage.Format_RGB32) def onClose(self): """ @@ -147,17 +158,22 @@ def onClose(self): self._buffer.save(self._path) log.info("close") + def checkUpdate(self): + self._controller.close() + controller.setPassword(self._password) - return ScreenShotObserver(controller, self._path) + return ScreenShotObserver(controller, self._path, self._timeout, self._reactor) def help(): print("Usage: rdpy-vncscreenshot [options] ip[:port]") print("\t-o: file path of screenshot default(/tmp/rdpy-vncscreenshot.jpg)") + print("\t-t: timeout of connection without any updating order (default is 2s)") print("\t-p: password for VNC Session") if __name__ == '__main__': #default script argument path = "/tmp/" + timeout = 2.0 password = "" try: @@ -172,6 +188,8 @@ def help(): path = arg elif opt == "-p": password = arg + elif opt == "-t": + timeout = float(arg) #create application app = QtWidgets.QApplication(sys.argv) @@ -208,8 +226,8 @@ def hack(data): out.close() RawLayer.__hack__ = hack - reactor.connectTCP(ip, int(port), RFBScreenShotFactory(password, path + "%s.jpg"%ip)) - + reactor.connectTCP(ip, int(port), RFBScreenShotFactory(reactor, password, path + "%s.jpg" % ip, timeout)) + reactor.runReturn() app.exec_() \ No newline at end of file diff --git a/setup.py b/setup.py index e686f5a9..618f4216 100644 --- a/setup.py +++ b/setup.py @@ -4,7 +4,7 @@ from distutils.core import setup, Extension setup(name='rdpy', - version='1.3.3-bs1', + version='1.3.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.