Home A Python Program that Self-destructs but Makes a Clone of Itself Just in Time to Stay Alive
Post
Cancel

A Python Program that Self-destructs but Makes a Clone of Itself Just in Time to Stay Alive

This article shows how to write a Python program which destructs itself when it is called, by deleting its own source code, and then creates a copy of itself just to call this copy to “live” on forever while reproducing itself. You might ask, why would anyone ever need such a program? I must admit that such a program doesn’t have any practical value. However, it is an interesting challenge which helps you to learn the concepts of code inspection at run time, file I/O, and processes of the given programming language.

To start off, let’s implement a Python program which takes a single number as a command line parameter that is then printed:

1
2
3
4
5
6
7
8
import sys

if len(sys.argv) < 2:
    number = 0
else:
    number = int(sys.argv[1])

print(number)

This program makes use of the Python module sys which provides system-specific parameters and functions such as the sys.argv list which contains all command line parameters that are passed to a program. The value at position sys.argv[0] is always the name of the program or Python script which was called. Therefore, the first command line parameter passed to that program is at sys.argv[1]. To check if any command line parameters have been passed, you need to check if sys.argv contains more than one value using the len() function. In the program above, the variable number is set to 0 if no command line parameters have been passed, otherwise number is set to the integer value which was passed as the first command line parameter. Lastly, number is printed on the command line.

As a next step, the program should be able to clone itself. For this purpose, the Python module inspect is used which allows accessing the code of a Python program while it is running:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import sys
import inspect

if len(sys.argv) < 2:
    number = 0
else:
    number = int(sys.argv[1])

# get program code
code = inspect.getsource(inspect.currentframe())

print(code)

print(f"number: {number}")

With inspect.currentframe() the currently running program part can be accessed as a code object. Passing a code object to the inspect.getsource() function returns the source code of the code object as a string. The program above does exactly that, and stores the code of the current running program in the code variable.

To create a clone of the currently running program, the string in the code a new file needs to be created and the contents of the code variable written into it. Opening a file to write into Python is straightforward using with and open. If you are new to Python, check out my video on reading and writing files in Python

And pick up your free Python file I/O cheat sheet from my Gumroad shop:

Free Python File I/O Cheat Sheet
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import sys
import inspect

if len(sys.argv) < 2:
    number = 0
else:
    number = int(sys.argv[1])

# get program code
code = inspect.getsource(inspect.currentframe())

# write program code into cloned program
with open("tmp.py", "w") as f:
    f.write(code)

print(f"number: {number}")

When you run the program above, you will see that the code was copied into the file tmp.py.

Now comes the self-destruction part. Deleting a file is made easy using the Python os module, which provides access to several operating system functions such as file system manipulation. When running the program, os.remove(__file__) is called after the program’s source code was stored in the code variable. The special variable __file__ returns the path to the current Python file which is being executed, afterward __file__ can be used to write the code back to disk:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import sys
import inspect
import os

if len(sys.argv) < 2:
    number = 0
else:
    number = int(sys.argv[1])

# get program code
code = inspect.getsource(inspect.currentframe())

# delete file
os.remove(__file__)

# write program code into cloned program
with open(__file__, "w") as f:
    f.write(code)

print(f"number: {number}")

The program above already self-destructs and then creates a clone with the same file name. The last part that is missing is to start the execution of the clone. To achieve this, the Python modules shlex and subprocess are used. In this context, shlex helps to format a string (cmd) into a command list (cmd_list) using shlex.split() which is then passed to the Popen() function of subprocess which executes a command. subprocess.Popen() is instructed to start a new session with start_new_session=True, which allows the original (and deleted) program to terminate because the launched clone is detached from it:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
import sys
import inspect
import os
import shlex
import subprocess


if len(sys.argv) < 2:
    number = 0
else:
    number = int(sys.argv[1])

print(f"start: {number}")

# get program code
code = inspect.getsource(inspect.currentframe())

# delete file
os.remove(__file__)

# write program code into cloned program
with open(__file__, "w") as f:
    f.write(code)

# run cloned program
cmd = f"python {__file__} {number + 1}"
cmd_list = shlex.split(cmd)

p = subprocess.Popen(cmd_list, start_new_session=True)

print(f"end: {number}")

Run this program in a new terminal window, it will live on forever by constantly self-destructing and cloning itself. Every time a new instance is launched, the number is incremented by one, resulting in an output looking like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
start: 0
end: 0
start: 1
end: 1
start: 2
end: 2
start: 3
end: 3
start: 4
end: 4
start: 5
end: 5
start: 6
end: 6
start: 7
end: 7
start: 8
end: 8
start: 9
end: 9
start: 10
end: 10
start: 11
end: 11
start: 12
end: 12
start: 13
end: 13
start: 14
end: 14

This concludes this silly experiment. You’ve learned how to get the source code of a running Python program, how to delete the source code file at runtime, and how to create a copy of the program so it can start itself just in time to stay alive indefinitely.

This post is licensed under CC BY 4.0 by the author.