/*************************************************** * FILE NAME: selfdel.c * * PURPOSE: * NSIS plug-in for self deleting uninstaller for * Win9x/WinNT (all versions) * * CONSIDERATIONS * * MSVC6: works with Release built only, because source * file must be compiled with /GZ turned OFF, but in * Debug builds it is always on (basically, disable * run-time stack checks) * * CHANGE HISTORY * * James Brown - Oct 01 2003 * - Original http://www.catch22.net/tuts/selfdel.asp * * Takhir Bedertdinov - Jan 21 2006 * - Converted to NSIS plug-in, rmdir implementation, MSVCRT * dependencies removed * * Stuart Welch - Jul 17 2011 * - Fixed for x64 by specifying full path to explorer.exe * - Ensures WOW64 file system redirection is enabled * - Reduced deletion retry to 500ms * - Built with VS2010 * - Added Unicode build * - Added version information resource * - Calls MoveFileEx with MOVEFILE_DELAY_UNTIL_REBOOT on failure * * Stuart Welch - Aug 10 2011 * - Added /REBOOT * **************************************************/ #define WINVER 0x0400 #define _WIN32_WINNT 0x0400 #include #ifdef UNICODE #include "nsis_unicode\pluginapi.h" #else #include "nsis_ansi\pluginapi.h" #endif #ifdef MoveFileEx #undef MoveFileEx #endif #ifndef EWX_FORCEIFHUNG #define EWX_FORCEIFHUNG 0x00000010 #endif #pragma pack(push, 1) #define CODESIZE 0x200 #define SWITCH_RMDIR TEXT("/RMDIR") #define SWITCH_REBOOT TEXT("/REBOOT") // // Structure to inject into remote process. Contains // function pointers and code to execute. // typedef struct _SELFDEL { struct _SELFDEL *Arg0; // pointer to self BYTE opCodes[CODESIZE]; // code HANDLE hParent; // parent process handle FARPROC fnWaitForSingleObject; FARPROC fnCloseHandle; FARPROC fnDeleteFile; FARPROC fnSleep; FARPROC fnExitProcess; FARPROC fnRemoveDirectory; FARPROC fnGetLastError; FARPROC fnExitWindowsEx; TCHAR szFileName[MAX_PATH]; // file to delete BOOL fRemDir; BOOL fReboot; } SELFDEL; #pragma pack(pop) #define NSISFUNC(name) void __declspec(dllexport) name(HWND hWndParent, int string_size, TCHAR* variables, stack_t** stacktop, extra_parameters* extra) #define DLL_INIT() EXDLL_INIT(); typedef BOOLEAN (WINAPI* PWow64EnableWow64FsRedirection)(BOOLEAN Wow64FsEnableRedirection); typedef BOOL (WINAPI* PMoveFileEx)(LPCTSTR lpExistingFileName, LPCTSTR lpNewFileName, DWORD dwFlags); #ifdef _DEBUG #define FUNC_ADDR(func) (PVOID)(*(DWORD *)((BYTE *)func + 1) + (DWORD)((BYTE *)func + 5)) #else #define FUNC_ADDR(func) func #endif /***************************************************** * FUNCTION NAME: remote_thread() * PURPOSE: * Routine to execute in remote process * SPECIAL CONSIDERATIONS: * Takhir: I hope it still less then CODESIZE after * I added rmdir *****************************************************/ static void remote_thread(SELFDEL *remote) { TCHAR *p = remote->szFileName, *e; // Wait for parent process to terminate remote->fnWaitForSingleObject(remote->hParent, INFINITE); remote->fnCloseHandle(remote->hParent); // Try to delete the executable file while(!remote->fnDeleteFile(remote->szFileName)) { // Failed - try again in a bit remote->fnSleep(500); } // Takhir: my rmdir add-on :) // Do we have at least one back slash in full path-name // strrchr() implementation if(remote->fRemDir) { while(*++p != 0) { if(*p == '\\') e = p; } *e = 0; // Root install safe, rmdir on Wins doesn't delete 'c:' remote->fnRemoveDirectory(remote->szFileName); } // Afrow UK: reboot add-on if (remote->fReboot) { remote->fnExitWindowsEx(EWX_REBOOT|EWX_FORCEIFHUNG, 0); } // Finished! Exit so that we don't execute garbage code remote->fnExitProcess(0); } /***************************************************** * FUNCTION NAME: my_memcpy() * PURPOSE: * msvcrt replacement * SPECIAL CONSIDERATIONS: * *****************************************************/ void my_memcpy(BYTE* dst, BYTE* src, int len) { int i; for(i=0;i