PE 格式執行檔若不修改檔頭與中間內容,僅在檔尾附加資料,仍可正常執行。利用此特性,將多個 EXE 綁定成單一檔案,執行時由引導程式 (Stub) 解包並啟動原始程式。
目標檔案 (Target.exe) 結構: --------------------------------------- | Stub.exe (引導) | App1.exe | App2.exe | Len2 (30 bytes) | Len1 (30 bytes) | ---------------------------------------
// 取得自身模組完整路徑 (_pgmptr 為 CRT 全域變數)
CFile fSource(_pgmptr, CFile::modeRead | CFile::modeNoTruncate);
int iSourceLength = fSource.GetLength();
// --- 讀取第 2 個檔案長度 (Len2) ---
fSource.Seek(iSourceLength - 60, CFile::begin);
char buffer[40] = {0};
fSource.Read(buffer, 30);
int iTarget2Len = atoi(buffer);
// --- 提取第 2 個檔案 ---
fSource.Seek(iSourceLength - iTarget2Len - 60, CFile::begin);
char* pBuffer = new char[iTarget2Len];
fSource.Read(pBuffer, iTarget2Len);
CFile fTarget(_T("c:\\app2.exe"), CFile::modeCreate | CFile::modeWrite | CFile::modeNoTruncate);
fTarget.Write(pBuffer, iTarget2Len);
delete[] pBuffer;
// --- 讀取第 1 個檔案長度 (Len1) ---
fSource.Seek(iSourceLength - 30, CFile::begin);
ZeroMemory(buffer, 40);
fSource.Read(buffer, 30);
int iTarget1Len = atoi(buffer);
// --- 提取第 1 個檔案 ---
fSource.Seek(iSourceLength - 60 - iTarget1Len - iTarget2Len, CFile::begin);
pBuffer = new char[iTarget1Len];
fSource.Read(pBuffer, iTarget1Len);
fTarget.Open(_T("c:\\app1.exe"), CFile::modeCreate | CFile::modeWrite | CFile::modeNoTruncate);
fTarget.Write(pBuffer, iTarget1Len);
delete[] pBuffer;
fSource.Close(); fTarget.Close();
// --- 啟動兩個進程 ---
STARTUPINFO si = { sizeof(si) };
PROCESS_INFORMATION pi;
CreateProcess(_T("c:\\app1.exe"), NULL, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
CreateProcess(_T("c:\\app2.exe"), NULL, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
ExitProcess(0); // 結束 Stub 自身
// OnInitDialog 中
ModifyStyleEx(WS_EX_APPWINDOW, WS_EX_TOOLWINDOW); // 不在工作列顯示
::MoveWindow(m_hWnd, 0, 0, 0, 0, TRUE); // 尺寸歸零
CFile fSource(_T("c:\\stub.exe"), CFile::modeReadWrite | CFile::modeNoTruncate);
fSource.SeekToEnd();
// 附加 App1.exe
CFile fApp1(m_strApp1Path, CFile::modeRead | CFile::modeNoTruncate);
int len1 = fApp1.GetLength();
char* buf = new char[len1];
fApp1.Read(buf, len1);
fSource.Write(buf, len1);
delete[] buf; fApp1.Close();
// 附加 App2.exe
CFile fApp2(m_strApp2Path, CFile::modeRead | CFile::modeNoTruncate);
int len2 = fApp2.GetLength();
buf = new char[len2];
fApp2.Read(buf, len2);
fSource.Write(buf, len2);
delete[] buf; fApp2.Close();
// 寫入長度資訊 (固定 30 字節,不足補空格)
auto WriteLen = [&](int len) {
char tmp[30] = {0};
itoa(len, tmp, 10);
int l = strlen(tmp);
if (l < 30) memset(tmp + l, ' ', 30 - l);
fSource.Write(tmp, 30);
};
WriteLen(len2); // 先寫 Len2
WriteLen(len1); // 再寫 Len1
fSource.Close();
AfxMessageBox(_T("綁定完成"));