c++pythonwindows-xpalternate-data-stream

How do I fix my "self-deleting" .exe from deleting itself early?


For the sake of testing and personal proof of concept, I have a .exe file that only outputs a simple string and then calls a system pause (literally system("pause") in C++).

I have a simple Python script I'm testing on a Windows XP VM that does these operations when messing up:

subprocess.call(r'echo Nothing special. > c:\blank.txt', shell=True)
subprocess.call(r'type pause.exe > c:\blank.txt:ads.exe', shell=True)
subprocess.call(r'start c:\blank.txt:ads.exe', shell=True)
subprocess.call(r'del c:\blank.txt', shell=True)

Obviously, those commands all work fine alone on the command line, why don't they work fine when called through Python?

I receive this pop-up error message:

blank.txt:ads.exe has encountered a problem and needs to close. We are sorry for the inconvenience.

If you were in the middle of something, the information you were working on might be lost.

The file is indeed deleted, also. It seems that the system pause is just crushed by the delete command, when I expect the .exe to pop up, wait for me to push enter, and then the script will continue and delete the file.


Solution

  • Given the symptoms, my understanding is that you can only safely delete an executable in this particular setting (Windows XP, perhaps at a particular patch level, when the executable is from an alternate stream) once this executable has finished initializing. If you delete an executable while it's loading, the program crashes.

    When you type these commands at a prompt, some time elapses between running start c:\blank.txt:ads.exe and del c:\blank.txt, giving the program enough time to finish loading. When you're running them from a script, the interval between the two is a lot shorter (start branches off a new process, and the new program's initialization happens asynchronously). There's race condition between the initialization and the deletion; which one wins depends on how soon the deletion is performed.

    Try experimenting with a delay before deleting the file:

    import subprocess, time
    subprocess.call(r'echo Nothing special. > c:\blank.txt', shell=True)
    subprocess.call(r'type pause.exe > c:\blank.txt:ads.exe', shell=True)
    subprocess.call(r'start c:\blank.txt:ads.exe', shell=True)
    time.sleep(42)  # 42 seconds is overkill, but the delay isn't predictable
    subprocess.call(r'del c:\blank.txt', shell=True)