首页 > 编程语言 >提取 PE文件 / 目标程序 的各种信息

提取 PE文件 / 目标程序 的各种信息

时间:2024-01-10 17:58:00浏览次数:48  
标签:case 08X 提取 PE pOptionalHeader 目标程序 break printf t%

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

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

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

实现代码:

#include "stdafx.h"
#include <Windows.h>
 
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 文件的版本信息:

#include "stdafx.h"
#include <string>
#include <iostream>
#include "attribute.h"  
 
#pragma comment(lib, "version")
 
using namespace std;
 
bool QueryValue(const std::string& ValueName, const std::string& szModuleName, std::string& RetStr)
{
	bool bSuccess = FALSE;
	BYTE*  m_lpVersionData = NULL;
	DWORD   m_dwLangCharset = 0;
	CHAR *tmpstr = NULL;
 
	do
	{
		if (!ValueName.size() || !szModuleName.size())
			break;
 
		DWORD dwHandle;
		// 判断系统能否检索到指定文件的版本信息
		DWORD dwDataSize = ::GetFileVersionInfoSizeA((LPCSTR)szModuleName.c_str(), &dwHandle);
		if (dwDataSize == 0)
			break;
 
		m_lpVersionData = new (std::nothrow) BYTE[dwDataSize];// 分配缓冲区
		if (NULL == m_lpVersionData)
			break;
 
		// 检索信息
		if (!::GetFileVersionInfoA((LPCSTR)szModuleName.c_str(), dwHandle, dwDataSize, (void*)m_lpVersionData))
			break;
 
		UINT nQuerySize;
		DWORD* pTransTable;
		// 设置语言
		if (!::VerQueryValueA(m_lpVersionData, "\\VarFileInfo\\Translation", (void **)&pTransTable, &nQuerySize))
			break;
 
		m_dwLangCharset = MAKELONG(HIWORD(pTransTable[0]), LOWORD(pTransTable[0]));
		if (m_lpVersionData == NULL)
			break;
 
		tmpstr = new (std::nothrow) CHAR[128];
		if (NULL == tmpstr)
			break;
		sprintf_s(tmpstr, 128, "\\StringFileInfo\\%08lx\\%s", m_dwLangCharset, ValueName.c_str());
		LPVOID lpData;
 
		// 调用此函数查询前需要先依次调用函数GetFileVersionInfoSize和GetFileVersionInfo
		if (::VerQueryValueA((void *)m_lpVersionData, tmpstr, &lpData, &nQuerySize))
			RetStr = (char*)lpData;
 
		bSuccess = TRUE;
	} while (FALSE);
 
	// 销毁缓冲区
	if (m_lpVersionData)
	{
		delete[] m_lpVersionData;
		m_lpVersionData = NULL;
	}
	if (tmpstr)
	{
		delete[] tmpstr;
		tmpstr = NULL;
	}
 
	return bSuccess;
}

bool BaseFlow::Attribute::GetInternalName(const std::string& szModuleName, std::string& RetStr) 
{ 
	// return QueryValue("InternalName", szModuleName, RetStr);          //获取内部名称
    // return QueryValue("CompanyName", szModuleName, RetStr);           //获取公司名称
    // return QueryValue("LegalCopyright", szModuleName, RetStr);        //获取版权
    // return QueryValue("OriginalFilename", szModuleName, RetStr);      //获取原始文件名
    // return QueryValue("ProductName", szModuleName, RetStr);           //获取产品名称
    return QueryValue("ProductVersion", szModuleName, RetStr);           //获取产品版本
};	   

效果演示:

标签:case,08X,提取,PE,pOptionalHeader,目标程序,break,printf,t%
From: https://www.cnblogs.com/RainbowTechnology/p/17957030

相关文章

  • agx orin 使用 sdm 刷机后,vscode 使用 C++ 版本的 opencv, 出现红色的波浪线,但是程序
    原因:vscode没有链接好opencv的头文件先找到opencv头文件的位置:sudofind/-iname"opencv"/usr/include/opencv4/usr/include/opencv4/opencv2解决:ctril+sheft+p:打开:c_cpp_properties.json,写入:"includePath":["${workspaceFo......
  • opensuse修改cgroup到v2
    识别Linux节点上的cgroup版本cgroup版本取决于正在使用的Linux发行版和操作系统上配置的默认cgroup版本。要检查你的发行版使用的是哪个cgroup版本,请在该节点上运行stat-fc%T/sys/fs/cgroup/命令:对于cgroupv2,输出为cgroup2fs。对于cgroupv1,输出为tmpfs......
  • 【服务器数据恢复】虚拟机文件丢失导致Hyper-V服务瘫痪,虚拟机无法使用的数据恢复案例
    服务器数据恢复环境:WindowsServer操作系统服务器,部署Hyper-V虚拟化环境,虚拟机的硬盘文件和配置文件存放在某品牌MD3200存储中,MD3200存储中有一组由4块硬盘组成的raid5阵列,存放虚拟机的数据文件;另外还有一块硬盘存放虚拟机数据文件的备份。服务器故障&检测:由于MD3200存储中虚拟......
  • golang 用os.OpenFile写入文件
    funcmain(){ filename:="测试.txt" //如果文件存在,则追加写入,如果文件不存在则新建文件写入 //f,err:=os.OpenFile(filename,os.O_WRONLY|os.O_CREATE|os.O_APPEND,os.ModePerm) //本行是无法写入文件的,因为以O_RDONLY只读方式打开 //f,err:=os.OpenFile(fi......
  • OpenHarmony社区运营报告(2023年12月)
     • 截至2023年12月22日,OpenAtom OpenHarmony(简称“OpenHarmony")社区累计超过6700名贡献者,产生26.9万多个PR,2.4万多个Star,6.7万多个Fork,59个SIG。• 2023年12月16日,以“技术创新,照见未来”为主题的首届开放原子开发者大会OpenHarmony分论坛在无锡隆重举行。作为开放原子......
  • 测试SuspendThread、ResumeThread
    #include<iostream>#include<windows.h>#include<process.h>#include<conio.h>enum{ EVT_PAUSE=0, EVT_RESUME, EVT_QUIT, EVT_TOTAL};staticHANDLEevents[EVT_TOTAL]={NULL,NULL,NULL};staticunsignedint__stdcallhe......
  • Attribute 和 Property 的区别
    Attribute和Property的区别在阅读源码文档时,经常会看到Attribute和Property这两个词。中文直译是相同的,这就导致了概念的混淆。因此有必要区分这两者。Property在英语里有财产的含义,一般指对象的组成部分,可以是简单数据也可以是对象或对象集合.Attribute多指一个对......
  • PageOfficeV6.0提取在线编辑保存的excel单元格数据
    转载:提取单元格数据提取单元格数据查看本示例演示效果本示例关键代码的编写位置Vue+Springboot注意本文中展示的代码均为关键代码,复制粘贴到您的项目中,按照实际的情况,例如文档路径,用户名等做适当修改即可使用。在实际的开发过程中,经常会遇到提取Excel文档中数据保存到数据......
  • 安卓之从视频中提取音频的应用场景及技术优劣分析
    引言随着移动设备性能的不断提升和多媒体内容的广泛传播,从视频中提取音频已成为众多开发者与用户日常操作的一部分。在安卓平台上,这项技术经历了从早期的复杂专业工具到现今便捷易用的应用程序的演变过程。本文旨在探讨安卓系统中视频转音频(VideotoAudioExtraction,VAE)技术的发......
  • puppeteer的简单使用
    引言对于编写应用程序,尤其是要部署上线投入生产使用的应用,QA是其中重要的一环,在过去的工作经历中,我参与的项目开发,大多是由测试同学主要来把控质量的,我很少编写前端方面的测试代码,对于测试工具的使用,也基本停留在一个小玩具的样子,所以接触的也少,回忆上一次写单元测试,还是在一个vu......