在2002年剛學VC的時候寫過文件捆綁工具,當時是配合自己寫的一個QQ木馬使用。後來去年在某個論壇上有人問起了文件捆綁的事,我就翻出以前的程序,寫下了這篇文檔,今天整理硬盤的時候,把這文章發了上來,其實很簡單。
文件捆綁可以用在很多地方,比如木馬。也可以在發行軟件的時候把DLL捆綁在EXE文件後面,然後在EXE執行的時候動態調用DLL等等。。
編譯環境:WIN2K+VC6。
先假設我們要把 test1.exe和test2.exe這兩個文件捆綁成target.exe這一個文件,然後在運行target.exe的時候實現同時運行test1.exe和test2.exe。
提一個小常識,PE格式的文件只要不修改文件頭和文件中間的內容,而只是在文件末尾添加數據,那麼這個PE文件可以正常執行。你可以試一試在命令行方式下執行copy
test1.exe+test2.exe,命令執行完成後,test2.exe被添加到test1.exe文件尾,執行合並後的test1.exe雖然正常,但是test2.exe得不到執行。OK,這就是我們今天要解決的問題。我的想法是這樣的。把三個文件捆綁在一起,捆綁後target.exe實際包含三個文件,其中aaa.exe是我們自己寫的程序,test1.exe和test2.exe是我們要捆綁的程序。
結構如下
---------------------------------------
|aaa.exe|test1.exe|test2.exe|
---------------------------------------
整個文件就叫target.exe,如果結構如上所示,那麼我們執行target.exe的時候實際上只有aaa.exe才會得到執行,這裡的aaa.exe是我們自己寫的,我們就讓aaa.exe多做點事,他要做的事就是:1、把test2.exe讀出來另存為c:\test2.exe,把test1.exe的內容讀出來另存為c:\test1.exe。2、調用CreateProcess來創建兩個新進程運行test1.exe和test2.exe。3、調用ExitProcess結束自身的進程。
這樣一來我們的目的就達到了。同時為了隱蔽起見,我們可以把aaa.exe的窗口界面不顯示出來。
但是又有一個問題,讀取的時候怎樣才能分辨出哪一段數據是test1.exe,哪一段數據是test2.exe?那我們就再想辦法把上面的結構再擴充一下。
-----------------------------------------------------
|aaa.exe|test1.exe|test2.exe|len2|len1|
-----------------------------------------------------
在文件最後面再加兩段數據,分別用來存放test1.exe的文件長度和test2.exe的文件長度。並且固定len2和len1為30字節的長度。這樣在aaa.exe得到執行的時候先後面的兩個30字節內容,內容就是兩個文件的長度,再根據這兩個長度就可以准確讀取到test1.exe和test1.exe的內容。
看看aaa.exe程序的關鍵代碼:
CFile fSource(_pgmptr,CFile::modeRead | CFile::modeNoTruncate);
//得到target.exe的文件長度
int iSourceLength = fSource.GetLength();
fSource.Seek(iSourceLength-60,CFile::begin);//移動文件指針到第test2.exe文件的末尾
char buffer[40];
ZeroMemory(buffer,40);
fSource.Read(buffer,30);//讀取第len2的內容,也就是test2.exe的長度
int iTargetLength = atoi(buffer);
fSource.Seek(iSourceLength-iTargetLength-60,CFile::begin);//移動文件指針到test2.exe文件的開頭
CFile fTarget("c:\\test2.exe",CFile::modeCreate | CFile::modeWrite
|
CFile::modeNoTruncate);//創建一個新文件為c:\\test2.exe
char *pBuffer = new char[iTargetLength];//分配緩沖區
ZeroMemory(pBuffer,iTargetLength);
fSource.Read(pBuffer,iTargetLength);//將第test2.exe文件讀到緩沖區
fTarget.Write(pBuffer,iTargetLength);//將緩沖區內容寫入c:\test2.exe
delete []pBuffer;
好了,現在test2.exe文件已經讀出來了,接下來就是要讀test1.exe的內容,過程大同小異
fSource.Seek(iSourceLength-30,CFile::begin);//將文件指針移動到len1的開頭
ZeroMemory(buffer,40);
fSource.Read(buffer,30);//讀取len1的內容,len1的內容是test1.exe文件的長度
int filelen = atoi(buffer);
fSource.Seek(iSourceLength-60-filelen-iTargetLength,CFile::begin);//將文件指針移動到test1.exe文件頭
fTarget.Open("c:\\test2.exe",CFile::modeCreate | CFile::modeWrite
| CFile::modeNoTruncate);
pBuffer = new char[filelen];
ZeroMemory(pBuffer,filelen);
fSource.Read(pBuffer,filelen);//將test1.exe文件讀到緩沖區
fTarget.Write(pBuffer,filelen);//將test1.exe文件寫入c:\test1.exe
delete []pBuffer;
fSource.Close();
fTarget.Close();
現在我們就用CreateProcess來運行創建兩個新進程就可以運行c:\test1.exe和c:\test2.exe了。創建新進程的代碼很簡單我就不寫了。
這部分是寫完了,但是我們捆綁文件的部分還沒寫完,重新新建一個基於對話框的程序。
CFile fSource("c:\\aaa.exe",CFile::modeReadWrite | CFile::modeNoTruncate);
//就是上面我們寫的aaa.exe
fSource.SeekToEnd();//移動文件指針到文件尾
CFile fFirstFile(m_FirstFile,CFile::modeRead | CFile::modeNoTruncate);
//這段代碼是把test1.exe添加到aaa.exe尾部
int ilen = fFirstFile.GetLength();
int len = ilen;
char *pBuffer = new char[ilen];
ZeroMemory(pBuffer,ilen);
fFirstFile.Read(pBuffer,ilen);
fSource.Write(pBuffer,ilen);
fFirstFile.Close();
delete pBuffer;
CFile fSecondFile(m_SecondFile,CFile::modeRead | CFile::modeNoTruncate);
//這段代碼是捆綁test2.exe的
ilen = fSecondFile.GetLength();
pBuffer = new char[ilen];
ZeroMemory(pBuffer,ilen);
fSecondFile.Read(pBuffer,ilen);
fSource.Write(pBuffer,ilen);
fSecondFile.Close();
delete pBuffer;
char tempbuffer[30];//將test2.exe的長度轉換成字符串,如果長度不夠30就添加空格至30,再添加到文件尾部
ZeroMemory(tempbuffer,30);
itoa(ilen,tempbuffer,10);
while (strlen(tempbuffer) < 30)
{
strcat(tempbuffer," ");
}
fSource.Write(tempbuffer,30);
ZeroMemory(tempbuffer,30);//將test2.exe的長度轉換成字符串,如果長度不夠30就添加空格至30,再添加到文件尾部
itoa(len,tempbuffer,10);
while (strlen(tempbuffer) < 30)
{
strcat(tempbuffer," ");
}
fSource.Write(tempbuffer,30);
fSource.Close();
::MessageBox(NULL,"捆綁完成","提示",MB_ICONINFORMATION);
OK,這樣我們就生成了一個新文件target.exe,這個target.exe的結構上面已經說了。執行target.exe後,aaa.exe首先得到執行,然後test1.exe和test2.exe都會執行。為了增強隱蔽性,我們在aaa.exe的OnInitDialog()函數裡寫下如下代碼:
ModifyStyleEx(WS_EX_APPWINDOW, WS_EX_TOOLWINDOW);
::MoveWindow(m_hWnd,0,0,0,0,TRUE);
這樣aaa.exe執行的時候沒窗口,也不會在任務欄上顯示任務條。