「殼程式」模式:主程式(Shell)僅負責驗證授權、解密載入、提取圖示等輔助邏輯,真正業務邏輯封裝於內嵌的目標執行檔中。本文詳細說明如何在 C++Builder 中實現此架構:資源內嵌、圖示提取同步、授權驗證、記憶體載入執行(或釋放磁碟執行),並附帶簡易感染式複製代碼分析(僅供防禦研究)。
+------------------+ +----------------------+ +-------------------+
| Shell.exe (殼) | --> | 驗證授權/解密/提取圖示 | --> | Target.exe (內嵌) |
+------------------+ +----------------------+ +-------------------+
│ │ │
│ 修改自身圖示 釋放至記憶體/磁碟
│ │ │
▼ ▼ ▼
啟動 → 檢查授權 → 解密資源 → 建立進程 (CreateProcess / 記憶體載入)
RT_RCDATA 或自訂 "EXEFILE"IDR_TARGET_EXE 101BRCC32 編譯 .rc,或 Resource Hacker 直接加入編譯後的 .exe
// 從資源讀取目標 EXE 並提取圖示
HRSRC hRes = FindResource(hInst, MAKEINTRESOURCE(IDR_TARGET_EXE), RT_RCDATA);
HGLOBAL hGlob = LoadResource(hInst, hRes);
LPVOID pExeData = LockResource(hGlob);
DWORD exeSize = SizeofResource(hInst, hRes);
// 解析目標 EXE 的 PE 結構,提取圖示資源目錄
// 簡化:使用 ExtractIconEx 或 LoadLibraryEx(LOAD_LIBRARY_AS_DATAFILE)
// 實際需手動解析 .rsrc 區段找到 RT_GROUP_ICON + RT_ICON
// 將提取的圖示設為 Shell 視窗圖示
HICON hIcon = ExtractIcon(hInst, "target.exe", 0); // 若已釋放磁碟
SendMessage(ShellWnd, WM_SETICON, ICON_BIG, (LPARAM)hIcon);
SendMessage(ShellWnd, WM_SETICON, ICON_SMALL, (LPARAM)hIcon);
bool VerifyLicense()
{
// 1. 讀取註冊表/檔案/網路驗證
// 2. 硬體指紋綁定 (CPU ID, MAC, 磁碟序號)
// 3. 時間限制 (試用期)
// 4. 簽名驗證 (RSA/ECDSA 驗證 License 檔)
// 簡易範例:檢查註冊表
HKEY hKey;
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, "Software\\MyApp", 0, KEY_READ, &hKey) == ERROR_SUCCESS)
{
char key[256]; DWORD size = 256;
if (RegQueryValueEx(hKey, "LicenseKey", 0, NULL, (LPBYTE)key, &size) == ERROR_SUCCESS)
{
RegCloseKey(hKey);
return ValidateKey(key); // 實作簽名驗證
}
RegCloseKey(hKey);
}
return false;
}
| 方式 | 優點 | 缺點 | 適用場景 |
|---|---|---|---|
| 釋放磁碟 + CreateProcess | 簡單、相容性好、支援所有 EXE | 留下檔案、易被複製、防毒誤報 | 快速原型、安裝程式 |
| 記憶體載入 (Manual Mapping) | 無檔案落地、隱蔽、可註入現有進程 | 極複雜:需手動解析 PE、重定位、IAT、TLS、例外表、載入 DLL | 高隱蔽需求、殼開發 |
| Process Hollowing (RunPE) | 掛載到合法進程、繞過部分監控 | 行為極度可疑、現代 EDR 重點偵測 | 惡意軟體(不建議合法使用) |
void RunEmbeddedExe()
{
// 1. 讀取資源
HRSRC hRes = FindResource(hInst, MAKEINTRESOURCE(IDR_TARGET_EXE), RT_RCDATA);
DWORD size = SizeofResource(hInst, hRes);
HGLOBAL hGlob = LoadResource(hInst, hRes);
LPVOID pData = LockResource(hGlob);
// 2. 寫入暫存檔
char tempPath[MAX_PATH];
GetTempPath(MAX_PATH, tempPath);
strcat(tempPath, "target_XXXXXX.exe"); // 需用 GetTempFileName 產生唯一名
HANDLE hFile = CreateFile(tempPath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
DWORD written;
WriteFile(hFile, pData, size, &written, NULL);
CloseHandle(hFile);
// 3. 執行並等待
STARTUPINFO si = {sizeof(si)};
PROCESS_INFORMATION pi;
if (CreateProcess(tempPath, NULL, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi))
{
WaitForSingleObject(pi.hProcess, INFINITE);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
}
// 4. 清理
DeleteFile(tempPath);
}
原文附帶的 inFect 函式展示典型「前綴型病毒」邏輯:
FindFirstFile/FindNextFile)。"AntGhazi")。ModifyIcon),偽裝成原檔。防禦對策:
IsDebuggerPresent、CheckRemoteDebuggerPresent、時序檢查、硬體斷點檢測。殼技術本身中性,但:
開發者應確保殼程式行為透明、用戶知情同意、符合數位簽名與軟體分發規範。
理解殼架構與 PE 內嵌技術,不僅能實現軟體保護,更能深入掌握 Windows 載入器機制,為安全研究與系統開發奠定堅實基礎。