Merge branch 'experimental' into 'master'

Experimental

See merge request radixcl/pyvncs!1
This commit is contained in:
Matias Fernandez Lillo
2019-07-30 02:57:12 +00:00
23 changed files with 1411 additions and 423 deletions

2
.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
__pycache__/
*.py[cod]

327
ctrlsrv.py Executable file
View File

@@ -0,0 +1,327 @@
#!/usr/bin/env python3
# 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 <http://www.gnu.org/licenses/>.
import pyvncs
from lib import log
from lib import common
from argparse import ArgumentParser
from threading import Thread
import time
import sys
import socket
import signal
import readline
import traceback
#_debug = log.debug
_debug = print
if common.isWindows():
_debug("Wintendo...")
import win32ts
import win32security
import win32con
import win32api
import ntsecuritycon
import win32process
import win32event
def signal_handler(signal, frame):
_debug("Exiting on signal %s..." % signal)
sys.exit(0)
signal.signal(signal.SIGINT, signal_handler)
config = {
}
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:
time.sleep(1)
for t in threads:
if not t.isAlive():
_debug("ControlThread removing dead", t)
threads.remove(t)
class VNCThread(Thread):
def __init__(self, port, password):
Thread.__init__(self)
self.ip = None
self.port = port
self.sock = None
self.password = password
self.setDaemon(True)
def __del__(self):
_debug("VNCThread died")
def run(self):
TCP_IP = '0.0.0.0'
_debug("[+] Listen...")
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
self.sock.bind((TCP_IP, int(self.port)))
self.sock.listen(4)
(conn, (ip,port)) = self.sock.accept()
_debug("[+] New server socket started for " + ip + ":" + str(port))
#_debug("Thread", self)
server = pyvncs.server.VncServer(conn, self.password)
#server.CONFIG._8bitdither = CONFIG._8bitdither
status = server.init()
if not status:
_debug("Error negotiating client init")
return False
server.protocol()
class ClientThread(Thread):
def __init__(self, sock, ip, port, config):
Thread.__init__(self)
self.ip = ip
self.port = port
self.sock = sock
self.setDaemon(True)
self.config = config
def __del__(self):
_debug("ClientThread died")
def run(self):
#_debug("[+] New server socket thread started for " + self.ip + ":" + str(self.port))
#_debug("Thread", self)
f = self.sock.makefile('rw')
f.write("AUTH:>")
f.flush()
passwd = f.readline().strip("\n")
if passwd != config["PASSWORD"]:
time.sleep(1)
f.write("!NO AUTH")
f.flush()
_debug("NO AUTH '%s' != '%s'" % (passwd, config["PASSWORD"]))
self.sock.close()
return
while True:
f.write("OK:>")
f.flush()
try:
data = f.readline()
cmd = data.strip()
if not data: break
if cmd == "_DEBUG":
sys.stdout = sys.stderr = f
f.write("OK\n")
elif cmd == "PING":
f.write("PONG\n")
elif cmd == "QUIT":
f.write("BYE\n")
self.sock.close()
return
elif cmd.startswith("STARTVNC"):
params = cmd.split()
if len(params) != 3:
f.write("!NOT_PARAMS\n")
f.flush()
continue
_debug("START VNC !!!")
newthread = VNCThread(params[1], params[2])
newthread.setDaemon(True)
newthread.start()
elif cmd == "_WINSESSIONS" and common.isWindows():
winsessions = win32ts.WTSEnumerateSessions(win32ts.WTS_CURRENT_SERVER_HANDLE)
print(winsessions, file=f)
elif cmd == "_WINCONSOLE" and common.isWindows():
winsessions = win32ts.WTSEnumerateSessions(win32ts.WTS_CURRENT_SERVER_HANDLE)
print(winsessions, file=f)
active = win32ts.WTSGetActiveConsoleSessionId()
print(active, file=f)
token = win32ts.WTSQueryUserToken(active)
print(token, file=f)
duplicated = win32security.DuplicateTokenEx(token, win32con.MAXIMUM_ALLOWED, win32con.NULL, win32security.TokenPrimary, win32security.SECURITY_ATTRIBUTES())
print("duplicated", token, file=f)
elif cmd == "_TEST" and common.isWindows():
winsessions = win32ts.WTSEnumerateSessions(win32ts.WTS_CURRENT_SERVER_HANDLE)
print(winsessions, file=f)
active = win32ts.WTSGetActiveConsoleSessionId()
print(active, file=f)
token = win32ts.WTSQueryUserToken(active)
print("token", token, file=f)
ntoken = win32security.DuplicateTokenEx(token, 3 , win32con.MAXIMUM_ALLOWED , win32security.TokenPrimary , win32security.SECURITY_ATTRIBUTES() )
print("ntoken", ntoken, file=f)
#th = win32security.OpenProcessToken(win32api.GetCurrentProcess(), win32con.MAXIMUM_ALLOWED)
#print("th", th, file=f)
shell_as2(ntoken, True, "cmd")
elif cmd == "_EVAL":
while True:
f.write("EV:>")
f.flush()
data = f.readline()
cmd = data.strip()
if cmd == "": continue
if cmd == "_QUIT": break
if not data: break
try:
eval(data)
except:
print("ERROR:", sys.exc_info()[0], file=f)
print(traceback.format_exc(), file=f)
f.flush()
_debug("eval:", cmd.strip())
f.flush()
elif cmd == "_ERROR":
a = 1/0
else:
f.write("!NO_CMD %s\n" % cmd)
_debug("command:", cmd.strip())
f.flush()
except:
print("ERROR:", sys.exc_info()[0], file=f)
print(traceback.format_exc(), file=f)
f.flush()
def get_all_privs(th):
# Try to give ourselves some extra privs (only works if we're admin):
# SeBackupPrivilege - so we can read anything
# SeDebugPrivilege - so we can find out about other processes (otherwise OpenProcess will fail for some)
# SeSecurityPrivilege - ??? what does this do?
# Problem: Vista+ support "Protected" processes, e.g. audiodg.exe. We can't see info about these.
# Interesting post on why Protected Process aren't really secure anyway: http://www.alex-ionescu.com/?p=34
privs = win32security.GetTokenInformation(th, ntsecuritycon.TokenPrivileges)
for privtuple in privs:
privs2 = win32security.GetTokenInformation(th, ntsecuritycon.TokenPrivileges)
newprivs = []
for privtuple2 in privs2:
if privtuple2[0] == privtuple[0]:
newprivs.append((privtuple2[0], 2)) # SE_PRIVILEGE_ENABLED
else:
newprivs.append((privtuple2[0], privtuple2[1]))
# Adjust privs
privs3 = tuple(newprivs)
win32security.AdjustTokenPrivileges(th, False, privs3)
def shell_as(th, enable_privs = 0):
#t = thread(th)
#print(t.as_text())
new_tokenh = win32security.DuplicateTokenEx(th, 3 , win32con.MAXIMUM_ALLOWED , win32security.TokenPrimary , win32security.SECURITY_ATTRIBUTES() )
print("new_tokenh: %s" % new_tokenh)
print("Impersonating...")
if enable_privs:
get_all_privs(new_tokenh)
commandLine = "cmd"
si = win32process.STARTUPINFO()
print("pysecdump: Starting shell with required privileges...")
(hProcess, hThread, dwProcessId, dwThreadId) = win32process.CreateProcessAsUser(
new_tokenh,
None, # AppName
commandLine, # Command line
None, # Process Security
None, # ThreadSecurity
1, # Inherit Handles?
win32process.NORMAL_PRIORITY_CLASS,
None, # New environment
None, # Current directory
si) # startup info.
win32event.WaitForSingleObject( hProcess, win32event.INFINITE );
print("pysecdump: Quitting")
def shell_as2(new_tokenh, enable_privs = 0, commandLine = "cmd"):
print("new_tokenh: %s" % new_tokenh)
print("Impersonating...")
if enable_privs:
get_all_privs(new_tokenh)
si = win32process.STARTUPINFO()
print("pysecdump: Starting shell with required privileges...")
(hProcess, hThread, dwProcessId, dwThreadId) = win32process.CreateProcessAsUser(
new_tokenh,
None, # AppName
commandLine, # Command line
None, # Process Security
None, # ThreadSecurity
1, # Inherit Handles?
win32process.NORMAL_PRIORITY_CLASS,
None, # New environment
None, # Current directory
si) # startup info.
win32event.WaitForSingleObject( hProcess, win32event.INFINITE )
print("pysecdump: Quitting")
def main(argv):
global threads, config
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" % ("5899"), type=int, required=False, default='5899')
parser.add_argument("-P", "--password", help="Sets password", required=True, dest="PASSWORD")
args = parser.parse_args()
config["PASSWORD"] = args.PASSWORD
config["PORT"] = args.TCP_PORT
sockServer = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sockServer.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sockServer.bind((args.TCP_IP, args.TCP_PORT))
controlthread = ControlThread(threads)
controlthread.start()
threads.append(controlthread)
#_debug("Multithreaded Python server : Waiting for connections from TCP clients...")
_debug("Runing on:", sys.platform)
while True:
sockServer.listen(4)
(conn, (ip,port)) = sockServer.accept()
newthread = ClientThread(conn, ip, port, config)
newthread.setDaemon(True)
newthread.start()
threads.append(newthread)
#print(threads)
if __name__ == "__main__":
threads = []
main(sys.argv)

260
lib/bgr233_palette.py Normal file
View File

@@ -0,0 +1,260 @@
# BGR233 palette
palette = [
0, 0, 0,
36, 0, 0,
73, 0, 0,
109, 0, 0,
146, 0, 0,
182, 0, 0,
219, 0, 0,
255, 0, 0,
0, 36, 0,
36, 36, 0,
73, 36, 0,
109, 36, 0,
146, 36, 0,
182, 36, 0,
219, 36, 0,
255, 36, 0,
0, 73, 0,
36, 73, 0,
73, 73, 0,
109, 73, 0,
146, 73, 0,
182, 73, 0,
219, 73, 0,
255, 73, 0,
0, 109, 0,
36, 109, 0,
73, 109, 0,
109, 109, 0,
146, 109, 0,
182, 109, 0,
219, 109, 0,
255, 109, 0,
0, 146, 0,
36, 146, 0,
73, 146, 0,
109, 146, 0,
146, 146, 0,
182, 146, 0,
219, 146, 0,
255, 146, 0,
0, 182, 0,
36, 182, 0,
73, 182, 0,
109, 182, 0,
146, 182, 0,
182, 182, 0,
219, 182, 0,
255, 182, 0,
0, 219, 0,
36, 219, 0,
73, 219, 0,
109, 219, 0,
146, 219, 0,
182, 219, 0,
219, 219, 0,
255, 219, 0,
0, 255, 0,
36, 255, 0,
73, 255, 0,
109, 255, 0,
146, 255, 0,
182, 255, 0,
219, 255, 0,
255, 255, 0,
0, 0, 85,
36, 0, 85,
73, 0, 85,
109, 0, 85,
146, 0, 85,
182, 0, 85,
219, 0, 85,
255, 0, 85,
0, 36, 85,
36, 36, 85,
73, 36, 85,
109, 36, 85,
146, 36, 85,
182, 36, 85,
219, 36, 85,
255, 36, 85,
0, 73, 85,
36, 73, 85,
73, 73, 85,
109, 73, 85,
146, 73, 85,
182, 73, 85,
219, 73, 85,
255, 73, 85,
0, 109, 85,
36, 109, 85,
73, 109, 85,
109, 109, 85,
146, 109, 85,
182, 109, 85,
219, 109, 85,
255, 109, 85,
0, 146, 85,
36, 146, 85,
73, 146, 85,
109, 146, 85,
146, 146, 85,
182, 146, 85,
219, 146, 85,
255, 146, 85,
0, 182, 85,
36, 182, 85,
73, 182, 85,
109, 182, 85,
146, 182, 85,
182, 182, 85,
219, 182, 85,
255, 182, 85,
0, 219, 85,
36, 219, 85,
73, 219, 85,
109, 219, 85,
146, 219, 85,
182, 219, 85,
219, 219, 85,
255, 219, 85,
0, 255, 85,
36, 255, 85,
73, 255, 85,
109, 255, 85,
146, 255, 85,
182, 255, 85,
219, 255, 85,
255, 255, 85,
0, 0, 170,
36, 0, 170,
73, 0, 170,
109, 0, 170,
146, 0, 170,
182, 0, 170,
219, 0, 170,
255, 0, 170,
0, 36, 170,
36, 36, 170,
73, 36, 170,
109, 36, 170,
146, 36, 170,
182, 36, 170,
219, 36, 170,
255, 36, 170,
0, 73, 170,
36, 73, 170,
73, 73, 170,
109, 73, 170,
146, 73, 170,
182, 73, 170,
219, 73, 170,
255, 73, 170,
0, 109, 170,
36, 109, 170,
73, 109, 170,
109, 109, 170,
146, 109, 170,
182, 109, 170,
219, 109, 170,
255, 109, 170,
0, 146, 170,
36, 146, 170,
73, 146, 170,
109, 146, 170,
146, 146, 170,
182, 146, 170,
219, 146, 170,
255, 146, 170,
0, 182, 170,
36, 182, 170,
73, 182, 170,
109, 182, 170,
146, 182, 170,
182, 182, 170,
219, 182, 170,
255, 182, 170,
0, 219, 170,
36, 219, 170,
73, 219, 170,
109, 219, 170,
146, 219, 170,
182, 219, 170,
219, 219, 170,
255, 219, 170,
0, 255, 170,
36, 255, 170,
73, 255, 170,
109, 255, 170,
146, 255, 170,
182, 255, 170,
219, 255, 170,
255, 255, 170,
0, 0, 255,
36, 0, 255,
73, 0, 255,
109, 0, 255,
146, 0, 255,
182, 0, 255,
219, 0, 255,
255, 0, 255,
0, 36, 255,
36, 36, 255,
73, 36, 255,
109, 36, 255,
146, 36, 255,
182, 36, 255,
219, 36, 255,
255, 36, 255,
0, 73, 255,
36, 73, 255,
73, 73, 255,
109, 73, 255,
146, 73, 255,
182, 73, 255,
219, 73, 255,
255, 73, 255,
0, 109, 255,
36, 109, 255,
73, 109, 255,
109, 109, 255,
146, 109, 255,
182, 109, 255,
219, 109, 255,
255, 109, 255,
0, 146, 255,
36, 146, 255,
73, 146, 255,
109, 146, 255,
146, 146, 255,
182, 146, 255,
219, 146, 255,
255, 146, 255,
0, 182, 255,
36, 182, 255,
73, 182, 255,
109, 182, 255,
146, 182, 255,
182, 182, 255,
219, 182, 255,
255, 182, 255,
0, 219, 255,
36, 219, 255,
73, 219, 255,
109, 219, 255,
146, 219, 255,
182, 219, 255,
219, 219, 255,
255, 219, 255,
0, 255, 255,
36, 255, 255,
73, 255, 255,
109, 255, 255,
146, 255, 255,
182, 255, 255,
219, 255, 255,
255, 255, 255
]

68
lib/common.py Normal file
View File

@@ -0,0 +1,68 @@
# 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 <http://www.gnu.org/licenses/>.
import sys
from multiprocessing import Process, Value
import subprocess
import os
import time
import mmap
import psutil
def isWindows():
return sys.platform.startswith("win")
def isOSX():
return sys.platform.startswith("darwin")
def isLinux():
return sys.platform.startswith("linux")
class proc:
def __init__(self):
self.pid = Value('i', 0)
self._process = None
def __del__(self):
pass
def _setpid(self, pid):
self.pid.value = pid
def getpid(self):
return self.pid.value
def _newproc(self, cmd):
pr = subprocess.Popen(cmd)
#print("Launched forkproc Process ID:", str(pr.pid))
self._setpid(pr.pid)
def run(self, *cmd):
self._process = Process(target=self._newproc, args=(cmd))
self._process.start()
self._process.join()
return self.pid.value
def terminate(self):
if psutil.pid_exists(self.pid.value):
p = psutil.Process(self.pid.value)
p.terminate()
self._process.terminate()
def waitproc(self):
while psutil.pid_exists(self.pid):
time.sleep(.25)

29
lib/const.py Normal file
View File

@@ -0,0 +1,29 @@
# 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 <http://www.gnu.org/licenses/>.
import sys
# constants workaround
class _const:
class ConstError(TypeError): pass
def __setattr__(self, name, value):
if name in self.__dict__.keys():
raise (self.ConstError, "Can't rebind const(%s)" % name)
self.__dict__[name]=value
sys.modules[__name__]=_const()

View File

@@ -16,5 +16,7 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
# at least, raw encoding is needed by the rfb protocol # at least, raw encoding is needed by the rfb protocol
from . import common as enc from . import common
from . import raw from . import raw
from . import zlib
from . import cursor

29
lib/encodings/common.py Normal file
View File

@@ -0,0 +1,29 @@
# 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 <http://www.gnu.org/licenses/>.
encodings = {}
class ENCODINGS:
raw = 0
zlib = 6
# supported pseudo-encodings
cursor = -239
encodings_priority = [
ENCODINGS.zlib,
ENCODINGS.raw
]

36
lib/encodings/cursor.py Normal file
View File

@@ -0,0 +1,36 @@
# 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 <http://www.gnu.org/licenses/>.
from . import common
from struct import *
from lib import log
import zlib
class Encoding:
name = 'Cursor'
id = -239
description = 'Cursor pseudo encoding'
enabled = True
pseudoEncoding = True
cursor_sent = False
def __init__(self):
log.debug("Initialized", __name__)
common.encodings[common.ENCODINGS.cursor] = Encoding
log.debug("Loaded encoding: %s (%s)" % (__name__, Encoding.id))

46
lib/encodings/raw.py Normal file
View File

@@ -0,0 +1,46 @@
# 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 <http://www.gnu.org/licenses/>.
from . import common
from struct import *
from lib import log
class Encoding:
_buff = None
name = 'raw'
id = 0
description = 'Raw VNC encoding'
enabled = True
firstUpdateSent = False
def __init__(self):
log.debug("Initialized", __name__)
def send_image(self, x, y, w, h, image):
self._buff = bytearray()
rectangles = 1
self._buff.extend(pack("!BxH", 0, rectangles)) # message type 0 == FramebufferUpdate
self._buff.extend(pack("!HHHH", x, y, w, h))
self._buff.extend(pack(">i", self.id))
self._buff.extend( image.tobytes() )
return self._buff
common.encodings[common.ENCODINGS.raw] = Encoding
log.debug("Loaded encoding: %s (%s)" % (__name__, Encoding.id))

54
lib/encodings/zlib.py Normal file
View File

@@ -0,0 +1,54 @@
from . import common
from struct import *
from lib import log
import zlib
class Encoding:
name = 'zlib'
id = 6
description = 'zlib VNC encoding'
enabled = True
firstUpdateSent = False
_compressObj = None
def __init__(self):
log.debug("Initialized", __name__)
self._compressObj = zlib.compressobj(
zlib.Z_DEFAULT_COMPRESSION, # level: 0-9
zlib.DEFLATED, # method: must be DEFLATED
zlib.MAX_WBITS, # window size in bits:
# -15..-8: negate, suppress header
# 8..15: normal
# 16..30: subtract 16, gzip header
zlib.DEF_MEM_LEVEL, # 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
)
def send_image(self, x, y, w, h, image):
sendbuff = bytearray()
rectangles = 1
sendbuff.extend(pack("!BxH", 0, rectangles)) # message type 0 == FramebufferUpdate
sendbuff.extend(pack("!HHHH", x, y, w, h))
sendbuff.extend(pack(">i", self.id))
#log.debug("Compressing...")
zlibdata = self._compressObj.compress( image.tobytes() )
zlibdata += self._compressObj.flush(zlib.Z_FULL_FLUSH)
#log.debug("LEN", len(zlibdata))
l = pack("!I", len(zlibdata) )
sendbuff.extend( l ) # send length
sendbuff.extend( zlibdata ) # send compressed data
return sendbuff
common.encodings[common.ENCODINGS.zlib] = Encoding
log.debug("Loaded encoding: %s (%s)" % (__name__, Encoding.id))

41
lib/imagegrab.py Normal file
View File

@@ -0,0 +1,41 @@
import sys
from PIL import Image
from lib import log
if sys.platform == "linux" or sys.platform == "linux2":
log.debug("ImageGrab: running on Linux")
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":
log.debug("ImageGrab: running on 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:
log.debug("ImageGrab: running on Unknown!")
from PIL import ImageGrab

47
lib/kbdctrl.py Normal file
View File

@@ -0,0 +1,47 @@
import sys
from struct import pack, unpack
from pynput import keyboard
from lib import log
from lib.kbdmap import *
class KeyboardController:
kbdmap = kbdmap
kbdkey = ''
downflag = None
key = None
controller = None
kbd = None
def __init__(self):
self.kbd = keyboard
self.controller = self.kbd.Controller()
def process_event(self, data):
# B = U8, L = U32
(self.downflag, self.key) = unpack("!BxxL", data)
log.debug("KeyEvent", self.downflag, hex(self.key))
# special key
if self.key in self.kbdmap:
self.kbdkey = self.kbdmap[self.key]
log.debug("SPECIAL KEY", self.kbdkey)
else: # normal key
try:
self.kbdkey = self.kbd.KeyCode.from_char(chr(self.key))
except:
self.kbdkey = None
# debug keypress to stdout
try:
log.debug("KEY:", self.kbdkey)
except:
log.debug("KEY: (unprintable)")
# send the actual keyboard event
try:
if self.downflag:
self.controller.press(self.kbdkey)
else:
self.controller.release(self.kbdkey)
except:
log.debug("Error sending key")

79
lib/kbdmap.py Normal file
View File

@@ -0,0 +1,79 @@
import sys
from pynput import keyboard
__all__ = ['kbdmap']
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,
0xffe9: keyboard.Key.alt,
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,
0xfe03: keyboard.Key.cmd_l,
}
if sys.platform == "darwin":
kbdmap[0xffe2] = keyboard.Key.shift

28
lib/log.py Normal file
View File

@@ -0,0 +1,28 @@
# 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 <http://www.gnu.org/licenses/>.
import logging
logging.basicConfig(level=logging.DEBUG, format='[%(threadName)s] %(message)s')
logger = logging.getLogger('pyvncs')
def debug(*args):
str = ""
for s in args:
str = "%s %s" % (str, s)
str = str.strip()
logger.debug(str)

60
lib/mousectrl.py Normal file
View File

@@ -0,0 +1,60 @@
from struct import pack, unpack
from pynput import mouse
from lib import log
class MouseController():
def __init__(self):
self.buttonmask = 0
self.buttons = [0, 0, 0, 0, 0, 0, 0, 0]
self.left_pressed = 0
self.right_pressed = 0
self.middle_pressed = 0
def process_event(self, data):
(self.buttonmask, x, y) = unpack("!BHH", data)
self.buttons[0] = self.buttonmask & int("0000001", 2) # left button
self.buttons[1] = self.buttonmask & int("0000010", 2) # middle button
self.buttons[2] = self.buttonmask & int("0000100", 2) # right button
self.buttons[3] = self.buttonmask & int("0001000", 2) # scroll up
self.buttons[4] = self.buttonmask & int("0010000", 2) # scroll down
# set mouse position
mouse.Controller().position = (x, y)
# process mouse button events
if self.buttons[0] and not self.left_pressed:
log.debug("LEFT PRESSED")
mouse.Controller().press(mouse.Button.left)
self.left_pressed = 1
elif not self.buttons[0] and self.left_pressed:
log.debug("LEFT RELEASED")
mouse.Controller().release(mouse.Button.left)
self.left_pressed = 0
if self.buttons[1] and not self.middle_pressed:
log.debug("MIDDLE PRESSED")
mouse.Controller().press(mouse.Button.middle)
self.middle_pressed = 1
elif not self.buttons[1] and self.middle_pressed:
log.debug("MIDDLE RELEASED")
mouse.Controller().release(mouse.Button.middle)
self.middle_pressed = 0
if self.buttons[2] and not self.right_pressed:
log.debug("RIGHT PRESSED")
mouse.Controller().press(mouse.Button.right)
self.right_pressed = 1
elif not self.buttons[2] and self.right_pressed:
log.debug("RIGHT RELEASED")
mouse.Controller().release(mouse.Button.right)
self.right_pressed = 0
if self.buttons[3]:
log.debug("SCROLLUP PRESSED")
mouse.Controller().scroll(0, 2)
if self.buttons[4]:
log.debug("SCROLLDOWN PRESSED")
mouse.Controller().scroll(0, -2)
#log.debug("PointerEvent", buttonmask, x, y)

31
lib/oshelpers/windows.py Normal file
View File

@@ -0,0 +1,31 @@
import ctypes
import sys
from elevate import elevate
def is_admin():
try:
return ctypes.windll.shell32.IsUserAnAdmin()
except:
return False
def run_as_admin_old(argv=None):
shell32 = ctypes.windll.shell32
if argv is None and shell32.IsUserAnAdmin():
return True
if argv is None:
argv = sys.argv
if hasattr(sys, '_MEIPASS'):
# Support pyinstaller wrapped program.
arguments = argv[1:]
else:
arguments = argv
argument_line = u' '.join(arguments)
executable = sys.executable
ret = shell32.ShellExecuteW(None, u"runas", executable, argument_line, None, 1)
if int(ret) <= 32:
return False
return None
def run_as_admin():
elevate()

View File

@@ -19,16 +19,24 @@ from struct import *
from pyDes import * from pyDes import *
from time import sleep from time import sleep
from pynput import mouse, keyboard from pynput import mouse, keyboard
from PIL import Image, ImageChops, ImageDraw, ImagePalette
import socket import socket
import select import select
import os import os
import sys import sys
import random import random
import zlib
import numpy as np import numpy as np
from lib.encodings import * from lib import mousectrl
from lib import kbdctrl
from lib.imagegrab import ImageGrab
from lib import log
from lib import bgr233_palette
# encodings support
import lib.encodings as encs
from lib.encodings.common import ENCODINGS
def hexdump(data): def hexdump(data):
str = "" str = ""
@@ -38,7 +46,7 @@ def hexdump(data):
return str return str
def quantizetopalette(silf, palette, dither=False): def quantizetopalette(silf, palette, dither=False):
"""Convert an RGB or L mode image to use a given P image's palette.""" """Converts an RGB or L mode image to use a given P image's palette."""
silf.load() silf.load()
@@ -59,50 +67,13 @@ def quantizetopalette(silf, palette, dither=False):
except AttributeError: except AttributeError:
return silf._makeself(im) 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 VncServer():
class CONFIG: class CONFIG:
_8bitdither = False _8bitdither = False
encoding_object = None
def __init__(self, socket, password): def __init__(self, socket, password):
self.RFB_VERSION = '003.008' self.RFB_VERSION = '003.008'
self.RFB_SECTYPES = [ self.RFB_SECTYPES = [
@@ -114,75 +85,10 @@ class VncServer():
self.framebuffer = None self.framebuffer = None
self.password = password self.password = password
self.sectypes = self.RFB_SECTYPES self.sectypes = self.RFB_SECTYPES
self.remotecursor = False self.cursor_support = 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): def __del__(self):
print("VncServer died") log.debug("VncServer died")
def encrypt(self, key, data): def encrypt(self, key, data):
k = des(key, ECB, "\0\0\0\0\0\0\0\0", pad=None, padmode=PAD_PKCS5) k = des(key, ECB, "\0\0\0\0\0\0\0\0", pad=None, padmode=PAD_PKCS5)
@@ -221,7 +127,7 @@ class VncServer():
data = sock.recv(1024) data = sock.recv(1024)
except socket.timeout: except socket.timeout:
data = None data = None
print("getbuff() timeout") log.debug("getbuff() timeout")
return data return data
@@ -232,15 +138,15 @@ class VncServer():
# RFB version handshake # RFB version handshake
data = self.getbuff(30) data = self.getbuff(30)
print("init received: '%s'" % data) log.debug("init received: '%s'" % data)
server_version = float(self.RFB_VERSION) server_version = float(self.RFB_VERSION)
try: try:
client_version = float(data[4:11]) client_version = float(data[4:11])
except: except:
print("Error parsing client version") log.debug("Error parsing client version")
return False return False
print("client, server:", client_version, server_version) log.debug("client, server:", client_version, server_version)
# security types handshake # security types handshake
sendbuff = pack("B", len(self.sectypes)) # number of security types sendbuff = pack("B", len(self.sectypes)) # number of security types
@@ -254,13 +160,13 @@ class VncServer():
sectype = None sectype = None
if sectype not in self.sectypes: if sectype not in self.sectypes:
print("Incompatible security type: %s" % data) log.debug("Incompatible security type: %s" % data)
sock.send(pack("B", 1)) # failed handshake sock.send(pack("B", 1)) # failed handshake
self.sendmessage("Incompatible security type") self.sendmessage("Incompatible security type")
sock.close() sock.close()
return False return False
print("sec type data: %s" % data) log.debug("sec type data: %s" % data)
# VNC Auth # VNC Auth
if sectype == 2: if sectype == 2:
@@ -278,9 +184,9 @@ class VncServer():
if data == crypted: if data == crypted:
# Handshake successful # Handshake successful
sock.send(pack("I", 0)) sock.send(pack("I", 0))
print("Auth OK") log.debug("Auth OK")
else: else:
print("Invalid auth") log.debug("Invalid auth")
return False return False
#unsupported VNC auth type #unsupported VNC auth type
@@ -289,7 +195,7 @@ class VncServer():
# get ClientInit # get ClientInit
data = self.getbuff(30) data = self.getbuff(30)
print("Clientinit (shared flag)", repr(data)) log.debug("Clientinit (shared flag)", repr(data))
self.ServerInit() self.ServerInit()
@@ -300,9 +206,9 @@ class VncServer():
sock = self.socket sock = self.socket
screen = ImageGrab.grab() screen = ImageGrab.grab()
print("screen", repr(screen)) log.debug("screen", repr(screen))
size = screen.size size = screen.size
print("size", repr(size)) log.debug("size", repr(size))
del screen del screen
width = size[0] width = size[0]
@@ -339,105 +245,29 @@ class VncServer():
sendbuff += pack("!I", desktop_name_len) sendbuff += pack("!I", desktop_name_len)
sendbuff += desktop_name.encode() sendbuff += desktop_name.encode()
print("width", repr(width)) log.debug("width", repr(width))
print("height", repr(height)) log.debug("height", repr(height))
sock.send(sendbuff) sock.send(sendbuff)
def protocol(self): def protocol(self):
self.socket.settimeout(None) # set nonblocking socket self.socket.settimeout(None) # set nonblocking socket
screen = ImageGrab.grab() screen = ImageGrab.grab()
size = screen.size size = screen.size
width = size[0] width = size[0]
height = size[1] height = size[1]
del screen del screen
mousecontroller = mousectrl.MouseController()
kbdcontroller = kbdctrl.KeyboardController()
self.primaryOrder = "rgb" self.primaryOrder = "rgb"
self.encoding = enc.ENCODINGS.raw self.encoding = ENCODINGS.raw
buttonmask = 0 self.encoding_object = encs.common.encodings[self.encoding]()
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: while True:
#print(".", end='', flush=True) #log.debug(".", end='', flush=True)
r,_,_ = select.select([self.socket],[],[],0) r,_,_ = select.select([self.socket],[],[],0)
if r == []: if r == []:
#no data #no data
@@ -448,10 +278,10 @@ class VncServer():
try: try:
data = sock.recv(1) # read first byte data = sock.recv(1) # read first byte
except socket.timeout: except socket.timeout:
#print("timeout") #log.debug("timeout")
continue continue
except Exception as e: except Exception as e:
print("exception '%s'" % e) log.debug("exception '%s'" % e)
sock.close() sock.close()
break break
@@ -462,141 +292,75 @@ class VncServer():
if data[0] == 0: # client SetPixelFormat if data[0] == 0: # client SetPixelFormat
data2 = sock.recv(19, socket.MSG_WAITALL) data2 = sock.recv(19, socket.MSG_WAITALL)
print("Client Message Type: Set Pixel Format (0)") log.debug("Client Message Type: Set Pixel Format (0)")
(self.bpp, self.depth, self.bigendian, self.truecolor, self.red_maximum, (self.bpp, self.depth, self.bigendian, self.truecolor, self.red_maximum,
self.green_maximum, self.blue_maximum, self.green_maximum, self.blue_maximum,
self.red_shift, self.green_shift, self.blue_shift self.red_shift, self.green_shift, self.blue_shift
) = unpack("!xxxBBBBHHHBBBxxx", data2) ) = unpack("!xxxBBBBHHHBBBxxx", data2)
print("IMG bpp, depth, endian, truecolor", self.bpp, self.depth, self.bigendian, self.truecolor) log.debug("IMG bpp, depth, endian, truecolor", self.bpp, self.depth, self.bigendian, self.truecolor)
print("SHIFTS", self.red_shift, self.green_shift, self.blue_shift) log.debug("SHIFTS", self.red_shift, self.green_shift, self.blue_shift)
print("MAXS", self.red_maximum, self.green_maximum, self.blue_maximum) log.debug("MAXS", self.red_maximum, self.green_maximum, self.blue_maximum)
if self.red_shift > self.blue_shift: if self.red_shift > self.blue_shift:
self.primaryOrder = "rgb" self.primaryOrder = "rgb"
else: else:
self.primaryOrder = "bgr" self.primaryOrder = "bgr"
print("Using order: ", self.primaryOrder) log.debug("Using order:", self.primaryOrder)
continue continue
if data[0] == 2: # SetEncoding if data[0] == 2: # SetEncoding
data2 = sock.recv(3) data2 = sock.recv(3)
print("Client Message Type: SetEncoding (2)") log.debug("Client Message Type: SetEncoding (2)")
(nencodings,) = unpack("!xH", data2) (nencodings,) = unpack("!xH", data2)
print("SetEncoding: total encodings", repr(nencodings)) log.debug("SetEncoding: total encodings", repr(nencodings))
data2 = sock.recv(4 * nencodings, socket.MSG_WAITALL) data2 = sock.recv(4 * nencodings, socket.MSG_WAITALL)
#print("len", len(data2)) #log.debug("len", len(data2))
self.client_encodings = unpack("!%si" % nencodings, data2) self.client_encodings = unpack("!%si" % nencodings, data2)
#print("data", repr(self.client_encodings), len(self.client_encodings)) log.debug("client_encodings", repr(self.client_encodings), len(self.client_encodings))
if hasattr(enc.ENCODINGS, "cursor") and enc.ENCODINGS.cursor in self.client_encodings: # cursor support?
print("Remote cursor encoding present") if ENCODINGS.cursor in self.client_encodings:
self.remotecursor = True log.debug("client cursor support")
self.cursorchanged = True self.cursor_support = True
if hasattr(enc.ENCODINGS, "zlib") and enc.ENCODINGS.zlib in self.client_encodings: # which pixel encoding to use?
print("Using zlib encoding") log.debug("encs.common.encodings_priority", encs.common.encodings_priority)
self.encoding = enc.ENCODINGS.zlib for e in encs.common.encodings_priority:
log.debug("E", e)
if e in self.client_encodings:
if self.encoding == e:
# don't initialize same encoding again
break
self.encoding = e
log.debug("Using %s encoding" % self.encoding)
self.encoding_object = encs.common.encodings[self.encoding]()
break
continue continue
if data[0] == 3: # FBUpdateRequest if data[0] == 3: # FBUpdateRequest
data2 = sock.recv(9, socket.MSG_WAITALL) data2 = sock.recv(9, socket.MSG_WAITALL)
#print("Client Message Type: FBUpdateRequest (3)") #log.debug("Client Message Type: FBUpdateRequest (3)")
#print(len(data2)) #print(len(data2))
(incremental, x, y, w, h) = unpack("!BHHHH", data2) (incremental, x, y, w, h) = unpack("!BHHHH", data2)
#print("RFBU:", incremental, x, y, w, h) #log.debug("RFBU:", incremental, x, y, w, h)
self.SendRectangles(sock, x, y, w, h, incremental) self.SendRectangles(sock, x, y, w, h, incremental)
if self.remotecursor and self.cursorchanged:
# FIXME: send cursor to remote client
self.cursorchanged = False
continue continue
if data[0] == 4: if data[0] == 4: # keyboard event
kbdkey = '' kbdcontroller.process_event(sock.recv(7))
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 continue
if data[0] == 5: # PointerEvent if data[0] == 5: # PointerEvent
data2 = sock.recv(5, socket.MSG_WAITALL) mousecontroller.process_event(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 continue
else: else:
data2 = sock.recv(4096) data2 = sock.recv(4096)
print("RAW Server received data:", repr(data[0]) , data+data2) log.debug("RAW Server received data:", repr(data[0]) , data+data2)
def GetRectangle(self, x, y, w, h): def GetRectangle(self, x, y, w, h):
@@ -621,7 +385,7 @@ class VncServer():
def SendRectangles(self, sock, x, y, w, h, incremental=0): def SendRectangles(self, sock, x, y, w, h, incremental=0):
# send FramebufferUpdate to client # send FramebufferUpdate to client
#print("start SendRectangles") #log.debug("start SendRectangles")
rectangle = self.GetRectangle(x, y, w, h) rectangle = self.GetRectangle(x, y, w, h)
if not rectangle: if not rectangle:
rectangle = Image.new("RGB", [w, h], (0,0,0)) rectangle = Image.new("RGB", [w, h], (0,0,0))
@@ -629,19 +393,20 @@ class VncServer():
lastshot = rectangle lastshot = rectangle
sendbuff = bytearray() sendbuff = bytearray()
firstUpdateSent = False self.encoding_object.firstUpdateSent = False
# try to send only the actual changes # try to send only the actual changes
if self.framebuffer != None and incremental == 1: if self.framebuffer != None and incremental == 1:
diff = ImageChops.difference(rectangle, self.framebuffer) diff = ImageChops.difference(rectangle, self.framebuffer)
if diff.getbbox() is None: if diff.getbbox() is None:
# no changes...
rectangles = 0 rectangles = 0
sendbuff.extend(pack("!BxH", 0, rectangles)) sendbuff.extend(pack("!BxH", 0, rectangles))
try: try:
sock.sendall(sendbuff) sock.sendall(sendbuff)
except: except:
return False return False
sleep(0.3) sleep(0.1)
return return
if diff.getbbox() is not None: if diff.getbbox() is not None:
@@ -650,126 +415,77 @@ class VncServer():
(x, y, _, _) = diff.getbbox() (x, y, _, _) = diff.getbbox()
w = rectangle.width w = rectangle.width
h = rectangle.height h = rectangle.height
#print("XYWH:", x,y,w,h, "diff", repr(diff.getbbox())) #log.debug("XYWH:", x,y,w,h, "diff", repr(diff.getbbox()))
stimeout = sock.gettimeout() stimeout = sock.gettimeout()
sock.settimeout(None) sock.settimeout(None)
if self.bpp == 32 or self.bpp == 8: if self.bpp == 32 or self.bpp == 16 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: if self.bpp == 32:
redBits = 8 redBits = 8
greenBits = 8 greenBits = 8
blueBits = 8 blueBits = 8
elif self.bpp == 8:
redBits = 4
greenBits = 4
blueBits = 4
#redMask = ((1 << redBits) - 1) << self.red_shift # image array
#greenMask = ((1 << greenBits) - 1) << self.green_shift a = np.asarray(rectangle).copy()
#blueMask = ((1 << blueBits) - 1) << self.blue_shift
#print("redMask", redMask, greenMask, blueMask) if self.primaryOrder == "bgr": # bit shifting
blueMask = (1 << blueBits) - 1
greenMask = ((1 << greenBits) - 1) << self.green_shift
redMask = ((1 << redBits) - 1) << self.red_shift
if self.primaryOrder == "bgr": a[..., 0] = ( a[..., 0] ) & blueMask >> self.blue_shift
self.blue_shift = 0 a[..., 1] = ( a[..., 1] ) & greenMask >> self.green_shift
blueMask = (1 << blueBits) - 1 a[..., 2] = ( a[..., 2] ) & redMask >> self.red_shift
self.green_shift = blueBits
greenMask = ((1 << greenBits) - 1) << self.green_shift else: # RGB
self.red_shift = self.green_shift + greenBits redMask = ((1 << redBits) - 1) << self.red_shift
redMask = ((1 << redBits) - 1) << self.red_shift greenMask = ((1 << greenBits) - 1) << self.green_shift
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
else: # RGB image = Image.fromarray(a)
self.red_shift = 0 if self.primaryOrder == "rgb":
redMask = (1 << redBits) - 1 (b, g, r) = image.split()
self.green_shift = redBits image = Image.merge("RGB", (r, g, b))
greenMask = ((1 << greenBits) - 1) << self.green_shift del b,g,r
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") image = image.convert("RGBX")
elif self.bpp == 8: if self.bpp == 16: #BGR565
#FIXME: improve 8 bit routines up!, image looks awful! greenBits = 5
if rectangle.mode is not "RGB": blueBits = 6
image = rectangle.convert("RGB") redBits = 5
else:
image = rectangle
(r, g, b) = image.split() image = rectangle
image = Image.merge("RGB", (g, r, b)) if self.depth == 16:
del b,g,r image = image.convert('BGR;16')
if self.depth == 15:
image = image.convert('BGR;15')
elif self.bpp == 8: #bgr233
redBits = 3
greenBits = 3
blueBits = 2
image = rectangle
p = Image.new('P',(16,16))
p.putpalette(bgr233_palette.palette)
p = Image.new("P",(16,16))
p.putpalette(self.BGR233)
image = quantizetopalette(image, p, dither=self.CONFIG._8bitdither) image = quantizetopalette(image, p, dither=self.CONFIG._8bitdither)
image.putpalette(self.BGR233)
del p #image = image.convert('RGB', colors=4).quantize(palette=p)
rectangles = 1 #log.debug(image)
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 hasattr(enc.ENCODINGS, "zlib") and self.encoding == enc.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 # send image with client defined encoding
sendbuff.extend(pack("!BxH", 0, rectangles)) sendbuff.extend(self.encoding_object.send_image(x, y, w, h, image))
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
else:
# send with RAW encoding
sendbuff.extend(enc.ENCODINGS.raw_send_image(x, y, w, h, image))
else: else:
print("[!] Unsupported BPP: %s" % self.bpp) log.debug("[!] Unsupported BPP: %s" % self.bpp)
self.framebuffer = lastshot self.framebuffer = lastshot
try: try:
@@ -778,4 +494,4 @@ class VncServer():
# connection closed? # connection closed?
return False return False
sock.settimeout(stimeout) sock.settimeout(stimeout)
#print("end SendRectangles") #log.debug("end SendRectangles")

View File

@@ -1,2 +1,5 @@
pyuserinput pydes
pynput
numpy
Pillow-PIL
elevate

View File

@@ -5,9 +5,19 @@ import pyvncs
from argparse import ArgumentParser from argparse import ArgumentParser
from threading import Thread from threading import Thread
from time import sleep from time import sleep
import sys import sys
import socket import socket
import signal
from lib import log
_debug = log.debug
#_debug = print
def signal_handler(signal, frame):
_debug("Exiting on %s signal..." % signal)
sys.exit(0)
signal.signal(signal.SIGINT, signal_handler)
class ControlThread(Thread): class ControlThread(Thread):
@@ -22,7 +32,7 @@ class ControlThread(Thread):
sleep(1) sleep(1)
for t in threads: for t in threads:
if not t.isAlive(): if not t.isAlive():
print("ControlThread removing dead", t) _debug("ControlThread removing dead", t)
threads.remove(t) threads.remove(t)
class ClientThread(Thread): class ClientThread(Thread):
@@ -34,17 +44,17 @@ class ClientThread(Thread):
self.setDaemon(True) self.setDaemon(True)
def __del__(self): def __del__(self):
print("ClientThread died") _debug("ClientThread died")
def run(self): def run(self):
print("[+] New server socket thread started for " + self.ip + ":" + str(self.port)) _debug("[+] New server socket thread started for " + self.ip + ":" + str(self.port))
#print("Thread", self) #_debug("Thread", self)
server = pyvncs.server.VncServer(self.sock, VNC_PASSWORD) server = pyvncs.server.VncServer(self.sock, VNC_PASSWORD)
server.CONFIG._8bitdither = CONFIG._8bitdither server.CONFIG._8bitdither = CONFIG._8bitdither
status = server.init() status = server.init()
if not status: if not status:
print("Error negotiating client init") _debug("Error negotiating client init")
return False return False
server.protocol() server.protocol()
@@ -61,11 +71,17 @@ def main(argv):
help="Listen in this port, default: %s" % ("5901"), type=int, required=False, default='5901') 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("-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") parser.add_argument("-8", "--8bitdither", help="Enable 8 bit dithering", required=False, action='store_true', dest="dither")
parser.add_argument("-O", "--output-file", help="Redirects all debug output to file", required=False, dest="OUTFILE")
args = parser.parse_args() args = parser.parse_args()
if args.OUTFILE is not None:
fsock = open(args.OUTFILE, 'w')
sys.stdout = sys.stderr = fsock
# Multithreaded Python server # Multithreaded Python server
TCP_IP = '0.0.0.0' if not hasattr(args,"TCP_IP") else args.TCP_IP 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 TCP_PORT = '5901' if not hasattr(args,"TCP_PORT") else args.TCP_PORT
VNC_PASSWORD = args.VNC_PASSWORD VNC_PASSWORD = args.VNC_PASSWORD
CONFIG._8bitdither = args.dither CONFIG._8bitdither = args.dither
@@ -77,8 +93,21 @@ def main(argv):
controlthread.start() controlthread.start()
threads.append(controlthread) threads.append(controlthread)
print("Multithreaded Python server : Waiting for connections from TCP clients...") _debug("Multithreaded Python server : Waiting for connections from TCP clients...")
print("Runing on:", sys.platform) _debug("Runing on:", sys.platform)
if sys.platform in ['win32', 'win64']:
from lib.oshelpers import windows as win32
if not win32.is_admin():
ret = win32.run_as_admin()
if ret is None:
log.debug("Respawning with admin rights")
sys.exit(0)
elif ret is True:
# admin rights
log.debug("Running with admin rights!")
else:
print('Error(ret=%d): cannot elevate privilege.' % (ret))
sys.exit(1)
while True: while True:
sockServer.listen(4) sockServer.listen(4)
(conn, (ip,port)) = sockServer.accept() (conn, (ip,port)) = sockServer.accept()
@@ -95,8 +124,8 @@ if __name__ == "__main__":
main(sys.argv) main(sys.argv)
except KeyboardInterrupt: except KeyboardInterrupt:
# quit # quit
print("Exiting on ctrl+c...") _debug("Exiting on ctrl+c...")
#for t in threads: #for t in threads:
# print("Killing", t) # _debug("Killing", t)
sys.exit() sys.exit()

16
test.py Normal file
View File

@@ -0,0 +1,16 @@
from lib import common
import time
if __name__ == '__main__':
#c = ["/bin/ls", "-alh"]
#c = ["/bin/sleep", "5"]
c = ["./test.sh"]
r = common.proc()
r.run(c)
print("PID", r.getpid())
#print("Waiting...")
#r.waitproc()
time.sleep(1)
r.terminate()
del r
print("DONE")

6
test.sh Executable file
View File

@@ -0,0 +1,6 @@
#!/bin/bash
for a in $(seq 1 5); do
echo "$a $$"
sleep 1
done

79
winservice.py Normal file
View File

@@ -0,0 +1,79 @@
import win32service
import win32serviceutil
import win32api
import win32con
import win32event
import win32evtlogutil
import servicemanager
import os
import sys
from lib import const
from lib import common
from win32api import OutputDebugString as ODS
import traceback
const.SERVICENAME = "Test Service"
const.SERVICEDNAME = "Test Service"
const.SERVICEDESC = "Test Service Description"
const.CHILD = [
"C:\\Program Files\\Python36\\python.exe",
"C:\\pyvncs\\ctrlsrv.py",
"-P",
"kaka80"
]
class service(win32serviceutil.ServiceFramework):
_svc_name_ = const.SERVICENAME
_svc_display_name_ = const.SERVICEDNAME
_svc_description_ = const.SERVICEDESC
def __init__(self, args):
win32serviceutil.ServiceFramework.__init__(self, args)
self.hWaitStop = win32event.CreateEvent(None, 0, 0, None)
def SvcStop(self):
self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
win32event.SetEvent(self.hWaitStop)
def SvcDoRun(self):
servicemanager.LogMsg(servicemanager.EVENTLOG_INFORMATION_TYPE,servicemanager.PYS_SERVICE_STARTED,(self._svc_name_, ''))
self.timeout = 3000
servicemanager.LogInfoMsg("%s - is running 1" % const.SERVICENAME)
r = common.proc()
try:
r.run(const.CHILD)
except:
servicemanager.LogInfoMsg("ERROR: %s" % sys.exc_info()[0])
servicemanager.LogInfoMsg(traceback.format_exc())
sys.exit(1)
newpid = r.getpid()
servicemanager.LogInfoMsg("%s - started child with pid %s" % (const.SERVICENAME, newpid))
while True:
# Wait for service stop signal, if I timeout, loop again
rc = win32event.WaitForSingleObject(self.hWaitStop, self.timeout)
# Check to see if self.hWaitStop happened
if rc == win32event.WAIT_OBJECT_0:
# Stop signal encountered
servicemanager.LogInfoMsg("%s - STOPPED" % const.SERVICENAME)
r.terminate()
break
#else:
# servicemanager.LogInfoMsg("%s - still running" % const.SERVICENAME)
def ctrlHandler(ctrlType):
return True
if __name__ == '__main__':
ODS("__main__\n")
servicemanager.LogInfoMsg("TEST")
appdir = os.path.abspath(os.path.dirname(sys.argv[0]))
os.chdir(appdir)
win32api.SetConsoleCtrlHandler(ctrlHandler, True)
win32serviceutil.HandleCommandLine(service)