天天看點

vc編譯exe檔案之體積極速優化

人們都說vc做出的東西可以小點,現在你打開vc編譯一個Hello World出來!點屬性看下,咦!我沒走眼吧,就一Hello World就160kb真是要人命啊! 呵呵!上面的情況是筆者所遭遇的情況.不過後來了解vc可以通過設定參數來自定義編譯方式.為什麼檔案那麼大!主要是編譯器加入了很多沒必要的代碼(這裡是對我們而言,不過有些代碼還是有利于安全的).好了我們就手動改下編譯器的參數來看看能到多大!

我們主要用到的技巧有:

一,使用release版而不用debug版編譯

使用debug版編譯會生成許多垃圾資訊.我們先使用預設的設定進行一下編譯.可以看到編譯後生成的檔案有152k之巨.使用release版編譯具體方法是:在"build(編譯)--->Configuration(配置)"中将"Win32 debug"移去,然後再次編譯可以發現檔案已經小了很多,才24k.但離我們的目标還很遠呢.

二,設定自己的入口點函數

C或C++程式預設的入口函數是main()或WinMain(),但我們現在不用什麼Main,WinMain.因為這些都不是直接的入口點,編譯器在産生exe檔案的時候,将為我們生成真正的入口點.下面我們來定義自己的入口函數,具體是把main或WinMain改成其它的名字(如MyFun),打開"Project(工程)--->settings(設定)"選項,選中"link"頁籤,在"Category(分類)"下拉清單中選"output",在" Entry-Point symbol(輸入項-點符号)"中輸入我們剛才定義的入口函數(MyFun),在源程式中也要做相應修改,然後再編譯.現在是16k了:)

三,更改編譯對齊方式

通常VC在編譯的時候,采用的對齊方式是0x1000,即4096bytes,我們現在将他改成0x200,即512bytes.

在剛才打開的"link"頁籤,在下面的"Project options(工程選項)"中添加:/align:512(還可以将512設

置的更小如16,32.....).注意兩個參數之間有個空格. 3k了^_^用32試試 1.84k好~~~用16 1.79k天哪!

再把程式的資料段和代碼段放在一起,添加:/merge.data=.text /merge:.rdata=.text 1.76k go on!

另外,如果要是用到MFC函數的程式,可在"Project(工程)--->settings(設定)"裡面的"通用(General)"頁籤中在"Microsoft Foundation Classes"中選擇使用一個MFC的dll(Use MFC in a Share Dll)也會使檔案大小縮小很多.現在我們的超小後門編譯好了,試下能用否. ok 沒問題哦

大家注意到程式運作時會産生一個cmd視窗,要讓他沒有就好了.這也好辦.

回到VC++中,在"Project(工程)--->settings(設定)"選項,選中"link"頁籤,在下面的"Project options(工程選項)"有/subsystem:console選項,表示程式是控制台程式,輕按兩下運作是會有一個cmd視窗,把console改為windows就沒有視窗了.:),運作一下 沒有視窗哦 但有程序 連接配接一下試試

// 編譯器 cl.exe(Visual C++ 6.0)
 // 沒有做任何優化情況下,編譯大小為:16K
 // 編譯優化後: 1K (用16進制編輯器把尾部的0x00去掉: 712bytes)
 #include 
 #pragma comment(lib,"kernel32.lib")// 作用: 指定節對齊為512位元組
 #pragma comment(linker, "/align:512")// 作用: 合并節
 // 将.data節和.rdata節合并到.text節(代碼節)
 #pragma comment(linker, "/merge:.data=.text")
 #pragma comment(linker, "/merge:.rdata=.text")// 作用: 指定子系統為windows (和優化無關)
 // vc編譯器預設是console,會有個黑糊糊的CMD視窗,不好看.用windows就好了
 #pragma comment(linker, "/subsystem:windows")// 作用: 指定入口函數
 // 子系統為windows的預設入口點WinMain和console的預設入口點main,都會引入#pragma comment(linker, "/ENTRY:main")
//int WinMain(HINSTANCE current, HINSTANCE prev, LPSTR cmdline, int
 //showcmd)// 作用: 去掉函數的棧幀代碼,純屬吹毛求疵:-)
 // 即函數開頭的push ebp / mov ebp, esp和結尾的pop ebp / retn
 __declspec(naked)
 void main()
 {
 // 調用wmp. 這是按套路出牌的方法.
 //typedef VOID (__stdcall *fnRunDllW)(HWND, HINSTANCE, LPCWSTR, DWORD);
 //((fnRunDllW)GetProcAddress(LoadLibrary("msdxm.ocx"), "RunDllW"))(0,0,0,0);// 不按套路出牌,不壓入RunDllW的函數參數,直接調用.
 //GetProcAddress(LoadLibrary("msdxm.ocx"), "RunDllW")();
 MessageBox(0,0,0,0);
 // 注意此時的堆棧是不平衡的.
 // 但是通過ExitProcess()退出自身,就不用去考慮平衡了.
 ExitProcess(0);
 }      

繼續閱讀