提取 PE 文件的各种信息

  提取 PE 文件的各种信息_第1张图片

      前段时间项目需要实现对 Windows PE 文件版本信息的提取,如文件说明、文件版本、产品名称、版权、原始文件名等信息。获取这些信息在 Windows 下当然有一系列的 API 函数供调用,简单方便。

        我们先看一下PE文件结构,PE文件由DOS首部,PE文件头,块表,块和调试信息组成,有关PE文件的数据结构信息在winnt.h中定义。

提取 PE 文件的各种信息_第2张图片

文章不过多赘述,直接上代码简单明了。

实现代码:

#include "stdafx.h"
#include 
 
extern void DirectoryString(DWORD dwIndex);
 
int _tmain(int argc, _TCHAR* argv[])
{
	//获取文件句柄
	HANDLE hFile = CreateFile(
		_T("D:\\Wmplayer.exe"),
		GENERIC_READ,
		0,
		NULL,
		OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
	//获取文件大小
	DWORD dwFileSize = GetFileSize(hFile, NULL);
	CHAR *pFileBuf = new CHAR[dwFileSize];
	//将文件读取到内存
	DWORD ReadSize = 0;
	ReadFile(hFile, pFileBuf, dwFileSize, &ReadSize, NULL);
 
	//判断是否为PE文件
	PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)pFileBuf;
	if (pDosHeader->e_magic != IMAGE_DOS_SIGNATURE)
	{
		printf("非 PE 文件\n");
		system("pause");
		return 0;
	}
 
	PIMAGE_NT_HEADERS pNtHeader = (PIMAGE_NT_HEADERS)(pFileBuf + pDosHeader->e_lfanew);
	if (pNtHeader->Signature != IMAGE_NT_SIGNATURE)
	{
		printf("非 PE 文件\n");
		system("pause");
		return 0;
	}
 
	//获取基本PE头信息
	//获取信息所用到的两个结构体指针	(这两个结构体都属于NT头)
	PIMAGE_FILE_HEADER		pFileHeader		= &(pNtHeader->FileHeader);
	PIMAGE_OPTIONAL_HEADER	pOptionalHeader	= &(pNtHeader->OptionalHeader);
	//输出PE头信息
	printf("================== 基 本 P E 头 信 息 ==================\n\n");
	printf("入 口 点:\t%08X\t", pOptionalHeader->AddressOfEntryPoint);
	printf("子 系 统:\t%04X\n", pOptionalHeader->Subsystem);
	printf("镜像基址:\t%08X\t", pOptionalHeader->ImageBase);
	printf("区段数目:\t%04X\n", pFileHeader->NumberOfSections);
	printf("镜像大小:\t%08X\t", pOptionalHeader->SizeOfImage);
	printf("日期时间标志:\t%08X\n", pFileHeader->TimeDateStamp);
	printf("代码基址:\t%08X\t", pOptionalHeader->BaseOfCode);
	printf("部首大小:\t%08X\n", pOptionalHeader->SizeOfHeaders);
	printf("数据基址:\t%08X\t", pOptionalHeader->BaseOfData);
	printf("特 征 值:\t%04X\n", pFileHeader->Characteristics);
	printf("块 对 齐:\t%08X\t", pOptionalHeader->SectionAlignment);
	printf("校 验 和:\t%08X\n", pOptionalHeader->CheckSum);
	printf("文件块对齐:\t%08X\t", pOptionalHeader->FileAlignment);
	printf("可选头部大小:\t%04X\n", pFileHeader->SizeOfOptionalHeader);
	printf("标 志 字:\t%04X\t\t", pOptionalHeader->Magic);
	printf("RVA数及大小:\t%08X\n\n", pOptionalHeader->NumberOfRvaAndSizes);
 
	printf("======================= 目 录 表 =======================\n");
	//获取目录表头指针
	PIMAGE_DATA_DIRECTORY pDataDirectory = pOptionalHeader->DataDirectory;
	printf("\t\t  RAV\t\t  大小\n");
	for (DWORD i = 0; i < IMAGE_NUMBEROF_DIRECTORY_ENTRIES; i++)
	{
		DirectoryString(i);
		printf("%08X\t%08X\n",
			pDataDirectory[i].VirtualAddress, pDataDirectory[i].Size);
	}
 
	printf("======================= 区 段 表 =======================\n");
	//获取区段表头指针
	PIMAGE_SECTION_HEADER pSectionHeader = IMAGE_FIRST_SECTION(pNtHeader);
	printf("名称      VOffset   VSize     ROffset   RSize     标志\n");
	//获取区段个数
	DWORD dwSectionNum = pFileHeader->NumberOfSections;
	//根据区段个数遍历区段信息
	for (DWORD i = 0; i < dwSectionNum; i++, pSectionHeader++)
	{
		for (DWORD j = 0; j < IMAGE_SIZEOF_SHORT_NAME; j++)
		{
			printf("%c", pSectionHeader->Name[j]);
		}
		printf("  %08X  %08X  %08X  %08X  %08X\n",
			pSectionHeader->VirtualAddress,
			pSectionHeader->Misc.VirtualSize,
			pSectionHeader->PointerToRawData,
			pSectionHeader->SizeOfRawData,
			pSectionHeader->Characteristics);
	}
	printf("\n");
 
    system("start https://www.chwm.vip/?PEinfo");
	system("pause");
	return 0;
}
 
void DirectoryString(DWORD dwIndex)
{
	switch (dwIndex)
	{
	case 0:printf("输出表:\t\t");
		break;
	case 1:printf("输入表:\t\t");
		break;
	case 2:printf("资源:\t\t");
		break;
	case 3:printf("异常:\t\t");
		break;
	case 4:printf("安全:\t\t");
		break;
	case 5:printf("重定位:\t\t");
		break;
	case 6:printf("调试:\t\t");
		break;
	case 7:printf("版权:\t\t");
		break;
	case 8:printf("全局指针:\t");
		break;
	case 9:printf("TLS表:\t\t");
		break;
	case 10:printf("载入配置:\t");
		break;
	case 11:printf("输入范围:\t");
		break;
	case 12:printf("IAT:\t\t");
		break;
	case 13:printf("延迟输入:\t");
		break;
	case 14:printf("COM:\t\t");
		break;
	case 15:printf("保留:\t\t");
		break;
	}
}

获取某指定区段的信息实现代码:

HANDLE hFile = CreateFile(_T("C:\\Windows\\SysNative\\ntoskrnl.exe"), GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
	if (hFile == INVALID_HANDLE_VALUE) {
		cout << "CreateFile failed:" << GetLastError() << endl;
		return false;
	}
	DWORD dwFileSize = GetFileSize(hFile, NULL);
	CHAR* pFileBuf = new CHAR[dwFileSize];
	DWORD ReadSize = 0;
	if (!ReadFile(hFile, pFileBuf, dwFileSize, &ReadSize, NULL)) {
		cout << "ReadFile failed:" << GetLastError() << endl;
		return false;
	}
	PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)pFileBuf;
	PIMAGE_NT_HEADERS pNtHeader = (PIMAGE_NT_HEADERS)(pFileBuf + pDosHeader->e_lfanew);
	PIMAGE_FILE_HEADER		pFileHeader = &(pNtHeader->FileHeader);
	PIMAGE_OPTIONAL_HEADER	pOptionalHeader = &(pNtHeader->OptionalHeader);
	PIMAGE_SECTION_HEADER pSectionHeader = IMAGE_FIRST_SECTION(pNtHeader);
	DWORD dwSectionNum = pFileHeader->NumberOfSections;
	int page_vaddr = 0, page_roff = 0;
	for (DWORD i = 0; i < dwSectionNum; i++, pSectionHeader++) {
		string s_name;
		for (DWORD j = 0; j < IMAGE_SIZEOF_SHORT_NAME; j++) {
			if (pSectionHeader->Name[j]) {
				s_name += pSectionHeader->Name[j];
			}
		}
		if (s_name == "PAGE") {
			page_vaddr = pSectionHeader->VirtualAddress;
			page_roff = pSectionHeader->PointerToRawData;
			break;
		}
	}
	if (page_vaddr == 0 || page_roff == 0) { cout << "没有找到 PAGE 区段" << endl; return false; }

效果演示:

提取 PE 文件的各种信息_第3张图片

你可能感兴趣的:(系统安全,系统监控,系统安全,PE文件信息截取)