bug fix on gui + add license neg (almost)

This commit is contained in:
speyrefitte
2014-11-28 17:54:49 +01:00
parent 4e7ea06906
commit 5af9f0708a
7 changed files with 389 additions and 127 deletions

View File

@@ -930,7 +930,7 @@ class OrderUpdateDataPDU(CompositeType):
self.pad2OctetsA = UInt16Le()
self.numberOrders = UInt16Le(lambda:len(self.orderData._array))
self.pad2OctetsB = UInt16Le()
self.orderData = ArrayType(order.DrawingOrder, readLen = self.numberOrders)
self.orderData = ArrayType(order.PrimaryDrawingOrder, readLen = self.numberOrders)
class BitmapCompressedDataHeader(CompositeType):
"""

View File

@@ -136,6 +136,8 @@ class Client(PDULayer, tpkt.IFastPathListener):
self._listener = listener
#enable or not fast path
self._fastPathSender = None
#todo generate hostname
self._licenceManager = lic.LicenseManager(self, self._info.userName.value, "wav-glw-009")
def connect(self):
"""
@@ -177,18 +179,9 @@ class Client(PDULayer, tpkt.IFastPathListener):
if not (securityFlag.value & data.SecurityFlag.SEC_LICENSE_PKT):
raise InvalidExpectedDataException("Waiting license packet")
validClientPdu = lic.LicPacket()
s.readType(validClientPdu)
if validClientPdu.bMsgtype.value == lic.MessageType.ERROR_ALERT and validClientPdu.licensingMessage.dwErrorCode.value == lic.ErrorCode.STATUS_VALID_CLIENT and validClientPdu.licensingMessage.dwStateTransition.value == lic.StateTransition.ST_NO_TRANSITION:
if self._licenceManager.recv(s):
self.setNextState(self.recvDemandActivePDU)
#not tested because i can't buy RDP license server
elif validClientPdu.bMsgtype.value == lic.MessageType.LICENSE_REQUEST:
newLicenseReq = lic.createNewLicenseRequest(validClientPdu.licensingMessage)
self._transport.send((UInt16Le(data.SecurityFlag.SEC_LICENSE_PKT), UInt16Le(), newLicenseReq))
else:
raise InvalidExpectedDataException("Not a valid license packet")
def recvDemandActivePDU(self, s):
"""
Receive demand active PDU which contains
@@ -343,6 +336,13 @@ class Client(PDULayer, tpkt.IFastPathListener):
"""
self._transport.send((UInt16Le(data.SecurityFlag.SEC_INFO_PKT), UInt16Le(), self._info))
def sendLicensePacket(self, licPkt):
"""
@summary: send license packet
@param licPktr: license packet
"""
self._transport.send((UInt16Le(data.SecurityFlag.SEC_LICENSE_PKT), UInt16Le(), licPkt))
def sendConfirmActivePDU(self):
"""
Send all client capabilities

View File

@@ -18,17 +18,20 @@
#
"""
RDP extended license
@summary: RDP extended license
@see: http://msdn.microsoft.com/en-us/library/cc241880.aspx
"""
from rdpy.network.type import CompositeType, UInt8, UInt16Le, UInt32Le, String, sizeof, FactoryType, ArrayType
from rdpy.network.type import CompositeType, UInt8, UInt16Le, UInt32Le, String, sizeof, FactoryType, ArrayType,\
Stream
from rdpy.base.error import InvalidExpectedDataException
import rdpy.base.log as log
import rdpy.protocol.rdp.sec as sec
import rdpy.protocol.rdp.rc4 as rc4
class MessageType(object):
"""
License packet message type
@summary: License packet message type
"""
LICENSE_REQUEST = 0x01
PLATFORM_CHALLENGE = 0x02
@@ -42,7 +45,7 @@ class MessageType(object):
class ErrorCode(object):
"""
License error message code
@summary: License error message code
@see: http://msdn.microsoft.com/en-us/library/cc240482.aspx
"""
ERR_INVALID_SERVER_CERTIFICATE = 0x00000001
@@ -57,7 +60,7 @@ class ErrorCode(object):
class StateTransition(object):
"""
Automata state transition
@summary: Automata state transition
@see: http://msdn.microsoft.com/en-us/library/cc240482.aspx
"""
ST_TOTAL_ABORT = 0x00000001
@@ -67,9 +70,10 @@ class StateTransition(object):
class BinaryBlobType(object):
"""
Binary blob data type
@summary: Binary blob data type
@see: http://msdn.microsoft.com/en-us/library/cc240481.aspx
"""
BB_ANY_BLOB = 0x0000
BB_DATA_BLOB = 0x0001
BB_RANDOM_BLOB = 0x0002
BB_CERTIFICATE_BLOB = 0x0003
@@ -82,25 +86,25 @@ class BinaryBlobType(object):
class Preambule(object):
"""
Preambule version
@summary: Preambule version
"""
PREAMBLE_VERSION_2_0 = 0x2
PREAMBLE_VERSION_3_0 = 0x3
class LicenseBinaryBlob(CompositeType):
"""
Blob use by license manager to exchange security data
@summary: Blob use by license manager to exchange security data
@see: http://msdn.microsoft.com/en-us/library/cc240481.aspx
"""
def __init__(self, blobType = 0):
def __init__(self, blobType = BinaryBlobType.BB_ANY_BLOB):
CompositeType.__init__(self)
self.wBlobType = UInt16Le(blobType, constant = True)
self.wBlobType = UInt16Le(blobType, constant = True if blobType != BinaryBlobType.BB_ANY_BLOB else False)
self.wBlobLen = UInt16Le(lambda:sizeof(self.blobData))
self.blobData = String(readLen = self.wBlobLen)
class LicensingErrorMessage(CompositeType):
"""
License error message
@summary: License error message
@see: http://msdn.microsoft.com/en-us/library/cc240482.aspx
"""
_MESSAGE_TYPE_ = MessageType.ERROR_ALERT
@@ -113,7 +117,7 @@ class LicensingErrorMessage(CompositeType):
class ProductInformation(CompositeType):
"""
License server product information
@summary: License server product information
@see: http://msdn.microsoft.com/en-us/library/cc241915.aspx
"""
def __init__(self):
@@ -121,15 +125,15 @@ class ProductInformation(CompositeType):
self.dwVersion = UInt32Le()
self.cbCompanyName = UInt32Le(lambda:sizeof(self.pbCompanyName))
#may contain "Microsoft Corporation" from server microsoft
self.pbCompanyName = String(readLen = self.cbCompanyName)
self.pbCompanyName = String(readLen = self.cbCompanyName, unicode = True)
self.cbProductId = UInt32Le(lambda:sizeof(self.pbProductId))
#may contain "A02" from microsoft license server
self.pbProductId = String(readLen = self.cbProductId)
self.pbProductId = String(readLen = self.cbProductId, unicode = True)
class Scope(CompositeType):
"""
Use in license nego
@summary: Use in license nego
@see: http://msdn.microsoft.com/en-us/library/cc241917.aspx
"""
def __init__(self):
@@ -138,7 +142,7 @@ class Scope(CompositeType):
class ScopeList(CompositeType):
"""
Use in license nego
@summary: Use in license nego
@see: http://msdn.microsoft.com/en-us/library/cc241916.aspx
"""
def __init__(self):
@@ -148,8 +152,8 @@ class ScopeList(CompositeType):
class ServerLicenseRequest(CompositeType):
"""
Send by server to signal license request
server -> client
@summary: Send by server to signal license request
server -> client
@see: http://msdn.microsoft.com/en-us/library/cc241914.aspx
"""
_MESSAGE_TYPE_ = MessageType.LICENSE_REQUEST
@@ -164,8 +168,8 @@ class ServerLicenseRequest(CompositeType):
class ClientNewLicenseRequest(CompositeType):
"""
Send by client to ask new license for client.
RDPY doesn'support license reuse, need it in futur version
@summary: Send by client to ask new license for client.
RDPY doesn'support license reuse, need it in futur version
@see: http://msdn.microsoft.com/en-us/library/cc241918.aspx
"""
_MESSAGE_TYPE_ = MessageType.NEW_LICENSE_REQUEST
@@ -181,6 +185,32 @@ class ClientNewLicenseRequest(CompositeType):
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)
class ServerPlatformChallenge(CompositeType):
"""
@summary: challenge send from server to client
@see: http://msdn.microsoft.com/en-us/library/cc241921.aspx
"""
_MESSAGE_TYPE_ = MessageType.PLATFORM_CHALLENGE
def __init__(self):
CompositeType.__init__(self)
self.connectFlags = UInt32Le()
self.encryptedPlatformChallenge = LicenseBinaryBlob(BinaryBlobType.BB_ANY_BLOB)
self.MACData = String(readLen = UInt8(16))
class ClientPLatformChallengeResponse(CompositeType):
"""
@summary: client challenge response
@see: http://msdn.microsoft.com/en-us/library/cc241922.aspx
"""
_MESSAGE_TYPE_ = MessageType.PLATFORM_CHALLENGE_RESPONSE
def __init__(self):
CompositeType.__init__(self)
self.encryptedPlatformChallengeResponse = LicenseBinaryBlob(BinaryBlobType.BB_ENCRYPTED_DATA_BLOB)
self.encryptedHWID = LicenseBinaryBlob(BinaryBlobType.BB_ENCRYPTED_DATA_BLOB)
self.MACData = String(readLen = UInt8(16))
class LicPacket(CompositeType):
"""
@@ -198,7 +228,7 @@ class LicPacket(CompositeType):
factory for message nego
Use in read mode
"""
for c in [LicensingErrorMessage, ServerLicenseRequest, ClientNewLicenseRequest]:
for c in [LicensingErrorMessage, ServerLicenseRequest, ClientNewLicenseRequest, ServerPlatformChallenge, ClientPLatformChallengeResponse]:
if self.bMsgtype.value == c._MESSAGE_TYPE_:
return c()
log.debug("unknown license message : %s"%self.bMsgtype.value)
@@ -210,23 +240,94 @@ class LicPacket(CompositeType):
raise InvalidExpectedDataException("Try to send an invalid license message")
self.licensingMessage = message
def createValidClientLicensingErrorMessage():
"""
@summary: Create a licensing error message that accept client
server automata message
"""
message = LicensingErrorMessage()
message.dwErrorCode.value = ErrorCode.STATUS_VALID_CLIENT
message.dwStateTransition.value = StateTransition.ST_NO_TRANSITION
return LicPacket(message = message)
class LicenseManager(object):
"""
Create a licensing error message that accept client
server automata message
@summary: handle license automata
@see: http://msdn.microsoft.com/en-us/library/cc241890.aspx
"""
message = LicensingErrorMessage()
message.dwErrorCode.value = ErrorCode.STATUS_VALID_CLIENT
message.dwStateTransition.value = StateTransition.ST_NO_TRANSITION
return LicPacket(message = message)
def createNewLicenseRequest(serverLicenseRequest):
"""
Create new license request in response to server license request
@see: http://msdn.microsoft.com/en-us/library/cc241989.aspx
@see: http://msdn.microsoft.com/en-us/library/cc241918.aspx
"""
message = ClientNewLicenseRequest()
def __init__(self, transport, username, hostname):
"""
@param transport: layer use to send packet
"""
self._clientRandom = "\x00" * 32
self._serverRandom = None
self._serverEncryptedChallenge = None
self._transport = transport
self._username = username
self._hostname = hostname
def generateKeys(self):
"""
@summary: generate key for license session
"""
self._masterSecret = sec.generateMicrosoftKey("\x00" * 64, self._clientRandom, self._serverRandom)
self._sessionKeyBlob = sec.generateMicrosoftKey(self._masterSecret, self._serverRandom, self._clientRandom)
self._macSalt = self._sessionKeyBlob[:16]
self._licenseKey = sec.md5_16_32_32(self._sessionKeyBlob[16:], self._clientRandom, self._serverRandom)
def recv(self, s):
"""
@summary: receive license packet from PDU layer
@return true when license automata is finish
"""
licPacket = LicPacket()
s.readType(licPacket)
#end of automata
if licPacket.bMsgtype.value == MessageType.ERROR_ALERT and licPacket.licensingMessage.dwErrorCode.value == ErrorCode.STATUS_VALID_CLIENT and licPacket.licensingMessage.dwStateTransition.value == StateTransition.ST_NO_TRANSITION:
return True
elif licPacket.bMsgtype.value == MessageType.LICENSE_REQUEST:
self._serverRandom = licPacket.licensingMessage.serverRandom.value
self.generateKeys()
self.sendClientNewLicenseRequest()
elif licPacket.bMsgtype.value == MessageType.PLATFORM_CHALLENGE:
self._serverEncryptedChallenge = licPacket.licensingMessage.encryptedPlatformChallenge.blobData.value
self.sendClientChallengeResponse()
else:
raise InvalidExpectedDataException("Not a valid license packet")
return LicPacket(message)
def sendClientNewLicenseRequest(self):
"""
@summary: Create new license request in response to server license request
@see: http://msdn.microsoft.com/en-us/library/cc241989.aspx
@see: http://msdn.microsoft.com/en-us/library/cc241918.aspx
"""
message = ClientNewLicenseRequest()
message.clientRandom.value = self._clientRandom
message.encryptedPreMasterSecret.blobData = String("\x00" * (64 + 8))
message.ClientMachineName.blobData = String(self._hostname + "\x00")
message.ClientUserName.blobData = String(self._username + "\x00")
self._transport.sendLicensePacket(LicPacket(message))
def sendClientChallengeResponse(self):
#it should be TEST in unicode format
serverChallenge = rc4.crypt(self._licenseKey, self._serverEncryptedChallenge)
#generate hwid
s = Stream()
s.writeType((UInt32Le(2), String(self._username + self._hostname + "\x00" * 20)))
hwid = s.getvalue()[:20]
signature = sec.macData(self._macSalt, serverChallenge + hwid)
message = ClientPLatformChallengeResponse()
message.encryptedPlatformChallengeResponse.blobData.value = self._serverEncryptedChallenge
message.encryptedHWID.blobData.value = rc4.crypt(self._licenseKey, hwid)
message.MACData.value = signature
self._transport.sendLicensePacket(LicPacket(message))

56
rdpy/protocol/rdp/rc4.py Normal file
View File

@@ -0,0 +1,56 @@
"""
Copyright (C) 2012 Bo Zhu http://about.bozhu.me
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
"""
def KSA(key):
keylength = len(key)
S = range(256)
j = 0
for i in range(256):
j = (j + S[i] + key[i % keylength]) % 256
S[i], S[j] = S[j], S[i] # swap
return S
def PRGA(S):
i = 0
j = 0
while True:
i = (i + 1) % 256
j = (j + S[i]) % 256
S[i], S[j] = S[j], S[i] # swap
K = S[(S[i] + S[j]) % 256]
yield K
def RC4(key):
S = KSA(key)
return PRGA(S)
def crypt(key, plaintext):
keystream = RC4([ord(c) for c in key])
return "".join([chr(ord(c) ^ keystream.next()) for c in plaintext])

View File

@@ -68,13 +68,13 @@ class RDPClientController(pdu.layer.PDUClientListener):
def setPerformanceSession(self):
"""
Set particular flag in RDP stack to avoid wall-paper, theme, menu animation etc...
@summary: Set particular flag in RDP stack to avoid wall-paper, theme, menu animation etc...
"""
self._pduLayer._info.extendedInfo.performanceFlags.value = pdu.data.PerfFlag.PERF_DISABLE_WALLPAPER | pdu.data.PerfFlag.PERF_DISABLE_MENUANIMATIONS | pdu.data.PerfFlag.PERF_DISABLE_CURSOR_SHADOW | pdu.data.PerfFlag.PERF_DISABLE_THEMING | pdu.data.PerfFlag.PERF_DISABLE_FULLWINDOWDRAG
def setScreen(self, width, height):
"""
Set screen dim of session
@summary: Set screen dim of session
@param width: width in pixel of screen
@param height: height in pixel of screen
"""
@@ -84,7 +84,7 @@ class RDPClientController(pdu.layer.PDUClientListener):
def setUsername(self, username):
"""
Set the username for session
@summary: Set the username for session
@param username: username of session
"""
#username in PDU info packet
@@ -92,7 +92,7 @@ class RDPClientController(pdu.layer.PDUClientListener):
def setPassword(self, password):
"""
Set password for session
@summary: Set password for session
@param password: password of session
"""
self.setAutologon()
@@ -100,7 +100,7 @@ class RDPClientController(pdu.layer.PDUClientListener):
def setDomain(self, domain):
"""
Set the windows domain of session
@summary: Set the windows domain of session
@param domain: domain of session
"""
self._pduLayer._info.domain.value = domain
@@ -113,14 +113,14 @@ class RDPClientController(pdu.layer.PDUClientListener):
def addClientObserver(self, observer):
"""
Add observer to RDP protocol
@summary: Add observer to RDP protocol
@param observer: new observer to add
"""
self._clientObserver.append(observer)
def removeClientObserver(self, observer):
"""
Remove observer to RDP protocol stack
@summary: Remove observer to RDP protocol stack
@param observer: observer to remove
"""
for i in range(0, len(self._clientObserver)):
@@ -130,7 +130,7 @@ class RDPClientController(pdu.layer.PDUClientListener):
def onUpdate(self, rectangles):
"""
Call when a bitmap data is received from update PDU
@summary: Call when a bitmap data is received from update PDU
@param rectangles: [pdu.BitmapData] struct
"""
for observer in self._clientObserver:
@@ -140,7 +140,7 @@ class RDPClientController(pdu.layer.PDUClientListener):
def onReady(self):
"""
Call when PDU layer is connected
@summary: Call when PDU layer is connected
"""
self._isReady = True
#signal all listener
@@ -149,7 +149,7 @@ class RDPClientController(pdu.layer.PDUClientListener):
def onClose(self):
"""
Event call when RDP stack is closed
@summary: Event call when RDP stack is closed
"""
self._isReady = False
for observer in self._clientObserver:
@@ -157,7 +157,7 @@ class RDPClientController(pdu.layer.PDUClientListener):
def sendPointerEvent(self, x, y, button, isPressed):
"""
send pointer events
@summary: send pointer events
@param x: x position of pointer
@param y: y position of pointer
@param button: 1 or 2 or 3
@@ -189,10 +189,44 @@ class RDPClientController(pdu.layer.PDUClientListener):
except InvalidValue:
log.info("try send pointer event with incorrect position")
def sendWheelEvent(self, x, y, step, isNegative = False, isHorizontal = False):
"""
@summary: Send a mouse wheel event
@param x: x position of pointer
@param y: y position of pointer
@param step: number of step rolled
@param isHorizontal: horizontal wheel (default is vertical)
@param isNegative: is upper (default down)
"""
if not self._isReady:
return
try:
event = pdu.data.PointerEvent()
if isHorizontal:
event.pointerFlags.value |= pdu.data.PointerFlag.PTRFLAGS_HWHEEL
else:
event.pointerFlags.value |= pdu.data.PointerFlag.PTRFLAGS_WHEEL
if isNegative:
event.pointerFlags.value |= pdu.data.PointerFlag.PTRFLAGS_WHEEL_NEGATIVE
event.pointerFlags.value |= (step & pdu.data.PointerFlag.WheelRotationMask)
#position
event.xPos.value = x
event.yPos.value = y
#send proper event
self._pduLayer.sendInputEvents([event])
except InvalidValue:
log.info("try send wheel event with incorrect position")
def sendKeyEventScancode(self, code, isPressed):
"""
Send a scan code to RDP stack
@summary: Send a scan code to RDP stack
@param code: scan code
@param isPressed: True if key is pressed and false if it's released
"""
@@ -215,7 +249,7 @@ class RDPClientController(pdu.layer.PDUClientListener):
def sendKeyEventUnicode(self, code, isPressed):
"""
Send a scan code to RDP stack
@summary: Send a scan code to RDP stack
@param code: unicode
@param isPressed: True if key is pressed and false if it's released
"""
@@ -236,7 +270,7 @@ class RDPClientController(pdu.layer.PDUClientListener):
def sendRefreshOrder(self, left, top, right, bottom):
"""
Force server to resend a particular zone
@summary: Force server to resend a particular zone
@param left: left coordinate
@param top: top coordinate
@param right: right coordinate
@@ -253,13 +287,13 @@ class RDPClientController(pdu.layer.PDUClientListener):
def close(self):
"""
Close protocol stack
@summary: Close protocol stack
"""
self._pduLayer.close()
class RDPServerController(pdu.layer.PDUServerListener):
"""
Controller use in server side mode
@summary: Controller use in server side mode
"""
def __init__(self, privateKeyFileName, certificateFileName, colorDepth):
"""
@@ -283,7 +317,7 @@ class RDPServerController(pdu.layer.PDUServerListener):
def close(self):
"""
Close protocol stack
@summary: Close protocol stack
"""
self._pduLayer.close()
@@ -296,28 +330,28 @@ class RDPServerController(pdu.layer.PDUServerListener):
def getUsername(self):
"""
Must be call after on ready event else always empty string
@summary: Must be call after on ready event else always empty string
@return: username send by client may be an empty string
"""
return self._pduLayer._info.userName.value
def getPassword(self):
"""
Must be call after on ready event else always empty string
@summary: Must be call after on ready event else always empty string
@return: password send by client may be an empty string
"""
return self._pduLayer._info.password.value
def getDomain(self):
"""
Must be call after on ready event else always empty string
@summary: Must be call after on ready event else always empty string
@return: domain send by client may be an empty string
"""
return self._pduLayer._info.domain.value
def getCredentials(self):
"""
Must be call after on ready event else always empty string
@summary: Must be call after on ready event else always empty string
@return: tuple(domain, username, password)
"""
return (self.getDomain(), self.getUsername(), self.getPassword())
@@ -337,15 +371,15 @@ class RDPServerController(pdu.layer.PDUServerListener):
def addServerObserver(self, observer):
"""
Add observer to RDP protocol
@summary: Add observer to RDP protocol
@param observer: new observer to add
"""
self._serverObserver.append(observer)
def setColorDepth(self, colorDepth):
"""
Set color depth of session
if PDU stack is already connected send a deactive-reactive sequence
@summary: Set color depth of session
if PDU stack is already connected send a deactive-reactive sequence
@param colorDepth: depth of session (15, 16, 24)
"""
self._colorDepth = colorDepth
@@ -357,13 +391,13 @@ class RDPServerController(pdu.layer.PDUServerListener):
def setKeyEventUnicodeSupport(self):
"""
Enable key event in unicode format
@summary: Enable key event in unicode format
"""
self._pduLayer._serverCapabilities[pdu.caps.CapsType.CAPSTYPE_INPUT].capability.inputFlags.value |= pdu.caps.InputFlags.INPUT_FLAG_UNICODE
def onReady(self):
"""
RDP stack is now ready
@summary: RDP stack is now ready
"""
self._isReady = True
for observer in self._serverObserver:
@@ -371,7 +405,7 @@ class RDPServerController(pdu.layer.PDUServerListener):
def onClose(self):
"""
Event call when RDP stack is closed
@summary: Event call when RDP stack is closed
"""
self._isReady = False
for observer in self._serverObserver:
@@ -379,7 +413,7 @@ class RDPServerController(pdu.layer.PDUServerListener):
def onSlowPathInput(self, slowPathInputEvents):
"""
Event call when slow path input are available
@summary: Event call when slow path input are available
@param slowPathInputEvents: [data.SlowPathInputEvent]
"""
for observer in self._serverObserver:
@@ -404,7 +438,7 @@ class RDPServerController(pdu.layer.PDUServerListener):
def sendUpdate(self, destLeft, destTop, destRight, destBottom, width, height, bitsPerPixel, isCompress, data):
"""
send bitmap update
@summary: send bitmap update
@param destLeft: xmin position
@param destTop: ymin position
@param destRight: xmax position because RDP can send bitmap with padding
@@ -454,7 +488,7 @@ class ClientFactory(layer.RawLayerClientFactory):
class ServerFactory(layer.RawLayerServerFactory):
"""
Factory of Server RDP protocol
@summary: Factory of Server RDP protocol
"""
def __init__(self, privateKeyFileName, certificateFileName, colorDepth):
"""
@@ -476,7 +510,7 @@ class ServerFactory(layer.RawLayerServerFactory):
def buildRawLayer(self, addr):
"""
Function call from twisted and build rdp protocol stack
@summary: Function call from twisted and build rdp protocol stack
@param addr: destination address
"""
controller = RDPServerController(self._privateKeyFileName, self._certificateFileName, self._colorDepth)
@@ -485,7 +519,7 @@ class ServerFactory(layer.RawLayerServerFactory):
def buildObserver(self, controller, addr):
"""
Build observer use for connection
@summary: Build observer use for connection
@param controller: RDP stack controller
@param addr: destination address
"""
@@ -493,7 +527,7 @@ class ServerFactory(layer.RawLayerServerFactory):
class RDPClientObserver(object):
"""
Class use to inform all RDP event handle by RDPY
@summary: Class use to inform all RDP event handle by RDPY
"""
def __init__(self, controller):
"""
@@ -504,19 +538,19 @@ class RDPClientObserver(object):
def onReady(self):
"""
Stack is ready and connected
@summary: Stack is ready and connected
"""
raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "onReady", "RDPClientObserver"))
def onClose(self):
"""
Stack is closes
@summary: Stack is closes
"""
raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "onClose", "RDPClientObserver"))
def onUpdate(self, destLeft, destTop, destRight, destBottom, width, height, bitsPerPixel, isCompress, data):
"""
Notify bitmap update
@summary: Notify bitmap update
@param destLeft: xmin position
@param destTop: ymin position
@param destRight: xmax position because RDP can send bitmap with padding
@@ -531,7 +565,7 @@ class RDPClientObserver(object):
class RDPServerObserver(object):
"""
Class use to inform all RDP event handle by RDPY
@summary: Class use to inform all RDP event handle by RDPY
"""
def __init__(self, controller):
"""
@@ -542,20 +576,20 @@ class RDPServerObserver(object):
def onReady(self):
"""
Stack is ready and connected
@summary: Stack is ready and connected
May be called after an setColorDepth too
"""
raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "onReady", "RDPServerObserver"))
def onClose(self):
"""
Stack is closes
@summary: Stack is closes
"""
raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "onClose", "RDPClientObserver"))
def onKeyEventScancode(self, code, isPressed):
"""
Event call when a keyboard event is catch in scan code format
@summary: Event call when a keyboard event is catch in scan code format
@param code: scan code of key
@param isPressed: True if key is down
"""
@@ -563,7 +597,7 @@ class RDPServerObserver(object):
def onKeyEventUnicode(self, code, isPressed):
"""
Event call when a keyboard event is catch in unicode format
@summary: Event call when a keyboard event is catch in unicode format
@param code: unicode of key
@param isPressed: True if key is down
"""
@@ -571,7 +605,7 @@ class RDPServerObserver(object):
def onPointerEvent(self, x, y, button, isPressed):
"""
Event call on mouse event
@summary: Event call on mouse event
@param x: x position
@param y: y position
@param button: 1, 2 or 3 button

View File

@@ -22,6 +22,7 @@ Some use full methods for security in RDP
"""
import sha, md5
from rdpy.network.type import Stream, UInt32Le
def saltedHash(inputData, salt, salt1, salt2):
"""
@@ -47,6 +48,46 @@ def saltedHash(inputData, salt, salt1, salt2):
return md5Digest.digest()
def masterSecret(preMasterSecret, clientRandom, serverRandom):
def md5_16_32_32(in0, in1, in2):
"""
"""
@summary: MD5(in0[:16] + in1[:32] + in2[:32])
@param in0: in 16
@param in1: in 32
@param in2: in 32
@return MD5(in0[:16] + in1[:32] + in2[:32])
"""
md5Digest = md5.new()
md5Digest.update(in0[:16])
md5Digest.update(in1[:32])
md5Digest.update(in2[:32])
return md5Digest.digest()
def generateMicrosoftKey(secret, random1, random2):
"""
@summary: Generate master secret
@param secret: secret
@param clientRandom : client random
@param serverRandom : server random
"""
return saltedHash("A", secret, random1, random2) + saltedHash("BB", secret, random1, random2) + saltedHash("CCC", secret, random1, random2)
def macData(macSaltKey, data):
sha1Digest = sha.new()
md5Digest = md5.new()
#encode length
s = Stream()
s.writeType(UInt32Le(len(data)))
sha1Digest.update(macSaltKey)
sha1Digest.update("\x36" * 40)
sha1Digest.update(s.getvalue())
sha1Digest.update(data)
sha1Sig = sha1Digest.digest()
md5Digest.update(macSaltKey)
md5Digest.update("\x5c" * 48)
md5Digest.update(sha1Sig)
return md5Digest.digest()

View File

@@ -34,12 +34,12 @@ import rle
class QAdaptor(object):
"""
Adaptor model with link between protocol
And Qt widget
@summary: Adaptor model with link between protocol
And Qt widget
"""
def sendMouseEvent(self, e, isPressed):
"""
Interface to send mouse event to protocol stack
@summary: Interface to send mouse event to protocol stack
@param e: QMouseEvent
@param isPressed: event come from press or release action
"""
@@ -47,11 +47,18 @@ class QAdaptor(object):
def sendKeyEvent(self, e, isPressed):
"""
Interface to send key event to protocol stack
@summary: Interface to send key event to protocol stack
@param e: QEvent
@param isPressed: event come from press or release action
"""
raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "sendKeyEvent", "QAdaptor"))
raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "sendKeyEvent", "QAdaptor"))
def sendWheelEvent(self, e):
"""
@summary: Interface to send wheel event to protocol stack
@param e: QWheelEvent
"""
raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "sendWheelEvent", "QAdaptor"))
def getWidget(self):
"""
@@ -61,7 +68,7 @@ class QAdaptor(object):
def closeEvent(self, e):
"""
Call when you want to close connection
@summary: Call when you want to close connection
@param: QCloseEvent
"""
raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "closeEvent", "QAdaptor"))
@@ -77,7 +84,7 @@ def qtImageFormatFromRFBPixelFormat(pixelFormat):
class RFBClientQt(RFBClientObserver, QAdaptor):
"""
QAdaptor for specific RFB protocol stack
@summary: QAdaptor for specific RFB protocol stack
is to an RFB observer
"""
def __init__(self, controller):
@@ -97,7 +104,7 @@ class RFBClientQt(RFBClientObserver, QAdaptor):
def onUpdate(self, width, height, x, y, pixelFormat, encoding, data):
"""
Implement RFBClientObserver interface
@summary: Implement RFBClientObserver interface
@param width: width of new image
@param height: height of new image
@param x: x position of new image
@@ -136,7 +143,7 @@ class RFBClientQt(RFBClientObserver, QAdaptor):
def sendMouseEvent(self, e, isPressed):
"""
Convert Qt mouse event to RFB mouse event
@summary: Convert Qt mouse event to RFB mouse event
@param e: qMouseEvent
@param isPressed: event come from press or release action
"""
@@ -152,29 +159,37 @@ class RFBClientQt(RFBClientObserver, QAdaptor):
def sendKeyEvent(self, e, isPressed):
"""
Convert Qt key press event to RFB press event
@summary: Convert Qt key press event to RFB press event
@param e: qKeyEvent
@param isPressed: event come from press or release action
"""
self.keyEvent(isPressed, e.nativeVirtualKey())
def sendWheelEvent(self, e):
"""
@summary: Convert Qt wheel event to RFB Wheel event
@param e: QKeyEvent
@param isPressed: event come from press or release action
"""
pass
def closeEvent(self, e):
"""
Call when you want to close connection
@summary: Call when you want to close connection
@param: QCloseEvent
"""
self._controller.close()
def onClose(self):
"""
Call when stack is close
@summary: Call when stack is close
"""
#do something maybe a message
pass
def RDPBitmapToQtImage(destLeft, width, height, bitsPerPixel, isCompress, data):
"""
Bitmap transformation to Qt object
@summary: Bitmap transformation to Qt object
@param width: width of bitmap
@param height: height of bitmap
@param bitsPerPixel: number of bit per pixel
@@ -204,15 +219,15 @@ def RDPBitmapToQtImage(destLeft, width, height, bitsPerPixel, isCompress, data):
if isCompress:
buf = bytearray(width * height * 3)
rle.bitmap_decompress(buf, width, height, data, 3)
image = QtGui.QImage(buf, width, height, QtGui.QImage.Format_RGB24)
image = QtGui.QImage(buf, width, height, QtGui.QImage.Format_RGB888)
else:
image = QtGui.QImage(data, width, height, QtGui.QImage.Format_RGB24).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.QMatrix(1.0, 0.0, 0.0, -1.0, 0.0, 0.0))
elif bitsPerPixel == 32:
if isCompress:
buf = bytearray(width * height * 4)
rle.bitmap_decompress(buf, width, height, data, 4)
image = QtGui.QImage(buf, width, height, QtGui.QImage.Format_RGB24)
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))
else:
@@ -222,7 +237,7 @@ def RDPBitmapToQtImage(destLeft, width, height, bitsPerPixel, isCompress, data):
class RDPClientQt(RDPClientObserver, QAdaptor):
"""
Adaptor for RDP client
@summary: Adaptor for RDP client
"""
def __init__(self, controller, width, height):
"""
@@ -243,7 +258,7 @@ class RDPClientQt(RDPClientObserver, QAdaptor):
def sendMouseEvent(self, e, isPressed):
"""
Convert Qt mouse event to RDP mouse event
@summary: Convert Qt mouse event to RDP mouse event
@param e: qMouseEvent
@param isPressed: event come from press(true) or release(false) action
"""
@@ -251,15 +266,15 @@ class RDPClientQt(RDPClientObserver, QAdaptor):
buttonNumber = 0
if button == QtCore.Qt.LeftButton:
buttonNumber = 1
elif button == QtCore.Qt.MidButton:
buttonNumber = 2
elif button == QtCore.Qt.RightButton:
buttonNumber = 2
elif button == QtCore.Qt.MidButton:
buttonNumber = 3
self._controller.sendPointerEvent(e.pos().x(), e.pos().y(), buttonNumber, isPressed)
def sendKeyEvent(self, e, isPressed):
"""
Convert Qt key press event to RFB press event
@summary: Convert Qt key press event to RDP press event
@param e: QKeyEvent
@param isPressed: event come from press or release action
"""
@@ -267,17 +282,25 @@ class RDPClientQt(RDPClientObserver, QAdaptor):
if sys.platform == "linux2":
code -= 8
self._controller.sendKeyEventScancode(code, isPressed)
def sendWheelEvent(self, e):
"""
@summary: Convert Qt wheel event to RDP Wheel event
@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)
def closeEvent(self, e):
"""
Convert Qt close widget event into close stack event
@summary: Convert Qt close widget event into close stack event
@param e: QCloseEvent
"""
self._controller.close()
def onUpdate(self, destLeft, destTop, destRight, destBottom, width, height, bitsPerPixel, isCompress, data):
"""
Notify bitmap update
@summary: Notify bitmap update
@param destLeft: xmin position
@param destTop: ymin position
@param destRight: xmax position because RDP can send bitmap with padding
@@ -295,14 +318,14 @@ class RDPClientQt(RDPClientObserver, QAdaptor):
def onReady(self):
"""
Call when stack is ready
@summary: Call when stack is ready
"""
#do something maybe a loader
pass
def onClose(self):
"""
Call when stack is close
@summary: Call when stack is close
"""
#do something maybe a message
pass
@@ -310,7 +333,7 @@ class RDPClientQt(RDPClientObserver, QAdaptor):
class QRemoteDesktop(QtGui.QWidget):
"""
Qt display widget
@summary: Qt display widget
"""
def __init__(self, adaptor, width, height):
"""
@@ -334,7 +357,7 @@ class QRemoteDesktop(QtGui.QWidget):
def notifyImage(self, x, y, qimage, width, height):
"""
Function call from QAdaptor
@summary: Function call from QAdaptor
@param x: x position of new image
@param y: y position of new image
@param qimage: new QImage
@@ -346,7 +369,7 @@ class QRemoteDesktop(QtGui.QWidget):
def paintEvent(self, e):
"""
Call when Qt renderer engine estimate that is needed
@summary: Call when Qt renderer engine estimate that is needed
@param e: QEvent
"""
#fill buffer image
@@ -362,42 +385,49 @@ class QRemoteDesktop(QtGui.QWidget):
def mouseMoveEvent(self, event):
"""
Call when mouse move
@summary: Call when mouse move
@param event: QMouseEvent
"""
self._adaptor.sendMouseEvent(event, False)
def mousePressEvent(self, event):
"""
Call when button mouse is pressed
@summary: Call when button mouse is pressed
@param event: QMouseEvent
"""
self._adaptor.sendMouseEvent(event, True)
def mouseReleaseEvent(self, event):
"""
Call when button mouse is released
@summary: Call when button mouse is released
@param event: QMouseEvent
"""
self._adaptor.sendMouseEvent(event, False)
def keyPressEvent(self, event):
"""
Call when button key is pressed
@summary: Call when button key is pressed
@param event: QKeyEvent
"""
self._adaptor.sendKeyEvent(event, True)
def keyReleaseEvent(self, event):
"""
Call when button key is released
@summary: Call when button key is released
@param event: QKeyEvent
"""
self._adaptor.sendKeyEvent(event, False)
def wheelEvent(self, event):
"""
@summary: Call on wheel event
@param event: QWheelEvent
"""
self._adaptor.sendWheelEvent(event)
def closeEvent(self, event):
"""
Call when widget is closed
@summary: Call when widget is closed
@param event: QCloseEvent
"""
self._adaptor.closeEvent(event)