• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            aurain
            技術文摘
            posts - 137,  comments - 268,  trackbacks - 0
            來源:安全中國

            零 前言

                PE格式,是Windows的可執行文件的格式。Windows中的 exe文件,dll文件,都是PE格式。PE 就是Portable Executable 的縮寫。Portable 是指對于不同的Windows版本和不同的CPU類型上PE文件的格式是一樣的,當然CPU不一樣了,CPU指令的二進制編碼是不一樣的。只是文件中各種東西的布局是一樣的。

             

            圖 1.1

                圖1.1是 JIURL PEDUMP 打開 Win2K 中的 explorer.exe 的截圖。JIURL PEDUMP 是我寫的一個小工具,從文件開始的 Dos Header 一直到 Section Table,打開PE文件之后,點擊相應結構,就會高亮顯示文件中相應的部分。不過沒有Sections。對了解 PE 格式有所幫助,可以很好的配合后面的介紹。可以到我的主頁 http://jiurl.yeah.net/ 上下載。

            一   PE文件格式概述

            PE文件結構的總體層次分布如下所示

             --------------
            |DOS MZ Header |
            |--------------|
            |DOS Stub      |
            |--------------|
            |PE Header     |
            |--------------|
            |Section Table |
            |--------------|
            |Section 1     |
            |--------------|
            |Section 2     |
            |--------------|
            |Section ...   |
            |--------------|
            |Section n     |
             --------------

             

            1.1 DOS Header

                PE文件最開始是一個簡單的 DOS MZ header,它是一個 IMAGE_DOS_HEADER 結構。有了它,一旦程序在DOS下執行,DOS就能識別出這是有效的執行體,然后運行緊隨 MZ Header 之后的 DOS Stub。

             1.2  DOS Stub   

                DOS Stub 是一個有效的 DOS 程序。當程序在DOS下運時,輸出象 "This program cannot be run in DOS mode" 這樣的提示。在 圖1.1中就可以看到字符串 "This program cannot be run in DOS mode"。這是編譯器生成的默認stub程序。你也可以通過鏈接選項 /STUB:filename 指定任何有效的MS-DOS可執行文件來替換它。

            1.3 PE Header

                緊接著 DOS Stub 的是 PE Header。它是一個 IMAGE_NT_HEADERS 結構。其中包含了很多PE文件被載入內存時需要用到的重要域。執行體在支持PE文件結構的操作系統中執行時,PE裝載器將從 DOS MZ header 中找到 PE header 的起始偏移量。因而跳過了 DOS stub 直接定位到真正的文件頭 PE header。

            1.4 Section Table

                PE Header 接下來的數組結構 Section Table (節表)。如果PE文件里有5個節,那么此 Section Table 結構數組內就有5個成員,每個成員包含對應節的屬性、文件偏移量、虛擬偏移量等。圖1中的節表有4個成員。

            1.5 Sections

                PE文件的真正內容劃分成塊,稱之為sections(節)。Sections 是以其起始位址來排列,而不是以其字母次序來排列。通過節表提供的信息,我們可以找到這些節。圖1.1所示的 explorer.exe 中有4個節。程序的代碼,資源等等就放在這些節中。

            二  PE文件格式中的結構及其作用

            這部分內容請參考下面的幾篇文章,使用工具 JIURL PEDUMP 有助于快速了解。
            大家不要因此,而失望不看,本文重點在后三篇,本篇只是為了有個交代,和介紹些相關內容。
            注意,在WINNT.H中,有所有PE相關結構的定義。我們用到的結構定義都來自那里。

            Microsoft Portable Executable and Common Object File Format Specification
            MSDN 

            《Windows95系統程式設計大奧秘》
            第8章 PE 與COFF OBJ 檔案格式
            Matt Pietrek 著 侯杰譯

            Iczelion的PE教程

            PE學習筆記(一) rivershan
            PE學習筆記(二) rivershan

            Inside Windows 
            An In-Depth Look into the Win32 Portable Executable File Format 
            Matt Pietrek 
            已經被人翻譯了。

            Inside Windows 
            An In-Depth Look into the Win32 Portable Executable File Format 
            Matt Pietrek

            三 幾個要注意的問題

            3.1 文件中大量的空白

                在 PE Header結構 中的 OptionalHeader 結構中的成員 FileAlignment 的值是文件中節的對齊粒度,單位是字節,這個值應該是2的n次方,范圍從512到64k。如果這里的值是512,那么PE文件中的節的長度都是512字節的整數倍,內容不夠的部分用0填充。比如一個PE文件的 FileAlignment 為200h(十進制512),它的第一個節在400h處,長度為100h,那么從文件400h到500h中為這一節的內容,而文件對齊粒度是200h,所以為了使這一節長度為FileAlignment的整數倍,500h到600h會被用零填充。而下一個節的開始地址為600h。用16進制編輯器打開PE文件,就可以看到這種情況,PE文件頭的內容結束到第一個節開始之間的地方,每一個節中內容結束到下一節開始的地方都會有大量的空白。VC6編譯鏈接時默認的FileAlignment為1000h(4k),可以使用鏈接選項 /ALIGN:number 來改變這個值。比如把4k改成512時,可以明顯減小生成文件的大小。

            3.2 big-endian和little-endian

                PE Header中的 FileHeader 的成員 Machine 中的值,根據WINNT.H中的定義,對于 Intel CPU 應該為 0x014c。但是你用16進制編輯器打開PE文件,看到這個WORD顯示的卻是 4c 01 。你看到的并沒有錯,你看到的 4c 01 就是 0x014c,只不過由于 intel cpu 是ittle-endian,所以顯示出來是這樣的。對于 big-endian 和 little-endian,請看下面的例子。

            比如一個整形int變量。長為四個字節。
            這個變量的地址比如為n。
            則這個變量的4個字節地址分別為n,n+1,n+2,n+3。

            當 這個整形變量 的值為 0x12345678 時,

            對于 big-endian 來說
            地址n+0的那個字節中的值為 0x12
            地址n+1的那個字節中的值為 0x34
            地址n+2的那個字節中的值為 0x56
            地址n+3的那個字節中的值為 0x78

            按如下方式就會顯示為
            n n+1 n+2 n+3 
            12 34 56 78

            對于 ittle-endian 來說
            地址n+0的那個字節中的值為 0x78
            地址n+1的那個字節中的值為 0x56
            地址n+2的那個字節中的值為 0x34
            地址n+3的那個字節中的值為 0x12

            按如下方式就會顯示為
            n n+1 n+2 n+3 
            78 56 34 12

            Intel使用的是 ittle-endian 。

            一個整形 int 變量 i,的地址是&i,那么這個i的四個字節是&i,&i+1,&i+2,&i+3。
            可以用這樣一個程序看到。

            #include <stdio.h>
            #include <conio.h>

            void main()
            {
            int i;
            char* p;
            p=(char*)&i;

            printf("i: ");
            scanf("%x",&i);
            printf("\n");

            printf("&i+0: %x\n",*p);
            printf("&i+1: %x\n",*(p+1));
            printf("&i+2: %x\n",*(p+2));
            printf("&i+3: %x\n",*(p+3));

            printf("\n");
            printf("&i-4: %x\n",*(p-4));
            printf("&i-3: %x\n",*(p-3));
            printf("&i-2: %x\n",*(p-2));
            printf("&i-1: %x\n",*(p-1));

            printf("\n");
            printf("&i+4: %x\n",*(p+4));
            printf("&i+5: %x\n",*(p+5));
            printf("&i+6: %x\n",*(p+6));
            printf("&i+7: %x\n",*(p+7));

            getch();

            }

            當我們輸入 12345678 的時候可以看到,輸出

            i: 12345678

            &i+0: 78
            &i+1: 56
            &i+2: 34
            &i+3: 12

            &i-4: 7c
            &i-3: ffffffff
            &i-2: 12
            &i-1: 0

            &i+4: ffffffc0
            &i+5: ffffffff
            &i+6: 12
            &i+7: 0
            正是&i,&i+1,&i+2,&i+3這四個字節中儲存了i的值。

            對于int,WORD,DWORD等等都要注意 big-endian 和 little-endian 。

            3.3 RVA (Relative Virtual Address) 相對虛擬地址

                RVA是一個簡單的相對于PE載入點的內存偏移。比如,PE載入點為0X400000,那么代碼節中的地址0X401000的RVA為(target address) 0x401000 - (load address)0x400000 = (RVA)0x1000.換句話說 RVA是0x1000,載入點為0X400000,那么該RVA的在內存中的實際地址就是0X401000。注意一下RVA是指內存中,不是指文件中。是指相對于載入點的偏移而不是一個內存地址,只有RVA加上載入點的地址,才是一個實際的內存地址。

            3.4 三種不同的地址

                PE的各種結構中,涉及到很多地址,偏移。有些是指在文件中的偏移,有的是指在內存中的偏移。一定要搞清楚,這個地址或者是偏移,是指在文件中,還是指在內存中。第一種,文件中的地址。比如用16進制編輯器打開PE文件,看到的地址(偏移)就是文件中的地址,我們使用某個結構的文件地址,就可以在文件中找到該結構。第二種,文件被整個映射到內存時,比如某些PE分析軟件,把整個PE文件映射到內存中,這時是內存中的地址,如果知道某一個結構在文件中的地址的話,那么這個PE文件被映射到內存之后該結構的在內存中的地址,可以用文件中的地址加上映射內存的地址,就可以得到在該結構內存中的地址。第三種,執行PE時,PE文件會被載入器載入內存,這時經常需要的是RVA。比如知道一個結構的RVA,那么載入點加上RVA就可以得到內存中該結構的實際地址。比如,某個程序,我們用16進制編輯器打開它,看到PE Header開始在16進制編輯器顯示為000000C8的地方。于是我們在16進制編輯器顯示為000000FC的地方找到了OptionalHeader的ImageBase,值為400000h,那么當這個程序被執行時,如果內存中400000h處沒有使用,該程序就會被載入到那里。而我用CreateFileMapping將這個PE文件映射到內存中時,可以得到塊內存的地址為5505024。對于映射入內存的這個PE文件,我們就可以在內存中000000FCh+05505024h=5505120處找到這個PE的OptionalHeader的ImageBase。

            3.5 幾個重要結構的說明

            PE Header 的 FileHeader 的 NumberOfSections:這是一個很重要的字段,用來確定文件中節的數目。

            PE Header 的 OptionalHeader 的 IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
            #define IMAGE_NUMBEROF_DIRECTORY_ENTRIES 16
            DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]:一個IMAGE_DATA_DIRECTORY 結構數組。到目前為止這個數組的長度是固定的,有16個元素,這16個元素分別代表
            #define IMAGE_DIRECTORY_ENTRY_EXPORT 0 // Export Directory
            #define IMAGE_DIRECTORY_ENTRY_IMPORT 1 // Import Directory
            #define IMAGE_DIRECTORY_ENTRY_RESOURCE 2 // Resource Directory
            #define IMAGE_DIRECTORY_ENTRY_EXCEPTION 3 // Exception Directory
            #define IMAGE_DIRECTORY_ENTRY_SECURITY 4 // Security Directory
            #define IMAGE_DIRECTORY_ENTRY_BASERELOC 5 // Base Relocation Table
            #define IMAGE_DIRECTORY_ENTRY_DEBUG 6 // Debug Directory
            // IMAGE_DIRECTORY_ENTRY_COPYRIGHT 7 // (X86 usage)
            #define IMAGE_DIRECTORY_ENTRY_ARCHITECTURE 7 // Architecture Specific Data
            #define IMAGE_DIRECTORY_ENTRY_GLOBALPTR 8 // RVA of GP
            #define IMAGE_DIRECTORY_ENTRY_TLS 9 // TLS Directory
            #define IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG 10 // Load Configuration Directory
            #define IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT 11 // Bound Import Directory in headers
            #define IMAGE_DIRECTORY_ENTRY_IAT 12 // Import Address Table
            #define IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT 13 // Delay Load Import Descriptors
            #define IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR 14 // COM Runtime descriptor
            每個元素是一個IMAGE_DATA_DIRECTORY結構,IMAGE_DATA_DIRECTORY定義如下。
            typedef struct _IMAGE_DATA_DIRECTORY {
            DWORD VirtualAddress;
            DWORD Size;
            } IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;
            第一個字段是一個RVA,第二個字段是一個大小。

            Section Table 節表緊跟在OptionalHeader之后,是一個IMAGE_SECTION_HEADER結構的數組。該數組中成員的個數由 File Header (IMAGE_FILE_HEADER) 結構中 NumberOfSections 域的域值來定。節表中的成員是IMAGE_SECTION_HEADER 結構,IMAGE_SECTION_HEADER 結構的長度固定,長40個字節。整個Section Table 的長度不固定,等于 NumberOfSections*sizeof(IMAGE_SECTION_HEADER)。IMAGE_SECTION_HEADER 結構中,
            VirtualAddress:本節的RVA(相對虛擬地址)。
            PointerToRawData:這是本節基于文件的偏移量。

            3.6 DOS MZ Header 中的 MZ

                MZ是MZ格式的主要作者 Mark Zbikowski 的名字的縮寫。

            posted on 2009-06-29 13:45 閱讀(913) 評論(0)  編輯 收藏 引用 所屬分類: Windows開發

            <2008年8月>
            272829303112
            3456789
            10111213141516
            17181920212223
            24252627282930
            31123456

            常用鏈接

            留言簿(17)

            隨筆分類(138)

            隨筆檔案(137)

            網絡開發

            最新隨筆

            搜索

            •  

            積分與排名

            • 積分 - 497533
            • 排名 - 36

            最新隨筆

            最新評論

            閱讀排行榜

            評論排行榜

            亚洲国产一成久久精品国产成人综合| 国产精品久久久99| 久久天天日天天操综合伊人av| 久久男人AV资源网站| 久久人人爽人人精品视频| 久久精品卫校国产小美女| 色欲久久久天天天综合网精品| 久久综合中文字幕| 人妻无码中文久久久久专区| 久久综合伊人77777麻豆| 亚洲精品乱码久久久久久久久久久久 | 久久久婷婷五月亚洲97号色| 久久精品一区二区影院| 久久久91精品国产一区二区三区| 久久精品成人免费国产片小草| 日韩精品久久无码人妻中文字幕| 久久综合视频网站| 久久香蕉国产线看观看99| 久久人人爽人人爽人人片AV东京热 | 狠狠综合久久AV一区二区三区| 午夜精品久久久内射近拍高清| 国产激情久久久久影院小草 | 国产毛片久久久久久国产毛片| 久久亚洲精品人成综合网| 香蕉久久夜色精品国产尤物| 少妇久久久久久被弄到高潮| 精品一区二区久久| 伊人久久大香线焦综合四虎| 国产福利电影一区二区三区久久老子无码午夜伦不| 亚洲人AV永久一区二区三区久久| 一本色道久久88加勒比—综合| 久久99国产综合精品| 天天综合久久久网| 丁香狠狠色婷婷久久综合| 99re这里只有精品热久久| 久久综合给合久久狠狠狠97色69| 99蜜桃臀久久久欧美精品网站| 99久久免费国产精品特黄| 人妻精品久久久久中文字幕一冢本| 久久精品极品盛宴观看| 伊人色综合久久天天人守人婷|