一、作业
1.编写程序读取一个.exe文件,输出所有的PE头信息
#include "stdafx.h"
#include <stdlib.h>
typedef unsigned short WORD;
typedef unsigned int DWORD;
typedef unsigned char BYTE;
//宏定义MZ标记和PE标记,方便后面判断
#define MZ 0x5A4D
#define PE 0x4550
//DOS头
struct _IMAGE_DOS_HEADER {
WORD e_magic; //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; //PE文件真正开始的偏移地址
};
//标准PE头
struct _IMAGE_FILE_HEADER {
WORD Machine; //文件运行平台
WORD NumberOfSections; //节数量
DWORD TimeDateStamp; //时间戳
DWORD PointerToSymbolTable;
DWORD NumberOfSymbols;
WORD SizeOfOptionalHeader; //可选PE头大小
WORD Characteristics; //特征值
};
//可选PE头
struct _IMAGE_OPTIONAL_HEADER {
WORD Magic; //文件类型
BYTE MajorLinkerVersion;
BYTE MinorLinkerVersion;
DWORD SizeOfCode; //代码节文件对齐后的大小
DWORD SizeOfInitializedData; //初始化数据文件对齐后的大小
DWORD SizeOfUninitializedData; //未初始化数据文件对齐后大小
DWORD AddressOfEntryPoint; //程序入口点(偏移量)
DWORD BaseOfCode; //代码基址
DWORD BaseOfData; //数据基址
DWORD ImageBase; //内存镜像基址
DWORD SectionAlignment; //内存对齐粒度
DWORD FileAlignment; //文件对齐粒度
WORD MajorOperatingSystemVersion;
WORD MinorOperatingSystemVersion;
WORD MajorImageVersion;
WORD MinorImageVersion;
WORD MajorSubsystemVersion;
WORD MinorSubsystemVersion;
DWORD Win32VersionValue;
DWORD SizeOfImage; //文件装入虚拟内存后大小
DWORD SizeOfHeaders; //DOS、NT头和节表大小
DWORD CheckSum; //校验和
WORD Subsystem;
WORD DllCharacteristics;
DWORD SizeOfStackReserve; //预留堆栈大小
DWORD SizeOfStackCommit; //实际分配堆栈大小
DWORD SizeOfHeapReserve; //预留堆大小
DWORD SizeOfHeapCommit; //实际分配堆大小
DWORD LoaderFlags;
DWORD NumberOfRvaAndSizes; //目录项数目
//_IMAGE_DATA_DIRECTORY DataDirectory[16]; //这个先不管
};
//NT头
struct _IMAGE_NT_HEADERS {
DWORD Signature; //PE签名
_IMAGE_FILE_HEADER FileHeader;
_IMAGE_OPTIONAL_HEADER OptionalHeader;
};
//将文件读入FileBuffer函数
char* to_FileBuffer(char* filePath){
FILE* fp = fopen(filePath,"rb");
if(!fp){
printf("打开文件失败");
exit(0);
}
fseek(fp,0,2);
int size = ftell(fp); //计算文件大小
fseek(fp,0,0);
char* mp = (char*)malloc(sizeof(char) * size); //分配内存空间
if(!mp){
printf("分配空间失败");
fclose(fp);
exit(0);
}
int isSucceed = fread(mp,size,1,fp);
if(!isSucceed){
printf("读取数据失败");
free(mp);
fclose(fp);
exit(0);
}
fclose(fp);
return mp;
}
//打印PE头各字段函数
void PE_header_print(char* filePath){
char* mp = to_FileBuffer(filePath); //将文件读入内存并返回FileBuffer首地址
//定义各个结构结构体指针,方便查找数据
_IMAGE_DOS_HEADER* _image_dos_header = NULL;
_IMAGE_FILE_HEADER* _image_file_header = NULL;
_IMAGE_OPTIONAL_HEADER* _image_optional_header = NULL;
_IMAGE_NT_HEADERS* _image_nt_header = NULL;
//打印DOS头
_image_dos_header = (_IMAGE_DOS_HEADER*)mp;
printf("************DOS头*************\n");
if(_image_dos_header->e_magic != MZ){
printf("此文件不满足MZ标记,不再继续分析");
exit(0);
}
printf("e_magic:%04X\n",_image_dos_header->e_magic); //%04X表示输出格式为宽度为4不够用0补的十六进制
printf("e_lfanew:%08X\n",_image_dos_header->e_lfanew);
//打印PE签名
_image_nt_header = (_IMAGE_NT_HEADERS*)((char*)mp + _image_dos_header->e_lfanew);
printf("\n\n************PE签名*************\n");
if(_image_nt_header->Signature != PE){
printf("不是有效的PE标记");
exit(0);
}
printf("Signature:%08X\n",_image_nt_header->Signature);
//打印标准PE头
_image_file_header = (_IMAGE_FILE_HEADER*)((char*)_image_nt_header + 4);
printf("\n\n************标准PE头*************\n");
printf("Machine:%04X\n",_image_file_header->Machine);
printf("NumberOfSections:%04X\n",_image_file_header-> NumberOfSections);
printf("TimeDateStamp:%08X\n",_image_file_header->TimeDateStamp);
printf("SizeOfOptionalHeader:%04X\n",_image_file_header->SizeOfOptionalHeader);
printf("Characteristics:%04X\n",_image_file_header-> Characteristics);
//打印可选PE头
_image_optional_header = (_IMAGE_OPTIONAL_HEADER*)((char*)_image_nt_header + 24);
printf("\n\n************可选PE头*************\n");
printf("Magic:%04X\n",_image_optional_header->Magic);
printf("SizeOfCode:%08X\n",_image_optional_header->SizeOfCode);
printf("SizeOfInitializedData:%08X\n",_image_optional_header-> SizeOfInitializedData);
printf("SizeOfUninitializedData:%08X\n",_image_optional_header->SizeOfUninitializedData);
printf("AddressOfEntryPoint:%08X\n",_image_optional_header->AddressOfEntryPoint);
printf("BaseOfCode:%08X\n",_image_optional_header-> BaseOfCode);
printf("BaseOfData:%08X\n",_image_optional_header->BaseOfData);
printf("ImageBase:%08X\n",_image_optional_header-> ImageBase);
printf("SectionAlignment:%08X\n",_image_optional_header->SectionAlignment);
printf("FileAlignment:%08X\n",_image_optional_header->FileAlignment);
printf("SizeOfImage:%08X\n",_image_optional_header->SizeOfImage);
printf("SizeOfHeaders:%08X\n",_image_optional_header-> SizeOfHeaders);
printf("CheckSum:%08X\n",_image_optional_header->CheckSum);
printf("SizeOfStackReserve:%08X\n",_image_optional_header->SizeOfStackReserve);
printf("SizeOfStackCommit:%08X\n",_image_optional_header->SizeOfStackCommit);
printf("SizeOfHeapReserve:%08X\n",_image_optional_header->SizeOfHeapReserve);
printf("SizeOfHeapCommit:%08X\n",_image_optional_header->SizeOfHeapCommit);
//别忘了释放分配的内存mp
free(mp);
}
int main(int argc,char* argv[]){
char* filePath = "D:/C-language/file/notepad.exe"; //你要打开的PE文件绝对路径
PE_header_print(filePath);
return 0;
}
2.使用第三方的PE工具,对比如下信息,看是否一致
-
验证如下: