首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C++ >> 關於C++

C++ 經典技巧:讓執行檔在運行時「自我刪除」的優雅實作

     編輯:關於C++

為什麼要自我刪除?

典型場景:解安裝程式、一次性執行工具、安全敏感組件。使用者雙擊執行檔,程式完成任務後自動從磁碟消失,過程中主程式仍在記憶體中運行——這種「幽靈模式」常讓初學者驚呼「中毒了!」

核心難題:作業系統鎖定執行中映像

Windows 在載入 EXE 時會以獨佔共享模式開啟檔案,導致:

  • 無法 DeleteFile 自身
  • 無法 MoveFile 自身
  • 甚至無法以寫入模式 CreateFile 開啟自身

Jeffrey Richter 的「分身術」解法

核心策略:

  1. 原始進程將自身複製到 %TEMP% 目錄(Clone)
  2. 以 FILE_FLAG_DELETE_ON_CLOSE 開啟 Clone,承諾「所有句柄關閉時自動刪除」
  3. 啟動 Clone 進程,傳遞「原始進程 PID」與「原始 EXE 路徑」
  4. 原始進程立即退出 → 釋放檔案鎖定
  5. Clone 進程 WaitForSingleObject 等待原始進程結束
  6. DeleteFile 刪除原始 EXE
  7. Clone 結束 → 系統自動刪除 Clone(因 DELETE_ON_CLOSE)

關鍵代碼逐行解讀

// 原始進程分支
if (__argc == 1) {
    TCHAR szOrig[MAX_PATH], szClone[MAX_PATH];
    GetModuleFileName(NULL, szOrig, MAX_PATH);          // 取得自身完整路徑
    GetTempPath(MAX_PATH, szClone);                     // 取得 %TEMP%
    GetTempFileName(szClone, _T("Del"), 0, szClone);    // 產生唯一暫存檔名
    CopyFile(szOrig, szClone, FALSE);                   // 複製自身

    // 關鍵:以 DELETE_ON_CLOSE 開啟 Clone
    HANDLE hClone = CreateFile(szClone, 0, FILE_SHARE_READ, NULL,
                               OPEN_EXISTING, FILE_FLAG_DELETE_ON_CLOSE, NULL);

    // 取得原始進程同步句柄
    HANDLE hProc = OpenProcess(SYNCHRONIZE, TRUE, GetCurrentProcessId());

    // 命令列:Clone路徑 PID 原始路徑
    TCHAR cmd[512];
    wsprintf(cmd, _T("%s %d \"%s\""), szClone, hProc, szOrig);

    STARTUPINFO si = {sizeof(si)};
    PROCESS_INFORMATION pi;
    CreateProcess(NULL, cmd, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi);

    CloseHandle(hProc);
    CloseHandle(hClone);   // 關閉句柄,但檔案不刪除(Clone 進程仍持有)
    return 0;              // 原始進程退出
}

// Clone 進程分支
else {
    HANDLE hOrig = (HANDLE)_ttoi(__targv[1]);  // 還原 PID
    WaitForSingleObject(hOrig, INFINITE);      // 等待原始進程死亡
    CloseHandle(hOrig);
    DeleteFile(__targv[2]);                    // 刪除原始 EXE
    // 此處可補充:刪除安裝目錄、註冊表等清理工作
    // Clone 結束 → 系統自動刪除自身暫存檔
}

三大關鍵技術細節

技術點作用注意事項
FILE_FLAG_DELETE_ON_CLOSE 所有句柄關閉時自動刪除檔案 臨時檔案標配屬性,需在 CreateFile 指定
OpenProcess(SYNCHRONIZE, ...) 取得可用於同步的進程句柄 需 SYNCHRONIZE 權限,NT 系有效
WaitForSingleObject(hProc, INFINITE) 阻塞等待目標進程終止 避免原始進程尚未釋放檔案鎖就嘗試刪除

替代方案速覽

  • 批次檔自刪:啟動前寫入 del %0 的 .bat,再 WinExec。簡單但會閃現命令提示字元。
  • MoveFileEx 延遲刪除:MoveFileEx(szOrig, NULL, MOVEFILE_DELAY_UNTIL_REBOOT),下次重啟才生效,不適合即時需求。
  • 自我覆寫:Ring0 驅動層面修改檔案系統權限(如 Lu0 大神法),風險極高、極不推薦。

實戰檢核清單

  1. Clone 複製是否完整(含資源段、簽名、數位憑證)?
  2. 路徑含空白時,命令列參數是否正確加雙引號?
  3. 權限不足(Program Files)時,Clone 能否正確啟動?
  4. 殺毒軟體是否誤報「自我複製行為」?建議簽名驗證。
  5. 64 位元進程複製 32 位元副本(或反向)時,GetModuleFileName 行為差異。

結語

「分身術」以用戶模式 API 完美解決「執行中無法刪除」的死結,代碼簡潔、無需驅動、相容性極佳。下次寫 Uninstaller 時,不妨直接採用這套經典模式——既專業又優雅。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved