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

C++ Builder 將可執行檔作為資源內嵌並動態釋放執行

     編輯:關於C++

在軟體保護、安裝包製作、單檔案部署等場景中,常需將一個完整的可執行檔 (EXE) 作為資源內嵌到主程式中,運行時釋放到磁碟並執行。本文示範在 C++ Builder 中使用自訂資源 (RCDATA/CUSTOM) 內嵌 write.exe (寫字板),並透過 FindResource/LoadResource/LockResource API 釋放重建的完整流程。

核心步驟

  1. 準備資源檔:使用資源編輯器 (如 Visual Studio 資源編輯器、Borland Resource Workshop、ResHacker) 將目標 EXE 作為 RCDATA 或自訂類型 (如 CUSTOM) 資源導入,指定資源 ID (如 1111)。
  2. 主程式編譯:資源隨主程式編譯鏈接,生成單一 EXE。
  3. 運行時釋放:呼叫資源 API 定位、載入、鎖定資源記憶體,寫入磁碟檔案。
  4. 執行釋放檔案:使用 ShellExecute 或 CreateProcess 啟動。

完整實作程式碼


// 資源定義 (在 .rc 檔或 IDE 資源管理器中添加)
// CUSTOM 1111 "write.exe"  // 類型 CUSTOM, ID 1111, 來源檔案

#include <windows.h>

void ExtractAndRunEmbeddedExe() {
    // 1. 定位資源
    HRSRC hRes = FindResource(
        (HMODULE)GetModuleHandle(NULL), // 當前模組句柄
        MAKEINTRESOURCE(1111),          // 資源 ID
        "CUSTOM"                        // 資源類型
    );
    if (!hRes) {
        ShowMessage("找不到資源: " + SysErrorMessage(GetLastError()));
        return;
    }

    // 2. 載入資源到全域記憶體
    HGLOBAL hGlobal = LoadResource(NULL, hRes);
    if (!hGlobal) {
        ShowMessage("載入資源失敗: " + SysErrorMessage(GetLastError()));
        return;
    }

    // 3. 鎖定獲取記憶體指標
    LPVOID pData = LockResource(hGlobal);
    if (!pData) {
        ShowMessage("鎖定資源失敗");
        return;
    }

    // 4. 獲取資源大小
    DWORD dwSize = SizeofResource(NULL, hRes);
    if (dwSize == 0) {
        ShowMessage("資源大小為 0");
        return;
    }

    // 5. 寫入磁碟檔案
    AnsiString outPath = "C:\\Temp\\MyWriter.exe"; // 實際應用用 GetTempPath
    HANDLE hFile = CreateFile(
        outPath.c_str(), GENERIC_WRITE, 0, NULL,
        CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL
    );
    if (hFile == INVALID_HANDLE_VALUE) {
        ShowMessage("建立檔案失敗: " + SysErrorMessage(GetLastError()));
        return;
    }

    DWORD dwWritten;
    if (!WriteFile(hFile, pData, dwSize, &dwWritten, NULL) || dwWritten != dwSize) {
        ShowMessage("寫入檔案失敗或不完整");
    } else {
        ShowMessage("釋放成功: " + outPath);
        // 6. 執行釋放的程式
        ShellExecute(Handle, "open", outPath.c_str(), NULL, NULL, SW_SHOW);
    }
    CloseHandle(hFile);
    // 無需 UnlockResource/FreeResource (LoadResource 記憶體由系統管理)
}

關鍵技術細節

API用途注意事項
FindResource在模組資源表中查找資源目錄項類型名區分大小寫;MAKEINTRESOURCE 用於整數 ID
LoadResource載入資源數據到全域堆疊,返回 HGLOBAL不增加引用計數;資源數據在模組卸載前常駐
LockResource將 HGLOBAL 轉為實際記憶體指標不可呼叫 UnlockResource (已過時);指標有效直到模組卸載
SizeofResource獲取資源原始大小 (位元組)必須用於 WriteFile 長度參數

資源類型選擇建議

  • RCDATA (RT_RCDATA / 10):標準原始資料類型,所有資源工具支援,推薦使用。
  • 自訂類型 (如 "CUSTOM", "MYEXE"):可避免與系統資源衝突,但需資源編譯器支援自訂類型字串。Borland Resource Workshop 早期版本對自訂類型支援有限,建議改用 Visual Studio 資源編輯器或 ResHacker 生成 .res 檔再鏈接。

進階應用:記憶體直接執行 (RunPE / Process Hollowing)

若不想寫入磁碟,可在記憶體中直接映射 PE 映像並建立進程 (所謂 RunPE 技術):

  1. 建立目標進程掛起狀態 (CREATE_SUSPENDED)。
  2. 獲取目標進程映像基址 (PEB->ImageBaseAddress)。
  3. 解析內嵌 PE 的區段表,逐區段寫入目標進程記憶體 (WriteProcessMemory)。
  4. 修改目標進程入口點 (Context->Eax/Rcx 指向新 EntryPoint)。
  5. 恢復執行緒 (ResumeThread)。
警示:此技術常被惡意軟體利用 (免殺、注入),屬高風險行為。合法場景極少 (極少數加密殼、虛擬化保護)。本文不提供實作細節,僅作原理認知。

總結

「資源內嵌 EXE + 運行時釋放」是單檔案部署、安裝程式生成器、軟體護盾殼的基礎技術。C++ Builder 透過標準 Windows 資源 API 即可輕松實現。關鍵在於資源編輯器正確導入二進位資料,以及釋放時精確控制檔案路徑、權限與清理策略。

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