Self-deleding Executables
This is a subject that tends to come up every so often in the newsgroups, so I thought I'd write an article about the techniques I've collected to enable an executable to delete itself from disk (whilst running, that is). There is very little information on the web, and what information there is is also hard to find. Why would you want a program to delete itself? The only good reason I know of is an un-install program that needs to remove an application, as well as itself in order to completely remove the application from disk. I'm sure there are other good reasons for self-deleting executables, but most other cases would probably be viruses or trojans trying to hide themselves. Altogether I know of five different methods , each of which I will describe shortly. I must take this opportunity to mention that only one of these techniques has been developed by myself. Apart from the last method, I am presenting the same material described by Jeffrey Richter in his January 1996 MSJ column , t itled "Win32 Q & A". Click here to read the original article. So, I hope no-one thinks I am ripping off other people's ideas or work. Why the obvious does not work If you try to run the following code, nothing will . happen TCHAR szEXEPathname [_MAX_PATH]; GetModuleFileName (NULL, szEXEPathname, _MAX_PATH); DeleteFile (szEXEPathname); The code above retrieves the full path to the current executable, and then tries to delete the file whilst running This code will fail because all. 32bit versions of Windows (95, 98, ME, NT, 2000, XP etc) use a mechanism called memory-mapped files to load an executable image into memory. When the Windows loader runs an executable, it opens the executable '
s disk file and maps that region of disk into memory, effectively loading the executable into memory. This disk file is kept open during the lifetime of the process, and is only closed when the process terminates. Because of this lock on the file, it is normally impossible to delete an executable file whilst it is running Just run notepad.exe, then try to delete the notepad executable -.. it will not work The MoveFileEx method I'm going to mention this technique even though it does not really solve our problem, because it's quite useful to know and can be handy in other situations BOOL MoveFileEx (LPCTSTR lpExistingFileName, LPCTSTR lpNewFileName, DWORD dwFlags);.. This API call moves a file to a new location When you pass NULL as the second parameter, this causes the file to be moved "nowhere", effectively deleting the file. Now, ordinarily this would fail if you tried this with the path to the current executable. However, if we specify MOVEFILE_DELAY_UNTIL_REBOOT in the dwFlags parameter, this tells Windows not to move (or delete) the file until the system is shutdown or rebooted. There are a few problems with this technique. Firstly, you can not remove the directory that the executable resides in. Second, the file is not deleted immediately - if Your System Doesn '
t get rebooted very often, then the file will stay around. But the biggest problem is that MoveFileEx is not implemented on Windows 95/98 / ME. The WININIT.INI method Under Windows 95/98 / ME, an application called WININIT.EXE runs each time the system is started. This application looks for a file called WININIT.INI. If this file exists, wININIT.EXE looks for a section called [Rename]. each entry in the [Rename] section specifies a file rename operation which Will Occur (ONCE) WHEN TIME The System Starts. This Method Is Obviously Very Similar To The MoveEx Method Described Above. [Rename] NUL = C: /DIR/myApp.exe C: /DIR/NEW.EXE=C: / DIR /old.exe The filename to the left of the equal sign specifies the new name of the filename on the right. When NUL is used as the new filename, the file is deleted. This means that an application can write an entry into wININIT. INI, SPECIFYING NUL AND THE APPLICES OWN FULL WHEN WRITIN Entry to the [Rename] section. You Cannot U se WritePrivateProfileString API call, because this function prevents any duplicate entries from occuring under the same section. This restriction would prevent there from being more than one "NUL =" entry. Therefore you must manually write any entry if you want to use this technique. The Self-Deleting Batch File method This is quite a well known method, and was documented in MSDN some time ago. This technique works on both Windows 95 and Windows NT. It works because MS-DOS batch files are able to delete themselves. to Test this Technique, Create A Small Batch File Containing The Single Command: DEL% 0.Bat the Batch File, When Run, deletes itself and rsues an error "The Batch File Cannot Be Found"
. This error is just a simple message, so it can be safely ignored. By itself this is not too useful, but when modified to delete our executable it solves our problem, albeit in a rather forceful manner. Our executable will create a batch File (Called Delus.bat) with The Following Content:: Repeat Del "c: /mydir/myprog.exe" if exist "MyProg.exe" Goto Repeat RMDir "C: / mydir" del "/delus.bat" this Batch file repeatedly attempts to delete the specified file, and will run continuously consuming CPU until it succeeds. When the execuable has been deleted, the batch file then deletes itself. The executable needs to spawn off the batch file using CreateProcess, and then should exit immediately . It would be a good idea to give the batch file's thread of execution a low priority so that it does not get much execution time until the original executable has terminated. The COMSPEC method This is a method kindly shared by Tony Varnas, who recently EMAILED ME this Snippet: Bool Selfdelete () {Tchar SZF Ile [max_path], szcmd [max_path]; if (getModuleFileName (0, SZFILE, MAX_PATH! = 0) && (GetshortPathName (Szfile, Szfile, Max_Path)! = 0)) {LSTRCPY (SZCMD, "/ C Del" ); LSTRCAT (SZCMD, SZFILE); LSTRCAT (SZCMD, ">> NUL"); IF ((("COMSPEC", SZFILE, MAX_PATH)! = 0) && ((int) shellexecute (0, 0, szfile, SZCMD, 0, SW_HIDE)> 32)) Return true;} Return False;
} This method is very Similar to the bath, file method (above) But is alot next thing 32bitness. It works under all 32bit version of Windows (95,98, ME, NT, 2000, XP), As long as the comspec environment variable is defined. This is always defined (by default) to be the full path to the operating system's command interpreter. For Windows 95, this is "command.exe". For Windows NT, this is "cmd.exe". The function will only work if the executable has exited, so it is important to call this function and then exit immediately It works by spawning a copy of the system's command interpreter, and asking it to perform the following command:. del
s handle count is incremented. Also, when the new process was created, the full path of the current process was passed through the command-line argument. Next, the current executable (which wants to delete itself) closes the file handle used to create the new process, and then exits. Now, the duplicate's file-handle count is decremented, but because CreateProcess incremented its handle count when it started, the file is not deleted. At this point, the duplicate executable has started running. The PID specified on the command-line is used to open a handle to the original process. The duplicate waits for the original process to terminate, using WaitForSingleObject. When this call returns, the duplicate can call DeleteFile on the filename also specified through its command-line argument Has Been successful deleted. This Just Leaves The duplicate Copy, Which EXITS NORMALLY. The duplicate's file-hand-handle count drops to zero, th e DELETE_ON_CLOSE flag comes into effect, and the duplicate file is deleted also It sounds a bit complicated, but it's not too difficult Here's the steps one more time:.. [Current process] 1. Create a new file with FILE_FLAG_DELETE_ON_CLOSE 2. Copy. The Current Executable's Content Into The New File. 3. Create A New Process with the duplicate Executable: 4. Pass the current executable '
S Full Path and Pid in the call to createfile. 5. Sleep for a short time to give the new process time to start. 6. Close the new file. 7. exit current process. [duplicate process] 8. Wait for the process specified on command-line to die. 9. Delete file specified on command-line. 10. Exit duplicate process. There are just a couple of technicalities to mention. First, when the "new" process is spawned, the "old" process must sleep for a short period, enough to let the Windows loader open the file and create the process (thus incrementing it's file count). Second, the new process must wait until the old process terminates, which releases its file count. Third, when the duplicate executable is created, it must also have the FILE_SHARE_DELETE flag specified, otherwise CreateProcess will fail, because it will not be able to open the file whilst we have it open with the DELETE_ON_CLOSE flag set. Obviously this method will require careful coding, Because The Program Must Be Written in Such A WA y so that it can perform these dual tasks. The "new" executable must know that it's job is to delete the file specified on the command line, for instance. It's a little messy, but it does work very well. In fact, the uninstall program that I wrote, which is included with the software you can download from this site, uses this very method. I've included an example program which demonstrates this technique. An alternative method is to write a very small stand-alone executable, Which it's sole task is to delete the file-name specified on it's command-line. this Executable Could The Be Imbedded as a "payload"
to the executable which wants to delete itself. This payload would be created and executed in the same way as described above. The Ultimate Self-Deleting Executable! I thought I'd save the best until last. This inline assembly snippet is short and simple . I can not claim credit for this code - I found it posted on usenet some time ago The author's name is Gary Nebbett, also known as supreme King of Coding, and the author of "Windows NT Native API Reference" and other similar. Amazing Feats. Thanks Gary :) #include
GetModuleHandle (0); GetModuleFileName (module, buf, MAX_PATH); // Check for Win9x Kernel if (0x80000000 & GetVersion ()) {fnFreeOrUnmap = FreeLibrary;} // do for WinNT kernel else {fnFreeOrUnmap = UnmapViewOfFile; CloseHandle ((HANDLE 4);} __ASM {Lea EAX, BUF PUSH 0 PUSH 0 PUSH EAX PUSH EXITPROCESS PUSH MOD MAINMAP RET}} Int Main (int Argc, char * argv []) {deleteMyself (); return 0;} the Definitive Self Deleting Executable I am pleased to present what I believe is the definitive self-deleting executable, for all versions of Windows. This technique is quite involved but // // Delete currently running executable and exit // BOOL SelfDelete (BOOL fRemoveDirectory) {STARTUPINFO si = {sizeof (si)}; PROCESS_INFORMATION pi; cONTEXT context; DWORD oldProt; SELFDEL local; DWORD entrypoint; TCHAR szExe [MAX_PATH] = _T ( "explorer.exe"); // PreSelfDelete (szExe); // Return 0; // // Create Executable suspended //iff (CreateProcess (0, Szexe, 0, 0, 0, CREATE_SUSPENDED | IDL E_PRIORITY_CLASS, 0, 0, & si, π)) {local.fnWaitForSingleObject = (FARPROC) WaitForSingleObject; local.fnCloseHandle = (FARPROC) CloseHandle; local.fnDeleteFile = (FARPROC) DeleteFile; local.fnSleep = (FARPROC) Sleep; local. fnExitProcess = (FARPROC) ExitProcess; local.fnRemoveDirectory = (FARPROC) RemoveDirectory; local.fnGetLastError = (FARPROC) GetLastError; local.fRemDir = fRemoveDirectory; // Give remote process a copy of our own process handle DuplicateHandle (GetCurrentProcess (), GetCurrentProcess (), pi.hprocess, 0, false, 0); getModuleFileName (0, local.szfilename, max_path); // Copy In binary code memcpy (local.opcodes, func_addr (transote_thread), CODESize;