commit f4c77886bddd8d97a93f2e389195e7c038992551 Author: Matias Fernandez Date: Tue Mar 27 10:45:54 2018 -0300 Initial commit diff --git a/pyvncs/__init__.py b/pyvncs/__init__.py new file mode 100644 index 0000000..7b7400f --- /dev/null +++ b/pyvncs/__init__.py @@ -0,0 +1,22 @@ +# coding=utf-8 +# pyvncs +# Copyright (C) 2017-2018 Matias Fernandez +# +# This program is free software: you can redistribute it and/or modify it under +# the terms of the GNU Lesser 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 Lesser General Public License for more +# details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this program. If not, see . + +""" +The main pyvncs module +""" + +from . import server diff --git a/pyvncs/__pycache__/__init__.cpython-36.pyc b/pyvncs/__pycache__/__init__.cpython-36.pyc new file mode 100644 index 0000000..65bdec7 Binary files /dev/null and b/pyvncs/__pycache__/__init__.cpython-36.pyc differ diff --git a/pyvncs/__pycache__/server.cpython-36.pyc b/pyvncs/__pycache__/server.cpython-36.pyc new file mode 100644 index 0000000..44b0a05 Binary files /dev/null and b/pyvncs/__pycache__/server.cpython-36.pyc differ diff --git a/pyvncs/server.py b/pyvncs/server.py new file mode 100644 index 0000000..6bf81a5 --- /dev/null +++ b/pyvncs/server.py @@ -0,0 +1,816 @@ +# coding=utf-8 +# pyvncs +# Copyright (C) 2017-2018 Matias Fernandez +# +# This program is free software: you can redistribute it and/or modify it under +# the terms of the GNU Lesser 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 Lesser General Public License for more +# details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this program. If not, see . + +from struct import * +from pyDes import * +from time import sleep +from pynput import mouse, keyboard + +import socket +import select +import os +import sys +import random +import zlib +import numpy as np + +def hexdump(data): + str = "" + for d in data: + str += hex(d) + str += "(%s) " % d + return str + +def quantizetopalette(silf, palette, dither=False): + """Convert an RGB or L mode image to use a given P image's palette.""" + + silf.load() + + # use palette from reference image + palette.load() + if palette.mode != "P": + raise ValueError("bad mode for palette image") + if silf.mode != "RGB" and silf.mode != "L": + raise ValueError( + "only RGB or L mode images can be quantized to a palette" + ) + im = silf.im.convert("P", 1 if dither else 0, palette.im) + # the 0 above means turn OFF dithering + + # Later versions of Pillow (4.x) rename _makeself to _new + try: + return silf._new(im) + except AttributeError: + return silf._makeself(im) + + +from PIL import Image, ImageChops, ImageDraw, ImagePalette +if sys.platform == "linux" or sys.platform == "linux2": + from Xlib import display, X + # take screen images, that's not the best way, so here + # we use directly use xlib to take the screenshot. + class ImageGrab(): + def grab(): + dsp = display.Display() + root = dsp.screen().root + geom = root.get_geometry() + w = geom.width + h = geom.height + raw = root.get_image(0, 0, w ,h, X.ZPixmap, 0xffffffff) + image = Image.frombytes("RGB", (w, h), raw.data, "raw", "BGRX") + return image + +elif sys.platform == "darwin": + import Quartz.CoreGraphics as CG + class ImageGrab(): + def grab(): + screenshot = CG.CGWindowListCreateImage(CG.CGRectInfinite, CG.kCGWindowListOptionOnScreenOnly, CG.kCGNullWindowID, CG.kCGWindowImageDefault) + width = CG.CGImageGetWidth(screenshot) + height = CG.CGImageGetHeight(screenshot) + bytesperrow = CG.CGImageGetBytesPerRow(screenshot) + + pixeldata = CG.CGDataProviderCopyData(CG.CGImageGetDataProvider(screenshot)) + + i = Image.frombytes("RGBA", (width, height), pixeldata) + (b, g, r, x) = i.split() + i = Image.merge("RGBX", (r, g, b, x)) + + return i + +else: + from PIL import ImageGrab + + + +class VncServer(): + + class ENCODINGS: + raw = 0 + zlib = 6 # zlib + cursor = -239 # mouse cursor pseudo encoding + + class CONFIG: + _8bitdither = False + + def __init__(self, socket, password): + self.RFB_VERSION = '003.008' + self.RFB_SECTYPES = [ + 2, # VNC auth + 19 # VeNCrypt + ] + self.initmsg = ("RFB %s\n" % self.RFB_VERSION) + self.socket = socket + self.framebuffer = None + self.password = password + self.sectypes = self.RFB_SECTYPES + self.remotecursor = False + + self.BGR233 = [0, 0, 0, 0, 0, 85, 0, 0, 170, 0, 0, 255, 36, 0, 0, + 36, 0, 85, 36, 0, 170, 36, 0, 255, 73, 0, 0, 73, 0, + 85, 73, 0, 170, 73, 0, 255, 109, 0, 0, 109, 0, 85, + 109, 0, 170, 109, 0, 255, 146, 0, 0, 146, 0, 85, 146, + 0, 170, 146, 0, 255, 182, 0, 0, 182, 0, 85, 182, 0, + 170, 182, 0, 255, 219, 0, 0, 219, 0, 85, 219, 0, 170, + 219, 0, 255, 255, 0, 0, 255, 0, 85, 255, 0, 170, 255, + 0, 255, 0, 36, 0, 0, 36, 85, 0, 36, 170, 0, 36, 255, + 36, 36, 0, 36, 36, 85, 36, 36, 170, 36, 36, 255, 73, + 36, 0, 73, 36, 85, 73, 36, 170, 73, 36, 255, 109, 36, + 0, 109, 36, 85, 109, 36, 170, 109, 36, 255, 146, 36, + 0, 146, 36, 85, 146, 36, 170, 146, 36, 255, 182, 36, + 0, 182, 36, 85, 182, 36, 170, 182, 36, 255, 219, 36, + 0, 219, 36, 85, 219, 36, 170, 219, 36, 255, 255, 36, + 0, 255, 36, 85, 255, 36, 170, 255, 36, 255, 0, 73, 0, + 0, 73, 85, 0, 73, 170, 0, 73, 255, 36, 73, 0, 36, 73, + 85, 36, 73, 170, 36, 73, 255, 73, 73, 0, 73, 73, 85, + 73, 73, 170, 73, 73, 255, 109, 73, 0, 109, 73, 85, + 109, 73, 170, 109, 73, 255, 146, 73, 0, 146, 73, 85, + 146, 73, 170, 146, 73, 255, 182, 73, 0, 182, 73, 85, + 182, 73, 170, 182, 73, 255, 219, 73, 0, 219, 73, 85, + 219, 73, 170, 219, 73, 255, 255, 73, 0, 255, 73, 85, + 255, 73, 170, 255, 73, 255, 0, 109, 0, 0, 109, 85, 0, + 109, 170, 0, 109, 255, 36, 109, 0, 36, 109, 85, 36, + 109, 170, 36, 109, 255, 73, 109, 0, 73, 109, 85, 73, + 109, 170, 73, 109, 255, 109, 109, 0, 109, 109, 85, 109, + 109, 170, 109, 109, 255, 146, 109, 0, 146, 109, 85, + 146, 109, 170, 146, 109, 255, 182, 109, 0, 182, 109, + 85, 182, 109, 170, 182, 109, 255, 219, 109, 0, 219, + 109, 85, 219, 109, 170, 219, 109, 255, 255, 109, 0, + 255, 109, 85, 255, 109, 170, 255, 109, 255, 0, 146, 0, + 0, 146, 85, 0, 146, 170, 0, 146, 255, 36, 146, 0, 36, + 146, 85, 36, 146, 170, 36, 146, 255, 73, 146, 0, 73, + 146, 85, 73, 146, 170, 73, 146, 255, 109, 146, 0, 109, + 146, 85, 109, 146, 170, 109, 146, 255, 146, 146, 0, 146, + 146, 85, 146, 146, 170, 146, 146, 255, 182, 146, 0, 182, + 146, 85, 182, 146, 170, 182, 146, 255, 219, 146, 0, 219, + 146, 85, 219, 146, 170, 219, 146, 255, 255, 146, 0, 255, + 146, 85, 255, 146, 170, 255, 146, 255, 0, 182, 0, 0, + 182, 85, 0, 182, 170, 0, 182, 255, 36, 182, 0, 36, 182, + 85, 36, 182, 170, 36, 182, 255, 73, 182, 0, 73, 182, + 85, 73, 182, 170, 73, 182, 255, 109, 182, 0, 109, 182, + 85, 109, 182, 170, 109, 182, 255, 146, 182, 0, 146, + 182, 85, 146, 182, 170, 146, 182, 255, 182, 182, 0, 182, + 182, 85, 182, 182, 170, 182, 182, 255, 219, 182, 0, 219, + 182, 85, 219, 182, 170, 219, 182, 255, 255, 182, 0, 255, + 182, 85, 255, 182, 170, 255, 182, 255, 0, 219, 0, 20, + 219, 85, 0, 219, 170, 0, 219, 255, 36, 219, 0, 36, 219, + 85, 36, 219, 170, 36, 219, 255, 73, 219, 0, 73, 219, + 85, 73, 219, 170, 73, 219, 255, 109, 219, 0, 109, 219, + 85, 109, 219, 170, 109, 219, 255, 146, 219, 0, 146, 219, + 85, 146, 219, 170, 146, 219, 255, 182, 219, 0, 182, 219, + 85, 182, 219, 170, 182, 219, 255, 219, 219, 0, 219, 219, + 85, 219, 219, 170, 219, 219, 255, 255, 219, 0, 255, 219, + 85, 255, 219, 170, 255, 219, 255, 0, 255, 0, 0, 255, 85, + 0, 255, 170, 0, 255, 255, 36, 255, 0, 36, 255, 85, 36, + 255, 170, 36, 255, 255, 73, 255, 0, 73, 255, 85, 73, + 255, 170, 73, 255, 255, 109, 255, 0, 109, 255, 85, 109, + 255, 170, 109, 255, 255, 146, 255, 0, 146, 255, 85, + 146, 255, 170, 146, 255, 255, 182, 255, 0, 182, 255, 85, + 182, 255, 170, 182, 255, 255, 219, 255, 0, 219, 255, 85, + 219, 255, 170, 219, 255, 255, 255, 255, 0, 255, 255, 85, + 255, 255, 170, 255, 255, 255] + + + def __del__(self): + print("VncServer died") + + def encrypt(self, key, data): + k = des(key, ECB, "\0\0\0\0\0\0\0\0", pad=None, padmode=PAD_PKCS5) + d = k.encrypt(data) + return d + + def decrypt(self, challenge, data): + k = des(challenge, ECB, "\0\0\0\0\0\0\0\0", pad=None, padmode=PAD_PKCS5) + return k.decrypt(data) + + def mirrorBits(self, key): + newkey = [] + for ki in range(len(key)): + bsrc = key[ki] + btgt = 0 + for i in range(8): + if ord(bsrc) & (1 << i): + btgt = btgt | (1 << 7-i) + newkey.append(btgt) + + return newkey + + def sendmessage(self, message): + ''' sends a RFB message, usually an error message ''' + sock = self.socket + message = bytes(message, 'iso8859-1') + # 4 bytes lenght and string + buff = pack("I%ds" % (len(message),), len(message), message) + sock.send(message) + + def getbuff(self, timeout): + sock = self.socket + sock.settimeout(timeout) + + try: + data = sock.recv(1024) + except socket.timeout: + data = None + print("getbuff() timeout") + + return data + + def init(self): + sock = self.socket + sock.send(self.initmsg.encode()) + + # RFB version handshake + data = self.getbuff(30) + + print("init received: '%s'" % data) + server_version = float(self.RFB_VERSION) + try: + client_version = float(data[4:11]) + except: + print("Error parsing client version") + return False + + print("client, server:", client_version, server_version) + + # security types handshake + sendbuff = pack("B", len(self.sectypes)) # number of security types + sendbuff += pack('%sB' % len(self.sectypes), *self.sectypes) # send available sec types + sock.send(sendbuff) + + data = self.getbuff(30) + try: + sectype = unpack("B", data)[0] + except: + sectype = None + + if sectype not in self.sectypes: + print("Incompatible security type: %s" % data) + sock.send(pack("B", 1)) # failed handshake + self.sendmessage("Incompatible security type") + sock.close() + return False + + print("sec type data: %s" % data) + + # VNC Auth + if sectype == 2: + # el cliente encripta el challenge con la contraseña ingresada como key + pw = (self.password + '\0' * 8)[:8] + challenge = os.urandom(16) # challenge + sock.send(challenge) # send challenge + # obtener desde el cliente el dato encritado + data = self.getbuff(30) + # la encriptacion de challenge, con pw como key debe dar data + + k = des(self.mirrorBits(pw)) + crypted = k.encrypt(challenge) + + if data == crypted: + # Handshake successful + sock.send(pack("I", 0)) + print("Auth OK") + else: + print("Invalid auth") + return False + + #unsupported VNC auth type + else: + return False + + # get ClientInit + data = self.getbuff(30) + print("Clientinit (shared flag)", repr(data)) + + self.ServerInit() + + return True + + def ServerInit(self): + # ServerInit + + sock = self.socket + screen = ImageGrab.grab() + print("screen", repr(screen)) + size = screen.size + print("size", repr(size)) + del screen + + width = size[0] + self.width = width + height = size[1] + self.height = height + bpp = 32 # FIXME: get real bpp + depth = 32 # FIXME: get real depth + self.depth = depth + self.bpp = bpp + bigendian = 0 + truecolor = 1 + red_maximum = 255 + self.red_maximum = red_maximum + green_maximum = 255 + self.green_maximum = green_maximum + blue_maximum = 255 + self.blue_maximum = blue_maximum + red_shift = 16 + self.red_shift = red_shift + green_shift = 8 + self.green_shift = green_shift + blue_shift = 0 + self.blue_shift = blue_shift + + sendbuff = pack("!HH", width, height) + sendbuff += pack("!BBBB", bpp, depth, bigendian, truecolor) + sendbuff += pack("!HHHBBB", red_maximum, green_maximum, blue_maximum, red_shift, green_shift, blue_shift) + sendbuff += pack("!xxx") # padding + + desktop_name = "Test VNC" + desktop_name_len = len(desktop_name) + + sendbuff += pack("!I", desktop_name_len) + sendbuff += desktop_name.encode() + + print("width", repr(width)) + print("height", repr(height)) + + sock.send(sendbuff) + + + def protocol(self): + self.socket.settimeout(None) # set nonblocking socket + + screen = ImageGrab.grab() + size = screen.size + width = size[0] + height = size[1] + del screen + + self.primaryOrder = "rgb" + self.encoding = self.ENCODINGS.raw + buttonmask = 0 + buttons = [0, 0, 0, 0, 0, 0, 0, 0] + left_pressed = 0 + right_pressed = 0 + middle_pressed = 0 + + + kbdmap = { + 0xff08: keyboard.Key.backspace, + 0xff09: keyboard.Key.tab, + 0xff0d: keyboard.Key.enter, + 0xff1b: keyboard.Key.esc, + 0xff63: keyboard.Key.insert if hasattr(keyboard.Key, "insert") else None, + 0xffff: keyboard.Key.delete, + 0xff50: keyboard.Key.home, + 0xff57: keyboard.Key.end, + 0xff55: keyboard.Key.page_up, + 0xff56: keyboard.Key.page_down, + 0xff51: keyboard.Key.left, + 0xff52: keyboard.Key.up, + 0xff53: keyboard.Key.right, + 0xff54: keyboard.Key.down, + 0xffbe: keyboard.Key.f1, + 0xffbf: keyboard.Key.f2, + 0xffc0: keyboard.Key.f3, + 0xffc1: keyboard.Key.f4, + 0xffc2: keyboard.Key.f5, + 0xffc3: keyboard.Key.f6, + 0xffc4: keyboard.Key.f7, + 0xffc5: keyboard.Key.f8, + 0xffc6: keyboard.Key.f9, + 0xffc7: keyboard.Key.f10, + 0xffc8: keyboard.Key.f11, + 0xffc9: keyboard.Key.f12, + 0xffca: keyboard.Key.f13, + 0xffcb: keyboard.Key.f14, + 0xffcc: keyboard.Key.f15, + 0xffcd: keyboard.Key.f16, + 0xffce: keyboard.Key.f17, + 0xffcf: keyboard.Key.f18, + 0xffd0: keyboard.Key.f19, + 0xffd1: keyboard.Key.f20, + 0xffe1: keyboard.Key.shift_l, + 0xffe2: keyboard.Key.shift_r, + 0xffe3: keyboard.Key.ctrl_l, + 0xffe4: keyboard.Key.ctrl_r, + 0xffe7: None, # "KEY_MetaLeft" + 0xffe8: None, # "KEY_MetaRight" + 0xffe9: keyboard.Key.cmd_l, + 0xffea: keyboard.Key.alt_gr, # "KEY_AltRight" + 0xff14: keyboard.Key.scroll_lock if hasattr(keyboard.Key, "scroll_lock") else None, + 0xff15: keyboard.Key.print_screen if hasattr(keyboard.Key, "print_screen") else None, # "KEY_Sys_Req" + 0xff7f: keyboard.Key.num_lock if hasattr(keyboard.Key, "num_lock") else None, + 0xffe5: keyboard.Key.caps_lock, + 0xff13: keyboard.Key.pause if hasattr(keyboard.Key, "pause") else None, + 0xffeb: keyboard.Key.cmd_r, # "KEY_Super_L" + 0xffec: keyboard.Key.cmd_r, # "KEY_Super_R" + 0xffed: None, # "KEY_Hyper_L" + 0xffee: None, # "KEY_Hyper_R" + 0xffb0: None, # "KEY_KP_0" + 0xffb1: None, # "KEY_KP_1" + 0xffb2: None, # "KEY_KP_2" + 0xffb3: None, # "KEY_KP_3" + 0xffb4: None, # "KEY_KP_4" + 0xffb5: None, # "KEY_KP_5" + 0xffb6: None, # "KEY_KP_6" + 0xffb7: None, # "KEY_KP_7" + 0xffb8: None, # "KEY_KP_8" + 0xffb9: None, # "KEY_KP_9" + 0xff8d: None, # "KEY_KP_Enter" + 0x002f: "/", # KEY_ForwardSlash + 0x005c: "\\", # KEY_BackSlash + 0x0020: keyboard.Key.space, # "KEY_SpaceBar" + 0xff7e: keyboard.Key.alt_gr, # altgr, at least on a mac (?) + 0xfe03: keyboard.Key.alt_l, + } + + if sys.platform == "darwin": + kbdmap[0xffe2] = keyboard.Key.shift + + while True: + #print(".", end='', flush=True) + r,_,_ = select.select([self.socket],[],[],0) + if r == []: + #no data + sleep(0.1) + continue + + sock = r[0] + try: + data = sock.recv(1) # read first byte + except socket.timeout: + #print("timeout") + continue + except Exception as e: + print("exception '%s'" % e) + sock.close() + break + + if not data: + # clinet disconnected + sock.close() + break + + if data[0] == 0: # client SetPixelFormat + data2 = sock.recv(19, socket.MSG_WAITALL) + print("Client Message Type: Set Pixel Format (0)") + (self.bpp, self.depth, self.bigendian, self.truecolor, self.red_maximum, + self.green_maximum, self.blue_maximum, + self.red_shift, self.green_shift, self.blue_shift + ) = unpack("!xxxBBBBHHHBBBxxx", data2) + print("IMG bpp, depth, endian, truecolor", self.bpp, self.depth, self.bigendian, self.truecolor) + print("SHIFTS", self.red_shift, self.green_shift, self.blue_shift) + print("MAXS", self.red_maximum, self.green_maximum, self.blue_maximum) + + if self.red_shift > self.blue_shift: + self.primaryOrder = "rgb" + else: + self.primaryOrder = "bgr" + print("Using order: ", self.primaryOrder) + + continue + + if data[0] == 2: # SetEncoding + data2 = sock.recv(3) + print("Client Message Type: SetEncoding (2)") + (nencodings,) = unpack("!xH", data2) + print("SetEncoding: total encodings ", repr(nencodings)) + data2 = sock.recv(4 * nencodings, socket.MSG_WAITALL) + print("len", len(data2)) + self.client_encodings = unpack("!%si" % nencodings, data2) + print("data", repr(self.client_encodings), len(self.client_encodings)) + + if self.ENCODINGS.cursor in self.client_encodings: + print("Remote cursor encoding present") + self.remotecursor = True + self.cursorchanged = True + + if self.ENCODINGS.zlib in self.client_encodings: + print("Using zlib encoding") + self.encoding = self.ENCODINGS.zlib + continue + + + if data[0] == 3: # FBUpdateRequest + data2 = sock.recv(9, socket.MSG_WAITALL) + #print("Client Message Type: FBUpdateRequest (3)") + #print(len(data2)) + (incremental, x, y, w, h) = unpack("!BHHHH", data2) + #print("RFBU:", incremental, x, y, w, h) + self.SendRectangles(sock, x, y, w, h, incremental) + + if self.remotecursor and self.cursorchanged: + # FIXME: send cursor to remote client + self.cursorchanged = False + continue + + if data[0] == 4: + kbdkey = '' + data2 = sock.recv(7) + # B = U8, L = U32 + (downflag, key) = unpack("!BxxL", data2) + print("KeyEvent", downflag, hex(key)) + + # special key + if key in kbdmap: + kbdkey = kbdmap[key] + else: # normal key + try: + kbdkey = keyboard.KeyCode.from_char(chr(key)) + except: + kbdkey = None + + try: + print("KEY:", kbdkey) + except: + print("KEY: (unprintable)") + + try: + if downflag: + keyboard.Controller().press(kbdkey) + else: + keyboard.Controller().release(kbdkey) + except: + print("Error sending key") + + continue + + if data[0] == 5: # PointerEvent + data2 = sock.recv(5, socket.MSG_WAITALL) + (buttonmask, x, y) = unpack("!BHH", data2) + buttons[0] = buttonmask & int("0000001", 2) # left button + buttons[1] = buttonmask & int("0000010", 2) # middle button + buttons[2] = buttonmask & int("0000100", 2) # right button + buttons[3] = buttonmask & int("0001000", 2) # scroll up + buttons[4] = buttonmask & int("0010000", 2) # scroll down + + mouse.Controller().position = (x, y) + + if buttons[0] and not left_pressed: + print("LEFT PRESSED") + mouse.Controller().press(mouse.Button.left) + left_pressed = 1 + elif not buttons[0] and left_pressed: + print("LEFT RELEASED") + mouse.Controller().release(mouse.Button.left) + left_pressed = 0 + + if buttons[1] and not middle_pressed: + print("MIDDLE PRESSED") + mouse.Controller().press(mouse.Button.middle) + middle_pressed = 1 + elif not buttons[1] and middle_pressed: + print("MIDDLE RELEASED") + mouse.Controller().release(mouse.Button.middle) + middle_pressed = 0 + + if buttons[2] and not right_pressed: + print("RIGHT PRESSED") + mouse.Controller().press(mouse.Button.right) + right_pressed = 1 + elif not buttons[2] and right_pressed: + print("RIGHT RELEASED") + mouse.Controller().release(mouse.Button.right) + right_pressed = 0 + + if buttons[3]: + print("SCROLLUP PRESSED") + mouse.Controller().scroll(0, 2) + + if buttons[4]: + print("SCROLLDOWN PRESSED") + mouse.Controller().scroll(0, -2) + + #print("PointerEvent", buttonmask, x, y) + continue + + else: + data2 = sock.recv(4096) + print("RAW Server received data:", repr(data[0]) , data+data2) + + + def GetRectangle(self, x, y, w, h): + try: + scr = ImageGrab.grab() + except: + return False + (scr_width, scr_height) = scr.size + + if scr.mode != "RGB": + img = scr.convert("RGB") + else: + img = scr + + del scr + + crop = img.crop((x, y, w, h)) + del img + + return crop + + def SendRectangles(self, sock, x, y, w, h, incremental=0): + # send FramebufferUpdate to client + + #print("start SendRectangles") + rectangle = self.GetRectangle(x, y, w, h) + if not rectangle: + rectangle = Image.new("RGB", [w, h], (0,0,0)) + + lastshot = rectangle + sendbuff = bytearray() + + firstUpdateSent = False + + # try to send only the actual changes + if self.framebuffer != None and incremental == 1: + diff = ImageChops.difference(rectangle, self.framebuffer) + if diff.getbbox() is None: + rectangles = 0 + sendbuff.extend(pack("!BxH", 0, rectangles)) + try: + sock.sendall(sendbuff) + except: + return False + sleep(0.3) + return + + if diff.getbbox() is not None: + if hasattr(diff, "getbbox"): + rectangle = rectangle.crop(diff.getbbox()) + (x, y, _, _) = diff.getbbox() + w = rectangle.width + h = rectangle.height + #print("XYWH:", x,y,w,h, "diff", repr(diff.getbbox())) + + stimeout = sock.gettimeout() + sock.settimeout(None) + + if self.bpp == 32 or self.bpp == 8: + if rectangle.mode is not "RGB": + image = rectangle.convert("RGB") + else: + image = rectangle + + b = np.asarray(image) + a = b.copy() + del b + + if self.bpp == 32: + redBits = 8 + greenBits = 8 + blueBits = 8 + elif self.bpp == 8: + redBits = 4 + greenBits = 4 + blueBits = 4 + + #redMask = ((1 << redBits) - 1) << self.red_shift + #greenMask = ((1 << greenBits) - 1) << self.green_shift + #blueMask = ((1 << blueBits) - 1) << self.blue_shift + #print("redMask", redMask, greenMask, blueMask) + + if self.primaryOrder == "bgr": + self.blue_shift = 0 + blueMask = (1 << blueBits) - 1 + self.green_shift = blueBits + greenMask = ((1 << greenBits) - 1) << self.green_shift + self.red_shift = self.green_shift + greenBits + redMask = ((1 << redBits) - 1) << self.red_shift + + else: # RGB + self.red_shift = 0 + redMask = (1 << redBits) - 1 + self.green_shift = redBits + greenMask = ((1 << greenBits) - 1) << self.green_shift + self.blue_shift = self.green_shift + greenBits + blueMask = ((1 << blueBits) - 1) << self.blue_shift + + a[..., 0] = ( a[..., 0] ) & redMask >> self.red_shift + a[..., 1] = ( a[..., 1] ) & greenMask >> self.green_shift + a[..., 2] = ( a[..., 2] ) & blueMask >> self.blue_shift + + image = Image.fromarray(a) + del a + + if self.primaryOrder == "rgb": + (b, g, r) = image.split() + image = Image.merge("RGB", (r, g, b)) + del b,g,r + + if self.bpp == 32: + image = image.convert("RGBX") + + elif self.bpp == 8: + #FIXME: improve 8 bit routines up!, image looks awful! + if rectangle.mode is not "RGB": + image = rectangle.convert("RGB") + else: + image = rectangle + + (r, g, b) = image.split() + image = Image.merge("RGB", (g, r, b)) + del b,g,r + + p = Image.new("P",(16,16)) + p.putpalette(self.BGR233) + image = quantizetopalette(image, p, dither=self.CONFIG._8bitdither) + image.putpalette(self.BGR233) + del p + rectangles = 1 + sendbuff.extend(pack("!BxH", 0, rectangles)) + sendbuff.extend(pack("!HHHH", x, y, w, h)) + sendbuff.extend(pack(">i", self.encoding)) + sendbuff.extend( image.tobytes() ) + + + if self.encoding == self.ENCODINGS.zlib - 9998: + if not firstUpdateSent: + firstUpdateSent = True + compress = zlib.compressobj( + zlib.Z_DEFAULT_COMPRESSION, # level: 0-9 + zlib.DEFLATED, # method: must be DEFLATED + -15, # window size in bits: + # -15..-8: negate, suppress header + # 8..15: normal + # 16..30: subtract 16, gzip header + 1, # mem level: 1..8/9 + zlib.Z_DEFAULT_STRATEGY # strategy: + # 0 = Z_DEFAULT_STRATEGY + # 1 = Z_FILTERED + # 2 = Z_HUFFMAN_ONLY + # 3 = Z_RLE + # 4 = Z_FIXED + ) + + rectangles = 1 + sendbuff.extend(pack("!BxH", 0, rectangles)) + sendbuff.extend(pack("!HHHH", x, y, w, h)) + sendbuff.extend(pack(">i", self.encoding)) + + print("Compressing...") + zlibdata = compress.compress( image.tobytes() ) + zlibdata += compress.flush() + l = pack("!I", len(zlibdata) ) + + sendbuff.extend( l ) # send length + sendbuff.extend( zlibdata ) # send compressed data + + if self.encoding == self.ENCODINGS.zlib: + rectangles = 1 + sendbuff.extend(pack("!BxH", 0, rectangles)) + sendbuff.extend(pack("!HHHH", x, y, w, h)) + sendbuff.extend(pack(">i", self.encoding)) + + print("Compressing...") + + + if not firstUpdateSent: + firstUpdateSent = True + zlibdata = zlib.compress( image.tobytes() )[2:] + print("FIRSTTTTTTTTTTTTTTTTTTTTTTTTTT") + else: + zlibdata = zlib.compress( image.tobytes() )[2:-4] + + #zlibdata = zlib.compress( image.tobytes() )[2:-4] # no header and checksum + #zlibdata = zlib.compress( image.tobytes() )[:-4] # no checksum + #zlibdata = zlib.compress( image.tobytes() ) + + l = pack("!I", len(zlibdata) ) + sendbuff.extend( l ) # send length + sendbuff.extend( zlibdata ) # send compressed data + #sendbuff.extend( pack("!B", 0) ) + + #inf = inflate(zlibdata, winsize=-15) + + del zlibdata, l + else: + # send with RAW encoding + rectangles = 1 + sendbuff.extend(pack("!BxH", 0, rectangles)) + sendbuff.extend(pack("!HHHH", x, y, w, h)) + sendbuff.extend(pack(">i", self.encoding)) + sendbuff.extend( image.tobytes() ) + + else: + print("[!] Unsupported BPP: %s" % self.bpp) + + self.framebuffer = lastshot + try: + sock.sendall(sendbuff) + except: + # connection closed? + return False + sock.settimeout(stimeout) + #print("end SendRectangles") diff --git a/requeriments.txt b/requeriments.txt new file mode 100644 index 0000000..50504bc --- /dev/null +++ b/requeriments.txt @@ -0,0 +1,2 @@ +pyuserinput + diff --git a/server.py b/server.py new file mode 100755 index 0000000..aa1420d --- /dev/null +++ b/server.py @@ -0,0 +1,339 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +import socket, os, sys, wx +from threading import Thread +from time import sleep +from struct import * +from pyDes import * + +def hexdump(data): + print(" ".join(hex(ord(n)) for n in data)) + +class VncServer(): + def __init__(self, socket, ip, port): + self.initmsg = "RFB 003.008\n" + self.socket = socket + + self.sectypes = [ + 2, # VNC auth + 19 # VeNCrypt + ] + + def __del__(self): + print("VncServer died") + + def encrypt(self, key, data): + k = des(key, ECB, "\0\0\0\0\0\0\0\0", pad=None, padmode=PAD_PKCS5) + d = k.encrypt(data) + return d + + def decrypt(self, challenge, data): + k = des(challenge, ECB, "\0\0\0\0\0\0\0\0", pad=None, padmode=PAD_PKCS5) + return k.decrypt(data) + + def mirrorBits(self, key): + newkey = [] + for ki in range(len(key)): + bsrc = key[ki] + btgt = 0 + for i in range(8): + if ord(bsrc) & (1 << i): + btgt = btgt | (1 << 7-i) + newkey.append(btgt) + + return newkey + + def sendmessage(self, message): + ''' sends a RFB message, usually an error message ''' + sock = self.socket + message = bytes(message, 'iso8859-1') + # 4 bytes lenght and string + buff = pack("I%ds" % (len(message),), len(message), message) + sock.send(message) + + def getbuff(self, timeout): + sock = self.socket + sock.settimeout(timeout) + + try: + data = sock.recv(1024) + except socket.timeout: + data = None + print("getbuff() timeout") + + return data + + def init(self): + sock = self.socket + sock.send(self.initmsg.encode()) + + # RFB version handshake + data = self.getbuff(30) + + print("init received: '%s'" % data) + if data == self.initmsg.encode(): + print("init OK") + else: + print("init NOT OK!! '%s' '%s'" % (data, self.initmsg.encode())) + sock.send(pack("BB", 1, 0)) + self.sendmessage("RFB protocol not supported") + sock.close() + return False + + # security types handshake + sendbuff = pack("B", len(self.sectypes)) # number of security types + sendbuff += pack('%sB' % len(self.sectypes), *self.sectypes) # send available sec types + sock.send(sendbuff) + + data = self.getbuff(30) + try: + sectype = unpack("B", data)[0] + except: + sectype = None + + if sectype not in self.sectypes: + print("Incompatible security type: %s" % data) + sock.send(pack("B", 1)) # failed handshake + self.sendmessage("Incompatible security type") + sock.close() + return False + + print("sec type data: %s" % data) + + # VNC Auth + if sectype == 2: + # el cliente encripta el challenge con la contraseña ingresada como key + pw = (VNC_PASSWORD + '\0' * 8)[:8] + challenge = os.urandom(16) # challenge + sock.send(challenge) # send challenge + # obtener desde el cliente el dato encritado + data = self.getbuff(30) + # la encriptacion de challenge, con pw como key debe dar data + + k = des(self.mirrorBits(pw)) + crypted = k.encrypt(challenge) + + if data == crypted: + # Handshake successful + sock.send(pack("I", 0)) + print("Auth OK") + else: + print("Invalid auth") + return False + + #unsupported VNC auth type + else: + return False + + # get ClientInit + data = self.getbuff(30) + print("Clientinit (shared flag)", repr(data)) + + # ServerInit + screen = wx.ScreenDC() + print("screen", repr(screen)) + size = screen.GetSize() + print("size", repr(size)) + + width = size[0] + height = size[1] + bpp = 32 # FIXME: get real bpp + depth = 24 # FIXME: get real depth + self.depth = depth + self.bpp = 32 + bigendian = 0 + truecolor = 1 + red_maximum = 255 + green_maximum = 255 + blue_maximum = 255 + red_shift = 16 + self.red_shift = red_shift + green_shift = 8 + self.green_shift = green_shift + blue_shift = 0 + self.blue_shift = blue_shift + padding1 = 0 + padding2 = 0 + padding3 = 0 + + sendbuff = pack("!HH", width, height) + sendbuff += pack("!BBBB", bpp, depth, bigendian, truecolor) + sendbuff += pack("!HHHBBB", red_maximum, green_maximum, blue_maximum, red_shift, green_shift, blue_shift) + sendbuff += pack("!BBB", padding1, padding2, padding3) + + desktop_name = "Test VNC" + desktop_name_len = len(desktop_name) + + sendbuff += pack("!I", desktop_name_len) + sendbuff += desktop_name.encode() + + print("width", repr(width)) + print("height", repr(height)) + + sock.send(sendbuff) + + return True + + + def protocol(self): + sock = self.socket + sock.settimeout(1) # set nonblocking socket + + screen = wx.ScreenDC() + size = screen.GetSize() + width = size[0] + height = size[1] + + while True: + try: + data = sock.recv(1) # read first byte + except socket.timeout: + #print("timeout") + continue + except Exception as e: + print("exception '%s'" % e) + sock.close() + break + + if not data: + # clinet disconnected + sock.close() + break + + if data[0] == 0: # SetPixelFormat + data2 = sock.recv(19) + print("Client Message Type: Set Pixel Format (0)") + (self.bpp, self.depth, self.bigendian, self.truecolor, self.red_maximum, + self.green_maximum, self.blue_maximum, self.red_shift, self.green_shift, + self.blue_shift) = unpack("!xxxBBBBHHHBBBxxx", data2) + print("bpp", self.bpp) + print("depth", self.depth) + + if data[0] == 2: # SetEncoding + data2 = sock.recv(3) + print("Client Message Type: SetEncoding (2)") + h = unpack("xH", data2) + print("h", repr(h)) + data2 = sock.recv(4096) + + else: + data2 = sock.recv(4096) + print("RAW Server received data:", data+data2) + + #sleep(0.1) + #self.RAWSendRectangles(sock, 0, 0, width, height) + + def GetRectangle(self, x, y, w, h): + screen = wx.ScreenDC() + size = screen.GetSize() + bmp = wx.Bitmap(size[0], size[1], self.depth) + mem = wx.MemoryDC() + mem.SelectObject(bmp) + mem.Blit(0, 0, size[0], size[1], screen, 0, 0) + mem.SelectObject(wx.NullBitmap) + + rect = bmp.GetSubBitmap(wx.Rect(x, y, w, h)) + image = wx.Bitmap.ConvertToImage(rect) + + del mem + del bmp + del rect + + return image + + def RAWSendRectangles(self, sock, x, y, w, h): + image = self.GetRectangle(x, y, w, h) + pixelData = image.GetData() + + sendbuff = pack("!BBH", 0, 0, 1) + sendbuff += pack("!HHHH", x, y, w, h) + sendbuff += pack("!i", 0) + sock.send(sendbuff) + + sendbuff = bytearray() + print("Start...") + for b in range(0, len(pixelData), 3): + red = (pixelData[b] & 0x000000FF) >> self.red_shift + green = (pixelData[b+1] & 0x000000FF) >> self.green_shift + blue = (pixelData[b+2] & 0x000000FF) >> self.blue_shift + sendbuff.extend( pack("!BBBx", pixelData[b], pixelData[b+1], pixelData[b+2]) ) + #sendbuff += pack("BBBx", pixelData[b], pixelData[b+1], pixelData[b+2]) + #print(".", end='', flush=True) + + print("End...") + sock.sendall(sendbuff) + + #c = 0 + #for d in pixelData: + # if c == 3: + # c=0 + # sock.send( pack("x") ) + + # sock.send( pack("B", d)) + # c += 1 + + #sock.sendall(pack( "B" , pixelData)) + #print("Supossed data len:", w * h * self.depth) + #print("Real data len: ", len(pixelData)) + + +class ControlThread(Thread): + def __init__(self, threads): + Thread.__init__(self) + self.threads = threads + + def run(self): + # elimina los threads muertos + while True: + sleep(1) + for t in threads: + if not t.isAlive(): + threads.remove(t) + + +class ClientThread(Thread): + def __init__(self, sock, ip, port): + Thread.__init__(self) + self.ip = ip + self.port = port + self.sock = sock + + def __del__(self): + print("ClientThread died") + + def run(self): + print("[+] New server socket thread started for " + self.ip + ":" + str(self.port)) + server = VncServer(self.sock, self.ip, self.port) + status = server.init() + if not status: + print("Error negotiating client init") + return False + server.protocol() + + +# Multithreaded Python server +TCP_IP = '0.0.0.0' +TCP_PORT = 5901 + +VNC_PASSWORD='kaka80' + +app = wx.App(False) + +sockServer = socket.socket(socket.AF_INET, socket.SOCK_STREAM) +sockServer.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) +sockServer.bind((TCP_IP, TCP_PORT)) +threads = [] + +controlthread = ControlThread(threads) +controlthread.start() + +print("Multithreaded Python server : Waiting for connections from TCP clients...") +while True: + sockServer.listen(4) + (conn, (ip,port)) = sockServer.accept() + newthread = ClientThread(conn, ip, port) + newthread.setDaemon(True) + newthread.start() + threads.append(newthread) + #print(threads) diff --git a/server2.py b/server2.py new file mode 100755 index 0000000..05bc2a0 --- /dev/null +++ b/server2.py @@ -0,0 +1,854 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +import socket, select, os, sys, random, zlib +from threading import Thread +from time import sleep +from struct import * +from pyDes import * +from argparse import ArgumentParser + +from pymouse import PyMouse +from pykeyboard import PyKeyboard + +import numpy as np + +from PIL import Image, ImageChops, ImageDraw, ImagePalette +if sys.platform == "linux" or sys.platform == "linux2": + from Xlib import display, X + # take screen images, that's not the best way, so here + # we use directly use xlib to take the screenshot. + class ImageGrab(): + def grab(): + dsp = display.Display() + root = dsp.screen().root + geom = root.get_geometry() + w = geom.width + h = geom.height + raw = root.get_image(0, 0, w ,h, X.ZPixmap, 0xffffffff) + image = Image.frombytes("RGB", (w, h), raw.data, "raw", "BGRX") + return image + +elif sys.platform == "darwin": + import Quartz.CoreGraphics as CG + class ImageGrab(): + def grab(): + screenshot = CG.CGWindowListCreateImage(CG.CGRectInfinite, CG.kCGWindowListOptionOnScreenOnly, CG.kCGNullWindowID, CG.kCGWindowImageDefault) + width = CG.CGImageGetWidth(screenshot) + height = CG.CGImageGetHeight(screenshot) + bytesperrow = CG.CGImageGetBytesPerRow(screenshot) + + pixeldata = CG.CGDataProviderCopyData(CG.CGImageGetDataProvider(screenshot)) + + i = Image.frombytes("RGBA", (width, height), pixeldata) + (b, g, r, x) = i.split() + i = Image.merge("RGBX", (r, g, b, x)) + + return i + +else: + from PIL import ImageGrab + + +def selfRestart(): + try: + p = psutil.Process(os.getpid()) + for handler in p.get_open_files() + p.connections(): + os.close(handler.fd) + except Exception as e: + print(e) + + python = sys.executable + os.execl(python, python, *sys.argv) + +def hexdump(data): + str = "" + for d in data: + str += hex(d) + str += "(%s) " % d + return str + +def quantizetopalette(silf, palette, dither=False): + """Convert an RGB or L mode image to use a given P image's palette.""" + + silf.load() + + # use palette from reference image + palette.load() + if palette.mode != "P": + raise ValueError("bad mode for palette image") + if silf.mode != "RGB" and silf.mode != "L": + raise ValueError( + "only RGB or L mode images can be quantized to a palette" + ) + im = silf.im.convert("P", 1 if dither else 0, palette.im) + # the 0 above means turn OFF dithering + + # Later versions of Pillow (4.x) rename _makeself to _new + try: + return silf._new(im) + except AttributeError: + return silf._makeself(im) + + +def deflate(data, compresslevel=9, method=zlib.DEFLATED, winsize=-zlib.MAX_WBITS, memlevel=zlib.DEF_MEM_LEVEL, strategy=0): + compress = zlib.compressobj( + compresslevel, # level: 0-9 + method, # method: must be DEFLATED + winsize, # window size in bits: + # -15..-8: negate, suppress header + # 8..15: normal + # 16..30: subtract 16, gzip header + memlevel, # mem level: 1..8/9 + strategy # strategy: + # 0 = Z_DEFAULT_STRATEGY + # 1 = Z_FILTERED + # 2 = Z_HUFFMAN_ONLY + # 3 = Z_RLE + # 4 = Z_FIXED + ) + deflated = compress.compress(data) + deflated += compress.flush() + return deflated + +def inflate(data, winsize=-zlib.MAX_WBITS): + decompress = zlib.decompressobj( + winsize # see above + ) + inflated = decompress.decompress(data) + inflated += decompress.flush() + return inflated + +def getDictByValue(d, val): + try: + return [k for k,v in d.items() if v==val][0] + except: + return False + +RFB_VERSION = '003.008' +RFB_SECTYPES = [ + 2, # VNC auth + 19 # VeNCrypt + ] + +class VncServer(): + + class ENCODINGS: + raw = 0 + zlib = -6 # disabled + + def __init__(self, socket, ip, port): + self.initmsg = ("RFB %s\n" % RFB_VERSION) + self.socket = socket + self.framebuffer = None + + self.sectypes = RFB_SECTYPES + + self.BGR233 = [0, 0, 0, 0, 0, 85, 0, 0, 170, 0, 0, 255, 36, 0, 0, 36, 0, 85, 36, 0, 170, 36, 0, 255, 73, 0, 0, 73, 0, 85, 73, 0, 170, 73, 0, 255, 109, 0, 0, 109, 0, 85, 109, 0, 170, 109, 0, 255, 146, 0, 0, 146, 0, 85, 146, 0, 170, 146, 0, 255, 182, 0, 0, 182, 0, 85, 182, 0, 170, 182, 0, 255, 219, 0, 0, 219, 0, 85, 219, 0, 170, 219, 0, 255, 255, 0, 0, 255, 0, 85, 255, 0, 170, 255, 0, 255, 0, 36, 0, 0, 36, 85, 0, 36, 170, 0, 36, 255, 36, 36, 0, 36, 36, 85, 36, 36, 170, 36, 36, 255, 73, 36, 0, 73, 36, 85, 73, 36, 170, 73, 36, 255, 109, 36, 0, 109, 36, 85, 109, 36, 170, 109, 36, 255, 146, 36, 0, 146, 36, 85, 146, 36, 170, 146, 36, 255, 182, 36, 0, 182, 36, 85, 182, 36, 170, 182, 36, 255, 219, 36, 0, 219, 36, 85, 219, 36, 170, 219, 36, 255, 255, 36, 0, 255, 36, 85, 255, 36, 170, 255, 36, 255, 0, 73, 0, 0, 73, 85, 0, 73, 170, 0, 73, 255, 36, 73, 0, 36, 73, 85, 36, 73, 170, 36, 73, 255, 73, 73, 0, 73, 73, 85, 73, 73, 170, 73, 73, 255, 109, 73, 0, 109, 73, 85, 109, 73, 170, 109, 73, 255, 146, 73, 0, 146, 73, 85, 146, 73, 170, 146, 73, 255, 182, 73, 0, 182, 73, 85, 182, 73, 170, 182, 73, 255, 219, 73, 0, 219, 73, 85, 219, 73, 170, 219, 73, 255, 255, 73, 0, 255, 73, 85, 255, 73, 170, 255, 73, 255, 0, 109, 0, 0, 109, 85, 0, 109, 170, 0, 109, 255, 36, 109, 0, 36, 109, 85, 36, 109, 170, 36, 109, 255, 73, 109, 0, 73, 109, 85, 73, 109, 170, 73, 109, 255, 109, 109, 0, 109, 109, 85, 109, 109, 170, 109, 109, 255, 146, 109, 0, 146, 109, 85, 146, 109, 170, 146, 109, 255, 182, 109, 0, 182, 109, 85, 182, 109, 170, 182, 109, 255, 219, 109, 0, 219, 109, 85, 219, 109, 170, 219, 109, 255, 255, 109, 0, 255, 109, 85, 255, 109, 170, 255, 109, 255, 0, 146, 0, 0, 146, 85, 0, 146, 170, 0, 146, 255, 36, 146, 0, 36, 146, 85, 36, 146, 170, 36, 146, 255, 73, 146, 0, 73, 146, 85, 73, 146, 170, 73, 146, 255, 109, 146, 0, 109, 146, 85, 109, 146, 170, 109, 146, 255, 146, 146, 0, 146, 146, 85, 146, 146, 170, 146, 146, 255, 182, 146, 0, 182, 146, 85, 182, 146, 170, 182, 146, 255, 219, 146, 0, 219, 146, 85, 219, 146, 170, 219, 146, 255, 255, 146, 0, 255, 146, 85, 255, 146, 170, 255, 146, 255, 0, 182, 0, 0, 182, 85, 0, 182, 170, 0, 182, 255, 36, 182, 0, 36, 182, 85, 36, 182, 170, 36, 182, 255, 73, 182, 0, 73, 182, 85, 73, 182, 170, 73, 182, 255, 109, 182, 0, 109, 182, 85, 109, 182, 170, 109, 182, 255, 146, 182, 0, 146, 182, 85, 146, 182, 170, 146, 182, 255, 182, 182, 0, 182, 182, 85, 182, 182, 170, 182, 182, 255, 219, 182, 0, 219, 182, 85, 219, 182, 170, 219, 182, 255, 255, 182, 0, 255, 182, 85, 255, 182, 170, 255, 182, 255, 0, 219, 0, 20, 219, 85, 0, 219, 170, 0, 219, 255, 36, 219, 0, 36, 219, 85, 36, 219, 170, 36, 219, 255, 73, 219, 0, 73, 219, 85, 73, 219, 170, 73, 219, 255, 109, 219, 0, 109, 219, 85, 109, 219, 170, 109, 219, 255, 146, 219, 0, 146, 219, 85, 146, 219, 170, 146, 219, 255, 182, 219, 0, 182, 219, 85, 182, 219, 170, 182, 219, 255, 219, 219, 0, 219, 219, 85, 219, 219, 170, 219, 219, 255, 255, 219, 0, 255, 219, 85, 255, 219, 170, 255, 219, 255, 0, 255, 0, 0, 255, 85, 0, 255, 170, 0, 255, 255, 36, 255, 0, 36, 255, 85, 36, 255, 170, 36, 255, 255, 73, 255, 0, 73, 255, 85, 73, 255, 170, 73, 255, 255, 109, 255, 0, 109, 255, 85, 109, 255, 170, 109, 255, 255, 146, 255, 0, 146, 255, 85, 146, 255, 170, 146, 255, 255, 182, 255, 0, 182, 255, 85, 182, 255, 170, 182, 255, 255, 219, 255, 0, 219, 255, 85, 219, 255, 170, 219, 255, 255, 255, 255, 0, 255, 255, 85, 255, 255, 170, 255, 255, 255] + + def __del__(self): + print("VncServer died") + + def encrypt(self, key, data): + k = des(key, ECB, "\0\0\0\0\0\0\0\0", pad=None, padmode=PAD_PKCS5) + d = k.encrypt(data) + return d + + def decrypt(self, challenge, data): + k = des(challenge, ECB, "\0\0\0\0\0\0\0\0", pad=None, padmode=PAD_PKCS5) + return k.decrypt(data) + + def mirrorBits(self, key): + newkey = [] + for ki in range(len(key)): + bsrc = key[ki] + btgt = 0 + for i in range(8): + if ord(bsrc) & (1 << i): + btgt = btgt | (1 << 7-i) + newkey.append(btgt) + + return newkey + + def sendmessage(self, message): + ''' sends a RFB message, usually an error message ''' + sock = self.socket + message = bytes(message, 'iso8859-1') + # 4 bytes lenght and string + buff = pack("I%ds" % (len(message),), len(message), message) + sock.send(message) + + def getbuff(self, timeout): + sock = self.socket + sock.settimeout(timeout) + + try: + data = sock.recv(1024) + except socket.timeout: + data = None + print("getbuff() timeout") + + return data + + def init(self): + sock = self.socket + sock.send(self.initmsg.encode()) + + # RFB version handshake + data = self.getbuff(30) + + print("init received: '%s'" % data) + server_version = float(RFB_VERSION) + try: + client_version = float(data[4:11]) + except: + print("Error parsing client version") + return False + + print("client, server:", client_version, server_version) + + # security types handshake + sendbuff = pack("B", len(self.sectypes)) # number of security types + sendbuff += pack('%sB' % len(self.sectypes), *self.sectypes) # send available sec types + sock.send(sendbuff) + + data = self.getbuff(30) + try: + sectype = unpack("B", data)[0] + except: + sectype = None + + if sectype not in self.sectypes: + print("Incompatible security type: %s" % data) + sock.send(pack("B", 1)) # failed handshake + self.sendmessage("Incompatible security type") + sock.close() + return False + + print("sec type data: %s" % data) + + # VNC Auth + if sectype == 2: + # el cliente encripta el challenge con la contraseña ingresada como key + pw = (VNC_PASSWORD + '\0' * 8)[:8] + challenge = os.urandom(16) # challenge + sock.send(challenge) # send challenge + # obtener desde el cliente el dato encritado + data = self.getbuff(30) + # la encriptacion de challenge, con pw como key debe dar data + + k = des(self.mirrorBits(pw)) + crypted = k.encrypt(challenge) + + if data == crypted: + # Handshake successful + sock.send(pack("I", 0)) + print("Auth OK") + else: + print("Invalid auth") + return False + + #unsupported VNC auth type + else: + return False + + # get ClientInit + data = self.getbuff(30) + print("Clientinit (shared flag)", repr(data)) + + self.ServerInit() + + return True + + def ServerInit(self): + # ServerInit + + sock = self.socket + screen = ImageGrab.grab() + print("screen", repr(screen)) + size = screen.size + print("size", repr(size)) + del screen + + width = size[0] + self.width = width + height = size[1] + self.height = height + bpp = 32 # FIXME: get real bpp + depth = 32 # FIXME: get real depth + self.depth = depth + self.bpp = bpp + bigendian = 0 + truecolor = 1 + red_maximum = 255 + self.red_maximum = red_maximum + green_maximum = 255 + self.green_maximum = green_maximum + blue_maximum = 255 + self.blue_maximum = blue_maximum + red_shift = 16 + self.red_shift = red_shift + green_shift = 8 + self.green_shift = green_shift + blue_shift = 0 + self.blue_shift = blue_shift + + sendbuff = pack("!HH", width, height) + sendbuff += pack("!BBBB", bpp, depth, bigendian, truecolor) + sendbuff += pack("!HHHBBB", red_maximum, green_maximum, blue_maximum, red_shift, green_shift, blue_shift) + sendbuff += pack("!xxx") # padding + + desktop_name = "Test VNC" + desktop_name_len = len(desktop_name) + + sendbuff += pack("!I", desktop_name_len) + sendbuff += desktop_name.encode() + + print("width", repr(width)) + print("height", repr(height)) + + sock.send(sendbuff) + + + def protocol(self): + self.socket.settimeout(None) # set nonblocking socket + + screen = ImageGrab.grab() + size = screen.size + width = size[0] + height = size[1] + del screen + + self.primaryOrder = "rgb" + self.encoding = self.ENCODINGS.raw + buttonmask = 0 + buttons = [0, 0, 0, 0, 0, 0, 0, 0] + left_pressed = 0 + right_pressed = 0 + middle_pressed = 0 + + kdbmap = { + "KEY_BackSpace": 0xff08, + "KEY_Tab": 0xff09, + "KEY_Return": 0xff0d, + "KEY_Escape": 0xff1b, + "KEY_Insert": 0xff63, + "KEY_Delete": 0xffff, + "KEY_Home": 0xff50, + "KEY_End": 0xff57, + "KEY_PageUp": 0xff55, + "KEY_PageDown": 0xff56, + "KEY_Left": 0xff51, + "KEY_Up": 0xff52, + "KEY_Right": 0xff53, + "KEY_Down": 0xff54, + "KEY_F1": 0xffbe, + "KEY_F2": 0xffbf, + "KEY_F3": 0xffc0, + "KEY_F4": 0xffc1, + "KEY_F5": 0xffc2, + "KEY_F6": 0xffc3, + "KEY_F7": 0xffc4, + "KEY_F8": 0xffc5, + "KEY_F9": 0xffc6, + "KEY_F10": 0xffc7, + "KEY_F11": 0xffc8, + "KEY_F12": 0xffc9, + "KEY_F13": 0xFFCA, + "KEY_F14": 0xFFCB, + "KEY_F15": 0xFFCC, + "KEY_F16": 0xFFCD, + "KEY_F17": 0xFFCE, + "KEY_F18": 0xFFCF, + "KEY_F19": 0xFFD0, + "KEY_F20": 0xFFD1, + "KEY_ShiftLeft": 0xffe1, + "KEY_ShiftRight": 0xffe2, + "KEY_ControlLeft": 0xffe3, + "KEY_ControlRight": 0xffe4, + "KEY_MetaLeft": 0xffe7, + "KEY_MetaRight": 0xffe8, + "KEY_AltLeft": 0xffe9, + "KEY_AltRight": 0xffea, + "KEY_Scroll_Lock": 0xFF14, + "KEY_Sys_Req": 0xFF15, + "KEY_Num_Lock": 0xFF7F, + "KEY_Caps_Lock": 0xFFE5, + "KEY_Pause": 0xFF13, + "KEY_Super_L": 0xFFEB, + "KEY_Super_R": 0xFFEC, + "KEY_Hyper_L": 0xFFED, + "KEY_Hyper_R": 0xFFEE, + "KEY_KP_0": 0xFFB0, + "KEY_KP_1": 0xFFB1, + "KEY_KP_2": 0xFFB2, + "KEY_KP_3": 0xFFB3, + "KEY_KP_4": 0xFFB4, + "KEY_KP_5": 0xFFB5, + "KEY_KP_6": 0xFFB6, + "KEY_KP_7": 0xFFB7, + "KEY_KP_8": 0xFFB8, + "KEY_KP_9": 0xFFB9, + "KEY_KP_Enter": 0xFF8D, + "KEY_ForwardSlash": 0x002F, + "KEY_BackSlash": 0x005C, + "KEY_SpaceBar": 0x0020 + } + + # key mapping per SO (windows, osx, linux) + # FIXME: OSX maping + if sys.platform == "darwin": + keyboard.control_key = keyboard.key_code_translate_table['control'] + + + mapping = { + "KEY_ControlLeft" : [keyboard.control_key, "Control", keyboard.control_l_key], + "KEY_ControlRight" : [keyboard.control_key, "Control", keyboard.control_r_key], + "KEY_AltLeft": [keyboard.alt_l_key, "Alternate", keyboard.alt_l_key], + "KEY_AltRight": [keyboard.alt_r_key, "Alternate", keyboard.alt_r_key], + "KEY_ShiftLeft": [keyboard.shift_l_key, "shift", keyboard.shift_l_key], + "KEY_ShiftRight": [keyboard.shift_r_key, "shift", keyboard.shift_r_key], + "KEY_Up": [keyboard.up_key, "Up", keyboard.up_key], + "KEY_Down": [keyboard.down_key, "Down", keyboard.down_key], + "KEY_Left": [keyboard.left_key, "Left", keyboard.left_key], + "KEY_Right": [keyboard.right_key, "Right", keyboard.right_key], + "KEY_Delete": [keyboard.delete_key, "delete", keyboard.delete_key], + "KEY_Insert": [keyboard.insert_key, "insert", keyboard.insert_key], + "KEY_Home": [keyboard.home_key, "home", keyboard.home_key], + "KEY_End": [keyboard.end_key, "end", keyboard.end_key], + "KEY_PageUp": [keyboard.page_up_key, "PageUp", keyboard.page_up_key], + "KEY_PageDown": [keyboard.page_down_key, "PageDown", keyboard.page_down_key], + } + + # function keys mapping + for i in range(1,20): + mapping.update( { ("KEY_F%s" % i): [keyboard.function_keys[i], ("F%s" % i) , keyboard.function_keys[i]] } ) + + + while True: + #print(".", end='', flush=True) + r,_,_ = select.select([self.socket],[],[],0) + if r == []: + #no data + sleep(0.1) + continue + + sock = r[0] + try: + data = sock.recv(1) # read first byte + except socket.timeout: + #print("timeout") + continue + except Exception as e: + print("exception '%s'" % e) + sock.close() + break + + if not data: + # clinet disconnected + sock.close() + break + + if data[0] == 0: # client SetPixelFormat + data2 = sock.recv(19, socket.MSG_WAITALL) + print("Client Message Type: Set Pixel Format (0)") + (self.bpp, self.depth, self.bigendian, self.truecolor, self.red_maximum, + self.green_maximum, self.blue_maximum, + self.red_shift, self.green_shift, self.blue_shift + ) = unpack("!xxxBBBBHHHBBBxxx", data2) + print("IMG bpp, depth, endian, truecolor", self.bpp, self.depth, self.bigendian, self.truecolor) + print("SHIFTS", self.red_shift, self.green_shift, self.blue_shift) + print("MAXS", self.red_maximum, self.green_maximum, self.blue_maximum) + + if self.red_shift > self.blue_shift: + self.primaryOrder = "rgb" + else: + self.primaryOrder = "bgr" + print("Using order: ", self.primaryOrder) + + continue + + if data[0] == 2: # SetEncoding + data2 = sock.recv(3) + print("Client Message Type: SetEncoding (2)") + (nencodings,) = unpack("!xH", data2) + print("SetEncoding: total encodings ", repr(nencodings)) + data2 = sock.recv(4 * nencodings, socket.MSG_WAITALL) + print("len", len(data2)) + self.client_encodings = unpack("!%si" % nencodings, data2) + print("data", repr(self.client_encodings), len(self.client_encodings)) + + if self.ENCODINGS.zlib in self.client_encodings: + print("Using zlib encoding") + self.encoding = self.ENCODINGS.zlib + continue + + if data[0] == 3: # FBUpdateRequest + data2 = sock.recv(9, socket.MSG_WAITALL) + #print("Client Message Type: FBUpdateRequest (3)") + #print(len(data2)) + (incremental, x, y, w, h) = unpack("!BHHHH", data2) + #print("RFBU:", incremental, x, y, w, h) + self.SendRectangles(sock, x, y, w, h, incremental) + continue + + if data[0] == 4: + kbdkey = '' + data2 = sock.recv(7) + # B = U8, L = U32 + (downflag, key) = unpack("!BxxL", data2) + print("KeyEvent", downflag, hex(key)) + spKey = getDictByValue(kdbmap, key) + + if not spKey: + try: + kbdkey = chr(key) + except: + kbdkey = key + else: + kbdkey = key + + if downflag: + func = getattr(keyboard, "press_key") + else: + func = getattr(keyboard, "release_key") + + # dynamic keyboard mapping according to "mapping" obj + if spKey in mapping: + print("mapping:", mapping[spKey]) + if sys.platform == "win32" or sys.platform == "win64" and 0 in mapping[spKey]: + kbdkey = mapping[spKey][0] + if sys.platform == "darwin" and 1 in mapping[spKey]: + kbdkey = mapping[spKey][1] + if sys.platform == "linux" and 2 in mapping[spKey]: + kbdkey = mapping[spKey][2] + + print("getDictByValue", getDictByValue(kdbmap, key)) + + func(kbdkey) + + continue + + if data[0] == 5: # PointerEvent + data2 = sock.recv(5, socket.MSG_WAITALL) + (buttonmask, x, y) = unpack("!BHH", data2) + mouse.move(x, y) + buttons[0] = buttonmask & int("0000001", 2) # left button + buttons[1] = buttonmask & int("0000010", 2) # middle button + buttons[2] = buttonmask & int("0000100", 2) # right button + buttons[3] = buttonmask & int("0001000", 2) # scroll up + buttons[4] = buttonmask & int("0010000", 2) # scroll down + + if buttons[0] and not left_pressed: + print("LEFT PRESSED") + mouse.press(x, y, 1) + left_pressed = 1 + elif not buttons[0] and left_pressed: + print("LEFT RELEASED") + mouse.release(x, y, 1) + left_pressed = 0 + + if buttons[1] and not middle_pressed: + print("MIDDLE PRESSED") + mouse.press(x, y, 3) + middle_pressed = 1 + elif not buttons[1] and middle_pressed: + print("MIDDLE RELEASED") + mouse.release(x, y, 3) + middle_pressed = 0 + + if buttons[2] and not right_pressed: + print("RIGHT PRESSED") + mouse.press(x, y, 2) + right_pressed = 1 + elif not buttons[2] and right_pressed: + print("RIGHT RELEASED") + mouse.release(x, y, 2) + right_pressed = 0 + + if buttons[3]: + print("SCROLLUP PRESSED") + mouse.scroll(vertical=1) + + if buttons[4]: + print("SCROLLDOWN PRESSED") + mouse.scroll(vertical=-1) + + #print("PointerEvent", buttonmask, x, y) + continue + + else: + data2 = sock.recv(4096) + print("RAW Server received data:", repr(data[0]) , data+data2) + + + def GetRectangle(self, x, y, w, h): + try: + scr = ImageGrab.grab() + except: + return False + (scr_width, scr_height) = scr.size + + if scr.mode != "RGB": + img = scr.convert("RGB") + else: + img = scr + + del scr + + crop = img.crop((x, y, w, h)) + del img + + return crop + + def SendRectangles(self, sock, x, y, w, h, incremental=0): + # send FramebufferUpdate to client + + #print("start SendRectangles") + rectangle = self.GetRectangle(x, y, w, h) + if not rectangle: + rectangle = Image.new("RGB", [w, h], (0,0,0)) + + lastshot = rectangle + sendbuff = bytearray() + + # try to send only the actual changes + if self.framebuffer != None and incremental == 1: + diff = ImageChops.difference(rectangle, self.framebuffer) + if diff.getbbox() is None: + rectangles = 0 + sendbuff.extend(pack("!BxH", 0, rectangles)) + sock.sendall(sendbuff) + sleep(0.3) + return + + if diff.getbbox() is not None: + if hasattr(diff, "getbbox"): + rectangle = rectangle.crop(diff.getbbox()) + (x, y, _, _) = diff.getbbox() + w = rectangle.width + h = rectangle.height + #print("XYWH:", x,y,w,h, "diff", repr(diff.getbbox())) + + stimeout = sock.gettimeout() + sock.settimeout(None) + + if self.bpp == 32 or self.bpp == 8: + if rectangle.mode is not "RGB": + image = rectangle.convert("RGB") + else: + image = rectangle + + b = np.asarray(image) + a = b.copy() + del b + + if self.bpp == 32: + redBits = 8 + greenBits = 8 + blueBits = 8 + elif self.bpp == 8: + redBits = 4 + greenBits = 4 + blueBits = 4 + + #redMask = ((1 << redBits) - 1) << self.red_shift + #greenMask = ((1 << greenBits) - 1) << self.green_shift + #blueMask = ((1 << blueBits) - 1) << self.blue_shift + #print("redMask", redMask, greenMask, blueMask) + + if self.primaryOrder == "bgr": + self.blue_shift = 0 + blueMask = (1 << blueBits) - 1 + self.green_shift = blueBits + greenMask = ((1 << greenBits) - 1) << self.green_shift + self.red_shift = self.green_shift + greenBits + redMask = ((1 << redBits) - 1) << self.red_shift + + else: # RGB + self.red_shift = 0 + redMask = (1 << redBits) - 1 + self.green_shift = redBits + greenMask = ((1 << greenBits) - 1) << self.green_shift + self.blue_shift = self.green_shift + greenBits + blueMask = ((1 << blueBits) - 1) << self.blue_shift + + a[..., 0] = ( a[..., 0] ) & redMask >> self.red_shift + a[..., 1] = ( a[..., 1] ) & greenMask >> self.green_shift + a[..., 2] = ( a[..., 2] ) & blueMask >> self.blue_shift + + image = Image.fromarray(a) + del a + + if self.primaryOrder == "rgb": + (b, g, r) = image.split() + image = Image.merge("RGB", (r, g, b)) + del b,g,r + + if self.bpp == 32: + image = image.convert("RGBX") + elif self.bpp == 8: + image = image.convert("P") + #image = image.convert("RGB") + #p = Image.new("P",(16,16)) + #p.putpalette(self.BGR233) + #image = quantizetopalette(image, p, dither=CONFIG._8bitdither) + #image.putpalette(self.BGR233) + #del p + + #print(image) + if self.encoding == self.ENCODINGS.zlib: + rectangles = 1 + sendbuff.extend(pack("!BxH", 0, rectangles)) + sendbuff.extend(pack("!HHHH", x, y, w, h)) + sendbuff.extend(pack(">i", self.encoding)) + + print("Compressing...") + #zlibdata = zlib.compress( image.tobytes() )[2:-4] # no header and checksum + #zlibdata = zlib.compress( image.tobytes() )[:-4] # no checksum + zlibdata = zlib.compress( image.tobytes() ) + + l = pack("!I", len(zlibdata) ) + print("LEN:", hexdump(l), len(zlibdata) ) + sendbuff.extend( l ) # send length + print("ZLIB HEAD:", hexdump(zlibdata[0:2]) ) + chksum = zlibdata[-4:] + print("ZLIB CHECKSUM:", hexdump(chksum) ) + sendbuff.extend( zlibdata ) # send compressed data + + #inf = inflate(zlibdata, winsize=-15) + + del zlibdata, l + else: + # send with RAW encoding + rectangles = 1 + sendbuff.extend(pack("!BxH", 0, rectangles)) + sendbuff.extend(pack("!HHHH", x, y, w, h)) + sendbuff.extend(pack(">i", self.encoding)) + sendbuff.extend( image.tobytes() ) + + elif self.bpp == -8: + print("8BPP routines!") + if rectangle.mode is not "RGB": + image = rectangle.convert("RGB") + else: + image = rectangle + + (r, g, b) = image.split() + image = Image.merge("RGB", (g, r, b)) + del b,g,r + + p = Image.new("P",(16,16)) + p.putpalette(self.BGR233) + image = quantizetopalette(image, p, dither=CONFIG._8bitdither) + image.putpalette(self.BGR233) + del p + rectangles = 1 + sendbuff.extend(pack("!BxH", 0, rectangles)) + sendbuff.extend(pack("!HHHH", x, y, w, h)) + sendbuff.extend(pack(">i", self.encoding)) + sendbuff.extend( image.tobytes() ) + + else: + print("[!] Unsupported BPP: %s" % self.bpp) + + self.framebuffer = lastshot + sock.sendall(sendbuff) + sock.settimeout(stimeout) + #print("end SendRectangles") + + +class ControlThread(Thread): + def __init__(self, threads): + Thread.__init__(self) + self.threads = threads + self.setDaemon(True) + + def run(self): + # elimina los threads muertos + while True: + sleep(1) + for t in threads: + if not t.isAlive(): + print("ControlThread removing dead", t) + threads.remove(t) + + +class ClientThread(Thread): + def __init__(self, sock, ip, port): + Thread.__init__(self) + self.ip = ip + self.port = port + self.sock = sock + self.setDaemon(True) + + def __del__(self): + print("ClientThread died") + + def run(self): + print("[+] New server socket thread started for " + self.ip + ":" + str(self.port)) + #print("Thread", self) + server = VncServer(self.sock, self.ip, self.port) + status = server.init() + + if not status: + print("Error negotiating client init") + return False + server.protocol() + + +def main(argv): + global CONFIG, TCP_IP, TCP_PORT, VNC_PASSWORD, mouse, keyboard, threads, controlthread + + class CONFIG: + _8bitdither = False + + parser = ArgumentParser() + parser.add_argument("-l", "--listen-address", dest="TCP_IP", + help="Listen in this address, default: %s" % ("0.0.0.0"), required=False, default='0.0.0.0') + parser.add_argument("-p", "--port", dest="TCP_PORT", + help="Listen in this port, default: %s" % ("5901"), type=int, required=False, default='5901') + parser.add_argument("-P", "--password", help="Sets password", required=True, dest="VNC_PASSWORD") + + parser.add_argument("-8", "--8bitdither", help="Enable 8 bit dithering", required=False, action='store_true', dest="dither") + + args = parser.parse_args() + + # Multithreaded Python server + TCP_IP = '0.0.0.0' if not hasattr(args,"TCP_IP") else args.TCP_IP + TCP_PORT = '0.0.0.0' if not hasattr(args,"TCP_PORT") else args.TCP_PORT + VNC_PASSWORD = args.VNC_PASSWORD + CONFIG._8bitdither = args.dither + + mouse = PyMouse() + keyboard = PyKeyboard() + + sockServer = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + sockServer.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + sockServer.bind((TCP_IP, TCP_PORT)) + + controlthread = ControlThread(threads) + controlthread.start() + threads.append(controlthread) + + print("Multithreaded Python server : Waiting for connections from TCP clients...") + print("Runing on:", sys.platform) + while True: + sockServer.listen(4) + (conn, (ip,port)) = sockServer.accept() + newthread = ClientThread(conn, ip, port) + newthread.setDaemon(True) + newthread.start() + threads.append(newthread) + #print(threads) + +if __name__ == "__main__": + try: + threads = [] + main(sys.argv) + except KeyboardInterrupt: + # quit + print("Exiting on ctrl+c...") + #for t in threads: + # print("Killing", t) + sys.exit() diff --git a/server3.py b/server3.py new file mode 100755 index 0000000..72d86c9 --- /dev/null +++ b/server3.py @@ -0,0 +1,821 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +import socket, select, os, sys, random, zlib +from threading import Thread +from time import sleep +from struct import * +from pyDes import * +from argparse import ArgumentParser + +from pynput import mouse, keyboard + +import numpy as np + +from PIL import Image, ImageChops, ImageDraw, ImagePalette +if sys.platform == "linux" or sys.platform == "linux2": + from Xlib import display, X + # take screen images, that's not the best way, so here + # we use directly use xlib to take the screenshot. + class ImageGrab(): + def grab(): + dsp = display.Display() + root = dsp.screen().root + geom = root.get_geometry() + w = geom.width + h = geom.height + raw = root.get_image(0, 0, w ,h, X.ZPixmap, 0xffffffff) + image = Image.frombytes("RGB", (w, h), raw.data, "raw", "BGRX") + return image + +elif sys.platform == "darwin": + import Quartz.CoreGraphics as CG + class ImageGrab(): + def grab(): + screenshot = CG.CGWindowListCreateImage(CG.CGRectInfinite, CG.kCGWindowListOptionOnScreenOnly, CG.kCGNullWindowID, CG.kCGWindowImageDefault) + width = CG.CGImageGetWidth(screenshot) + height = CG.CGImageGetHeight(screenshot) + bytesperrow = CG.CGImageGetBytesPerRow(screenshot) + + pixeldata = CG.CGDataProviderCopyData(CG.CGImageGetDataProvider(screenshot)) + + i = Image.frombytes("RGBA", (width, height), pixeldata) + (b, g, r, x) = i.split() + i = Image.merge("RGBX", (r, g, b, x)) + + return i + +else: + from PIL import ImageGrab + + +def selfRestart(): + try: + p = psutil.Process(os.getpid()) + for handler in p.get_open_files() + p.connections(): + os.close(handler.fd) + except Exception as e: + print(e) + + python = sys.executable + os.execl(python, python, *sys.argv) + +def hexdump(data): + str = "" + for d in data: + str += hex(d) + str += "(%s) " % d + return str + +def quantizetopalette(silf, palette, dither=False): + """Convert an RGB or L mode image to use a given P image's palette.""" + + silf.load() + + # use palette from reference image + palette.load() + if palette.mode != "P": + raise ValueError("bad mode for palette image") + if silf.mode != "RGB" and silf.mode != "L": + raise ValueError( + "only RGB or L mode images can be quantized to a palette" + ) + im = silf.im.convert("P", 1 if dither else 0, palette.im) + # the 0 above means turn OFF dithering + + # Later versions of Pillow (4.x) rename _makeself to _new + try: + return silf._new(im) + except AttributeError: + return silf._makeself(im) + + +def deflate(data, compresslevel=9, method=zlib.DEFLATED, winsize=-zlib.MAX_WBITS, memlevel=zlib.DEF_MEM_LEVEL, strategy=0): + compress = zlib.compressobj( + compresslevel, # level: 0-9 + method, # method: must be DEFLATED + winsize, # window size in bits: + # -15..-8: negate, suppress header + # 8..15: normal + # 16..30: subtract 16, gzip header + memlevel, # mem level: 1..8/9 + strategy # strategy: + # 0 = Z_DEFAULT_STRATEGY + # 1 = Z_FILTERED + # 2 = Z_HUFFMAN_ONLY + # 3 = Z_RLE + # 4 = Z_FIXED + ) + deflated = compress.compress(data) + deflated += compress.flush() + return deflated + +def inflate(data, winsize=-zlib.MAX_WBITS): + decompress = zlib.decompressobj( + winsize # see above + ) + inflated = decompress.decompress(data) + inflated += decompress.flush() + return inflated + +def getDictByValue(d, val): + try: + return [k for k,v in d.items() if v==val][0] + except: + return False + +RFB_VERSION = '003.008' +RFB_SECTYPES = [ + 2, # VNC auth + 19 # VeNCrypt + ] + +class VncServer(): + + class ENCODINGS: + raw = 0 + zlib = -6 # disabled + + def __init__(self, socket, ip, port): + self.initmsg = ("RFB %s\n" % RFB_VERSION) + self.socket = socket + self.framebuffer = None + + self.sectypes = RFB_SECTYPES + + self.BGR233 = [0, 0, 0, 0, 0, 85, 0, 0, 170, 0, 0, 255, 36, 0, 0, 36, 0, 85, 36, 0, 170, 36, 0, 255, 73, 0, 0, 73, 0, 85, 73, 0, 170, 73, 0, 255, 109, 0, 0, 109, 0, 85, 109, 0, 170, 109, 0, 255, 146, 0, 0, 146, 0, 85, 146, 0, 170, 146, 0, 255, 182, 0, 0, 182, 0, 85, 182, 0, 170, 182, 0, 255, 219, 0, 0, 219, 0, 85, 219, 0, 170, 219, 0, 255, 255, 0, 0, 255, 0, 85, 255, 0, 170, 255, 0, 255, 0, 36, 0, 0, 36, 85, 0, 36, 170, 0, 36, 255, 36, 36, 0, 36, 36, 85, 36, 36, 170, 36, 36, 255, 73, 36, 0, 73, 36, 85, 73, 36, 170, 73, 36, 255, 109, 36, 0, 109, 36, 85, 109, 36, 170, 109, 36, 255, 146, 36, 0, 146, 36, 85, 146, 36, 170, 146, 36, 255, 182, 36, 0, 182, 36, 85, 182, 36, 170, 182, 36, 255, 219, 36, 0, 219, 36, 85, 219, 36, 170, 219, 36, 255, 255, 36, 0, 255, 36, 85, 255, 36, 170, 255, 36, 255, 0, 73, 0, 0, 73, 85, 0, 73, 170, 0, 73, 255, 36, 73, 0, 36, 73, 85, 36, 73, 170, 36, 73, 255, 73, 73, 0, 73, 73, 85, 73, 73, 170, 73, 73, 255, 109, 73, 0, 109, 73, 85, 109, 73, 170, 109, 73, 255, 146, 73, 0, 146, 73, 85, 146, 73, 170, 146, 73, 255, 182, 73, 0, 182, 73, 85, 182, 73, 170, 182, 73, 255, 219, 73, 0, 219, 73, 85, 219, 73, 170, 219, 73, 255, 255, 73, 0, 255, 73, 85, 255, 73, 170, 255, 73, 255, 0, 109, 0, 0, 109, 85, 0, 109, 170, 0, 109, 255, 36, 109, 0, 36, 109, 85, 36, 109, 170, 36, 109, 255, 73, 109, 0, 73, 109, 85, 73, 109, 170, 73, 109, 255, 109, 109, 0, 109, 109, 85, 109, 109, 170, 109, 109, 255, 146, 109, 0, 146, 109, 85, 146, 109, 170, 146, 109, 255, 182, 109, 0, 182, 109, 85, 182, 109, 170, 182, 109, 255, 219, 109, 0, 219, 109, 85, 219, 109, 170, 219, 109, 255, 255, 109, 0, 255, 109, 85, 255, 109, 170, 255, 109, 255, 0, 146, 0, 0, 146, 85, 0, 146, 170, 0, 146, 255, 36, 146, 0, 36, 146, 85, 36, 146, 170, 36, 146, 255, 73, 146, 0, 73, 146, 85, 73, 146, 170, 73, 146, 255, 109, 146, 0, 109, 146, 85, 109, 146, 170, 109, 146, 255, 146, 146, 0, 146, 146, 85, 146, 146, 170, 146, 146, 255, 182, 146, 0, 182, 146, 85, 182, 146, 170, 182, 146, 255, 219, 146, 0, 219, 146, 85, 219, 146, 170, 219, 146, 255, 255, 146, 0, 255, 146, 85, 255, 146, 170, 255, 146, 255, 0, 182, 0, 0, 182, 85, 0, 182, 170, 0, 182, 255, 36, 182, 0, 36, 182, 85, 36, 182, 170, 36, 182, 255, 73, 182, 0, 73, 182, 85, 73, 182, 170, 73, 182, 255, 109, 182, 0, 109, 182, 85, 109, 182, 170, 109, 182, 255, 146, 182, 0, 146, 182, 85, 146, 182, 170, 146, 182, 255, 182, 182, 0, 182, 182, 85, 182, 182, 170, 182, 182, 255, 219, 182, 0, 219, 182, 85, 219, 182, 170, 219, 182, 255, 255, 182, 0, 255, 182, 85, 255, 182, 170, 255, 182, 255, 0, 219, 0, 20, 219, 85, 0, 219, 170, 0, 219, 255, 36, 219, 0, 36, 219, 85, 36, 219, 170, 36, 219, 255, 73, 219, 0, 73, 219, 85, 73, 219, 170, 73, 219, 255, 109, 219, 0, 109, 219, 85, 109, 219, 170, 109, 219, 255, 146, 219, 0, 146, 219, 85, 146, 219, 170, 146, 219, 255, 182, 219, 0, 182, 219, 85, 182, 219, 170, 182, 219, 255, 219, 219, 0, 219, 219, 85, 219, 219, 170, 219, 219, 255, 255, 219, 0, 255, 219, 85, 255, 219, 170, 255, 219, 255, 0, 255, 0, 0, 255, 85, 0, 255, 170, 0, 255, 255, 36, 255, 0, 36, 255, 85, 36, 255, 170, 36, 255, 255, 73, 255, 0, 73, 255, 85, 73, 255, 170, 73, 255, 255, 109, 255, 0, 109, 255, 85, 109, 255, 170, 109, 255, 255, 146, 255, 0, 146, 255, 85, 146, 255, 170, 146, 255, 255, 182, 255, 0, 182, 255, 85, 182, 255, 170, 182, 255, 255, 219, 255, 0, 219, 255, 85, 219, 255, 170, 219, 255, 255, 255, 255, 0, 255, 255, 85, 255, 255, 170, 255, 255, 255] + + def __del__(self): + print("VncServer died") + + def encrypt(self, key, data): + k = des(key, ECB, "\0\0\0\0\0\0\0\0", pad=None, padmode=PAD_PKCS5) + d = k.encrypt(data) + return d + + def decrypt(self, challenge, data): + k = des(challenge, ECB, "\0\0\0\0\0\0\0\0", pad=None, padmode=PAD_PKCS5) + return k.decrypt(data) + + def mirrorBits(self, key): + newkey = [] + for ki in range(len(key)): + bsrc = key[ki] + btgt = 0 + for i in range(8): + if ord(bsrc) & (1 << i): + btgt = btgt | (1 << 7-i) + newkey.append(btgt) + + return newkey + + def sendmessage(self, message): + ''' sends a RFB message, usually an error message ''' + sock = self.socket + message = bytes(message, 'iso8859-1') + # 4 bytes lenght and string + buff = pack("I%ds" % (len(message),), len(message), message) + sock.send(message) + + def getbuff(self, timeout): + sock = self.socket + sock.settimeout(timeout) + + try: + data = sock.recv(1024) + except socket.timeout: + data = None + print("getbuff() timeout") + + return data + + def init(self): + sock = self.socket + sock.send(self.initmsg.encode()) + + # RFB version handshake + data = self.getbuff(30) + + print("init received: '%s'" % data) + server_version = float(RFB_VERSION) + try: + client_version = float(data[4:11]) + except: + print("Error parsing client version") + return False + + print("client, server:", client_version, server_version) + + # security types handshake + sendbuff = pack("B", len(self.sectypes)) # number of security types + sendbuff += pack('%sB' % len(self.sectypes), *self.sectypes) # send available sec types + sock.send(sendbuff) + + data = self.getbuff(30) + try: + sectype = unpack("B", data)[0] + except: + sectype = None + + if sectype not in self.sectypes: + print("Incompatible security type: %s" % data) + sock.send(pack("B", 1)) # failed handshake + self.sendmessage("Incompatible security type") + sock.close() + return False + + print("sec type data: %s" % data) + + # VNC Auth + if sectype == 2: + # el cliente encripta el challenge con la contraseña ingresada como key + pw = (VNC_PASSWORD + '\0' * 8)[:8] + challenge = os.urandom(16) # challenge + sock.send(challenge) # send challenge + # obtener desde el cliente el dato encritado + data = self.getbuff(30) + # la encriptacion de challenge, con pw como key debe dar data + + k = des(self.mirrorBits(pw)) + crypted = k.encrypt(challenge) + + if data == crypted: + # Handshake successful + sock.send(pack("I", 0)) + print("Auth OK") + else: + print("Invalid auth") + return False + + #unsupported VNC auth type + else: + return False + + # get ClientInit + data = self.getbuff(30) + print("Clientinit (shared flag)", repr(data)) + + self.ServerInit() + + return True + + def ServerInit(self): + # ServerInit + + sock = self.socket + screen = ImageGrab.grab() + print("screen", repr(screen)) + size = screen.size + print("size", repr(size)) + del screen + + width = size[0] + self.width = width + height = size[1] + self.height = height + bpp = 32 # FIXME: get real bpp + depth = 32 # FIXME: get real depth + self.depth = depth + self.bpp = bpp + bigendian = 0 + truecolor = 1 + red_maximum = 255 + self.red_maximum = red_maximum + green_maximum = 255 + self.green_maximum = green_maximum + blue_maximum = 255 + self.blue_maximum = blue_maximum + red_shift = 16 + self.red_shift = red_shift + green_shift = 8 + self.green_shift = green_shift + blue_shift = 0 + self.blue_shift = blue_shift + + sendbuff = pack("!HH", width, height) + sendbuff += pack("!BBBB", bpp, depth, bigendian, truecolor) + sendbuff += pack("!HHHBBB", red_maximum, green_maximum, blue_maximum, red_shift, green_shift, blue_shift) + sendbuff += pack("!xxx") # padding + + desktop_name = "Test VNC" + desktop_name_len = len(desktop_name) + + sendbuff += pack("!I", desktop_name_len) + sendbuff += desktop_name.encode() + + print("width", repr(width)) + print("height", repr(height)) + + sock.send(sendbuff) + + + def protocol(self): + self.socket.settimeout(None) # set nonblocking socket + + screen = ImageGrab.grab() + size = screen.size + width = size[0] + height = size[1] + del screen + + self.primaryOrder = "rgb" + self.encoding = self.ENCODINGS.raw + buttonmask = 0 + buttons = [0, 0, 0, 0, 0, 0, 0, 0] + left_pressed = 0 + right_pressed = 0 + middle_pressed = 0 + + + kbdmap = { + 0xff08: keyboard.Key.backspace, + 0xff09: keyboard.Key.tab, + 0xff0d: keyboard.Key.enter, + 0xff1b: keyboard.Key.esc, + 0xff63: keyboard.Key.insert if hasattr(keyboard.Key, "insert") else None, + 0xffff: keyboard.Key.delete, + 0xff50: keyboard.Key.home, + 0xff57: keyboard.Key.end, + 0xff55: keyboard.Key.page_up, + 0xff56: keyboard.Key.page_down, + 0xff51: keyboard.Key.left, + 0xff52: keyboard.Key.up, + 0xff53: keyboard.Key.right, + 0xff54: keyboard.Key.down, + 0xffbe: keyboard.Key.f1, + 0xffbf: keyboard.Key.f2, + 0xffc0: keyboard.Key.f3, + 0xffc1: keyboard.Key.f4, + 0xffc2: keyboard.Key.f5, + 0xffc3: keyboard.Key.f6, + 0xffc4: keyboard.Key.f7, + 0xffc5: keyboard.Key.f8, + 0xffc6: keyboard.Key.f9, + 0xffc7: keyboard.Key.f10, + 0xffc8: keyboard.Key.f11, + 0xffc9: keyboard.Key.f12, + 0xffca: keyboard.Key.f13, + 0xffcb: keyboard.Key.f14, + 0xffcc: keyboard.Key.f15, + 0xffcd: keyboard.Key.f16, + 0xffce: keyboard.Key.f17, + 0xffcf: keyboard.Key.f18, + 0xffd0: keyboard.Key.f19, + 0xffd1: keyboard.Key.f20, + 0xffe1: keyboard.Key.shift_l, + 0xffe2: keyboard.Key.shift_r, + 0xffe3: keyboard.Key.ctrl_l, + 0xffe4: keyboard.Key.ctrl_r, + 0xffe7: None, # "KEY_MetaLeft" + 0xffe8: None, # "KEY_MetaRight" + 0xffe9: keyboard.Key.cmd_l, + 0xffea: keyboard.Key.alt_gr, # "KEY_AltRight" + 0xff14: keyboard.Key.scroll_lock if hasattr(keyboard.Key, "scroll_lock") else None, + 0xff15: keyboard.Key.print_screen if hasattr(keyboard.Key, "print_screen") else None, # "KEY_Sys_Req" + 0xff7f: keyboard.Key.num_lock if hasattr(keyboard.Key, "num_lock") else None, + 0xffe5: keyboard.Key.caps_lock, + 0xff13: keyboard.Key.pause if hasattr(keyboard.Key, "pause") else None, + 0xffeb: keyboard.Key.cmd_r, # "KEY_Super_L" + 0xffec: keyboard.Key.cmd_r, # "KEY_Super_R" + 0xffed: None, # "KEY_Hyper_L" + 0xffee: None, # "KEY_Hyper_R" + 0xffb0: None, # "KEY_KP_0" + 0xffb1: None, # "KEY_KP_1" + 0xffb2: None, # "KEY_KP_2" + 0xffb3: None, # "KEY_KP_3" + 0xffb4: None, # "KEY_KP_4" + 0xffb5: None, # "KEY_KP_5" + 0xffb6: None, # "KEY_KP_6" + 0xffb7: None, # "KEY_KP_7" + 0xffb8: None, # "KEY_KP_8" + 0xffb9: None, # "KEY_KP_9" + 0xff8d: None, # "KEY_KP_Enter" + 0x002f: "/", # KEY_ForwardSlash + 0x005c: "\\", # KEY_BackSlash + 0x0020: keyboard.Key.space, # "KEY_SpaceBar" + 0xff7e: keyboard.Key.alt_gr, # altgr, at least on a mac (?) + 0xfe03: keyboard.Key.alt_l, + } + + if sys.platform == "darwin": + kbdmap[0xffe2] = keyboard.Key.shift + + while True: + #print(".", end='', flush=True) + r,_,_ = select.select([self.socket],[],[],0) + if r == []: + #no data + sleep(0.1) + continue + + sock = r[0] + try: + data = sock.recv(1) # read first byte + except socket.timeout: + #print("timeout") + continue + except Exception as e: + print("exception '%s'" % e) + sock.close() + break + + if not data: + # clinet disconnected + sock.close() + break + + if data[0] == 0: # client SetPixelFormat + data2 = sock.recv(19, socket.MSG_WAITALL) + print("Client Message Type: Set Pixel Format (0)") + (self.bpp, self.depth, self.bigendian, self.truecolor, self.red_maximum, + self.green_maximum, self.blue_maximum, + self.red_shift, self.green_shift, self.blue_shift + ) = unpack("!xxxBBBBHHHBBBxxx", data2) + print("IMG bpp, depth, endian, truecolor", self.bpp, self.depth, self.bigendian, self.truecolor) + print("SHIFTS", self.red_shift, self.green_shift, self.blue_shift) + print("MAXS", self.red_maximum, self.green_maximum, self.blue_maximum) + + if self.red_shift > self.blue_shift: + self.primaryOrder = "rgb" + else: + self.primaryOrder = "bgr" + print("Using order: ", self.primaryOrder) + + continue + + if data[0] == 2: # SetEncoding + data2 = sock.recv(3) + print("Client Message Type: SetEncoding (2)") + (nencodings,) = unpack("!xH", data2) + print("SetEncoding: total encodings ", repr(nencodings)) + data2 = sock.recv(4 * nencodings, socket.MSG_WAITALL) + print("len", len(data2)) + self.client_encodings = unpack("!%si" % nencodings, data2) + print("data", repr(self.client_encodings), len(self.client_encodings)) + + if self.ENCODINGS.zlib in self.client_encodings: + print("Using zlib encoding") + self.encoding = self.ENCODINGS.zlib + continue + + if data[0] == 3: # FBUpdateRequest + data2 = sock.recv(9, socket.MSG_WAITALL) + #print("Client Message Type: FBUpdateRequest (3)") + #print(len(data2)) + (incremental, x, y, w, h) = unpack("!BHHHH", data2) + #print("RFBU:", incremental, x, y, w, h) + self.SendRectangles(sock, x, y, w, h, incremental) + continue + + if data[0] == 4: + kbdkey = '' + data2 = sock.recv(7) + # B = U8, L = U32 + (downflag, key) = unpack("!BxxL", data2) + print("KeyEvent", downflag, hex(key)) + + # special key + if key in kbdmap: + kbdkey = kbdmap[key] + else: # normal key + try: + kbdkey = keyboard.KeyCode.from_char(chr(key)) + except: + kbdkey = None + + try: + print("KEY:", kbdkey) + except: + print("KEY: (unprintable)") + + try: + if downflag: + keyboard.Controller().press(kbdkey) + else: + keyboard.Controller().release(kbdkey) + except: + print("Error sending key") + + continue + + if data[0] == 5: # PointerEvent + data2 = sock.recv(5, socket.MSG_WAITALL) + (buttonmask, x, y) = unpack("!BHH", data2) + buttons[0] = buttonmask & int("0000001", 2) # left button + buttons[1] = buttonmask & int("0000010", 2) # middle button + buttons[2] = buttonmask & int("0000100", 2) # right button + buttons[3] = buttonmask & int("0001000", 2) # scroll up + buttons[4] = buttonmask & int("0010000", 2) # scroll down + + mouse.Controller().position = (x, y) + + if buttons[0] and not left_pressed: + print("LEFT PRESSED") + mouse.Controller().press(mouse.Button.left) + left_pressed = 1 + elif not buttons[0] and left_pressed: + print("LEFT RELEASED") + mouse.Controller().release(mouse.Button.left) + left_pressed = 0 + + if buttons[1] and not middle_pressed: + print("MIDDLE PRESSED") + mouse.Controller().press(mouse.Button.middle) + middle_pressed = 1 + elif not buttons[1] and middle_pressed: + print("MIDDLE RELEASED") + mouse.Controller().release(mouse.Button.middle) + middle_pressed = 0 + + if buttons[2] and not right_pressed: + print("RIGHT PRESSED") + mouse.Controller().press(mouse.Button.right) + right_pressed = 1 + elif not buttons[2] and right_pressed: + print("RIGHT RELEASED") + mouse.Controller().release(mouse.Button.right) + right_pressed = 0 + + if buttons[3]: + print("SCROLLUP PRESSED") + mouse.Controller().scroll(0, 2) + + if buttons[4]: + print("SCROLLDOWN PRESSED") + mouse.Controller().scroll(0, -2) + + #print("PointerEvent", buttonmask, x, y) + continue + + else: + data2 = sock.recv(4096) + print("RAW Server received data:", repr(data[0]) , data+data2) + + + def GetRectangle(self, x, y, w, h): + try: + scr = ImageGrab.grab() + except: + return False + (scr_width, scr_height) = scr.size + + if scr.mode != "RGB": + img = scr.convert("RGB") + else: + img = scr + + del scr + + crop = img.crop((x, y, w, h)) + del img + + return crop + + def SendRectangles(self, sock, x, y, w, h, incremental=0): + # send FramebufferUpdate to client + + #print("start SendRectangles") + rectangle = self.GetRectangle(x, y, w, h) + if not rectangle: + rectangle = Image.new("RGB", [w, h], (0,0,0)) + + lastshot = rectangle + sendbuff = bytearray() + + # try to send only the actual changes + if self.framebuffer != None and incremental == 1: + diff = ImageChops.difference(rectangle, self.framebuffer) + if diff.getbbox() is None: + rectangles = 0 + sendbuff.extend(pack("!BxH", 0, rectangles)) + sock.sendall(sendbuff) + sleep(0.3) + return + + if diff.getbbox() is not None: + if hasattr(diff, "getbbox"): + rectangle = rectangle.crop(diff.getbbox()) + (x, y, _, _) = diff.getbbox() + w = rectangle.width + h = rectangle.height + #print("XYWH:", x,y,w,h, "diff", repr(diff.getbbox())) + + stimeout = sock.gettimeout() + sock.settimeout(None) + + if self.bpp == 32 or self.bpp == 8: + if rectangle.mode is not "RGB": + image = rectangle.convert("RGB") + else: + image = rectangle + + b = np.asarray(image) + a = b.copy() + del b + + if self.bpp == 32: + redBits = 8 + greenBits = 8 + blueBits = 8 + elif self.bpp == 8: + redBits = 4 + greenBits = 4 + blueBits = 4 + + #redMask = ((1 << redBits) - 1) << self.red_shift + #greenMask = ((1 << greenBits) - 1) << self.green_shift + #blueMask = ((1 << blueBits) - 1) << self.blue_shift + #print("redMask", redMask, greenMask, blueMask) + + if self.primaryOrder == "bgr": + self.blue_shift = 0 + blueMask = (1 << blueBits) - 1 + self.green_shift = blueBits + greenMask = ((1 << greenBits) - 1) << self.green_shift + self.red_shift = self.green_shift + greenBits + redMask = ((1 << redBits) - 1) << self.red_shift + + else: # RGB + self.red_shift = 0 + redMask = (1 << redBits) - 1 + self.green_shift = redBits + greenMask = ((1 << greenBits) - 1) << self.green_shift + self.blue_shift = self.green_shift + greenBits + blueMask = ((1 << blueBits) - 1) << self.blue_shift + + a[..., 0] = ( a[..., 0] ) & redMask >> self.red_shift + a[..., 1] = ( a[..., 1] ) & greenMask >> self.green_shift + a[..., 2] = ( a[..., 2] ) & blueMask >> self.blue_shift + + image = Image.fromarray(a) + del a + + if self.primaryOrder == "rgb": + (b, g, r) = image.split() + image = Image.merge("RGB", (r, g, b)) + del b,g,r + + if self.bpp == 32: + image = image.convert("RGBX") + elif self.bpp == 8: + image = image.convert("P") + #image = image.convert("RGB") + #p = Image.new("P",(16,16)) + #p.putpalette(self.BGR233) + #image = quantizetopalette(image, p, dither=CONFIG._8bitdither) + #image.putpalette(self.BGR233) + #del p + + #print(image) + if self.encoding == self.ENCODINGS.zlib: + rectangles = 1 + sendbuff.extend(pack("!BxH", 0, rectangles)) + sendbuff.extend(pack("!HHHH", x, y, w, h)) + sendbuff.extend(pack(">i", self.encoding)) + + print("Compressing...") + #zlibdata = zlib.compress( image.tobytes() )[2:-4] # no header and checksum + #zlibdata = zlib.compress( image.tobytes() )[:-4] # no checksum + zlibdata = zlib.compress( image.tobytes() ) + + l = pack("!I", len(zlibdata) ) + print("LEN:", hexdump(l), len(zlibdata) ) + sendbuff.extend( l ) # send length + print("ZLIB HEAD:", hexdump(zlibdata[0:2]) ) + chksum = zlibdata[-4:] + print("ZLIB CHECKSUM:", hexdump(chksum) ) + sendbuff.extend( zlibdata ) # send compressed data + + #inf = inflate(zlibdata, winsize=-15) + + del zlibdata, l + else: + # send with RAW encoding + rectangles = 1 + sendbuff.extend(pack("!BxH", 0, rectangles)) + sendbuff.extend(pack("!HHHH", x, y, w, h)) + sendbuff.extend(pack(">i", self.encoding)) + sendbuff.extend( image.tobytes() ) + + elif self.bpp == -8: + print("8BPP routines!") + if rectangle.mode is not "RGB": + image = rectangle.convert("RGB") + else: + image = rectangle + + (r, g, b) = image.split() + image = Image.merge("RGB", (g, r, b)) + del b,g,r + + p = Image.new("P",(16,16)) + p.putpalette(self.BGR233) + image = quantizetopalette(image, p, dither=CONFIG._8bitdither) + image.putpalette(self.BGR233) + del p + rectangles = 1 + sendbuff.extend(pack("!BxH", 0, rectangles)) + sendbuff.extend(pack("!HHHH", x, y, w, h)) + sendbuff.extend(pack(">i", self.encoding)) + sendbuff.extend( image.tobytes() ) + + else: + print("[!] Unsupported BPP: %s" % self.bpp) + + self.framebuffer = lastshot + sock.sendall(sendbuff) + sock.settimeout(stimeout) + #print("end SendRectangles") + + +class ControlThread(Thread): + def __init__(self, threads): + Thread.__init__(self) + self.threads = threads + self.setDaemon(True) + + def run(self): + # elimina los threads muertos + while True: + sleep(1) + for t in threads: + if not t.isAlive(): + print("ControlThread removing dead", t) + threads.remove(t) + + +class ClientThread(Thread): + def __init__(self, sock, ip, port): + Thread.__init__(self) + self.ip = ip + self.port = port + self.sock = sock + self.setDaemon(True) + + def __del__(self): + print("ClientThread died") + + def run(self): + print("[+] New server socket thread started for " + self.ip + ":" + str(self.port)) + #print("Thread", self) + server = VncServer(self.sock, self.ip, self.port) + status = server.init() + + if not status: + print("Error negotiating client init") + return False + server.protocol() + + +def main(argv): + global CONFIG, TCP_IP, TCP_PORT, VNC_PASSWORD, mouse, keyboard, threads, controlthread + + class CONFIG: + _8bitdither = False + + parser = ArgumentParser() + parser.add_argument("-l", "--listen-address", dest="TCP_IP", + help="Listen in this address, default: %s" % ("0.0.0.0"), required=False, default='0.0.0.0') + parser.add_argument("-p", "--port", dest="TCP_PORT", + help="Listen in this port, default: %s" % ("5901"), type=int, required=False, default='5901') + parser.add_argument("-P", "--password", help="Sets password", required=True, dest="VNC_PASSWORD") + + parser.add_argument("-8", "--8bitdither", help="Enable 8 bit dithering", required=False, action='store_true', dest="dither") + + args = parser.parse_args() + + # Multithreaded Python server + TCP_IP = '0.0.0.0' if not hasattr(args,"TCP_IP") else args.TCP_IP + TCP_PORT = '0.0.0.0' if not hasattr(args,"TCP_PORT") else args.TCP_PORT + VNC_PASSWORD = args.VNC_PASSWORD + CONFIG._8bitdither = args.dither + + sockServer = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + sockServer.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + sockServer.bind((TCP_IP, TCP_PORT)) + + controlthread = ControlThread(threads) + controlthread.start() + threads.append(controlthread) + + print("Multithreaded Python server : Waiting for connections from TCP clients...") + print("Runing on:", sys.platform) + while True: + sockServer.listen(4) + (conn, (ip,port)) = sockServer.accept() + newthread = ClientThread(conn, ip, port) + newthread.setDaemon(True) + newthread.start() + threads.append(newthread) + #print(threads) + +if __name__ == "__main__": + try: + threads = [] + main(sys.argv) + except KeyboardInterrupt: + # quit + print("Exiting on ctrl+c...") + #for t in threads: + # print("Killing", t) + sys.exit() diff --git a/server4.py b/server4.py new file mode 100644 index 0000000..0a6afa2 --- /dev/null +++ b/server4.py @@ -0,0 +1,102 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +import pyvncs +from argparse import ArgumentParser +from threading import Thread +from time import sleep + +import sys +import socket + + +class ControlThread(Thread): + def __init__(self, threads): + Thread.__init__(self) + self.threads = threads + self.setDaemon(True) + + def run(self): + # elimina los threads muertos + while True: + sleep(1) + for t in threads: + if not t.isAlive(): + print("ControlThread removing dead", t) + threads.remove(t) + +class ClientThread(Thread): + def __init__(self, sock, ip, port): + Thread.__init__(self) + self.ip = ip + self.port = port + self.sock = sock + self.setDaemon(True) + + def __del__(self): + print("ClientThread died") + + def run(self): + print("[+] New server socket thread started for " + self.ip + ":" + str(self.port)) + #print("Thread", self) + server = pyvncs.server.VncServer(self.sock, VNC_PASSWORD) + server.CONFIG._8bitdither = CONFIG._8bitdither + status = server.init() + + if not status: + print("Error negotiating client init") + return False + server.protocol() + + +def main(argv): + global CONFIG, TCP_IP, TCP_PORT, VNC_PASSWORD, threads, controlthread + class CONFIG: + _8bitdither = False + + parser = ArgumentParser() + parser.add_argument("-l", "--listen-address", dest="TCP_IP", + help="Listen in this address, default: %s" % ("0.0.0.0"), required=False, default='0.0.0.0') + parser.add_argument("-p", "--port", dest="TCP_PORT", + help="Listen in this port, default: %s" % ("5901"), type=int, required=False, default='5901') + parser.add_argument("-P", "--password", help="Sets password", required=True, dest="VNC_PASSWORD") + parser.add_argument("-8", "--8bitdither", help="Enable 8 bit dithering", required=False, action='store_true', dest="dither") + args = parser.parse_args() + + # Multithreaded Python server + TCP_IP = '0.0.0.0' if not hasattr(args,"TCP_IP") else args.TCP_IP + TCP_PORT = '0.0.0.0' if not hasattr(args,"TCP_PORT") else args.TCP_PORT + VNC_PASSWORD = args.VNC_PASSWORD + CONFIG._8bitdither = args.dither + + sockServer = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + sockServer.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + sockServer.bind((TCP_IP, TCP_PORT)) + + controlthread = ControlThread(threads) + controlthread.start() + threads.append(controlthread) + + print("Multithreaded Python server : Waiting for connections from TCP clients...") + print("Runing on:", sys.platform) + while True: + sockServer.listen(4) + (conn, (ip,port)) = sockServer.accept() + newthread = ClientThread(conn, ip, port) + newthread.setDaemon(True) + newthread.start() + threads.append(newthread) + #print(threads) + + +if __name__ == "__main__": + try: + threads = [] + main(sys.argv) + except KeyboardInterrupt: + # quit + print("Exiting on ctrl+c...") + #for t in threads: + # print("Killing", t) + sys.exit() + \ No newline at end of file diff --git a/test.php b/test.php new file mode 100755 index 0000000..c0fb01b --- /dev/null +++ b/test.php @@ -0,0 +1,49 @@ +#!/usr/bin/php + 8){ + $cnt = 8; + } + + for($i=1; $i<=$cnt; $i++){ + $s = $arr[$i]; + $s = (($s >> 1) & 0x55) | (($s << 1) & 0xaa); + $s = (($s >> 2) & 0x33) | (($s << 2) & 0xcc); + $s = (($s >> 4) & 0x0f) | (($s << 4) & 0xf0); + $ret = $ret . chr($s); + } + return $ret; +} + +$passwd="kaka80\0\0"; +$data = "1234567890123456"; + +$iv = mcrypt_create_iv(mcrypt_get_iv_size (MCRYPT_DES, MCRYPT_MODE_ECB), MCRYPT_RAND); +$crypted = mcrypt_encrypt(MCRYPT_DES, mirrorBits($passwd), $data, MCRYPT_MODE_ECB, $iv); + +echo "Crypted: " . base64_encode($crypted); +echo "\n"; diff --git a/test.py b/test.py new file mode 100644 index 0000000..a05e776 --- /dev/null +++ b/test.py @@ -0,0 +1,15 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +from pynput import mouse, keyboard + +keyboard.Controller().press(keyboard.Key.shift) +keyboard.Controller().press('a') + +#keyboard.Controller().modifiers(keyboard.Key().shift) +#print("Shift:", keyboard.Controller().shift_pressed) +#keyboard.Controller().press('a') +#keyboard.Controller().release('a') +#keyboard.Controller().release(keyboard.Key.shift_r) + + diff --git a/test2.py b/test2.py new file mode 100755 index 0000000..0cec203 --- /dev/null +++ b/test2.py @@ -0,0 +1,12 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +zlibHeader = bytearray() +zlibLength = 300309 + +zlibHeader.append( (zlibLength>>24) & 0xFF ) +zlibHeader.append( (zlibLength>>16) & 0xFF ) +zlibHeader.append( (zlibLength>>8) & 0xFF ) +zlibHeader.append( zlibLength & 0xFF ) + +print(zlibHeader) diff --git a/test3.py b/test3.py new file mode 100755 index 0000000..c78f157 --- /dev/null +++ b/test3.py @@ -0,0 +1,43 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +from PIL import Image, ImageChops, ImageDraw + +def quantizetopalette(silf, palette, dither=False): + """Convert an RGB or L mode image to use a given P image's palette.""" + + silf.load() + + # use palette from reference image + palette.load() + if palette.mode != "P": + raise ValueError("bad mode for palette image") + if silf.mode != "RGB" and silf.mode != "L": + raise ValueError( + "only RGB or L mode images can be quantized to a palette" + ) + im = silf.im.convert("P", 1 if dither else 0, palette.im) + # the 0 above means turn OFF dithering + + # Later versions of Pillow (4.x) rename _makeself to _new + try: + return silf._new(im) + except AttributeError: + return silf._makeself(im) + + +BGR233 = [0, 0, 0, 0, 0, 85, 0, 0, 170, 0, 0, 255, 36, 0, 0, 36, 0, 85, 36, 0, 170, 36, 0, 255, 73, 0, 0, 73, 0, 85, 73, 0, 170, 73, 0, 255, 109, 0, 0, 109, 0, 85, 109, 0, 170, 109, 0, 255, 146, 0, 0, 146, 0, 85, 146, 0, 170, 146, 0, 255, 182, 0, 0, 182, 0, 85, 182, 0, 170, 182, 0, 255, 219, 0, 0, 219, 0, 85, 219, 0, 170, 219, 0, 255, 255, 0, 0, 255, 0, 85, 255, 0, 170, 255, 0, 255, 0, 36, 0, 0, 36, 85, 0, 36, 170, 0, 36, 255, 36, 36, 0, 36, 36, 85, 36, 36, 170, 36, 36, 255, 73, 36, 0, 73, 36, 85, 73, 36, 170, 73, 36, 255, 109, 36, 0, 109, 36, 85, 109, 36, 170, 109, 36, 255, 146, 36, 0, 146, 36, 85, 146, 36, 170, 146, 36, 255, 182, 36, 0, 182, 36, 85, 182, 36, 170, 182, 36, 255, 219, 36, 0, 219, 36, 85, 219, 36, 170, 219, 36, 255, 255, 36, 0, 255, 36, 85, 255, 36, 170, 255, 36, 255, 0, 73, 0, 0, 73, 85, 0, 73, 170, 0, 73, 255, 36, 73, 0, 36, 73, 85, 36, 73, 170, 36, 73, 255, 73, 73, 0, 73, 73, 85, 73, 73, 170, 73, 73, 255, 109, 73, 0, 109, 73, 85, 109, 73, 170, 109, 73, 255, 146, 73, 0, 146, 73, 85, 146, 73, 170, 146, 73, 255, 182, 73, 0, 182, 73, 85, 182, 73, 170, 182, 73, 255, 219, 73, 0, 219, 73, 85, 219, 73, 170, 219, 73, 255, 255, 73, 0, 255, 73, 85, 255, 73, 170, 255, 73, 255, 0, 109, 0, 0, 109, 85, 0, 109, 170, 0, 109, 255, 36, 109, 0, 36, 109, 85, 36, 109, 170, 36, 109, 255, 73, 109, 0, 73, 109, 85, 73, 109, 170, 73, 109, 255, 109, 109, 0, 109, 109, 85, 109, 109, 170, 109, 109, 255, 146, 109, 0, 146, 109, 85, 146, 109, 170, 146, 109, 255, 182, 109, 0, 182, 109, 85, 182, 109, 170, 182, 109, 255, 219, 109, 0, 219, 109, 85, 219, 109, 170, 219, 109, 255, 255, 109, 0, 255, 109, 85, 255, 109, 170, 255, 109, 255, 0, 146, 0, 0, 146, 85, 0, 146, 170, 0, 146, 255, 36, 146, 0, 36, 146, 85, 36, 146, 170, 36, 146, 255, 73, 146, 0, 73, 146, 85, 73, 146, 170, 73, 146, 255, 109, 146, 0, 109, 146, 85, 109, 146, 170, 109, 146, 255, 146, 146, 0, 146, 146, 85, 146, 146, 170, 146, 146, 255, 182, 146, 0, 182, 146, 85, 182, 146, 170, 182, 146, 255, 219, 146, 0, 219, 146, 85, 219, 146, 170, 219, 146, 255, 255, 146, 0, 255, 146, 85, 255, 146, 170, 255, 146, 255, 0, 182, 0, 0, 182, 85, 0, 182, 170, 0, 182, 255, 36, 182, 0, 36, 182, 85, 36, 182, 170, 36, 182, 255, 73, 182, 0, 73, 182, 85, 73, 182, 170, 73, 182, 255, 109, 182, 0, 109, 182, 85, 109, 182, 170, 109, 182, 255, 146, 182, 0, 146, 182, 85, 146, 182, 170, 146, 182, 255, 182, 182, 0, 182, 182, 85, 182, 182, 170, 182, 182, 255, 219, 182, 0, 219, 182, 85, 219, 182, 170, 219, 182, 255, 255, 182, 0, 255, 182, 85, 255, 182, 170, 255, 182, 255, 0, 219, 0, 20, 219, 85, 0, 219, 170, 0, 219, 255, 36, 219, 0, 36, 219, 85, 36, 219, 170, 36, 219, 255, 73, 219, 0, 73, 219, 85, 73, 219, 170, 73, 219, 255, 109, 219, 0, 109, 219, 85, 109, 219, 170, 109, 219, 255, 146, 219, 0, 146, 219, 85, 146, 219, 170, 146, 219, 255, 182, 219, 0, 182, 219, 85, 182, 219, 170, 182, 219, 255, 219, 219, 0, 219, 219, 85, 219, 219, 170, 219, 219, 255, 255, 219, 0, 255, 219, 85, 255, 219, 170, 255, 219, 255, 0, 255, 0, 0, 255, 85, 0, 255, 170, 0, 255, 255, 36, 255, 0, 36, 255, 85, 36, 255, 170, 36, 255, 255, 73, 255, 0, 73, 255, 85, 73, 255, 170, 73, 255, 255, 109, 255, 0, 109, 255, 85, 109, 255, 170, 109, 255, 255, 146, 255, 0, 146, 255, 85, 146, 255, 170, 146, 255, 255, 182, 255, 0, 182, 255, 85, 182, 255, 170, 182, 255, 255, 219, 255, 0, 219, 255, 85, 219, 255, 170, 219, 255, 255, 255, 255, 0, 255, 255, 85, 255, 255, 170, 255, 255, 255] + +im = Image.open("/Users/radix/Downloads/IMG_20170929_185311.jpg") +print(im) + +p = Image.new("P",(16,16)) +p.putpalette(BGR233) + +#im2 = im.quantize(palette=p) + +im2 = quantizetopalette(im, p, dither=False) + +im2.show() + +print(im2.getpalette() == BGR233) \ No newline at end of file diff --git a/testtkinker.py b/testtkinker.py new file mode 100644 index 0000000..7f56386 --- /dev/null +++ b/testtkinker.py @@ -0,0 +1,79 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +import sys + +from PIL import Image, ImageChops, ImageDraw, ImagePalette +if sys.platform == "linux" or sys.platform == "linux2": + from Xlib import display, X + # take screen images, that's not the best way, so here + # we use directly use xlib to take the screenshot. + class ImageGrab(): + def grab(): + dsp = display.Display() + root = dsp.screen().root + geom = root.get_geometry() + w = geom.width + h = geom.height + raw = root.get_image(0, 0, w ,h, X.ZPixmap, 0xffffffff) + image = Image.frombytes("RGB", (w, h), raw.data, "raw", "BGRX") + return image + +elif sys.platform == "darwin": + import Quartz.CoreGraphics as CG + class ImageGrab(): + def grab(): + screenshot = CG.CGWindowListCreateImage(CG.CGRectInfinite, CG.kCGWindowListOptionOnScreenOnly, CG.kCGNullWindowID, CG.kCGWindowImageDefault) + width = CG.CGImageGetWidth(screenshot) + height = CG.CGImageGetHeight(screenshot) + bytesperrow = CG.CGImageGetBytesPerRow(screenshot) + + pixeldata = CG.CGDataProviderCopyData(CG.CGImageGetDataProvider(screenshot)) + + i = Image.frombytes("RGBA", (width, height), pixeldata) + (b, g, r, x) = i.split() + i = Image.merge("RGBX", (r, g, b, x)) + + return i + +else: + from PIL import ImageGrab + + + +thickarrow_strings = ( #sized 24x24 + "XX ", + "XXX ", + "XXXX ", + "XX.XX ", + "XX..XX ", + "XX...XX ", + "XX....XX ", + "XX.....XX ", + "XX......XX ", + "XX.......XX ", + "XX........XX ", + "XX........XXX ", + "XX......XXXXX ", + "XX.XXX..XX ", + "XXXX XX..XX ", + "XX XX..XX ", + " XX..XX ", + " XX..XX ", + " XX..XX ", + " XXXX ", + " XX ", + " ", + " ", + " ") + + +buf = "" +for x in thickarrow_strings: + buf += x + +i = Image.frombytes("I", (24,24), str.encode(buf)) +print(i) +i.show() + +