分享

PE文件结构及其加载机制

 firefox_zyw 2014-03-15

PE文件结构及其加载机制(三)


上次我们学习了IMAGE_OPTIONAL_HEADER的前十个参数,下面我们继续学习。
第十一个值SectionAlignment,表示节对齐粒度。这个值一定要大于或等于文件对齐粒度。
The alignment of sections loaded in memory, in bytes. This value must be greater than or equal to the FileAlignment member.
The default value is the page size for the system.




原来是4096B,也就是4kb了。



第十二个值是FileAlignment,表示文件对齐粒度。



The alignment of the raw data of sections in the image file, in bytes.
The value should be a power of 2 between 512 and 64K (inclusive). The default is 512. If the SectionAlignment member
is less than the system page size, this member must be the same as SectionAlignment.





这个值应该是512B的倍数。



第十三个值是MajorOperatingSystemVersion,所需操作系统的主版本号。



The major version number of the required operating system.





第十四个值是MinorOperatingSystemVersion,所需操作系统的副版本号。



The minor version number of the required operating system.





第十五个值是MajorImageVersion



The major version number of the image.





第十六个值是MinorImageVersion



The minor version number of the image.





第十七个值是MajorSubsystemVersion



The major version number of the subsystem.





第十八个值为MinorSubsystemVersion



The minor version number of the subsystem.





第十九个值为Win32VersionValue,保留值,且必须为零。



This member is reserved and must be 0.



 





 



 



第二十个值为SizeOfImage,4个字节,表示程序调入后占用内存大小(字节),等于所有段的长度之和。



The size of the image, in bytes, including all headers. Must be a
multiple of SectionAlignment.



 





0x2B000=?





好吧,两三天了,终于弄明白这个值了,由于在实验过程中,为了防止意外,所以复制了一个副本在当前文件夹下,通过二进制的对比,发现这两个文件的SizeOfImage值是不一样的,所以走了弯路。



既然错了文件,那么我还是以这个文件为例吧,因为其他的部分都一样,所以就不修改其他的部分了。





0x25000+0x5188=0x2A188,再考虑内存对齐,我们试着用这个值除以对齐粒度0x1000,看是否能除尽。



结果是不能除尽,所以要求大一点,结果这个SizeOfImage就变成了0x2B000。



第二十一个值为SizeOfHeaders,占用4个字节,表示所有头加节表的大小。



The combined size of the following items, rounded to a multiple of
the value specified in the FileAlignment member.



 




  • 4 byte signature

  • size of IMAGE_FILE_HEADER

  • size of optional header

  • size of all section headers


 





也就是0x1000了。



 



第二十二个值为CheckSum,占用四个字节。



The image file checksum. The following files are validated(验证) at
load time: all drivers, any DLL loaded at boot time, and any DLL loaded into a critical (关键)system process.





 



 



第二十三个值为Subsystem,占用两个字节。表示文件运行所需的子系统。



 The subsystem required to run this image. The following values are
defined.



 






























































Value

Meaning



IMAGE_SUBSYSTEM_UNKNOWN

0



Unknown subsystem.





IMAGE_SUBSYSTEM_NATIVE

1



No subsystem required (device drivers and native system processes).





IMAGE_SUBSYSTEM_WINDOWS_GUI

2



Windows graphical user interface (GUI) subsystem.





IMAGE_SUBSYSTEM_WINDOWS_CUI

3



Windows character-mode user interface (CUI) subsystem.





IMAGE_SUBSYSTEM_OS2_CUI

5



OS/2 CUI subsystem.





IMAGE_SUBSYSTEM_POSIX_CUI

7



POSIX CUI subsystem.





IMAGE_SUBSYSTEM_WINDOWS_CE_GUI

9



Windows CE system.





IMAGE_SUBSYSTEM_EFI_APPLICATION

10



Extensible Firmware Interface (EFI) application.





IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER

11



EFI driver with boot services.





IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER

12



EFI driver with run-time services.





IMAGE_SUBSYSTEM_EFI_ROM

13



EFI ROM image.





IMAGE_SUBSYSTEM_XBOX

14



Xbox system.





IMAGE_SUBSYSTEM_WINDOWS_BOOT_APPLICATION

16



Boot application.




 



 



 





 



第二十四个值为DllCharacteristics,占用两个字节。表示dll文件的属性值。



The DLL characteristics of the image. The following values are defined.



 


































































Value

Meaning



0x0001



Reserved.(保留)





0x0002



Reserved.





0x0004



Reserved.





0x0008



Reserved.





IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE

0x0040



The DLL can be relocated at load time.(允许在载入的时候进行重定位)





IMAGE_DLLCHARACTERISTICS_FORCE_INTEGRITY

0x0080



Code integrity checks are forced. If you set this flag and a section contains only uninitialized data, set the PointerToRawData member
of IMAGE_SECTION_HEADER for
that section to zero; otherwise, the image will fail to load because the digital signature cannot be verified.





IMAGE_DLLCHARACTERISTICS_NX_COMPAT

0x0100



The image is compatible(兼容) with data execution prevention (DEP).





IMAGE_DLLCHARACTERISTICS_NO_ISOLATION

0x0200



The image is isolation(隔离) aware, but should not be isolated.





IMAGE_DLLCHARACTERISTICS_NO_SEH

0x0400



The image does not use structured exception handling (SEH). No handlers can be called in this image.





IMAGE_DLLCHARACTERISTICS_NO_BIND

0x0800



Do not bind the image.





0x1000



Reserved.





IMAGE_DLLCHARACTERISTICS_WDM_DRIVER

0x2000



A WDM driver.





0x4000



Reserved.





IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE

0x8000



The image is terminal server aware.




 



 



 





第二十五个值为SizeOfStackReserve,占用4个字节。表示初始化是的堆栈大小。



The number of bytes to reserve for the stack. Only the memory specified
by the SizeOfStackCommit member is committed at load time; the rest is made available one page
at a time until this reserve size is reached.



 





0x00100000=1MB



第二十六个值为SizeOfStackCommit,占用四个字节。表示初始化时实际提交的堆栈大小。



The number of bytes to commit for the stack.



 





0x1000字节=4kb



第二十七个值为SizeOfHeapReserve,占用四个字节。初始化时保留堆的大小。



The number of bytes to reserve for the local heap. Only the memory specified by the SizeOfHeapCommit member
is committed at load time; the rest is made available one page at a time until this reserve size is reached.



 





第二十八个值为SizeOfHeapCommit,占用四个字节。初始化时实际提交的堆得大小。



The number of bytes to commit for the local heap.



 





第二十九个值为LoaderFlags,占用4个字节。未使用。



This member is obsolete. 





第三十个值为NumberOfRvaAndSizes,占用四个字节。表示下面个成员数据目录结构的数量。



 





这个值一般就直接是16.



 





下面是最后一个成员DataDirectory,占用128个字节,为一个IMAGE_DATA_DIRECTORY structure结构体数组(16个)。



A pointer to the first IMAGE_DATA_DIRECTORY structure
in the data directory.



 





 



typedef struct _IMAGE_DATA_DIRECTORY {
     DWORD VirtualAddress;
     DWORD Size;
} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;



 



这个结构体有两个成员,一个成员占用4个字节,也就是8个字节。这个数组有16个数据,也就是16*8=128字节。



我们来看第一个。



IMAGE_DIRECTORY_ENTRY_EXPORT    导出表





这个程序没有导出函数,所以没有导出表。



第二个IMAGE_DIRECTORY_ENTRY_IMPORT  导入表



这个程序需要用到dll中的函数



 





我们用PEiD来查看下



 





结果是一样的。这个是RVA,表示偏移地址哦。



 



第三个IMAGE_DIRECTORY_ENTRY_RESOURCE   资源目录





从上面这张图也可以看出。RVA为00025000,大小为5188byte



 



第四个IMAGE_DIRECTORY_ENTRY_EXCEPTION  异常目录



 





未使用。



 





第五个 IMAGE_DIRECTORY_ENTRY_SECURITY  安全目录



 





 



第六个 IMAGE_DIRECTORY_ENTRY_BASERELOC   重定位表



 





 



第七个 IMAGE_DIRECTORY_ENTRY_DEBUG  调试信息



 





 



第八个 IMAGE_DIRECTORY_ENTRY_COPYRIGHT 版权信息



 





 



第九个  IMAGE_DIRECTORY_ENTRY_GLOBALPTR 



 





 



第十个 IMAGE_DIRECTORY_ENTRY_TLS  线程的本地存储器



 





 



第十一个 IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG 载入配置目录



Load configuration table address and size



 





 



第十二个 IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT  绑定导入表地址和大小



Bound import table address and size



 





 



第十三个 IMAGE_DIRECTORY_ENTRY_IAT  导入函数地址表Import Address Table



Import address table address and size



 





用Exeinfo PE 查看



 





 



第十四个 IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT



Delay import descriptor address and size



 





 



 



第十五个 IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR



The CLR header address and size



 





 



第十六个 IMAGE_NUMBEROF_DIRECTORY_ENTRIES   保留值



 





 



到此,整个PE文件头结束了。





PE文件结构及其加载机制(四)






下面我们开始学习节表。



不知道还记不记得在前面哪个结构体中出现过节的数量?



 



嘿嘿,忘记了吧,我们翻开以前的记录,看看。



原来是



typedef struct IMAGE_NT_HEADERS
  {
        DWORD Signature;
        IMAGE_FILE_HEADER FileHeader;
        IMAGE_OPTIONAL_HEADER32 OptionalHeader;
  }IMAGE_NT_HEADERS,*PIMAGE_NT_HEADERS; 



中的




复制代码

typedef struct _IMAGE_FILE_HEADER {   
        WORD      Machine;                 //运行平台 
        WORD      NumberOfSections;        //块(section)数目      
        DWORD     TimeDateStamp;           //时间日期标记     
        DWORD     PointerToSymbolTable;    //COFF符号指针,这是程序调试信息    
        DWORD     NumberOfSymbols;         //符号数  
        WORD      SizeOfOptionalHeader;    //可选部首长度,是IMAGE_OPTIONAL_HEADER的长度    
        WORD      Characteristics;         //文件属性 
}


复制代码



第二个成员就是了。



我们回去找找这个程序的这个值是多少。





原来是四个节啊,当然了,也可以说四个段。





果然是四个段。



好了,复习完需要的知识,我们就继续学习。



 



================================================














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;







 同样的,这也是一个结构体,而且有几个节,就有几个这种类似的结构体。



"#define IMAGE_SIZEOF_SHORT_NAME 8"    原来是个8



IMAGE_SECTION_HEADER的结构如下

 

typedef struct _IMAGE_SECTION_HEADER  



        BYTE Name[IMAGE_SIZEOF_SHORT_NAME];     // 节表名称,如“.text”  

        //IMAGE_SIZEOF_SHORT_NAME=8 

        union 

         { 

                DWORD PhysicalAddress;        // 物理地址 

                DWORD VirtualSize;                // 真实长度,这两个值是一个联合结构,可以使用其中的任何一个,一 

                                                              // 般是取后一个 

        } Misc; 

        DWORD VirtualAddress;              // 节区的RVA 地址 

        DWORD SizeOfRawData;            // 在文件中对齐后的尺寸 

        DWORD PointerToRawData;        // 在文件中的偏移量 

        DWORD PointerToRelocations;     // 在OBJ文件中使用,重定位的偏移 

        DWORD PointerToLinenumbers;   // 行号表的偏移(供调试使用地) 

        WORD NumberOfRelocations;      // 在OBJ文件中使用,重定位项数目 

        WORD NumberOfLinenumbers;    // 行号表中行号的数目 

        DWORD Characteristics;              // 节属性如可读,可写,可执行等} IMAGE_SECTION_HEADER,
*PIMAGE_SECTION_HEADER;  


Name 里面存的是区块的名字

.text code 什么的就是放代码用的

.data 就是放数据,已经初始化好的

.idata 就是输入表 ,很多加壳程序会修改输入表,hook api 在程序运行api时,让壳取得一定时间的权限来反跟踪,脱壳的一大步骤就是还原输入表。

.edata 输出表

.bbs 未初始化的数据

VirtualSizes是一个非常牛逼的成员,其中的值是区块没有按FileAlignment对其前的大小,通过它可以推算出区块中还有多少没有被使用,很多病毒会在未被是用的空间里

插入自己的代码。

Characteristics 表示该区块的属性 可读啊 可写啊什么的

 

//   IMAGE_SCN_TYPE_REG        0x00000000 // Reserved. 

//   IMAGE_SCN_TYPE_DSECT       0x00000001 // Reserved. 

//   IMAGE_SCN_TYPE_NOLOAD       0x00000002 // Reserved. 

//   IMAGE_SCN_TYPE_GROUP       0x00000004 // Reserved. 

#define IMAGE_SCN_TYPE_NO_PAD       0x00000008 // Reserved. 

//   IMAGE_SCN_TYPE_COPY        0x00000010 // Reserved. 

 

#define IMAGE_SCN_CNT_CODE        0x00000020 // Section contains code. 

                           //区段包含代码 

#define IMAGE_SCN_CNT_INITIALIZED_DATA  0x00000040 // Section contains initialized
data. 


                           //区段包含已初始化数据 

#define IMAGE_SCN_CNT_UNINITIALIZED_DATA 0x00000080 // Section contains uninitialized
data. 


                           //区段包含未初始化数据 

#define IMAGE_SCN_LNK_OTHER        0x00000100 // Reserved. 

#define IMAGE_SCN_LNK_INFO        0x00000200 // Section contains comments 

                           // or some other type of information. 

//   IMAGE_SCN_TYPE_OVER        0x00000400 // Reserved. 

#define IMAGE_SCN_LNK_REMOVE       0x00000800 // Section contents will not become part
of image. 


#define IMAGE_SCN_LNK_COMDAT       0x00001000 // Section contents comdat. 

//                    0x00002000 // Reserved. 

//   IMAGE_SCN_MEM_PROTECTED - Obsolete 0x00004000 

#define IMAGE_SCN_NO_DEFER_SPEC_EXC    0x00004000 // Reset speculative exceptions handling
bits 


                           // in the TLB entries for this section. 

#define IMAGE_SCN_GPREL          0x00008000 // Section content can be accessed relative
to GP 


#define IMAGE_SCN_MEM_FARDATA       0x00008000 

//   IMAGE_SCN_MEM_SYSHEAP - Obsolete 0x00010000 

#define IMAGE_SCN_MEM_PURGEABLE      0x00020000 

#define IMAGE_SCN_MEM_16BIT        0x00020000 

#define IMAGE_SCN_MEM_LOCKED       0x00040000 

#define IMAGE_SCN_MEM_PRELOAD       0x00080000 

 

#define IMAGE_SCN_ALIGN_1BYTES      0x00100000 // 

#define IMAGE_SCN_ALIGN_2BYTES      0x00200000 // 

#define IMAGE_SCN_ALIGN_4BYTES      0x00300000 // 

#define IMAGE_SCN_ALIGN_8BYTES      0x00400000 // 

#define IMAGE_SCN_ALIGN_16BYTES      0x00500000 // Default alignment if no others are
specified. 


#define IMAGE_SCN_ALIGN_32BYTES      0x00600000 // 

#define IMAGE_SCN_ALIGN_64BYTES      0x00700000 // 

#define IMAGE_SCN_ALIGN_128BYTES     0x00800000 // 

#define IMAGE_SCN_ALIGN_256BYTES     0x00900000 // 

#define IMAGE_SCN_ALIGN_512BYTES     0x00A00000 // 

#define IMAGE_SCN_ALIGN_1024BYTES     0x00B00000 // 

#define IMAGE_SCN_ALIGN_2048BYTES     0x00C00000 // 

#define IMAGE_SCN_ALIGN_4096BYTES     0x00D00000 // 

#define IMAGE_SCN_ALIGN_8192BYTES     0x00E00000 // 

// Unused                 0x00F00000 

 

#define IMAGE_SCN_LNK_NRELOC_OVFL     0x01000000 // Section contains extended relocations. 

#define IMAGE_SCN_MEM_DISCARDABLE     0x02000000 // Section can be discarded. 

                           //该区段可丢弃 

#define IMAGE_SCN_MEM_NOT_CACHED     0x04000000 // Section is not cachable. 

#define IMAGE_SCN_MEM_NOT_PAGED      0x08000000 // Section is not pageable. 

#define IMAGE_SCN_MEM_SHARED       0x10000000 // Section is shareable. 

                           //该区段可共享 

#define IMAGE_SCN_MEM_EXECUTE       0x20000000 // Section is executable. 

                           //该区段可执行 

#define IMAGE_SCN_MEM_READ        0x40000000 // Section is readable. 

                           //该区段可读 

#define IMAGE_SCN_MEM_WRITE        0x80000000 // Section is writeable. 

                           //该区段可写 

 

最后写个程序把这个结构读出来

由于我比较懒就只读了Name这个成员,有些加壳软件会修改Name这个字段使读出来的东西乱七八糟,比如UPX的压缩壳,会把Name字段改成UPX0,UPX1这样

 

#include "windows.h" 

#include "stdio.h" 

 

int main(int argc, char* argv[]) 



    FILE *p; 

    int i; 

    unsigned long Signature; 

    IMAGE_FILE_HEADER myfileheader; 

    IMAGE_DOS_HEADER mydosheader; 

    IMAGE_OPTIONAL_HEADER myoptionalheader; 

    IMAGE_SECTION_HEADER mysectionheader; 

 

    p = fopen("test.exe","r+b"); 

    if(p == NULL)return -1; 

 

    fread(&mydosheader,sizeof(mydosheader),1,p); 

    fseek(p,mydosheader.e_lfanew,SEEK_SET); 

    fread(&Signature,sizeof(Signature),1,p); 

 

    fseek(p,mydosheader.e_lfanew+sizeof(Signature),SEEK_SET);//指向IMAGE_FILE_HEADER结构的偏移 

    fread(&myfileheader,sizeof(myfileheader),1,p); 

 

    fseek(p,mydosheader.e_lfanew+sizeof(Signature)+sizeof(myfileheader)+sizeof(myoptionalheader),SEEK_SET); 

    printf("Signature          : %04X\n",Signature); 

    printf("IMAGE_SECTION_HEADER       结构:\n"); 

    for(i=0;i<myfileheader.NumberOfSections;i++){ 

        fread(&mysectionheader,sizeof(mysectionheader),1,p); 

        printf("Name               : %s\n",mysectionheader.Name); 

    } 

    fclose(p); 

    return 0; 















    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多