S.l.e!ep.¢%

像打了激速一样,以四倍的速度运转,开心的工作
简单、开放、平等的公司文化;尊重个性、自由与个人价值;
posts - 1098, comments - 335, trackbacks - 0, articles - 1
  C++博客 :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理

PE文件(3)

Posted on 2009-09-14 23:18 S.l.e!ep.¢% 阅读(379) 评论(0)  编辑 收藏 引用 所属分类: PE
     typedef struct _IMAGE_OPTIONAL_HEADER
    { 
         //
         // Standard fields.
         //
         WORD   Magic;                   
// 总是 0B 01  P: 可选头的标志?意义是?
         BYTE    MajorLinkerVersion;   // 0 链接器的主版本号  // P:不同的链接器设置不同,因此不可靠?
         BYTE    MinorLinkerVersion;   // 0 链接器的小版本号
         DWORD  SizeOfCode;           // 0                        // 可执行的代码的大小  P: 这里的可执行代码是指整个PE文件的可执行代码段?
         DWORD  SizeOfInitializedData;     // 0                  // 已初始化数据的大小 ,数据段
         DWORD  SizeOfUninitializedData;  // 0                  // 未初始化数据的大小, BSS段  P: 已初始化的数据跟未初始化的数据有什么区别?它们都在数据段?
         DWORD  AddressOfEntryPoint;     //                    //  代码的入口点地址(是一个偏移量,RVA), 如 LibMain, WinMain....
         DWORD  BaseOfCode;  // 0                               //  可执行代码的偏移量, 代码基址  P: 不是很懂这里的意思,跟 AddressOfEntryPoint 的区别是?
         DWORD  BaseOfData;  // 0                               //  已初始化数据偏称量,数据基址  P: 同问
       
         //
         // NT additional fields.
         //
         DWORD  ImageBase;          //载入程序的RVA地址,LOADER可以改变 00 00 40 00 == 0x400000
         DWORD  SectionAlignment;   //段加载后在内存的对齐方式 00 10 00 00
         DWORD  FileAlignment;         //段在文件中的对齐方式      00 20 00 00
         WORD    MajorOperatingSystemVersion;  // 0
         WORD    MinorOperatingSystemVersion;  // 0
         WORD    MajorImageVersion;                //  0
         WORD    MinorImageVersion;                //  0
         WORD    MajorSubsystemVersion; //子系统版本号如果不是4.0  对话框不能显示3D风格 04 00
         WORD    MinorSubsystemVersion; // 0
         DWORD  Win32VersionValue;       // 0   P:没有作用?通常为0
         DWORD  SizeOfImage;               // 映象文件将要使用的内存数量, 如果是按照“SectionAlignment”对齐的,它就是所有头和节的长度的总和。它提示加载器,为了载入映象文件需要多少页。
         DWORD  SizeOfHeaders; //给出所有头的总长度,包括数据目录和节头(‘SizeOfHeaders’,“头的大小”)。同时,它也是从文件的开头到第一节的原始数据的偏移量。
         DWORD  CheckSum;      // 校验和,用 0?
         WORD    Subsystem;     // 子系统 02 00 或03 00 ?
         WORD    DllCharacteristics;     // 00
         DWORD  SizeOfStackReserve;  // 00
         DWORD  SizeOfStackCommit;
         DWORD  SizeOfHeapReserve;
         DWORD  SizeOfHeapCommit;
         DWORD  LoaderFlags;             // 00
         DWORD  NumberOfRvaAndSizes; 
      
         IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; // 16个结构,第二个结构(导入表) 
     } IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32;
 
     1. CheckSum:
     这个校验和,对于当前的NT版本,只在映象文件是NT驱动程序时才校验(如果校验和不正确,驱动就将装载失败)。
     对于其他的二进制文件形式,校验和不需提供并且可能为0。
     计算校验和的算法是微软的私产,他们不会告诉你的。
     但是,Win32 SDK的好几个工具都会计算和/或补正一个有效的校验和,而且imagehelp.dll中的CheckSumMappedFile()函数也会做同样的工作。
     使用校验和的目的是为了防止载入无论如何都会冲突的、已损坏的二进制文件----况且一个冲突的驱动程序会导致一个BSOD?错误,因此最好根本就不载入这样的坏文件。
    
     2. Subsystem

        IMAGE_SUBSYSTEM_NATIVE (1)
             二进制文件不需要子系统。用于驱动程序。
       
        IMAGE_SUBSYSTEM_WINDOWS_GUI (2)
             映象文件是一个Win32二进制图象文件。(它还是能用AllocConsole()打开一个控制台界面,但在开始时却不能自动地打开。)
            
        IMAGE_SUBSYSTEM_WINDOWS_CUI (3)
             二进制文件是一个Win32控制台界面二进制文件。(它将在开始时按照缺省值打开一个控制台,或者继承其父程序的控制台。)

        IMAGE_SUBSYSTEM_OS2_CUI (5)
              二进制文件是一个OS/2控制台界面二进制文件。(OS/2控制台界面二进制文件是OS/2格式,因此此值在PE文件中很少使用。)

        IMAGE_SUBSYSTEM_POSIX_CUI (7)
              二进制文件使用POSIX?控制台子系统。

       

        Windows 95的二进制文件总是使用Win32子系统,因此它的二进制文件的合法值只有2和3;我不知道windows 95的“原”二进制文件是否可能(会有其它值----译者添加,仅供参考)。

            
     3.  DllCharacteristics
          如果是DLL文件,何时调用DLL文件的入口点(‘DllCharacteristics’,“DLL特性”)。此值似乎不用;很明显地,DLL文件总是被通报所有的情况。
         如果位0被置1,DLL文件被通知进程附加(亦即DLL载入)。
         如果位1被置1,DLL文件被通知线程附加(亦即线程终止)。
         如果位2被置1,DLL文件被通知线程附加(亦即线程创建)。
         如果位3被置1,DLL文件被通知进程附加(亦即DLL卸载)。
         P: 不是很明白这里的意思。        
 
     4. SizeOfStackReserve  保留栈的大小
     5. SizeOfStackCommit   初始时指定栈大小
     6. SizeOfHeapReserve   保留堆的大小
     7. SizeOfHeapCommit    指定堆大小
     
     “保留的”数量是保留给特定目的的地址空间(不是真正的RAM);
      在程序开始时,“指定的”数量是指在RAM中实际分配的大小。
      如果需要的话,“指定的”值也是指定的堆或栈用来增加的数量。(有资料说,不管“SizeOfStackCommit”的值是多少,栈都是按页增加的。我没有验证过。)
      因此,举例来说,如一个程序的保留堆有1 MB,指定堆为64 KB,那么启动时堆的大小为64 KB,并且保证可以扩大到1 MB。
      堆将按64 KB一块来增加。“堆”在本文中是指主要(缺省)堆。如果它愿意的话,一个进程可创建很多堆。
      栈是指第一个线程的栈(启动main()的那个)。进程可以创建很多线程,每个线程都有自己的栈。
      DLL文件没有自己的堆或栈,所以它们的映象文件忽略这些值。我不知道驱动程序是否有它们自己的堆或栈,但我认为它们没有。


     8. LoaderFlags 设置为 0 , P: 作用未知

 

     9. NumberOfRvaAndSizes 

        它是紧随其后的目录的有效项的数目。我已发现此值不可靠;你也许希望用常量IMAGE_NUMBEROF_DIRECTORY_ENTRIES(映象文件目录项数目)来代替它,或者用它们中的较小者。


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理