PE解析

一、什么是可执行文件

1、可执行文件(executable file)指的是可以由操作系统进行加载执行的文件。

2、可执行文件的格式:

  • Windows平台:

    • PE(Portable Executable)文件结构
  • Linux平台:

    • ELF(Executable and Linking Format)文件结构

二、如何识别PE文件

1、PE文件的特征(PE指纹)

分别打开.exe .dll .sys等文件,观察特征前2个字节,都是4D5A,变成字母是MZ,是DOS系统开发人员的一个名字,再看3C字节是什么,3C存的是一个地址,这个地址对应的5045,变为字母就是PE。

2、不要仅仅通过文件的后缀名来认定PE文件

三、对齐

对齐是为了读写速度,找起来快,用空间换时间

1、硬盘对齐

早期计算机硬盘水平比较低,只有很小的几个G,节与节之间的空隙比较小,硬盘对齐为200H,后来随着硬件水平提高了,硬盘对齐与内存对齐一样了为1000H

2、内存对齐

四、为什么要分节

1、节省硬盘空间.(这个不是决定的,由编译器决定)

2、一个应用程序多开

比如一个qq程序有两个部分,数据1(可读),数据2(可读可写) ,都是100M,我运行一个账号就需要200M,我再开一个,数据1(可读)已经有了,就没必要在复制一份丢在内存中,只需要复制一份数据2就可以了

3、理解FileBuffer和ImageBuffer

五、DOS头(64个字节)

typedef struct IMAGE_DOS_HEADER{
      WORD e_magic;			//DOS头的标识,为4Dh和5Ah。分别为字母MZ
      WORD e_cblp;
      WORD e_cp;
      WORD e_crlc;
      WORD e_cparhdr;
      WORD e_minalloc;
      WORD e_maxalloc;
      WORD e_ss;
      WORD e_sp;
      WORD e_csum;
      WORD e_ip;
      WORD e_cs;
      WORD e_lfarlc;
      WORD e_ovno;
      WORD e_res[4];
      WORD e_oemid;
      WORD e_oeminfo;
      WORD e_res2[10];
      DWORD e_lfanew;             //指向IMAGE_NT_HEADERS的所在(PE头相对于文件的偏移,用子定位E文件
)
}IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;

WORD 为一个16bit 的无符号数,重点是e_magice_magic

六、PE文件头(NT头)

typedef struct IMAGE_NT_HEADERS{
      DWORD Signature;                    //PE标识
      IMAGE_FILE_HEADER FileHeader;        //标准PE头(20字节)
      IMAGE_OPTIONAL_HEADER32 OptionalHeader;  //扩展PE头(大小不确定)
}IMAGE_NT_HEADERS,*PIMAGE_NT_HEADERS; 

七、节表

#define IMAGE_SIZEOF_SHORT_NAME 8			
typedef struct _IMAGE_SECTION_HEADER {		
    BYTE    Name[IMAGE_SIZEOF_SHORT_NAME];	//ASCII字符串 可自定义  只截取8个 可以8个字节都是名字	
    union {				        //Misc  双字 是该节在没有对齐前的真实尺寸,该值可以不准确
            DWORD   PhysicalAddress;		//内存中的真实长度,这两个值是一个联合结构,可以使用其中的任何一个                     
            DWORD     VirtualSize;	        //一般是取后一个		
			
    } Misc;					
    DWORD   VirtualAddress;		       //在内存中的偏移地址,加上ImageBase才是在内存中的真正地址	
    DWORD   SizeOfRawData;		       //节在文件中对齐后的尺寸				
    DWORD   PointerToRawData;		       //节区在文件中的偏移			
    DWORD   PointerToRelocations;	       //调试相关			
    DWORD   PointerToLinenumbers;				
    WORD    NumberOfRelocations;				
    WORD    NumberOfLinenumbers;				
    DWORD   Characteristics;		       //节的属性			
} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;

八、导出表

typedef struct _IMAGE_EXPORT_DIRECTORY {							
	DWORD   Characteristics;		// 未使用			
	DWORD   TimeDateStamp;			// 时间戳			
	WORD    MajorVersion;			// 未使用			
	WORD    MinorVersion;			// 未使用			
	DWORD   Name;				// 指向该导出表文件名字符串			
	DWORD   Base;				// 导出函数起始序号			
	DWORD   NumberOfFunctions;		// 所有导出函数的个数(不准确,有可能是错的)			
	DWORD   NumberOfNames;		        // 以函数名字导出的函数个数			
	DWORD   AddressOfFunctions;             // 导出函数地址表RVA							
	DWORD   AddressOfNames;                 // 导出函数名称表RVA							
	DWORD   AddressOfNameOrdinals;          // 导出函数序号表RVA							
} IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY;														

九、重定位表

typedef struct _IMAGE_BASE_RELOCATION {						
	DWORD   VirtualAddress;						
	DWORD   SizeOfBlock;						
} IMAGE_BASE_RELOCATION;						
typedef IMAGE_BASE_RELOCATION ,* PIMAGE_BASE_RELOCATION;												

十、导入表


	typedef struct _IMAGE_IMPORT_DESCRIPTOR {											
	    union {											
	        DWORD   Characteristics;           											
	        DWORD   OriginalFirstThunk;         			//RVA 指向IMAGE_THUNK_DATA结构数组					
	    };											
	    DWORD   TimeDateStamp;               			//时间戳					
	    DWORD   ForwarderChain;              											
	    DWORD   Name;						//RVA,指向dll名字,该名字已0结尾					
	    DWORD   FirstThunk;                 			//RVA,指向IMAGE_THUNK_DATA结构数组					
	} IMAGE_IMPORT_DESCRIPTOR;											
	typedef IMAGE_IMPORT_DESCRIPTOR UNALIGNED *PIMAGE_IMPORT_DESCRIPTOR;											
posted @ 2021-12-06 16:49  lnterpreter  阅读(227)  评论(0编辑  收藏  举报