想完全掌控安裝/解除安裝畫面、不依賴第三方安裝包工具?本文揭秘 自刪除 DLL + Rundll32 核心技術,實現可執行檔「自我銷毀」,並結合 Windows 內建 LZCopy 解壓縮 API,打造零運行時依賴、體積極小的安裝/解除安裝程式。關鍵技術點:rundll32.exe 呼叫慣例、DLL 入口點精簡、資源嵌入與重建、compress.exe/expand.exe 工具鏈。
執行中的 EXE 檔案被系統鎖定,無法直接 DeleteFile。常見替代方案(修改執行緒屬性、批次檔延遲刪除)平台相容性差、時序難控制。本文採用 自刪除 DLL 代理刪除 EXE,再自我銷毀 的創新路徑。
系統內建 rundll32.exe 可直接載入 DLL 並呼叫導出函數:
rundll32.exe DllName,ExportedFuncName arguments
導出函數簽名**必須**為:
extern "C" __declspec(dllexport) void CALLBACK FuncName(
HWND hwnd, HINSTANCE hInst, LPTSTR lpCmdLine, int nCmdShow);
lpCmdLine 接收命令列參數(此處傳遞待刪除 EXE 路徑)。extern "C" 防止 C++ 名稱修飾,__declspec(dllexport) 導出。HMODULE g_hmodDLL;
BOOL WINAPI DllMain(HINSTANCE hinst, DWORD reason, LPVOID) {
if (reason == DLL_PROCESS_ATTACH) g_hmodDLL = hinst;
return TRUE;
}
extern "C" __declspec(dllexport) void CALLBACK MagicDel(HWND, HINSTANCE, LPTSTR lpCmdLine, int) {
Sleep(2000); // 等待呼叫端進程退出
DeleteFile(lpCmdLine); // 刪除目標 EXE
// 以下組合語言實現:FreeLibrary → DeleteFile(self) → ExitProcess
char self[MAX_PATH];
GetModuleFileName(g_hmodDLL, self, MAX_PATH);
__asm {
lea eax, self
push 0; push 0; push eax
push ExitProcess; push g_hmodDLL
push DeleteFile; push FreeLibrary
ret
}
}
精簡 DLL 體積關鍵(預設 40KB → 優化 3KB):
/NODEFAULTLIBDllMain否 (/GS-)(移除 __security_cookie 依賴)// 資源定義
#define RC_BINARYTYPE 256
#define ID_MAGICDEL_DLL 100
// .rc: ID_MAGICDEL_DLL RC_BINARYTYPE MagicDel.dll
void WriteResourceToFile(HINSTANCE hInst, int idRes, const char* filename) {
HRSRC hRes = FindResource(hInst, MAKEINTRESOURCE(idRes), MAKEINTRESOURCE(RC_BINARYTYPE));
HGLOBAL hg = LoadResource(hInst, hRes);
void* pv = LockResource(hg);
DWORD cb = SizeofResource(hInst, hRes);
HANDLE hFile = CreateFile(filename, GENERIC_WRITE, 0, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
DWORD wr; WriteFile(hFile, pv, cb, &wr, 0); CloseHandle(hFile);
}
void SelfDelete(HINSTANCE hInst) {
WriteResourceToFile(hInst, ID_MAGICDEL_DLL, "magicdel.dll");
// 組裝命令列
char cmd[MAX_PATH*3];
GetWindowsDirectory(cmd, MAX_PATH); lstrcat(cmd, "\\rundll32.exe");
if (GetFileAttributes(cmd) == INVALID_FILE_ATTRIBUTES) {
GetSystemDirectory(cmd, MAX_PATH); lstrcat(cmd, "\\rundll32.exe");
}
lstrcat(cmd, " magicdel.dll,_MagicDel@16 "); // 注意修飾名
char self[MAX_PATH]; GetModuleFileName(hInst, self, MAX_PATH);
lstrcat(cmd, self);
// 啟動並立即退出
STARTUPINFO si = {sizeof(si)}; si.dwFlags = STARTF_FORCEOFFFEEDBACK;
PROCESS_INFORMATION pi;
CreateProcess(0, cmd, 0, 0, FALSE, NORMAL_PRIORITY_CLASS, 0, 0, &si, &pi);
}
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE, LPSTR, int) {
SelfDelete(hInst);
}
Setup.exe(授權協議、選項、複製檔案...)。compress.exe (SDK 附帶) 壓縮:compress Setup.exe Setup.ex_。Setup.ex_ 作為二進制資源嵌入安裝程式 Installer.exe。Installer.exe 啟動流程:WriteResourceToFile(hInst, ID_COMPRESSED_SETUP, "AppSetup.ex_");
DecompressFile("AppSetup.ex_", "AppSetup.exe"); // LZCopy API
DeleteFile("AppSetup.ex_");
CreateProcess(0, "AppSetup.exe", ...); // 啟動安裝精靈
DecompressFile 實作:
void DecompressFile(const char* src, const char* dst) {
OFSTRUCT ofs = {sizeof(ofs)};
int hSrc = LZOpenFile((char*)src, &ofs, OF_READ);
int hDst = LZOpenFile((char*)dst, &ofs, OF_CREATE | OF_WRITE);
LZCopy(hSrc, hDst);
LZClose(hSrc); LZClose(hDst);
}
lz32.lib (Platform SDK Lib 目錄)。/MT 靜態連結 CRT,達成零依賴。%TEMP% 目錄(避免鎖定安裝目錄)。SelfDelete 刪除自身副本。compress.exe:ftp://ftp.microsoft.com/softlib/mslfiles/CP0982.EXE 解包後取得。expand.exe:系統內建,命令列解壓縮 expand file.ex_ file.exe。全平台 (Win9x/NT/2000/XP) 驗證通過。附件含完整安裝/解除安裝專案與
MagicDel.dll原始碼。