pe文件格式:PE文件格式(3)

  ID意义依赖和在树内层次ID可能是个数字(高位清0)或者名字(高位置1)如果是名字低31位是从资源节原始数据开始到名字偏移量名字是16位长度以宽结尾不是0

  如果在根目录下如果ID是数字是资源类型:

  1:cursor

  2:bitmap

  3:icon

  4:menu

  5:dialog

  6:table

  7:fontdirectory

  8:font

  9:accelerators

  10:unformattedresourcedata

  11:messagetable

  12:groupcursor

  14:groupicon

  16:versioninformation

  任何其他数字都是自定义任何带类型名字资源类型都是自定义更深ID是资源ID或者资源名字

  如果再深入ID必须是数字它是特定资源例子语言ID例如可以具有区别本地化语言对话框他们使用统资源ID系统会选择基于线程地域加载对话框反过来反应用户区域设置如果对于线程本地没有资源发现系统首先试图发现中立语言为资源区域如果还不能够发现带有最小语言ID例子将被使用解码语言ID拆分为主语言ID和子语言ID使用宏PRIMARYLANGID和SUBLANGID,分别是0-910-15其值定义在"winresrc.h".

  语言资源只被加速键对话框菜单串表支持其他资源类型必须是LANG_NEUTRAL/SUBLANG_NEUTRAL.

  要找出资源目录下级目录是否是另个目录检查偏移量高位如果置1其余31位是从资源原始数据开始到下个目录偏移量格式还是IMAGE_RESOURCE_DIRECTORY后面跟着IMAGE_RESOURCE_DIRECTORY_ENTRYs项目.

  如果高位清0偏移量是从节开始到资源原始数据描述结构(个IMAGE_RESOURCE_DATA_ENTRY)偏移量个IMAGE_RESOURCE_DATA_ENTRY包括

IMAGE_RESOURCE_DATA_ENTRYSTRUCT
  OffToDatadd?
  Size1dd    ?
  CodePagedd  ?
  Reserveddd  ?
IMAGE_RESOURCE_DATA_ENTRYENDS
  32位'OffToData'从资源节开始到原始数据偏移量32位数据大小Size32位'CodePage'

  和32保留

  原始数据格式依赖于资源类型任何串资源都是UNICODE格式

  重定位relocations

  -----------

  最后个数据目录是重定位基重定位目录被IMAGE_DIRECTORY_ENTRY_BASERELOC指向典型包括个自己名字是".reloc"以及IMAGE_SCN_CNT_INITIALIZED_DATA,IMAGE_SCN_MEM_DISCARDABLE和

  IMAGE_SCN_MEM_READ位集合

  如果映象没有被加载器调入优先地址则该数据被加载器使用这种情况下给链接器填入地址无效了加载器必须修复用于静态变量绝对地址串等

IMAGE_BASE_RELOCATIONSTRUCT
  VirtualAddressdd ?
  SizeOfBlockdd   ?
IMAGE_BASE_RELOCATIONENDS
  重定位目录是系列块每个块包括重定位信息针对4K映象个块起始于

  'IMAGE_BASE_RELOCATION'结构包括32位'VirtualAddress'和32位'SizeOfBlock'.随后是实际重定位数据每个都是16位'VirtualAddress'是本块要应用基地址'SizeOfBlock'是整个块大小后面重定位数目是('SizeOfBlock'-(IMAGE_BASE_RELOCATION))/2重定位信息以VirtualAddress'=0IMAGE_BASE_RELOCATION结构结束

  每个16位重定位信息包括低12位重定位位置和高4位重定位类型要得到重定位RVA,IMAGE_BASE_RELOCATION''VirtualAddress'需要加上12位位置偏移量.类型是下列的:

  IMAGE_REL_BASED_ABSOLUTE(0)使块按照32位对齐位置为0

  IMAGE_REL_BASED_HIGH(1)高16位必须应用于偏移量所指高字16位

  IMAGE_REL_BASED_LOW(2) 低16位必须应用于偏移量所指低字16位

  IMAGE_REL_BASED_HIGHLOW(3)全部32位应用于所有32位.

  IMAGE_REL_BASED_HIGHADJ(4)需要32位高16位位于偏移量低16位位于下个偏移量元素组合为个带符号数加上32位个数然后加上8000然后把高16位保存在偏移量16位域内

  IMAGE_REL_BASED_MIPS_JMPADDR(5)    Unknown

  IMAGE_REL_BASED_SECTION(6)    Unknown

  IMAGE_REL_BASED_REL32(7)    Unknown

  举例:

  0x00004000   (32bits,startingRVA)
  0x00000010   (32bits,chunk)
  0x3012     (16bitsrelocdata)
  0x3080     (16bitsrelocdata)
  0x30f6     (16bitsrelocdata)
  0x0000     (16bitsrelocdata)
  0x00000000   (nextchunk'sRVA)
  0xff341234
  第块描述重定位起始于RVA0x4000长度16字节头用去8字节个重定位用2个字节总共(16-8)/2=4个重定位个重定位被用于0x4012个重定位于4080,第 3个定位于0x40f6.最后个无用最后个结束

  附录:Appendix:helloworld

  ---------------------

Theprogramwillbetheequivalentof
  #<stdio.h>
  (void)
  {
    puts(hello,world);
    0;
  }
  用Win32代替Cruntime:

  #STD_OUTPUT_HANDLE-11UL
  #hello"hello,world "
  __declspec(dllimport)unsignedlong__stdcall
  GetStdHandle(unsignedlonghdl);
  __declspec(dllimport)unsignedlong__stdcall
  WriteConsoleA(unsignedlonghConsoleOutput,
          constvoid*buffer,
          unsignedlongchrs,
          unsignedlong*written,
          unsignedlongunused
          );
  unsignedlongwritten;
  voidstartup(void)
  {
    WriteConsoleA(GetStdHandle(STD_OUTPUT_HANDLE),hello,(hello)-1,&written,0);
    ;
  }
  汇编语言

  startup:
        ;参数WriteConsole,逆向
  6A00          push   0x00000000
  68????????      push   off_written
  6A0D          push   0x0000000d
  68????????      push   offhello
        ;参数GetStdHandle
  6AF5          push   0xfffffff5
  2EFF15????????   call   dwordptrcs:__imp__GetStdHandle@4
        ;resultislastparameterforWriteConsole
  50            push   eax
  2EFF15????????   call   dwordptrcs:__imp__WriteConsoleA@20
  C3            ret   
  hello:
  68656C6C6F2C20776F726C640A "hello,world "
  _written:
  00000000
  下面是链接器:

  我们需要找出WriteConsoleAandGetStdHandle.他们在"kernel32.dll".此为输入库部分我们现在生成可执行文件问号在后面被找出

  DOS-stub,起始于0x00x40字节:

  00|4d5a0000000000000000000000000000
  10|00000000000000000000000000000000
  20|00000000000000000000000000000000
  30|00000000000000000000000040000000
  只是个头前面带有签字"MZ"后面是e_lfa指针然后是PE签名起始于0x400x4字节:

  50450000

  下面是文件头起始于0x44,0x14字节:

  Machine          4c01   ;i386
  NumberOfSections      0200   ;codeanddata
  TimeDateStamp       00000000;whocares?
  PoerToSymbolTable    00000000;unused
  NumberOfSymbols      00000000;unused
  SizeOfOptionalHeader    e000   ;constant
  Characteristics      0201   ;executableon32-bit-machine
  下面是optionalheader,起始于0x580x60slong:

  Magic           0b01   ;constant
  MajorLinkerVersion     00     ;I'mversion0.0:-)
  MinorLinkerVersion     00     ;
  SizeOfCode         20000000;32sofcode
  SizeOfInitializedData   ????????;yettofindout
  SizeOfUninitializedData  00000000;wedon'thaveaBSS
  AddressOfEntryPo    ????????;yettofindout
  BaseOfCode         ????????;yettofindout
  BaseOfData         ????????;yettofindout
  ImageBase         00001000;1MB,chosenarbitrarily
  SectionAlignment      20000000;32-s-alignment
  FileAlignment       20000000;32-s-alignment
  MajorOperatingVersion 0400   ;NT4.0
  MinorOperatingVersion 0000   ;
  MajorImageVersion     0000   ;version0.0
  MinorImageVersion     0000   ;
  MajorSubsystemVersion   0400   ;Win324.0
  MinorSubsystemVersion   0000   ;
  Win32VersionValue     00000000;unused?
  SizeOfImage        ????????;yettofindout
  SizeOfHeaders       ????????;yettofindout
  CheckSum          00000000;notusedfornon-drivers
  Subsystem         0300   ;Win32console
  DllCharacteristics     0000   ;unused(notaDLL)
  SizeOfStackReserve     00001000;1MBstack
  SizeOfStackCommit     00100000;4KBtostartwith
  SizeOfHeapReserve     00001000;1MBheap
  SizeOfHeapCommit      00100000;4KBtostartwith
  LoaderFlags        00000000;unknown
  NumberOfRvaAndSizes    10000000;constant
  计划2个节个是代码个是数据(包括数据常量和输入目录)没有重定位没有其他资源没有BSS段变量'written'填入化数据节对齐和文件对齐都是32字节

  现在建立数据目录开始于0xb80x80字节长只有引入目录被使用

  Address    Size
  00000000  00000000    ;IMAGE_DIRECTORY_ENTRY_EXPORT(0)
  ????????  ????????    ;IMAGE_DIRECTORY_ENTRY_IMPORT(1)
  00000000  00000000    ;IMAGE_DIRECTORY_ENTRY_RESOURCE(2)
  00000000  00000000    ;IMAGE_DIRECTORY_ENTRY_EXCEPTION(3)
  00000000  00000000    ;IMAGE_DIRECTORY_ENTRY_SECURITY(4)
  00000000  00000000    ;IMAGE_DIRECTORY_ENTRY_BASERELOC(5)
  00000000  00000000    ;IMAGE_DIRECTORY_ENTRY_DEBUG(6)
  00000000  00000000    ;IMAGE_DIRECTORY_ENTRY_COPYRIGHT(7)
  00000000  00000000    ;IMAGE_DIRECTORY_ENTRY_GLOBALPTR(8)
  00000000  00000000    ;IMAGE_DIRECTORY_ENTRY_TLS(9)
  00000000  00000000    ;IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG(10)
  00000000  00000000    ;IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT(11)
  00000000  00000000    ;IMAGE_DIRECTORY_ENTRY_IAT(12)
  00000000  00000000    ;13
  00000000  00000000    ;14
  00000000  00000000    ;15
  下面是节头首先是代码节包括上述汇编32字节长开始于0x138长度x28:

  Name      2e636f6465000000  ;".code"
  VirtualSize    00000000      ;unused
  VirtualAddress   ????????      ;yettofindout
  SizeOfRawData   20000000      ;code
  PoerToRawData  ????????      ;yettofindout
  PoerToRelocations00000000      ;unused
  PoerToLinenumbers00000000      ;unused
  NumberOfRelocations 0000         ;unused
  NumberOfLinenumbers 0000         ;unused
  Characteristics  20000060      ;code,executable,readable
  第 2个节包括数据起始于0x160长度x28:

  Name      2e64617461000000  ;".data"
  VirtualSize    00000000      ;unused
  VirtualAddress   ????????      ;yettofindout
  SizeOfRawData   ????????      ;yettofindout
  PoerToRawData  ????????      ;yettofindout
  PoerToRelocations00000000      ;unused
  PoerToLinenumbers00000000      ;unused
  NumberOfRelocations 0000         ;unused
  NumberOfLinenumbers 0000         ;unused
  Characteristics  400000c0      ;initialized,readable,writeable
  下个是0x188,由于节必须按照32字节对齐所有填0到0x1a0:

  000000000000   ;padding
  000000000000
  000000000000
  000000000000
  现在第节代码节来到了开始于0x1a00x20字节长

  6A00          ;push   0x00000000
  68????????     ;push   off_written
  6A0D          ;push   0x0000000d
  68????????     ;push   offhello_
  6AF5          ;push   0xfffffff5
  2EFF15????????  ;call   dwordptrcs:__imp__GetStdHandle@4
  50           ;push   eax
  2EFF15????????  ;call   dwordptrcs:__imp__WriteConsoleA@20
  C3           ;ret
   

  由于前面节长度不需要填0数据节接着出现:起始于0x1c0:

    68656C6C6F2C20776F726C640A ;"hello,world "
  000000                ;paddingtoalign_written//为什么要对齐??文件对齐而已
  00000000              ;_written
  现在剩下是输入目录了引入2个从"kernel32.dll",紧随2个变量首先对齐到32个字节文件对齐

  000000000000000000000000  ;padding

  IMAGE_IMPORT_DESCRIPTOR从0x1e0开始:只有个DLL所以只有元素

  OriginalFirstThunk   ????????  ;yettofindout
  TimeDateStamp     00000000  ;unbound
  ForwarderChain     ffffffff  ;noforwarders
  Name          ????????  ;yettofindout
  FirstThunk       ????????  ;yettofindout
  我们需要结束输入目录用0填充0x1f4:

  OriginalFirstThunk   00000000  ;terminator
  TimeDateStamp     00000000  ;
  ForwarderChain     00000000  ;
  Name          00000000  ;
  FirstThunk       00000000  ;
  现在剩下DLL名字和2个thunks,及thunk-data,DLL名字从0x208开始:

  6b65726e656c33322e646c6c00 ;"kernel32.dll"
  000000                ;paddingto32-bit-boundary
  originalfirstthunk2个成员,起始于0x218:

  AddressOfData ????????      ;RVAtofunctionname"WriteConsoleA"
  AddressOfData ????????      ;RVAtofunctionname"GetStdHandle"
          00000000      ;terminator
  firstthunk含有同样列表起始于0x224:

(__imp__WriteConsoleA@20,at0x224)
  AddressOfData ????????      ;RVAtofunctionname"WriteConsoleA"
(__imp__GetStdHandle@4,at0x228)
  AddressOfData ????????      ;RVAtofunctionname"GetStdHandle"
          00000000      ;terminator
  现在只剩下2个名在IMAGE_IMPORT_BY_NAME.从0x230.

  0100                   ;ordinal,neednotbecorrect
  5772697465436f6e736f6c654100 ;"WriteConsoleA"
  0200                   ;ordinal,neednotbecorrect
  47657453746448616e646c6500  ;"GetStdHandle"
  下面填充到0x260:

  00000000000000000000000000000000;padding
  00
  ------------

  现在结束我们知道所有字节偏移量我们可以实施修补地址和尺寸了

DOS-header,startingat0x0:
  00|4d5a0000000000000000000000000000
  10|00000000000000000000000000000000
  20|00000000000000000000000000000000
  30|00000000000000000000000040000000
signature,startingat0x40:
    50450000
file-header,startingat0x44:
  Machine          4c01   ;i386
  NumberOfSections      0200   ;codeanddata
  TimeDateStamp       00000000;whocares?
  PoerToSymbolTable    00000000;unused
  NumberOfSymbols      00000000;unused
  SizeOfOptionalHeader    e000   ;constant
  Characteristics      0201   ;executableon32-bit-machine
optionalheader,startingat0x58:
  Magic           0b01   ;constant
  MajorLinkerVersion     00     ;I'mversion0.0:-)
  MinorLinkerVersion     00     ;
  SizeOfCode         20000000;32sofcode
  SizeOfInitializedData   a0000000;datasectionsize
  SizeOfUninitializedData  00000000;wedon'thaveaBSS
  AddressOfEntryPo    a0010000;beginningofcodesection
  BaseOfCode         a0010000;RVAtocodesection
  BaseOfData         c0010000;RVAtodatasection
  ImageBase         00001000;1MB,chosenarbitrarily
  SectionAlignment      20000000;32-s-alignment
  FileAlignment       20000000;32-s-alignment
  MajorOperatingVersion 0400   ;NT4.0
  MinorOperatingVersion 0000   ;
  MajorImageVersion     0000   ;version0.0
  MinorImageVersion     0000   ;
  MajorSubsystemVersion   0400   ;Win324.0
  MinorSubsystemVersion   0000   ;
  Win32VersionValue     00000000;unused?
  SizeOfImage        c0000000;sumofallsectionsizes//没有包含头尺寸跟前面所说矛盾了
  SizeOfHeaders       a0010000;offto1stsection
  CheckSum          00000000;notusedfornon-drivers
  Subsystem         0300   ;Win32console
  DllCharacteristics     0000   ;unused(notaDLL)
  SizeOfStackReserve     00001000;1MBstack
  SizeOfStackCommit     00100000;4KBtostartwith
  SizeOfHeapReserve     00001000;1MBheap
  SizeOfHeapCommit      00100000;4KBtostartwith
  LoaderFlags        00000000;unknown
  NumberOfRvaAndSizes    10000000;constant
datadirectories,startingat0xb8:
  Address    Size
  00000000  00000000    ;IMAGE_DIRECTORY_ENTRY_EXPORT(0)
  e0010000  6f000000    ;IMAGE_DIRECTORY_ENTRY_IMPORT(1)
  00000000  00000000    ;IMAGE_DIRECTORY_ENTRY_RESOURCE(2)
  00000000  00000000    ;IMAGE_DIRECTORY_ENTRY_EXCEPTION(3)
  00000000  00000000    ;IMAGE_DIRECTORY_ENTRY_SECURITY(4)
  00000000  00000000    ;IMAGE_DIRECTORY_ENTRY_BASERELOC(5)
  00000000  00000000    ;IMAGE_DIRECTORY_ENTRY_DEBUG(6)
  00000000  00000000    ;IMAGE_DIRECTORY_ENTRY_COPYRIGHT(7)
  00000000  00000000    ;IMAGE_DIRECTORY_ENTRY_GLOBALPTR(8)
  00000000  00000000    ;IMAGE_DIRECTORY_ENTRY_TLS(9)
  00000000  00000000    ;IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG(10)
  00000000  00000000    ;IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT(11)
  00000000  00000000    ;IMAGE_DIRECTORY_ENTRY_IAT(12)
  00000000  00000000    ;13
  00000000  00000000    ;14
  00000000  00000000    ;15
sectionheader(code),startingat0x138:
  Name      2e636f6465000000  ;".code"
  VirtualSize    00000000      ;unused
  VirtualAddress   a0010000      ;RVAtocodesection
  SizeOfRawData   20000000      ;code
  PoerToRawData  a0010000      ;fileofftocodesection
  PoerToRelocations00000000      ;unused
  PoerToLinenumbers00000000      ;unused
  NumberOfRelocations 0000         ;unused
  NumberOfLinenumbers 0000         ;unused
  Characteristics  20000060      ;code,executable,readable
sectionheader(data),startingat0x160:
  Name      2e64617461000000  ;".data"
  VirtualSize    00000000      ;unused
  VirtualAddress   c0010000      ;RVAtodatasection
  SizeOfRawData   a0000000      ;datasection
  PoerToRawData  c0010000      ;fileofftodatasection
  PoerToRelocations00000000      ;unused
  PoerToLinenumbers00000000      ;unused
  NumberOfRelocations 0000         ;unused
  NumberOfLinenumbers 0000         ;unused
  Characteristics  400000c0      ;initialized,readable,writeable
(padding)
  000000000000   ;padding
  000000000000
  000000000000
  000000000000
codesection,startingat0x1a0:
  6A00          ;push   0x00000000
  68d0011000     ;push   off_written
  6A0D          ;push   0x0000000d
  68c0011000     ;push   offhello_
  6AF5          ;push   0xfffffff5
  2EFF1528021000  ;call   dwordptrcs:__imp__GetStdHandle@4
  50           ;push   eax
  2EFF1524021000  ;call   dwordptrcs:__imp__WriteConsoleA@20
  C3           ;ret   
datasection,beginningat0x1c0:
  68656C6C6F2C20776F726C640A ;"hello,world "
  000000                ;paddingtoalign_written
  00000000              ;_written
padding:
  000000000000000000000000  ;padding
IMAGE_IMPORT_DESCRIPTOR,startingat0x1e0:
  OriginalFirstThunk   18020000  ;RVAtoorig.1stthunk
  TimeDateStamp     00000000  ;unbound
  ForwarderChain     ffffffff  ;noforwarders
  Name          08020000  ;RVAtoDLLname
  FirstThunk       24020000  ;RVAto1stthunk
terminator(0x1f4):
  OriginalFirstThunk   00000000  ;terminator
  TimeDateStamp     00000000  ;
  ForwarderChain     00000000  ;
  Name          00000000  ;
  FirstThunk       00000000  ;
TheDLLname,at0x208:
  6b65726e656c33322e646c6c00 ;"kernel32.dll"
  000000                ;paddingto32-bit-boundary
originalfirstthunk,startingat0x218:
  AddressOfData 30020000      ;RVAtofunctionname"WriteConsoleA"
  AddressOfData 40020000      ;RVAtofunctionname"GetStdHandle"
          00000000      ;terminator
firstthunk,startingat0x224:
  AddressOfData 30020000      ;RVAtofunctionname"WriteConsoleA"
  AddressOfData 40020000      ;RVAtofunctionname"GetStdHandle"
          00000000      ;terminator
IMAGE_IMPORT_BY_NAME,at0x230:
  0100                   ;ordinal,neednotbecorrect
  5772697465436f6e736f6c654100 ;"WriteConsoleA"
IMAGE_IMPORT_BY_NAME,at0x240:
  0200                   ;ordinal,neednotbecorrect
  47657453746448616e646c6500  ;"GetStdHandle"
(padding)
  00000000000000000000000000000000;padding
  00
Firstunused:0x260
  --------------



  是32字节节对齐所以在windows98下该不工作可以在NT下工作要想在WIN98下工作必须插入许多0并修改RVA



Tags:  pe文件 pe格式详解 pe格式 pe文件格式

延伸阅读

最新评论

发表评论