天天看點

手工構造典型PE檔案2

-->ASM

    00401000  6A 00         PUSH 0

    00401002  68 00304000   PUSH first_PE.00403000

    00401007  68 07304000   PUSH first_PE.00403007

    0040100C  6A 00         PUSH 0

    0040100E  E8 07000000   CALL <JMP.&user32.MessageBoxA>

    00401013  6A 00         PUSH 0

    00401015  E8 06000000   CALL <JMP.&kernel32.ExitProcess>

    0040101A  FF25 08204000 JMP DWORD PTR DS:[<&user32.MessageBoxA>]

    00401020  FF25 00204000 JMP DWORD PTR DS:[<&kernel32.ExitProcess>]

  4-2  .rdata (* 該區塊包含輸入表)

    4-2-1  IMAGE_THUNK_DATA32 (IAT 1)

    注釋:這裡有很多人都搞不明白,其實IMAGE_THUNK_DATA32是一個聯合體,可以同時代表IAT與INT。

      4-2-1-1 AddressOfData [DWORD] -->76 20 00 00 (* 指向IMAGE_IMPORT_BY_NAME的RVA)

      注釋:作為IAT時我們就會使用他的AddressOfData成員,用來存放指向IMAGE_IMPORT_BY_NAME的RVA,當程式裝入記憶體後,隻與IAT交換資訊,輸入表的其他部分就不再需要了。

      【由于本例子兩個API函數引自與兩個不同的DLL檔案,是以要補00000000h結束。】

       注釋:這裡同樣有很多人不明白,每當屬于某一個DLL檔案的API羅列完畢後,就要輸入00加以結束。

    4-2-3  IMAGE_IMPORT_DESCRIPTOR (IID 1)

    注釋:這裡稍微複雜些,它的作用就是使用INT指定某個DLL檔案中的API函數,并配合IAT指向相關API的位址。

      4-2-3-1 OriginalFirstThunk [DWORD] -->4C 20 00 00 (* 指向輸入名稱表INT的RVA)

      注釋:這裡指定某個系統DLL檔案中的API函數。

      4-2-3-4 Name  [DWORD] -->6A 20 00 00 (* 指向DLL名字的RVA與指針)

      注釋:這裡指定某個系統DLL檔案。

      4-2-3-5 FirstThunk  [DWORD] -->08 20 00 00 (* 指向輸入位址表IAT的RVA)

      注釋:這裡指定相關的IAT,并由IAT在IMAGE_IMPORT_BY_NAME中獲得相應API的位址。

    4-2-4  IMAGE_IMPORT_DESCRIPTOR (IID 2)

      4-2-4-1 OriginalFirstThunk [DWORD] -->54 20 00 00 (* 指向輸入名稱表INT的RVA)

      4-2-4-4 Name               [DWORD] -->84 20 00 00 (* 指向DLL名字的RVA與指針)

      4-2-4-5 FirstThunk         [DWORD] -->00 20 00 00 (* 指向輸入位址表IAT的RVA)

      【填充20個00h空位元組做結尾标記】

      注釋:關于填充20個位元組作為IID的結尾标記隻是一個規律,還沒找到相關資料證明。

    4-2-5  IMAGE_THUNK_DATA32 (INT 1)

      4-2-5-1  ForwarderString [DWORD] -->5C 20 00 00 (* 指向一個轉向字元的RVA)

      注釋:直接指向相關API函數。

      【由于本例子兩個API函數引自與兩個不同的DLL檔案,是以要補00000000h結束。】

       注釋:與上面的IAT原理一樣,就是這樣的一個格式。

    4-2-7  IMAGE_IMPORT_BY_NAME ( 1 )

      4-2-7-2  Name [BYTE] -->4D 65 73 73 61 67 65 42 6F 78 41 (* MessageBoxA的16進制碼)

      注釋:相關API函數的16進制代碼。

      【後跟輸出此函數的DLL名稱16進制碼00 75 73 65 72 33 32 2E 64 6C 6C 00 00 user32.dll】

      注釋:相關系統的API函數羅列完畢後,通常都在最後一個API後空00h,并跟着這個DLL名稱的16進制資料。

      總結:這裡羅列了一些需要手工建構的部分結構,如果想看更加詳細的請關注下面的内容。

三、PE檔案結構字段清單

1  DOS頭部

  1-1  DOS Header

    1-1-1   e_magic     [WORD]            -->4D 5A (* DOS可執行檔案頭标記)

    1-1-2   e_cblp        [WORD]              ->00 00 (檔案最後頁的位元組數)

    1-1-3   e_cp           [WORD]              ->00 00 (檔案頁數)

    1-1-4   e_crlc         [WORD]               ->00 00 (重定位元素個數)

    1-1-5   e_cparhdr  [WORD]               ->00 00 (以段落為機關的頭部大小)

    1-1-6   e_minalloc  [WORD]              ->00 00 (所需的最小附加段)

    1-1-7   e_maxalloc [WORD]               ->00 00 (所需的最大附加段)

    1-1-8   e_ss           [WORD]              ->00 00 (初始的堆棧段(SS)相對偏移量值)

    1-1-9   e_sp           [WORD]              ->00 00 (初始的堆棧指針(SP)值)

    1-1-10  e_csum     [WORD]               ->00 00 (校驗和)

    1-1-11  e_ip           [WORD]               ->00 00 (初始的指令指針(IP)值)

    1-1-12  e_cs          [WORD]               ->00 00 (初始的代碼段(CS)相對偏移量值)

    1-1-13  e_lfarlc      [WORD]               ->00 00 (重定位表在檔案中的偏移位址)

    1-1-14  e_ovno      [WORD]               ->00 00 (覆寫号)

    1-1-15  e_res         [WORD] 4 dup     ->00 00 (保留字,一般都是為確定對齊而預留)

    1-1-16  e_oemid     [WORD]              ->00 00 (OEM 辨別符,相對于 e_oeminfo)

    1-1-17  e_oeminfo  [WORD]              ->00 00 (OEM 資訊,即 e_oemid 的細節)

    1-1-18  e_res2       [WORD] 10 dup  ->00 00 (保留字,一般都是為確定對齊而預留)

    1-1-19  e_lfanew    [DWORD]          -->B0 00 00 00 (* 指向PE檔案頭的偏移量。0xB0=64+112)

  1-2  DOS Stub

    全部填00h

2  PE檔案頭

  2-1  "PE"00

    2-1-1  Signature [DWORD] -->50450000h (* PE檔案頭标記)

  2-2  IMAGE_FILE_HEADER

    2-2-1  Machine                        [WORD]    -->4C 01 (* 可執行檔案的目标CPU類型)

    2-2-2  NumberOfSections        [WORD]    -->03 00 (* 區塊數目)

    2-2-3  TimeDateStamp            [DWORD]   ->00 00 00 00 (檔案建立的時間與日期)

    2-2-4  PointerToSymbolTable [DWORD]   ->00 00 00 00 (指向符号表,用于調試)

    2-2-5  NumberOfSymbols        [DWORD]   ->00 00 00 00 (符号表中的符号個數,用于調試)

    2-2-6  SizeOfOptionalHeadr    [WORD]    -->E0 00 (* PE頭(IMAGE_OPTIONAL_HEADER32)大小)

    2-2-7  Characteristics              [WORD]    -->0F 01 (* 檔案屬性)

  2-3  IMAGE_OPTIONAL_HEADER32

    2-3-1   Magic                                       [WORD]     -->0B 01 (* 标記字)

    2-3-2   MajorLinkerVersion                  [BYTE]        ->00 (連接配接程式主版本号)

    2-3-3   MinorLinkerVersion                  [BYTE]        ->00 (連接配接程式次版本号)

    2-3-4   SizeOfCode                              [DWORD]   ->00 00 00 00 (所有含代碼區塊的總大小)

    2-3-5   SizeOfInitializedData                 [DWORD]   ->00 00 00 00 (所有初始化資料區塊大總大小)

    2-3-6   SizeOfUninitializedData             [DWORD]   ->00 00 00 00 (所有未初始化資料區塊大總大小)

    2-3-7   AddressOfEntryPoint                [DWORD]  -->00 10 00 00 (* 程式執行入口RAV)

    2-3-8   BaseOfCode                             [DWORD]   ->00 00 00 00 (代碼區塊起始RAV)

    2-3-9   BaseOfData                              [DWORD]   ->00 00 00 00 (資料區塊起始RAV)

    2-3-10  ImageBase                               [DWORD]  -->00 00 40 00 (* 程式預設裝入基位址)

    2-3-11  SectionAlignment                      [DWORD]  -->00 10 00 00 (* 記憶體中區塊對齊值)

    2-3-12  FileAlignment                            [DWORD]  -->00 02 00 00 (* 檔案中區塊對齊值)

    2-3-13  MajorOperatingSystemVersion [WORD]      ->00 00 (作業系統主版本号)

    2-3-14  MinorOperatingSystemVersion [WORD]      ->00 00 (作業系統次版本号)

    2-3-15  MajorImageVersion                   [WORD]      ->00 00 (使用者自定義主版本号)

    2-3-16  MinorImageVersion                   [WORD]      ->00 00 (使用者自定義次版本号)

    2-3-17  MajorSubsystemVersion           [WORD]     -->04 00 (* 運作所需最低子系統主版本号)

    2-3-18  MinorSubsystemVersion           [WORD]     -->00 00 (* 運作所需最低子系統次版本号)

    2-3-19  Win32VersionValue                  [DWORD]    ->00 00 00 00 (保留值,通常為0)

    2-3-20  SizeOfImage                             [DWORD]   -->00 40 00 00 (* 映像裝入記憶體後的總尺寸)

    2-3-21  SizeOfHeaders                         [DWORD]   -->00 04 00 00 (* DOS頭  PE頭  區塊表的總大小)

    2-3-22  CheckSum                                [DWORD]    ->00 00 00 00 (映像效驗和)

    2-3-23  Subsystem                                [WORD]     -->03 00 (* 檔案子系統)

    2-3-24  DllCharacteristics                      [WORD]      ->00 00 (顯示DLL特性的旗标)

    2-3-25  SizeOfStackReserve                 [DWORD]    ->00 00 00 00 (初始化堆棧總大小)

    2-3-26  SizeOfStackCommit                   [DWORD]   ->00 00 00 00 (初始化實際送出堆棧大小)

    2-3-27  SizeOfHeapReserve                  [DWORD]   ->00 00 00 00 (初始化保留堆棧大小)

    2-3-28  SizeOfHeapCommit                   [DWORD]   ->00 00 00 00 (初始化實際保留堆棧大小)

    2-3-29  LoaderFlags                              [DWORD]  ->00 00 00 00 (與調試相關,預設值為0)

    2-3-30  NumberOfRvaAndSizes             [DWORD] -->10 00 00 00 (* 資料目錄标的項數,預設總為16)

  2-4  資料目錄表

    2-4-1   Export Table

      2-4-1-1   VirtualAddress [DWORD]  ->00 00 00 00 (資料塊的起始RAV)

      2-4-1-2   Size                  [DWORD]  ->00 00 00 00 (資料塊的長度)

    2-4-2   Import Table

      2-4-2-1   VirtualAddress [DWORD] -->10 20 00 00 (* 資料塊的起始RAV)

      2-4-2-2   Size                 [DWORD] -->3C 00 00 00 (* 資料塊的長度)

    2-4-3   Resources Table

      2-4-3-1   VirtualAddress [DWORD]  ->00 00 00 00 (資料塊的起始RAV)

      2-4-3-2   Size                 [DWORD]  ->00 00 00 00 (資料塊的長度)

    2-4-4   Exception Table

      2-4-4-1   VirtualAddress [DWORD]  ->00 00 00 00 (資料塊的起始RAV)

      2-4-4-2   Size                  [DWORD]  ->00 00 00 00 (資料塊的長度)

    2-4-5   Security Table

      2-4-5-1   VirtualAddress [DWORD]  ->00 00 00 00 (資料塊的起始RAV)

      2-4-5-2   Size                  [DWORD]  ->00 00 00 00 (資料塊的長度)

    2-4-6   Base relocation Table

      2-4-6-1   VirtualAddress [DWORD]  ->00 00 00 00 (資料塊的起始RAV)

      2-4-6-2   Size                 [DWORD]  ->00 00 00 00 (資料塊的長度)

    2-4-7   Debug

      2-4-7-1   VirtualAddress [DWORD]  ->00 00 00 00 (資料塊的起始RAV)

      2-4-7-2   Size                  [DWORD]  ->00 00 00 00 (資料塊的長度)

    2-4-8   Copyright

      2-4-8-1   VirtualAddress [DWORD]  ->00 00 00 00 (資料塊的起始RAV)

      2-4-8-2   Size                  [DWORD]  ->00 00 00 00 (資料塊的長度)

    2-4-9   Global ptr

      2-4-9-1   VirtualAddress [DWORD]  ->00 00 00 00 (資料塊的起始RAV)

      2-4-9-2   Size                  [DWORD]  ->00 00 00 00 (資料塊的長度)

    2-4-10  Threda local storage(TLS)

      2-4-10-1  VirtualAddress [DWORD]  ->00 00 00 00 (資料塊的起始RAV)

      2-4-10-2  Size                  [DWORD]  ->00 00 00 00 (資料塊的長度)

    2-4-11  Load configuration

      2-4-11-1  VirtualAddress [DWORD]  ->00 00 00 00 (資料塊的起始RAV)

      2-4-11-2  Size                  [DWORD]  ->00 00 00 00 (資料塊的長度)

    2-4-12  Bound import

      2-4-12-1  VirtualAddress [DWORD]  ->00 00 00 00 (資料塊的起始RAV)

      2-4-12-2  Size                  [DWORD]  ->00 00 00 00 (資料塊的長度)

    2-4-13  Import Address Table(IAT)

      2-4-13-1  VirtualAddress [DWORD]  ->00 00 00 00 (資料塊的起始RAV)

      2-4-13-2  Size                  [DWORD]  ->00 00 00 00 (資料塊的長度)

    2-4-14  Delay import   

      2-4-14-1  VirtualAddress [DWORD]  ->00 00 00 00 (資料塊的起始RAV)

      2-4-14-2  Size                  [DWORD]  ->00 00 00 00 (資料塊的長度)

    2-4-15  COM descriptor

      2-4-15-1  VirtualAddress [DWORD]  ->00 00 00 00 (資料塊的起始RAV)

      2-4-15-2  Size                 [DWORD]  ->00 00 00 00 (資料塊的長度)

    2-4-16  保留

      2-4-16-1  VirtualAddress [DWORD]  ->00 00 00 00 (資料塊的起始RAV)

      2-4-16-2  Size                  [DWORD]  ->00 00 00 00 (資料塊的長度)

3  塊表

  3-1  IMAGE_SECTION_HEADER (1 .text)

    3-1-1   Name                            [BYTE]       -->2E 74 65 78 74 00 00 00 (* 8個位元組的塊名)

    3-1-2   VirtualSize                     [DWORD]  -->26 00 00 00 (* 被實際使用的區塊大小)

    3-1-3   VirtualAddress              [DWORD]  -->00 10 00 00 (* 區塊的RAV位址)

    3-1-4   SizeOfRawData             [DWORD]  -->00 02 00 00 (* 該塊在磁盤中所占的大小)

    3-1-5   PointerToRawData        [DWORD]  -->00 04 00 00 (* 該塊在磁盤檔案中的偏移)

    3-1-6   PointerToRelocations    [DWORD]   ->00 00 00 00 (在OBJ檔案中使用,重定位偏移)

    3-1-7   PointerToLinenumbers  [DWORD]   ->00 00 00 00 (行号表的偏移,調試中使用)

    3-1-8   NumberOfRelocations    [WORD]     ->00 00 (在OBJ檔案中使用,重定位項數目)

    3-1-9   NumberOfLinenumbers  [WORD]     ->00 00 (行号表中行号的數目)

    3-1-10  Characteristics              [DWORD] -->20 00 00 60 (* 該區塊的讀寫  執行屬性)

  3-2  IMAGE_SECTION_HEADER (2 .rdata)

    3-2-1   Name                            [BYTE]     -->2E 72 64 61 74 61 00 00 (* 8個位元組的塊名)

    3-2-2   VirtualSize                    [DWORD] -->92 00 00 00 (* 被實際使用的區塊大小)

    3-2-3   VirtualAddress              [DWORD] -->00 20 00 00 (* 區塊的RAV位址)

    3-2-4   SizeOfRawData             [DWORD] -->00 02 00 00 (* 該塊在磁盤中所占的大小)

    3-2-5   PointerToRawData        [DWORD] -->00 06 00 00 (* 該塊在磁盤檔案中的偏移)

    3-2-6   PointerToRelocations   [DWORD]   ->00 00 00 00 (在OBJ檔案中使用,重定位偏移)

    3-2-7   PointerToLinenumbers  [DWORD]  ->00 00 00 00 (行号表的偏移,調試中使用)

    3-2-8   NumberOfRelocations    [WORD]    ->00 00 (在OBJ檔案中使用,重定位項數目)

    3-2-9   NumberOfLinenumbers  [WORD]    ->00 00 (行号表中行号的數目)

    3-2-10  Characteristics              [DWORD] -->40 00 00 40 (* 該區塊的讀寫  執行屬性)

  3-3  IMAGE_SECTION_HEADER (3 .data)

    3-3-1   Name                             [BYTE]      -->2E 64 61 74 61 00 00 00 (* 8個位元組的塊名)

    3-3-2   VirtualSize                     [DWORD]  -->3E 00 00 00 (* 被實際使用的區塊大小)

    3-3-3   VirtualAddress               [DWORD]  -->00 30 00 00 (* 區塊的RAV位址)

    3-3-4   SizeOfRawData             [DWORD]  -->00 02 00 00 (* 該塊在磁盤中所占的大小)

    3-3-5   PointerToRawData        [DWORD]  -->00 08 00 00 (* 該塊在磁盤檔案中的偏移)

    3-3-6   PointerToRelocations    [DWORD]   ->00 00 00 00 (在OBJ檔案中使用,重定位偏移)

    3-3-7   PointerToLinenumbers  [DWORD]   ->00 00 00 00 (行号表的偏移,調試中使用)

    3-3-8   NumberOfRelocations    [WORD]     ->00 00 (在OBJ檔案中使用,重定位項數目)

    3-3-9   NumberOfLinenumbers  [WORD]     ->00 00 (行号表中行号的數目)

    3-3-10  Characteristics              [DWORD] -->40 00 00 C0 (* 該區塊的讀寫、執行屬性)

    【由于FileAlignment為0x200大小,而此時整個PE頭已經超過200,是以要填0到0x400處】

4  塊

  4-1  .text (* 此區段是一段彙編代碼的16進制形式,功能是彈出一個MessageBox提示框)

    -->HEX

    6A 00 68 00 30 40 00 68  07 30 40 00 6A 00 E8 07

    00 00 00 6A 00 E8 06 00  00 00 FF 25 08 20 40 00

    FF 25 00 20 40 00

    -->ASM

    00401000  6A 00         PUSH 0

    00401002  68 00304000   PUSH first_PE.00403000

    00401007  68 07304000   PUSH first_PE.00403007

    0040100C  6A 00         PUSH 0

    0040100E  E8 07000000   CALL <JMP.&user32.MessageBoxA>

    00401013  6A 00         PUSH 0

    00401015  E8 06000000   CALL <JMP.&kernel32.ExitProcess>

    0040101A  FF25 08204000 JMP DWORD PTR DS:[<&user32.MessageBoxA>]

    00401020  FF25 00204000 JMP DWORD PTR DS:[<&kernel32.ExitProcess>]

    【由于FileAlignment為0x200大小,而此時整個PE頭未超過200,是以要填0到0x600處】

  4-2  .rdata (* 該區塊包含輸入表)

    4-2-1  IMAGE_THUNK_DATA32 (IAT 1)

      4-2-1-1 AddressOfData [DWORD] -->76 20 00 00 (* 指向IMAGE_IMPORT_BY_NAME的RVA)

      【由于本例子兩個API函數引自與兩個不同的DLL檔案,是以要補00000000h結束。】

    4-2-2  IMAGE_THUNK_DATA32 (IAT 2)

      4-2-1-2 AddressOfData [DWORD] -->5C 20 00 00 (* 指向IMAGE_IMPORT_BY_NAME的RVA)

      【由于本例子兩個API函數引自與兩個不同的DLL檔案,是以要補00000000h結束。】

    4-2-3  IMAGE_IMPORT_DESCRIPTOR (IID 1)

      4-2-3-1 OriginalFirstThunk  [DWORD] -->4C 20 00 00 (* 指向輸入名稱表INT的RVA)

      4-2-3-2 TimeDateStamp      [DWORD]  ->00 00 00 00 (32位的時間标志)

      4-2-3-3 ForwarderChain      [DWORD]  ->00 00 00 00 (被轉向API的索引)

      4-2-3-4 Name                      [DWORD] -->6A 20 00 00 (* 指向DLL名字的RVA與指針)

      4-2-3-5 FirstThunk              [DWORD] -->08 20 00 00 (* 指向輸入位址表IAT的RVA)

    4-2-4  IMAGE_IMPORT_DESCRIPTOR (IID 2)

      4-2-4-1 OriginalFirstThunk  [DWORD] -->54 20 00 00 (* 指向輸入名稱表INT的RVA)

      4-2-4-2 TimeDateStamp      [DWORD]  ->00 00 00 00 (32位的時間标志)

      4-2-4-3 ForwarderChain      [DWORD]  ->00 00 00 00 (被轉向API的索引)

      4-2-4-4 Name                      [DWORD] -->84 20 00 00 (* 指向DLL名字的RVA與指針)

      4-2-4-5 FirstThunk              [DWORD] -->00 20 00 00 (* 指向輸入位址表IAT的RVA)

      【填充20個00h空位元組做結尾标記】

    4-2-5  IMAGE_THUNK_DATA32 (INT 1)

      4-2-5-1  ForwarderString [DWORD] -->5C 20 00 00 (* 指向一個轉向字元的RVA)

      【由于本例子兩個API函數引自與兩個不同的DLL檔案,是以要補00000000h結束。】

    4-2-6  IMAGE_THUNK_DATA32 (INT 2)

      4-2-6-1  ForwarderString [DWORD] -->76 20 00 00 (* 指向一個轉向字元的RVA)

      【由于本例子兩個API函數引自與兩個不同的DLL檔案,是以要補00000000h結束。】

    4-2-7  IMAGE_IMPORT_BY_NAME ( 1 )

      4-2-7-1  Hint    [WORD] -->00 00 (* 此函數所駐留DLL的輸出表序号)

      4-2-7-2  Name [BYTE]   -->4D 65 73 73 61 67 65 42 6F 78 41 (* MessageBoxA的16進制碼)

      【後跟輸出此函數的DLL名稱16進制碼00 75 73 65 72 33 32 2E 64 6C 6C 00 00 user32.dll】

    4-2-8  IMAGE_IMPORT_BY_NAME ( 2 )

      4-2-8-1  Hint    [WORD] -->00 00h  (* 此函數所駐留DLL的輸出表序号)

      4-2-8-2  Name [BYTE]   -->45 78 69 74 50 72 6F 63 65 73 73 (* ExitProcess的16進制碼)

      【後跟輸出此函數的DLL名稱16進制碼00 6B 65 72 6E 65 6C 33 32 2E 64 6C 6C 00 00 kernel32.dll】

      【由于FileAlignment為0x200大小,而此時整個PE頭未超過200,是以要填0到0x800處】

  4-3  .data

       填充資料

       -->HEX

       CF FB CF A2 BF F2 00 54  68 65 20 66 69 72 73 74

       20 50 45 20 66 69 6C 65  21 20 42 59 3A 41 31 50

       61 73 73 20 48 74 74 70  3A 2F 2F 61 31 70 61 73

       73 2E 62 6C 6F 67 2E 31  36 33 2E 63 6F 6D 00

       -->TEXT

       消息框 The first PE file! jayzou.com

      【由于FileAlignment為0x200大小,而此時整個PE頭未超過200,是以要填0到0x9FF處】

    到此,介紹手工構造典型PE檔案的知識就講完了,雖然過程枯燥,但是當第一個first_PE.EXE從你手中誕生時,你會覺得這一切都太值了!這點你應該相信我,因為我當時就是這種感覺,最後祝各位成功!

繼續閱讀