滴水三期:day28.2-编写程序读取.exe文件的头字段

一、作业

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工具,对比如下信息,看是否一致

  • 验证如下:

    image-20230322033632921

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值