[推薦] 如何將多個文件捆綁成一個可執行文件 |
|
axsoft
版主 發表:681 回覆:1056 積分:969 註冊:2002-03-13 發送簡訊給我 |
如何將多個文件捆綁成一個可執行文件 作者:徐景周 下載示例程序代碼(http://www.csdn.net/cnshare/soft/10/10356.shtm) 將多個文件合併成一個最終可執行文件,運行這個最終合成文件後,就相當於運行了合併前的多個文件。這種程序在木馬程序合併中會經常用到,你想知道它是怎麼用程序實現的麼?下面我就拿我用VC6.0做的一個文件捆綁器的例子代碼來告訴你,程序運行後界面如下: 圖例 基本構成思想:其實,其中的構成思想非常簡單。合併文件時:建立一個新的二進制文件,先寫入你的自身捆綁程序的資料和其文件長度,再寫入你要捆綁的第一個文件的資料和其文件長度,後再直接寫入你要捆綁的第二個文件的資料和文件長度……,最後可直接寫入你要捆綁的最後一個文件的資料(不需其文件長度)。分解釋放最終合成文件時,也就是將上面的方法思想倒過來既可:打開最終合成文件,讀取源自身捆綁程序文件長度,將文件指針移到自身捆綁程序資料後,讀取第一個被綁定文件的長度,接著讀取其長度的文件資料並寫入到一新建文件1中,再讀取第二個被綁定文件的長度,接著讀取其長度的資料並寫入到新建文件2中……,直到最後直接讀取最後一個被綁定文件的資料並將其寫入到最後一個新建文件中既可。(下面實例僅告訴你如何實現二個文件的捆綁,至於多個文件的捆綁,讀者只需略加改動既可,詳情請查看下載後的實例代碼。) 下面我來講講文件捆綁最核心的部分,以及如何具體將其用代碼來實現的方法:
1、 捆綁多個文件為一個可執行程序
先得到自身捆綁程序的文件長度和第一個要捆綁文件的文件長度,枚舉第一個要捆綁文件有無圖標,有的話就用它做為最終生成文件的圖標,否則用自身捆綁程序所帶默認圖標做最終生成文件的圖標。在新建二進制文件中寫入自身捆綁程序的資料和其文件長度,再寫入第一個要捆綁文件的資料及其文件長度,最後直接寫入第二個文件的資料既可。
合併程序涵數的具體代碼實現如下: //定義要使用到的捆綁程序自身文件訊息的結構體
struct MODIFY_DATA {
unsigned int finder; // 常量(定位自身)
_off_t my_length; //文件長度(自身)
} modify_data = {0x12345678, 0}; //綁定二個文件為一個可執行文件
bool CBindFileDlg::Bind_Files()
{
FILE* myself; //自身文件
FILE* out; //最終合成文件
FILE* in; //待綁定文件
int bytesin; //一次讀文件字節數
int totalbytes = 0; //讀出文件總字節數
struct _stat ST; //文件的狀態訊息(如文件長度等)
unsigned int finder = 0x12345678; //自身文件定位
unsigned int i, k;
int l=1; //進度條狀態顯示變量
char buff[20]; //進度條狀態顯示變量 his_name = strFirstFilePath; //第一個綁定的文件名 _stat(my_name, &ST); //獲取自身捆綁文件訊息
modify_data.my_length = ST.st_size; //得到自身文件長度
if (modify_data.my_length == 0)
{
MessageBox("綁定文件中,自身文件長度為零時出錯!","錯誤");
return false;
} buf = (BYTE *)malloc(modify_data.my_length); //分配一定大小緩衝區
if (buf == NULL)
{
MessageBox("綁定文件中,分配自身文件長度時出錯!","錯誤");
return false;
} myself = fopen(my_name, "rb"); //打開自身文件
if (myself == NULL)
{
free(buf);
MessageBox("綁定文件中,打開自身文件時出錯!","錯誤");
return false;
} //先讀取捆綁程序自身文件資料
bytesin = fread(buf, 1, modify_data.my_length, myself);
fclose(myself); if (bytesin != modify_data.my_length)
{
free(buf);
MessageBox("綁定文件中,不能完全讀取自身文件內容時出錯!","錯誤");
return false;
} //存儲自身文件訊息到緩衝區(如長度)
for (i = 0; i < modify_data.my_length - sizeof(finder); i += sizeof(finder))
{
for (k = 0; k < sizeof(finder); k++)
{
if (buf[i+k] != ((BYTE*)&finder)[k])
break;
}
if (k == sizeof(finder)) //定位並保存自身資料文件訊息
{
memcpy(buf+ i, &modify_data, sizeof(modify_data));
break;
}
} if (i >= modify_data.my_length - sizeof(finder))
{
free(buf);
MessageBox("綁定文件中,不能定位自身文件時出錯!","錯誤");
return false;
} //獲取第一個要綁定文件的訊息(文件長度)
if (_stat(strFirstFilePath, &ST) != 0 || ST.st_size == 0)
{
free(buf);
MessageBox("綁定文件中,讀取第一個要綁定文件時出錯!","錯誤");
return false;
} //獲取自身文件圖標及第一個要綁定文件的圖標(如第一個要綁定文件沒有圖標,
//則用自身文件圖標。其涵數實現請參看例程)
list_my_icons(); out = fopen(strFinalFilePath, "wb"); //創建最終合成文件
if (out == NULL)
{
free(buf);
MessageBox("綁定文件中,創建綁定後生成的合成文件時出錯!","錯誤");
return false;
} //先將前面讀出的自身捆綁程序的資料寫入最終合成文件中
totalbytes += fwrite(buf, 1, bytesin, out); in = fopen(strFirstFilePath, "rb"); //打開第一個要綁定的文件
if (in == NULL)
{
free(buf);
MessageBox("綁定文件中,打開第一個要綁定文件時出錯!","錯誤");
return false;
} //寫入第一個要綁定文件的長度到最終合成文件中
totalbytes += fwrite(&ST.st_size, 1, sizeof(ST.st_size), out); //寫入最終分解後文件執行方式的標誌位(同步或異步執行)
UpdateData(TRUE); //傳控件值到變量m_Sync中
totalbytes += fwrite(&m_Sync, 1, sizeof(int), out); //寫入第一個要綁定文件的資料到最終合成文件中
while (bytesin = fread(buf, 1, modify_data.my_length, in))
{
totalbytes += fwrite(buf, 1, bytesin, out);
}
fclose(in); //關閉第一個綁定文件句柄 //設置進度條顯示
m_Progress.SetRange(0,500);
for (int m = 0; m < 500; m++)
m_Progress.SetPos(m);
m_Parts = _ltoa(l, buff, 10);
m_Parts += _T("個文件已綁定");
UpdateData(FALSE);
l++; in = fopen(strSecondFilePath, "rb"); //打開第二個要綁定的文件
if (in == NULL)
{
free(buf);
MessageBox("綁定文件中,打開第二個要綁定文件時出錯!","錯誤");
return false;
}
//直接寫入第二個要綁定文件的資料到最終合成文件中
while (bytesin = fread(buf, 1, modify_data.my_length, in))
{
totalbytes += fwrite(buf, 1, bytesin, out);
} //設置進度條顯示
m_Progress.SetRange(0,500);
for (int n = 0; n < 500; n++)
m_Progress.SetPos(n);
m_Parts = _ltoa(l, buff, 10);
m_Parts += _T("個文件已綁定");
UpdateData(FALSE);
l++; fclose(in); //關閉第二個綁定文件句柄
fclose(out); //關閉最終合成文件句柄
free(buf); //釋放緩衝區 return true;
} 2、 釋放最終合成文件並同3、 時運行它們。
打開自身文件,從中得到自身捆綁程序的文件長度,便可將文件指針定位到第一個被捆綁文件的位置,讀取其文件長度和其資料,將其讀出資料寫入第一個新建文件中。同樣,通過已讀取的自身捆綁程序文件長度和第一個被捆綁文件的文件長度加上其保存這兩個文件長度值的字節數,既可準確定位第二個被捆綁文件的位置,讀取其資料,寫入到第二個新建文件中。同時,運行這兩個文件,最後再刪除這兩個文件既可。
釋放最終合成文件的代碼具體實現如下: //創建分解文件後,運行各分解文件時的進程
void CBindFileDlg::Create_Process(const char* temp_exe, BOOL async)
{
HANDLE hProcess; //進程句柄
HANDLE hThread; //線程句柄
PROCESS_INFORMATION PI; //進程訊息
STARTUPINFO SI; //啟動訊息 memset(&SI, 0, sizeof(SI)); //分配一定的內存
SI.cb = sizeof(SI); //大小賦給啟動訊息內CB
CreateProcess(temp_exe, NULL, NULL, NULL, FALSE,NORMAL_PRIORITY_CLASS, NULL, NULL, &SI, &PI);
/* --- 暫不用,否則需要保存原始綁定的文件名稱
//如果分解後的文件不是執行文件的話,則直接打開它
if(!CreateProcess(temp_exe, NULL, NULL, NULL, FALSE,NORMAL_PRIORITY_CLASS, NULL, NULL, &SI, &PI))
HINSTANCE result =ShellExecute(NULL, _T("open"), temp_exe, NULL,NULL, SW_SHOW);
--- */ hProcess = PI.hProcess;
hThread = PI.hThread;
//異步執行時,執行後不刪除分解後的文件;同步執行時,執行後刪除分解後的文件
if (!async) //當同步執行時
{
//一直等待,直到當前程序運行進程結束
WaitForSingleObject(hProcess, INFINITE);
unlink(temp_exe); //刪除temp.exe文件
}
} //分解已合併的文件,同時運行它們
void CBindFileDlg::Unbind()
{
FILE* myself; //自身文件
FILE* out; //分解後文件
int bytesin; //一次讀出文件的字節數
int totalbytes = 0; //讀出文件的總字節數
char temp_exe1[] = "temp1.exe"; //分解後的綁定文件名一(可任意取)
char temp_exe2[] = "temp2.exe"; //分解後的綁定文件名二(可任意取)
int SyncFlag; //文件最終執行標誌(同步或異步) //先分配一定大小的緩衝區(大小等於捆綁程序長度)
buf = (BYTE*)malloc(modify_data.my_length); myself = fopen(my_name, "rb"); //打開最終合成文件
if (myself == NULL)
{
free(buf);
MessageBox("分離文件中,打開自身文件時出錯!","錯誤");
return;
} out = fopen(temp_exe1, "wb"); //創建第一個綁定的文件
if (out == NULL)
{
free(buf);
MessageBox("分離文件中,創建第一個被綁定文件時出錯!","錯誤");
return;
} //將文件指針定位到捆綁器程序長度尾部
fseek(myself, modify_data.my_length, SEEK_SET); //讀取第一個綁定文件的長度
if (fread(&prog1_length, sizeof(prog1_length), 1, myself) == 0)
{
free(buf);
MessageBox("分離文件中,讀取第一個被綁定文件長度時出錯!","錯誤");
return;
} //讀取最終文件執行方式(同步或異步執行)
if (fread(&SyncFlag, sizeof(int), 1, myself) == 0)
{
free(buf);
MessageBox("分離文件中,讀取第一個被綁定文件長度時出錯!","錯誤");
return;
} //讀取第一個文件內容並寫入到新建的temp1.exe文件中
while (bytesin = fread(buf, 1, sizeof(buf), myself))
{
if (totalbytes + bytesin > prog1_length)
bytesin = prog1_length - totalbytes;
totalbytes += fwrite(buf, 1, bytesin, out);
}
fclose(out); //關閉第一個綁定文件句柄 #ifdef DEBUG_PRINT
fprintf(stderr, "已複製 %d 字節!\n", totalbytes);
#endif DEBUG_PRINT totalbytes = 0;
out = fopen(temp_exe2, "wb"); //創建第二個綁定的文件
if (out == NULL)
{
free(buf);
MessageBox("分離文件中,創建第二個被綁定文件時出錯!","錯誤");
return;
} //將文件指針定位到最終合成文件中的第二個綁定文件頭部, 偏移量 ==
//(捆綁器自身文件長度+保存第一個綁定文件長度所佔字節數+保存最終文件執行標誌所佔字節數+第一個綁定文件長度)
fseek(myself,modify_data.my_length+ sizeof(modify_data.my_length) + sizeof(int) + prog1_length, SEEK_SET); //讀取第二個綁定文件內容並寫入到新建的temp2.exe文件中
while (bytesin = fread(buf, 1, sizeof(buf), myself))
{
totalbytes += fwrite(buf, 1, bytesin, out);
}
fclose(out); //關閉第二個綁定文件句柄 #ifdef DEBUG_PRINT
fprintf(stderr, "已複製 %d 字節\n", totalbytes);
#endif DEBUG_PRINT fclose(myself); //關閉最終合成文件句柄 if (totalbytes == 0)
{
free(buf);
MessageBox("分離文件中,在自身文件中沒有被分離的對象!","錯誤");
return;
} free(buf); //釋放緩衝區 //判斷前面讀取的最終文件執行標誌,來決定以何種方式運行它
if(!SyncFlag) //(0 -- 同步執行,1 -- 異步執行)
{
//置為分解後,為同步執行方式
Create_Process(temp_exe1, false);
Create_Process(temp_exe2, false);
}
else
{
//置為分解後,為異步執行方式
Create_Process(temp_exe1, true);
Create_Process(temp_exe2, true);
}
}
3、判斷何時捆綁程序,何時又分解最終合成程序。
由於本程序是將自身捆綁程序作為文件頭,要綁定文件附加其後方式生成最終合成文件的。所以,只要知道自身捆綁程序的文件長度,再在初始化對話框涵數OnInitDialog()加以判斷及可知道是否是最終合成文件(要不要釋放內部綁定文件)。本例程用VC6.0採用靜態連接方式生成的Release版,文件大小為184K。 故判斷是捆綁還是釋放文件的代碼具體實現如下:
BOOL CBindFileDlg::OnInitDialog()
{
CDialog::OnInitDialog(); // Add "About..." menu item to system menu. // IDM_ABOUTBOX must be in the system command range.
ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
ASSERT(IDM_ABOUTBOX < 0xF000); CMenu* pSysMenu = GetSystemMenu(FALSE);
if (pSysMenu != NULL)
{
CString strAboutMenu;
strAboutMenu.LoadString(IDS_ABOUTBOX);
if (!strAboutMenu.IsEmpty())
{
pSysMenu->AppendMenu(MF_SEPARATOR);
pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
}
} // Set the icon for this dialog. The framework does this automatically
// when the application''s main window is not a dialog
SetIcon(m_hIcon, TRUE); // Set big icon
SetIcon(m_hIcon, FALSE); // Set small icon //在此初始化漸變色進度條
m_Progress.SetRange32(1,500);
m_Progress.SetBkColor(RGB(160,180,220));
m_Progress.ShowPercent(true);
m_Progress.SetPos(500); //初始置各文件名變量為空
strFirstFilePath = ""; //要綁定第一個文件名
strSecondFilePath = ""; //要綁定第二個文件名
strFinalFilePath = ""; //最終合成文件名 //初始化變量
prog1_length = 0; //文件長度
his_name = ""; //綁定文件名
buf = NULL; //緩衝區置空
//獲取自身文件名到my_mane變量中
::GetModuleFileName(0, my_name, sizeof(my_name)); struct _stat ST;
_stat(my_name, &ST); //獲取自身文件訊息(長度)
//在此加入捆綁器程序的最終大小,來判斷是綁定文件還是分解執行文件
//當發現自身文件大小大於原大小184K時,為釋放內部合成文件
if(ST.st_size > 184*1024)
{
Unbind(); //分離文件並運行
exit(0); //直接退出程序,不顯示捆綁程序畫面
} return TRUE; // return TRUE unless you set the focus to a control
} 時間就是金錢
|
hua2000
中階會員 發表:102 回覆:200 積分:65 註冊:2006-11-04 發送簡訊給我 |
本站聲明 |
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。 2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。 3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇! |