將多個文件合並成一個最終可執行文件,運行這個最終合成文件後,就相當於運行了合並前的多個文件,這種程序在木馬或後門程序合並中會經常用到,你想知道它是怎麼用程序實現的麼?下面我就用VC6做的一個文件捆綁器的例子來告訴你。
其實文件捆綁器的構成思想非常簡單:合並文件時,建立一個新的二進制文件,先寫入你的自身捆綁程序的數據和文件長度,再寫入你要捆綁的第一個文件的數據和其文件長度,跟著寫入你要捆綁的第二個文件的數據和文件長度……最後直接寫入你要捆綁的最後一個文件的數據(不需其文件長度)。分解釋放最終合成文件時,將上面的方法倒過來既可:打開最終合成文件,讀取源自身捆綁程序文件長度,將文件指針移到自身捆綁程序數據後,讀取第一個被綁定文件的長度,接著讀取其長度的文件數據並寫入到一新建文件1中,再讀取第二個被綁定文件的長度,接著讀取其長度的數據並寫入到新建文件2中……直到最後直接讀取最後一個被綁定文件的數據並將其寫入到最後一個新建文件中既可(下面實例僅告訴你如何實現兩個文件的捆綁,至於多個文件的捆綁,讀者只需略加改動既可,詳情請查看配套光盤中的實例代碼。)
下面我來講講文件捆綁最核心的部分,以及如何具體將其用代碼來實現的方法(文章盡量采取行行注釋的方法,希望每個讀者朋友都能看懂)。 捆綁多個文件為一個可執行程序
先得到自身捆綁程序的文件長度和第一個要捆綁文件的文件長度,枚舉第一個要捆綁文件有無圖標,有的話就用它做為最終生成文件的圖標,否則用自身捆綁程序所帶默認圖標做最終生成文件的圖標。在新建二進制文件中寫入自身捆綁程序的數據和其文件長度,再寫入第一個要捆綁文件的數據及其文件長度,最後直接寫入第二個文件的數據既可。
下面是合並程序函數的具體代碼實現如下:
//定義要使用到的捆綁程序自身文件信息的結構體
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;
} 釋放最終合成文件
打開自身文件,從中得到自身捆綁程序的文件長度,便可將文件指針定位到第一個被捆綁文件的位置,讀取其文件長度和其數據,將讀出的數據寫入第一個新建文件中。同樣,通過已讀取的自身捆綁程序文件長度和第一個被捆綁文件的文件長度加上保存這兩個文件長度值的字節數,便可以准確定位第二個被捆綁文件的位置,讀取其數據,寫入到第二個新建文件中。同時,運行這兩個文件,最後再刪除這兩個文件既可。
釋放最終合成文件的代碼具體實現如下:
//創建分解文件後,運行各分解文件時的進程
void CBindFileDlg::Create_Process(const char* temp_exe, BOOL async)
{
HANDLE hProcess; //進程句柄
HANDLE hThread; //線程句柄
PROCESS_INFORMATION PI;