前段时间项目需要实现对 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); //获取产品版本
};

效果演示:

提取 PE文件 / 目标程序 的各种信息的更多相关文章

  1. 用python提取txt文件中的特定信息并写入Excel

    这个是用 excel里面的 去掉空格最后导出的一个list: 原本是有空格的 后面是抵消了中间的空格. 然后 这里侧重说一下什么是split()函数 语法:str.split(str="&q ...

  2. PE文件结构部分解析以及输入的定位

    原文链接地址:http://www.cnblogs.com/shadow-lei/p/3554670.html PE文件定义 PE 文件("Portable executable" ...

  3. 【学习】Windows PE文件学习(一:导出表)

    今天做了一个读取PE文件导出表的小程序,用来学习. 参考了<Windows PE权威指南>一书. 首先, PE文件的全称是Portable Executable,可移植的可执行的文件,常见 ...

  4. C语言读取PE文件信息(一)

    接下来的内容来源于对该博客文章http://www.pediy.com/kssd/pediy06/pediy7006.htm的解析. 一.打印Sections信息.下面的程序打印出Windows_Gr ...

  5. C/C++ 实现PE文件特征码识别

    PE文件就是我们常说的EXE可执行文件,针对文件特征的识别可以清晰的知道该程序是使用何种编程语言实现的,前提是要有特征库,PE特征识别有多种形式,第一种是静态识别,此方法就是只针对磁盘中文件的特征码字 ...

  6. 破解软件系列-PE文件深入浅出之Section Table节表

    我们已经学了许多关于 DOS header 和 PE header 的知识.接下来就该轮到 section table(节表)了.节表其实就是紧挨着 PE header 的一结构数组.该数组成员的数目 ...

  7. 20145314郑凯杰《网络对抗技术》PE文件病毒捆绑(插入捆绑)的实现

    20145314郑凯杰<网络对抗技术>PE文件病毒捆绑(插入捆绑)的实现 一.本节摘要 简介:每个应用程序内部都有一定的空间(因为文件对齐余留的00字段)可以被利用,这样就可以保证被插入的 ...

  8. 浅析MSIL中间语言——PE文件结构篇

    一.开篇 开篇我想讲一下于本文无关的话题,其实我很想美化一下自己博客园一直没时间弄,无意间找了博客园李宝亨的博客园里面有一篇分享自己主题的文章,我就将这个模板暂时用作我的blog主题,我要讲述一个关于 ...

  9. PE文件学习系列笔记四-C++实现PE文件的分析

    合肥程序员群:49313181.    合肥实名程序员群:128131462 (不愿透露姓名和信息者勿加入) Q  Q:408365330     E-Mail:egojit@qq.com 综述: 首 ...

  10. PE文件学习系列三-PE头详解

    合肥程序员群:49313181.    合肥实名程序员群:128131462 (不愿透露姓名和信息者勿加入) Q  Q:408365330     E-Mail:egojit@qq.com 最近比较忙 ...

随机推荐

  1. IDEA降低注解检测级别

    在 File | Settings | Editor | Inspections 选项中使用搜索功能找到 Autowiring for Bean Class,将 Severity 的级别由之前的 er ...

  2. Django CMS搭建--1.虚拟环境搭建

    客户端环境:windows10 1.virtualenv使用 virtualenv 是 Python 中的一个包,用于创建和管理虚拟环境,可以在不同的项目中使用不同的 Python 版本和第三方库,避 ...

  3. C、C++函数和类库详解(VC++版)(2016-06-26更新)

    C.C++函数和类库详解(VC++版)(未完成) 整理者:赤勇玄心行天道 QQ:280604597 Email:280604597@qq.com 大家有什么不明白的地方,或者想要详细了解的地方可以联系 ...

  4. 《流畅的Python》 读书笔记 第5章 一等函数 20231025

    第5章 一等函数 第四章相对偏僻,但时间上一样要花我很久,就先跳过了,回头再补.而这个第5章节是非常重要的.只是最近工作有点忙,我读的越来越慢了~继续坚持吧. 在 Python 中,所有函数都是一等对 ...

  5. Redis 6 学习笔记 4 —— 通过秒杀案例,学习并发相关和apache bench的使用,记录遇到的问题

    背景 这是某硅谷的redis案例,主要问题是解决计数器和人员记录的事务操作 按照某硅谷的视频敲完之后出现这样乱码加报错的问题 乱码的问题要去tomcat根目录的conf文件夹下修改logging.pr ...

  6. [Python急救站课程]凯撒密码加密与解密

    密码的解密是一个有趣的过程,凯撒密码也是一个较为简单的密码,是通过位移来解决的. 当我们把凯撒密码位移量设置为3时就可以用Python做出以下程序. 加密程序: plaincode = input(& ...

  7. [Python急救站课程]蟒蛇的绘制

    Python的英文是有蟒蛇的意思,用Python画一条蟒蛇试试吧 一.普通蟒蛇的绘制 import turtle # 调用turtle(海龟绘图)加as t表示将库名改命名为t,后续用t.(函数名表式 ...

  8. HarmonyOS应用开发

    引言 本章将深入探讨 HarmonyOS 应用开发的关键方面,包括应用的生命周期.数据存储和网络访问.了解这些内容对于创建功能丰富.高效的 HarmonyOS 应用至关重要. 目录 HarmonyOS ...

  9. 题解 CF1004C

    题意描述: 给定 \(n\) 个数,从前往后找,看看能和后面的数组成多少个不同的数对. 若两个数对仅仅是位置不同,我们也认为是两个不同的数对. 题目分析: 阅读题目,我们不难看出,若前面有一个数已经出 ...

  10. A组Day7

    A. 放置石子 我们设第一格的东西为 \(x\) ,则接下来的格数为 \[2:1+x\\ 3:2x+1\\ 4:3x+2\\ 5:5x+3\\ ... \] 易得x的系数就是原来的斐波那契额数列,而后 ...