您的位置:首页 > 其它

用自删除dll实现应用程序的安装

2009-06-29 10:16 429 查看
实用程序 ? rundll32.exe ? 介绍 ?
? ?
? ?
?    从所周知,DLL的代码通常需要先加载到内存之后才能执行,那么如何执行某个DLL导出的代码而不用创建加载和调用该 ? DLL ? 的 ? EXE ? 文件呢?方法如下:从 ? Windows ? 95 ? 开始的每个 ? Windows ? 操作系统版本都附带一个系统实用程序:rundll32.exe。利用它可以象下面这样执行某些 ? DLL(但不是所有)输出的任何函数: ? ?
? ?
? rundll32.exe ? DllName,ExportedfnName ? args ?
? ?
? ExportedfnName ? 是DLL输出的函数名。在编写供 ? rundll32 ? 使用的 ? DLL时,可以象下面这样来声明输出函数: ?
? ?
? extern ? "C" ? __declspec(dllexport) ? void ? CALLBACK ? FunctionName ? ( ?
? HWND ? hwnd, ?
? HINSTANCE ? hInstance, ?
? LPTSTR ? lpCmdLine, ?
? int ? nCmdShow ?
? ) ?
? { ? ... ? } ? ? ?
? ?
? ?
? rundll32.exe ? 根据函数参数列表对函数进行调用,但根据经验,实际上用得上的参数值只有一个,那就是 ? lpCmdLine,该参数接收运行 ? rundll32.exe ? 时传入的参数值;__declspec(dllexport)的目的是输出函数;extern ? "C" ? 使输出的函数名有修饰符,如:_FunctionName@16 ? (函数名中被强制包含函数参数的大小,详细信息请参见 ? MSDN ? 中有关DLL输出函数调用规范说明)。rundll32.exe ? 加载指定的 ? DLL ? 并调用通过 ? args ? 参数传入的 ? lpCmdLine ? 的值指定的输出函数。有关 ? rundll32.exe ? 的正式文档参见 ? MSDN ? 库相关资料(Q164787): ? ?
? ?
? http://support.microsoft.com/default.aspx?scid=kb;en-us;164787 ?
? ?
? 实现能自删除的 ? DLL ? ?
? ?
? 下面是实现自删除DLL的示范代码: ?
? ?
? #include ? <windows.h> ?
? 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, ?
? HINSTANCE, ?
? LPTSTR ? lpCmdLine, ?
? int) ?
? { ?
? // ? 延时2秒 ?
? Sleep(2000); ?
? // ? 删除创建该进程的可执行文件 ?
? DeleteFile(lpCmdLine); ?
? ?
? // ? 删除DLL自己 ?
? char ? filenameDLL[MAX_PATH]; ?
? GetModuleFileName(g_hmodDLL, ? filenameDLL, ? sizeof(filenameDLL)); ?
? ?
? __asm ?
? { ?
? lea ? eax, ? filenameDLL ?
? push ? 0 ?
? push ? 0 ?
? push ? eax ?
? push ? ExitProcess ?
? push ? g_hmodDLL ?
? push ? DeleteFile ? //JMP调用函数需要手工保存返回值
? push ? FreeLibrary ?
? ret ?
? } ?
? } ? ?
? ?
? ?
?    上面这段代码首先删除某个文件,然后自删除。DllMain ? 是DLL的入口函数,当首次加载动态链接库时该函数被调用,此时将模块句柄赋值给全局变量 ? g_hmodDLL,以便梢后使用它来获取 ? DLL ? 本身的文件名。在 ? MagicDel ? 函数中,lpCmdLine ? 是DLL要删除的可执行文件的名称(如:卸载程序的文件名)。要删除它很容易——用 ? Sleep ? 做一个延时,以便可执行程序的进程有时间退出并调用 ? DeleteFile。为了掌握 ? MagicDel ? 的实现细节,你可以将可执行程序的进程句柄传给MagicDel并在调用 ? DeleteFile ? 之前做一个等待,看看会发生什么? ?
?    要让 ? DLL ? 进行自删除需要一点诀窍。rundll32 ? 调用 ? LoadModule ? 将 ? DLL ? 加载到它的地址空间。如果 ? DLL ? 函数可以返回的话,rundll32 ? 将会退出,从而导致 ? DLL ? 被释放(不是被删除)。为了解决这个问题,我们可以执行下面的代码: ? ?
? ?
? FreeLibrary(DLL ? module ? handle); ?
? ? ? ? ? ? ? DeleteFile(DLL ? filename); ?
? ? ? ? ? ? ? ExitProcess(0); ? ?
? ?
? ?
?    MagicDel ? 函数是不能按这样的顺序进行直接调用的,因为 ? FreeLibary ? 会使代码页无效。为此, ? MagicDel ? 采用将等效的汇编指令压入堆栈,然后执行它们,后跟一个 ? ret ? 指令,最后调用 ? ExitProccess ? 以防止进程继续往下执行。我参考 ? Gary ? Nebbit ? 在 ? Windows ? 开发杂志(WDJ)“Tech ? Tips”栏目发表的文章编写了一个汇编代码块。如果你用 ? Visual ? Studio ? 以默认选项生成DLL,最终的二进制文件大约为 ? 40K。由于我们打算将 ? DLL ? 作为可执行程序的资源,它的体积越小越好,为此,我们必须对它进行瘦身处理。思路是将无用的 ? C ? 运行时代码从DLL中删除掉,具体方法如下: ? ?
? 本文例子使用 ? Visual ? Studio.NET ? 2003 ? 中文版编译生成 ? DLL,先设置项目的编译/链接选项: ?
? 项目(P)| ? [项目名称] ? 属性(P)... ? | ? 链接器 ? | ? 输入 ? | ? 忽略所有默认库:是(/NODEFAULTLIB),此设置将 ? /NODEFAULTLIB ? 选项传给链接器以便过滤掉运行时代码。 ?
? ?
? 由于 ? DLL ? 入口点(Entry ? Point)通常是由运行时库提供(默认为 ? DllMain),所以完成上述第一步设置之后,还必须显式地将 ? DLL入口点设置为 ? DllMain: ?
? 项目(P)| ? [项目名称] ? 属性(P)... ? | ? 链接器 ? | ? 高级 ? | ? 入口点:DllMain。 ?
? 如果此时编译生成 ? DLL,编译器会报如下两个 ? 无法解析的外部符号( ? unresolved ? externals ? ) ? 错误: ? ?
? error ? LNK2019: ? 无法解析的外部符号 ? ___security_cookie ? ,该符号在函数 ? _MagicDel@16 ? 中被引用 ?
? error ? LNK2019: ? 无法解析的外部符号 ? @__security_check_cookie@4 ? ,该符号在函数 ? _MagicDel@16 ? 中被引用 ?
? 解决方法是进行下一步设置。 ?
? ?
? ?
? 项目(P)| ? [项目名称] ? 属性(P)... ? | ? C/C++ ? | ? 代码生成 ? | ? 缓冲区安全检查:否, ?
? 该设置不会将 ? /GS ? 标志传给编译器,从而摆脱 ? unresolved ? externals ? 错误。 ?
? 好了,现在编译生成 ? DLL,最终的 ? DLL ? 大小为 ? 3K,实际的文件大小只有 ? 2.5K。 ?
? ?
? ?
? ?
? 实现能自删除的可执行程序 ?
? ?
? ?
?    这里所用的主要思路是将一个能自删除的 ? DLL ? 作为资源保存在拟实现自删除的可执行程序中,然后在需要时重新创建它,同时,启动一个 ? rundll32.exe ? 进程实现删除行为。 ?
?    下面是用于将DLL存储为资源的头文件和资源文件。资源类型值只要大于 ? 256 ? 都可以,这是为用户定义类型预留的。此外还有一种可选方法是将 ? DLL ? 二进制文件以字节数组的形式直接存储在源中: ?
? ?
? ?
? 在资源中包含一个文件 ?
? // ? SelfDelete.h ?
? #define ? RC_BINARYTYPE ? 256 ?
? #define ? ID_MAGICDEL_DLL ? 100 ?
? ?
? // ? SelfDelete.rc ?
? #include ? "SelfDelete.h" ?
? ID_MAGICDEL_DLL ? RC_BINARYTYPE ? MagicDel.dll ? ?
? ?
? ?
? 下面是可执行程序关键代码: ?
? ?
? #include ? <windows.h> ?
? #include ? "SelfDelete.h" ?
? void ? WriteResourceToFile(HINSTANCE ? hInstance, ?
? int ? idResource, ?
? char ? const ? *filename) ?
? { ?
? // ? 存取二进制资源 ?
? HRSRC ? hResInfo ? = ? FindResource(hInstance, ? MAKEINTRESOURCE(idResource), ?
? MAKEINTRESOURCE(RC_BINARYTYPE)); ?
? HGLOBAL ? hgRes ? = ? LoadResource(hInstance, ? hResInfo); ?
? void ? *pvRes ? = ? LockResource(hgRes); ?
? DWORD ? cbRes ? = ? SizeofResource(hInstance, ? hResInfo); ?
? ?
? // ? 将二进制资源写到文件 ?
? 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. ? 查找 ? rundll32.exe ?
? char ? commandLine[MAX_PATH ? * ? 3]; ?
? GetWindowsDirectory(commandLine, ? sizeof(commandLine)); ?
? lstrcat(commandLine, ? "//rundll32.exe"); ?
? if ? (GetFileAttributes(commandLine) ? == ? INVALID_FILE_ATTRIBUTES) ?
? { ?
? GetSystemDirectory(commandLine, ? sizeof(commandLine)); ?
? lstrcat(commandLine, ? "//rundll32.exe"); ?
? } ?
? // ? 2. ? 添加 ? rundll32.exe ? 参数 ?
? lstrcat(commandLine, ? " ? magicdel.dll,_MagicDel@16 ? "); ?
? // ? 3. ? 添加本文件名 ?
? char ? thisName[MAX_PATH]; ?
? GetModuleFileName(hInstance, ? thisName, ? sizeof(thisName)); ?
? lstrcat(commandLine, ? thisName); ?
? // ? 执行命令行 ? ?
? 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 ? lpCmdLine, ? ?
? ? ? ? int ? nCmdShow) ?
? { ?
? SelfDelete(hInstance); ?
? } ?
? ?
? ?
? ?
?    WriteResourceToFile ? 的功能是存取二进制资源,以便能在磁盘中重建 ? DLL。Windows ? 资源 ? API ? 提供了一个指向原始数据的指针。 ?
? SelfDelete ? 的作用是重新创建DLL并生成如下命令行启动 ? rundll32.exe: ? ?
? ? ? ? ? ? ? path/rundll32.exe ? magicdel.dll,_MagicDel@16 ? path/executableName ? ? ? ? ? ? ?
?    rundll32.exe ? 位于 ? Windows ? 目录或者 ? System ? 目录中,所以 ? SelfDelete ? 检查它的位置是否正确。当 ? CreateProcess ? 被调用执行命令行时,必须设置 ?
? STARTF_FORCE-OFFFEEDBACK ? 标志以防止 ? Windows ? 在运行 ? rundll32.exe ? 时显示表示忙的沙漏或光标。这样做以后用户不会感觉到有新的进程正在运行。在这个新进程退出之后,DLL ? 和原来的可执行文件都不见了。 ?
?    为了让自删除的可执行程序不依赖于 ? C ? 运行时DLL,可执行程序必须静态链接到运行时库代码。为此修改项目编译选项即可: ?
? 项目(P)| ? [项目名称] ? 属性(P)... ? | ? C/C++ ? | ? 代码生成 ? | ? 运行时库:[单线程(/ML)] ? 或者 ? [多线程(/MT)](或者任何不包含此DLL的选项值) ?
?    此自删除技术在所有 ? Windows ? 版本中都工作得很稳定。在实际运用中,卸载程序首先将自己的拷贝放到 ? Windows ? 临时(Temp)目录,以便能删除所有程序文件和相关目录,最后它用自删除的 ? DLL ? 把自己删掉。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: