線上訂房服務-台灣趴趴狗聯合訂房中心
發文 回覆 瀏覽次數:3404
推到 Plurk!
推到 Facebook!

[轉貼] 如何修改可執行檔案的圖示

 
axsoft
版主


發表:681
回覆:1056
積分:969
註冊:2002-03-13

發送簡訊給我
#1 引用回覆 回覆 發表時間:2002-07-10 14:23:34 IP:61.218.xxx.xxx 未訂閱

如何修改可執行文件的圖標

資料來源:《駭客人間》http://www.yu123.idv.tw/hackzone/board.php?boardid=4 作者:不詳 在網上有很多關於PE文件格式的說明,講得最多莫過於IMAGE_DOS_HEADER、IMAGE_NT_HEADERS、IMAGE_SECTION_HEADER、等。而對於節的介紹最多的,也莫過於函數引入引出節。而關於資源節.rsrc的介紹則少之又少。好了,廢話少說。 PE文件格式如下﹕ 對於PE的詳細介紹在MSDN中也有,鄒丹(www.zaodan.com)與羅大俠(asm.yeah.net)的主頁上也有細詳的介紹。這裡我在修改ICON中的一種做法。講解中所用到的語句並不全面,重要的是這個思路。最後面我會給出一個直修改資源的函數。 首先,我們需要兩個可執行文件,並且已知這兩個exe文件都有圖標資源。 1、 peSource.exe (從此文件中提取圖標) 2、 peDesc.exe (將圖標寫入此文件) 第二部,分別打開這兩個文件,hFileSource設為只讀,hFileDesc設為可寫。 HANDLE hFileSource; HANDLE hFileDesc; 打開後,大家最常用的莫過於文件映射,這裡為方便與直觀,我們直接把文件讀到一個內存塊中。 //先得到長度 DWORD dwSourceSize =::GetFileSize(hFileSource); DWORD dwDescSize =::GetFileSize(hFileDesc); DWORD byte_write=0; //讀取 char *pFileSource =new char[dwSourceSize]; char *pFileDesc =new char[dwDescSize]; ::ReadFile(hFileSource,pFileSource,dwSourceSize,&byte_write,0); ::ReadFile(hFileDesc,pFileDesc,dwDescSize,&byte_write,0); 好了,現在我們已經分別將兩個文件讀入內存中。讓我們先將pFileSource指到資源節的頭部。Section的結構說明如下﹕ typedef struct _IMAGE_SECTION_HEADER { BYTE Name[IMAGE_SIZEOF_SHORT_NAME]; union { DWORD PhysicalAddress; DWORD VirtualSize; } Misc; DWORD VirtualAddress; DWORD SizeOfRawData; DWORD PointerToRawData; DWORD PointerToRelocations; DWORD PointerToLinenumbers; WORD NumberOfRelocations; WORD NumberOfLinenumbers; DWORD Characteristics; } IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER; 通常情況,資源節的名稱一般都為﹕.rsrc。目前我們只考慮這種情況。 IMAGE_DOS_HEADER *dosHeadA=(IMAGE_DOS_HEADER *)pFileSource; //DOS頭 IMAGE_NT_HEADERS *ntHeadA=(IMAGE_NT_HEADERS *) (pFileSource dosHeadA->e_lfanew); //NT頭 IMAGE_SECTION_HEADER *secHeadA=(IMAGE_SECTION_HEADER *)((char *)ntHeadA sizeof(IMAGE_NT_HEADERS)); //第一個節的首位址 //循環找出.rsrc節 for(int i=0;iFileHeader .NumberOfSections ;i ,secHeadA ){ if(strcmp((char *)secHeadA->Name,".rsrc")==0){ //找到.rsrc節 break; } } 好了,現在我們已經找到.rsrc節表。根據節表,我們就可以找到資源的入口位址。 IMAGE_RESOURCE_DIRECTORY *dirResourceA=(IMAGE_RESOURCE_DIRECTORY *)((char *)pFileSource secHeadA->PointerToRawData); //得到資源入口位址 到這裡,我才開始講到我們今天的目的----資源結構,下面有幾個需要用到的結構與相關的解釋﹕ // Resource Format. // // // Resource directory consists of two counts, following by a variable length // array of directory entries. The first count is the number of entries at // beginning of the array that have actual names associated with each entry. // The entries are in ascending order, case insensitive strings. The second // count is the number of entries that immediately follow the named entries. // This second count identifies the number of entries that have 16-bit integer // Ids as their name. These entries are also sorted in ascending order. // // This structure allows fast lookup by either name or number, but for any // given resource entry only one form of lookup is supported, not both. // This is consistant with the syntax of the .RC file and the .RES file. // typedef struct _IMAGE_RESOURCE_DIRECTORY { //資源樹結構 DWORD Characteristics; //標識此資源的類型 DWORD TimeDateStamp; WORD MajorVersion; WORD MinorVersion; WORD NumberOfNamedEntries; WORD NumberOfIdEntries; //此結構下還包函有的資源結構樹,即﹕還有幾個子樹。 // IMAGE_RESOURCE_DIRECTORY_ENTRY DirectoryEntries[]; //請注意這裡,下面還會講到。 } IMAGE_RESOURCE_DIRECTORY, *PIMAGE_RESOURCE_DIRECTORY; 此結構的其他解釋請見VC的頭文件winnt.h. 整個資源的結構就好像一棵樹型,不同資源如﹕menu,icon,dialog,cursor等。都如同每根樹枝,樹枝的Characteristics會標識不同的資源類型,而每根樹枝又會有子樹枝。這樣一直循環,直到IMAGE_RESOURCE_DIRECTORY的NumberOfIdEntries為零時才結束。通常情況,子樹都為為三層。每一個子樹的類型由IMAGE_RESOURCE_DIRECTORY中的Characteristics來標識。如﹕當第一層的Characteristics==3時,則說明此結構為ICON資源。Characteristics類型定義如下(可在winuser.h中找到)﹕ /* * Predefined Resource Types */ #define RT_CURSOR MAKEINTRESOURCE(1) #define RT_BITMAP MAKEINTRESOURCE(2) #define RT_ICON MAKEINTRESOURCE(3) #define RT_MENU MAKEINTRESOURCE(4) #define RT_DIALOG MAKEINTRESOURCE(5) #define RT_STRING MAKEINTRESOURCE(6) #define RT_FONTDIR MAKEINTRESOURCE(7) #define RT_FONT MAKEINTRESOURCE(8) #define RT_ACCELERATOR MAKEINTRESOURCE(9) #define RT_RCDATA MAKEINTRESOURCE(10) #define RT_MESSAGETABLE MAKEINTRESOURCE(11) 總結構如下(偷懶,copy而來)﹕ 好了,整個資源的結構已經弄清楚了。現在我們要做的就是得到每個子資源的入口位址。這裡要用到的一個結構是﹕ // Each directory contains the 32-bit Name of the entry and an offset, // relative to the beginning of the resource directory of the data associated // with this directory entry. If the name of the entry is an actual text // string instead of an integer Id, then the high order bit of the name field // is set to one and the low order 31-bits are an offset, relative to the // beginning of the resource directory of the string, which is of type // IMAGE_RESOURCE_DIRECTORY_STRING. Otherwise the high bit is clear and the // low-order 16-bits are the integer Id that identify this resource directory // entry. If the directory entry is yet another resource directory (i.e. a // subdirectory), then the high order bit of the offset field will be // set to indicate this. Otherwise the high bit is clear and the offset // field points to a resource data entry. // typedef struct _IMAGE_RESOURCE_DIRECTORY_ENTRY { union { struct { DWORD NameOffset:31; DWORD NameIsString:1; }; DWORD Name; WORD Id; }; union { DWORD OffsetToData; //指向資源的入口址 struct { DWORD OffsetToDirectory:31; DWORD DataIsDirectory:1; //指向下一級目錄的相對位址 }; }; }IMAGE_RESOURCE_DIRECTORY_ENTRY, *PIMAGE_RESOURCE_DIRECTORY_ENTRY; 上面對IMAGE_RESOURCE_DIRECTORY_ENTRY的解釋也已經是非常清楚了。 結構中有兩個成員﹕OffsetToData,DataIsDirectroy,當DiataIsDirectroy大於0時,則說明此結構還有下一級目錄,否則,OffsetToData肯定不為0。那OffsetToData的值就是我們所得到的資源入口的RVA了。 那麼,IMAGE_RESOURCE_DIRECTORY_ENTRY結構應該怎麼得到呢?讓我們再看一下,IMAGE_RESOURCE_DIRECTORY的結構說明吧。 typedef struct _IMAGE_RESOURCE_DIRECTORY { //資源樹結構 DWORD Characteristics; //標識此資源的類型 DWORD TimeDateStamp; WORD MajorVersion; WORD MinorVersion; WORD NumberOfNamedEntries; WORD NumberOfIdEntries; // 、、//IMAGE_RESOURCE_DIRECTORY_ENTRY DirectoryEntries[]; //緊跟在後面的就是 IMAGE_RESOURCE_DIRECTORY_ENTRY結構數組,DirectoryEntries數組的個數實際上也就是NumberOfIdEntries.你也可以理解為 IMAGE_RESOURCE_DIRECTORY_ENTRY DirectoryEntries[NumberOfIdEntries];, } IMAGE_RESOURCE_DIRECTORY, *PIMAGE_RESOURCE_DIRECTORY; 那這樣一看來,IMAGE_RESOURCE_DIRECTORY_ENTRY的第一個位址等於父樹位址加上IMAGE_RESOURCE_DIRECTORY結構的大小即可。 如﹕IMAGE_RESOURCE_DIRECTORY *dirTempB=(IMAGE_RESOURCE_DIRECTORY *)((char *)dirResourceB entryResourceB->OffsetToDirectory); 最後一個是IMAGE_RESOURCE_DATA_ENTRY結構,比較簡單,大家看一下就知道了。 // Each resource data entry describes a leaf node in the resource directory // tree. It contains an offset, relative to the beginning of the resource // directory of the data for the resource, a size field that gives the number // of bytes of data at that offset, a CodePage that should be used when // decoding code point values within the resource data. Typically for new // applications the code page would be the unicode code page. // typedef struct _IMAGE_RESOURCE_DATA_ENTRY { DWORD OffsetToData; DWORD Size; DWORD CodePage; DWORD Reserved; } IMAGE_RESOURCE_DATA_ENTRY, *PIMAGE_RESOURCE_DATA_ENTRY; 好了,講了這麼多,現在我們可以開始計算了,(我們以讀取第三層第一個ICON為例<通常資源都為三層>)﹕ 前面我們已經得到根資源的位址﹕dirResourceA IMAGE_RESOURCE_DIRECTORY *dirResourceA=(IMAGE_RESOURCE_DIRECTORY *)((char *)pFileA secHeadA->PointerToRawData); //根 IMAGE_RESOURCE_DIRECTORY_ENTRY *entryResourceA=(IMAGE_RESOURCE_DIRECTORY_ENTRY *)((DWORD)dirResourceA sizeof (IMAGE_RESOURCE_DIRECTORY)); IMAGE_RESOURCE_DIRECTORY *dirTemp; //第二層 IMAGE_RESOURCE_DIRECTORY_ENTRY *entryTemp; IMAGE_RESOURCE_DIRECTORY *dirTempICON; //第三層 IMAGE_RESOURCE_DIRECTORY_ENTRY *entryTempICON; IMAGE_RESOURCE_DATA_ENTRY *entryData; //資源入口結構 for(i=0;i<(dirResourceA->NumberOfIdEntries dirResourceA->NumberOfNamedEntries);i ,entryResourceA ){ //所有資源 if(entryResourceA->Name==3){ //ICON dirTemp=(IMAGE_RESOURCE_DIRECTORY *)((char *)dirResourceA entryResourceA->OffsetToDirectory); entryTemp=(IMAGE_RESOURCE_DIRECTORY_ENTRY *)((char *)dirTemp sizeof(IMAGE_RESOURCE_DIRECTORY)); for(int k=0;k<(dirTemp->NumberOfIdEntries dirTemp->NumberOfNamedEntries);k ,entryTemp ){ //子目錄 if(entryTemp->DataIsDirectory >0){ //還有子目錄 dirTempICON=(IMAGE_RESOURCE_DIRECTORY *)((char *)dirResourceA entryTemp->OffsetToDirectory ); entryTempICON=(IMAGE_RESOURCE_DIRECTORY_ENTRY *)((char *)dirTempICON sizeof(IMAGE_RESOURCE_DIRECTORY)); entryData=(IMAGE_RESOURCE_DATA_ENTRY *)((char *)dirResourceA entryTempICON->OffsetToData ); //資源入口結構 break; //得到後跳出 } } } } 最後,讀入內存中﹕ DWORD dwIconSize=entryDataA->Size; char *pSrcIcon=entryDataA->OffsetToData - secHeadA->VirtualAddress (char *)dirResourceA; char *pSourceIcon= new char[dwIconSize 1]; memcpy(pSourceIcon,pSrcIcon,dwIconSize); 最後得到的資料就在pSourceIcon中了。 同理,得到另一個文件中的ICON入口位址,用pSourceIcon覆蓋之即可。 函數位址﹕http://go3.163.com/antghazi/main3.htm 時間就是金錢
系統時間:2024-04-26 17:03:08
聯絡我們 | Delphi K.Top討論版
本站聲明
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。
2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。
3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇!