Use self-deletion DLL to implement the application installationuninstall code

xiaoxiao2021-03-06  43

[Translator]: This article translated from Alex Tilles published in Windows Developer Network (2003 No. 12): "Writing Your Own Install and Uninstall Code". This is an article with certain technical content. I believe that many developers need this techniques that include several important technologies: Rundll32.exe utility method; DLL or Exe self-deletion technology; embedded resources Treatment skills; LZCopy API uses demonstration; compress.exe, expand.exe instructions; Summary When I write "what to do" program (this is an application written by the author, small and exquisite, very practical - Translator Note) When you want to write your own installation and uninstall code, the main purpose is to control the screen you can see during the entire installation / uninstallation process as you want to control. This article we discuss how to implement self-deleted executables using the self-deleted dynamic link library (DLL) to implement the installation / uninstallation of the program. I believe many friends want to do this when writing a Windows program. This article will also show some very useful related technologies, which must make you open your eyes ... Realize the difficulties of deleting uninstalled programs to write uninstall the most challenging The part is how to delete yourself after deleting the target file and the relevant directory. In addition, uninstallation programs must also be run on all Windows operating system platforms (Windows 9X, Windows NT, Windows 2000, Windows XP .....), without requiring users to download any additional components. I have searched online. I found some relevant information to introduce how to delete the executable program file, but most of the proposed solutions have a problem, that is, I can only work on a version of Windows. Some methods are implemented by modifying thread properties, which generally leads to timing issues. There are still some ways to run serious errors, which cannot be used at all. I ponder, find a better solution to implement the executable program's self-deduplication function: to achieve self-deleted executables, thereby breaking through the limitations of the above methods. Utility Rundll32.exe Introduction From known, DLL code usually needs to be loaded into memory before executing, so how to perform a DLL export code without creating an EXE file that is loaded and called the DLL? The method is as follows: Each Windows operating system version starting from Windows 95 comes with a system utility: Rundll32.exe. Using it can perform any functions of some DLL (but not all) outputs below: rundell32.exe dllname, exportedfnname argsexportedfnname is the function name of the DLL output.

In preparing for DLL rundll32 use, it can be declared as an output the following functions: extern "C" __declspec (dllexport) void CALLBACK FunctionName (HWND hwnd, HINSTANCE hInstance, LPTSTR lpCmdLine, int nCmdShow) {...} rundll32.exe Call the function according to the function parameter list, but according to the experience, only one of the actually used parameter values, that is, lpcmdline, the parameter receives the parameter value incorporated when running Rundll32.exe; __ decspec (dllexport) The purpose is to output Function; extern "C" makes the output function names have modifiers, such as: _functionName @ 16 (forced to include the size of the function parameters in the function name, see the MSDN for DLL Output Function Call Specification Description). Rundll32.exe loads the specified DLL and calls the output function specified by the value of the LPCMDline incorporated by the Args parameter. See the MSDN library related information on Rundll32.exe (Q164787): http://support.microsoft.com/default.aspx?scid=kb;n-us;164787 Implementing self-deleting DLL below is to implement self-deletion DLL sample code: #include HMODULE g_hmodDLL; extern "C" BOOL WINAPI DllMain (HINSTANCE hinstDLL, DWORD reason, LPVOID) {if (reason == DLL_PROCESS_ATTACH) g_hmodDLL = hinstDLL; return TRUE;} extern "C "__Declspec (dllexport) Void Callback MagicDel (HWND, INSTANCE, LPTSTSTR LPCMDLINE, INT) {// delay 2 second sleep (2000); // Remove the executable DELETEFILE (LPCMDLINE) of the process to create the process; / / Delete DLL char filenameDLL [MAX_PATH]; GetModuleFileName (g_hmodDLL, filenameDLL, sizeof (filenameDLL)); __ asm {lea eax, filenameDLLpush 0push 0push eaxpush ExitProcesspush g_hmodDLLpush DeleteFilepush FreeLibraryret}} The above code first deletes a file, and delete from. DllMain is the entry function of the DLL, which is called when the dynamic link library is first loaded, and the module handle is assigned to the global variable g_hmoddll, so that it will use it to acquire the file name of the DLL itself. In the MAGICDEL function, LPCMDLINE is the name of the executable of the DLL to be deleted (eg, the file name of the uninstaller). To delete it is easy - make a delay with Sleep so that the process of executable has time to exit and call Deletefile. In order to grasp the details of MagicDel, you can pass the executable process handle to MagicDel and do a waiting before calling Deletefile, see what will happen? Let the DLL need to be self-deleted. Rundll32 calls LoadModule to load the DLL to its address space.

If the DLL function can be returned, Rundll32 will exit, resulting in the DLL release (not deleted). In order to solve this problem, we can perform the following code: FreeEltefile (DLL filename); exitprocess (0); MAGICDEL function can not be directly called in this order, because Freelibary will make code page invalid . To this end, MagicDel is pressing an equivalent assembly instruction into the stack, then executes them, and then follows an RET instruction, and finally calls EXITPROCESS to prevent the process from being executed down. I have written a compilation code block in the article published by the Gary NEBBIT in the Windows Development Magazine (WDJ) "TECH TIPS" section. If you use Visual Studio to generate a DLL with the default option, the final binary is approximately 40K. Since we intend to use the DLL as the resources of the executable program, its size is, better, for this, we must slim down. The idea is to remove the useless C runtime code from the DLL. The specific method is as follows: This example uses the Visual Studio.Net 2003 Chinese version to generate a DLL, first set the project's compilation / link option: Project (P) | [Project Name ] Properties (P) ... | LED | Enter | Ignore all default libraries: Yes (/ NodeFaultLib), this setting passes the / nodefaultlib option to the linker so that the runtime code is filtered. Since the DLL entry point is usually provided by the runtime library (default to dllmain), after the first step setting is completed, the DLL entry point must also be explicitly set to DLLMAIN: Item (P) | [Project Name] Properties (P) ... | Link | Advanced | Entry Point: Dllmain. If you build a DLL in this time, the compiler will report the following two unresolved externals errors: Error LNK2019: Unable to resolve external symbol __security_cookie, this symbol is referenced in the function _magicDel @ 16 error LNK2019: External symbol @__ security_check_cookie @ 4, the symbol is set in the function _magicDel @ 16 is to make the next setting. Item (P) | [Project Name] Properties (P) ... | C / C | Code Generation | Buffer Security Check: No, this setting does not pass the / GS flag to the compiler to get rid of Unresolved Externals errors. Ok, now compilation to generate a DLL, the final DLL size is 3K, the actual file size is only 2.5K. Implementable executables that can be deleted here The main idea is to save a self-deleted DLL as a resource to intend to implement a self-deleted executable, and then recreate it when needed, while starting a Rundll32.exe Process implementation delete behavior. Below is the header file and resource file used to store the DLL as the resource. The resource type value is only greater than 256, which is reserved for the user.

In addition, there is an alternative method to store the DLL binary in the form of byte arrays in the source: in the resource containing a file // selfdelete.h # define rc_binarytype 256 # define id_magicdel_dll 100 // selfdelete.rc # include "SelfDelete.h" ID_MAGICDEL_DLL RC_BINARYTYPE MagicDel.dll following the key code is an executable program: #include #include "SelfDelete.h" void WriteResourceToFile (hINSTANCE hInstance, int idResource, char const * filename) {// keep takes a binary resource HRSRC hResInfo = FindResource (hInstance, MAKEINTRESOURCE (idResource), MAKEINTRESOURCE (RC_BINARYTYPE)); HGLOBAL hgRes = LoadResource (hInstance, hResInfo); void * pvRes = LockResource (hgRes); DWORD cbRes = SizeofResource (hInstance, hResInfo); // write the binary resource files HANDLE hFile = CreateFile (filename, GENERIC_WRITE, 0, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); DWORD cbWritten; WriteFile (hFile, pvRes, cbRes, & cbWritten, 0); CloseHandle (hFile);} void SelfDelete (hINSTANCE hInstance) {WriteResourceToFile (hInstance, ID_MAGICDEL_DLL, "magicdel.dll"); // // 1. Find command generating rundll32.exechar commandLine [MAX_PATH * 3]; GetWindowsDirectory (commandLine, sizeof (commandLine)); Lstrcat (Comma ndLine, "//rundll32.exe");if (GetFileAttributes (commandLine) == INVALID_FILE_ATTRIBUTES) {GetSystemDirectory (commandLine, sizeof (commandLine)); lstrcat (commandLine," //rundll32.exe");}// 2. Add rundll32.exe parameters lstrcat (commandLine, "magicdel.dll, _MagicDel @ 16"); // 3. Add this filename char thisName [MAX_PATH]; GetModuleFileName (hInstance, thisName, sizeof (thisName)); lstrcat (commandLine, thisName); // Run line PROCESS_INFORMATION procInfo; STARTUPINFO startInfo; memset (& startInfo, 0, sizeof (startInfo)); startInfo.dwFlags = STARTF_FORCEOFFFEEDBACK; CreateProcess (0, commandLine, 0, 0, FALSE, NORMAL_PRIORITY_CLASS, 0, 0, & StartInfo, & procinfo;

} int WinAPI WinMain (Hinstance Hinstance, Hinstance Hprevinstance, LPSTR LPCMDLINS, INT NCMDSHOW) {selfdelete (Hinstance);} WriteResourceTofile features to access binary resources so that you can rebuild the DLL in the disk. The Windows Resource API provides a pointer to the original data. SelfDelete's role is to recreate the DLL and generate the following command line to launch Rundll32.exe: path / rundll32.exe magicdel.dll, _magicDel @ 16 Path / ExecutableName Rundll32.exe is located in a Windows directory or system directory, so SelfDelete checks if it is correct. When CreateProcess is called to execute a command line, you must set the startf_force-offfeedback flag to prevent Windows from displaying a busy hourglass or cursor when running Rundll32.exe. After doing so, the user will not feel that there is a new process being running. After this new process exits, the DLL and the original executable executive are gone. In order to let the self-deleted executor does not depend on C runtime DLL, the executable must be static to the runtime library code. Modify the project compilation option for this purpose: Project (P) | [Project Name] Properties (P) ... | C / C | Code Generation | Runtime Library: [Single Thread (/ ML)] or [Multithow / MT)] (or any option value that does not include this DLL) This self-deleting technology is very stable in all Windows versions. In practical use, uninstalling proceeds to copy their own copies to the Windows temporary (TEMP) directory so that all program files and related directories can be deleted, and finally delete themselves with self-deleted DLL. Writing the installer After determining what the installer is to do, it is then the production installer. Now a lot of installations are downloaded from the Internet and then run locally. The smaller the size of the downloaded file, the better the most effective method is to compress the file. How to make the user's first picture is my program screen instead of the installer screen of other companies, I have provided such support in Windows. First create an interactive setup program, which displays the software license agreement, prompting the user to install option, copy file, and then make the rest of the settings. The SETUP program is then saved in the installer (Installer) as the resource. This installer is only written back to the disk after rebuilding the setup program binary resource, unzip it, and then starts it with a new process. It is not difficult to save and read and write binary resources - the processing details and code have been described in front of this article. Since each Windows platform starting from Windows 95, each Windows platform starts with a set of decompressed files API - LZCopy.

Below is an example code using this API using this API: // install.h // # Define rc_binarytype 256 # define id_compressed_setup 100 //// install.rc // # include "install.h" id_compressed_setup rc_binarytype appsetup.ex _ /// / install.cpp // # include #include "install.h" void WriteResourceToFile (hINSTANCE hInstance, int idResource, char const * filename) {// see the Code} void DecompressFile (char const * source, char const * dest) {OFSTRUCT ofs; ofs.cBytes = sizeof (ofs); int zhfSource = LZOpenFile (const_cast (source), & ofs, OF_READ); int zhfDest = LZOpenFile (const_cast (dest), & ofs, OF_CREATE | OF_WRITE); LZCopy (zhfSource, zhfDest); LZClose (zhfSource); LZClose (zhfDest);} int WINAPI WinMain (hINSTANCE hInstance, hINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {WriteResourceToFile (hInstance, ID_COMPRESSED_SETUP, "AppSetup .ex _ "); DecompressFile (" AppSetup.ex_ "," AppSetup.exe "); DeleteFile (" AppSetup.ex _ "); // start AppSetup.exePROCESS_INFORMATION procInfo; STARTUPINFO startInfo; memset (& startInfo, 0, sizeof (startInfo) CREATEPROCESS (0, " Appsetup.exe ", 0, 0, False, Normal_Priority_Class, 0, 0, & StartInfo, & Procinfo);} You can see how the compressed SETUP program is saved as the resource of the installer. Thoughts discussed above in the above article. The DecompressFile function demonstrates how the LZCopy API is used. The installer recreates Appsetup.exe and then runs it.

转载请注明原文地址:https://www.9cbs.com/read-79427.html

New Post(0)