前段时间项目需要实现对 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. 用 Dijkstra 算法解决最短路问题

    话不多说,先看图 1.1 朴素版的Dijkstra算法 一般用到这个情况稠密图,也就是节点的个数比边的个数少. (稠密图用邻接矩阵存储) #include<cstring> #includ ...

  2. RocketMQ版控制台,在左侧

    打开IntelliJ IDEA,创建一个Java工程. 在pom.xml文件中添加以下依赖引入Java SDK的依赖库.   <dependency> <groupId>org ...

  3. P6066 [USACO05JAN] Watchcow S

    prologue 这个题这么水的一个板子题. analysis 这个题目我们正反建两条边,在跑欧拉回路的时候,看这个边是不是被走过,走过就不走,跳过这个边.如果没走,就走这条边并且标记这个边走过了. ...

  4. 手写商用Java虚拟机HotSpot,疯狂磨砺技术中

    在当前Java行业激烈竞争的形式下,唯有掌握技术,心中才不能慌.在多年前,我就开始苦练底层技术,但是眼看百遍也不如手过一遍,所以我打算把虚拟机的精华实现部分用手敲出来,这个过程注定不会轻松,但是心态不 ...

  5. [ABC208E] Digit Products 题解

    Digit Products 题目大意 求有多少个不大于 \(n\) 的正整数,使得该正整数各位乘积不大于 \(k\). 思路分析 观察数据范围,首先考虑数位 DP. 考虑设计记忆化搜索函数 dfs( ...

  6. 2D物理引擎 Box2D for javascript Games 第五章 碰撞处理

    2D物理引擎 Box2D for javascript Games 第五章 碰撞处理 碰撞处理 考虑到 Box2D 世界和在世界中移动的刚体之间迟早会发生碰撞. 而物理游戏的大多数功能则依赖于碰撞.在 ...

  7. [WPF]原生TabControl控件实现拖拽排序功能

    在UI交互中,拖拽操作是一种非常简单友好的交互.尤其是在ListBox,TabControl,ListView这类列表控件中更为常见.通常要实现拖拽排序功能的做法是自定义控件.本文将分享一种在原生控件 ...

  8. python 远程操作svn

    SVN操作脚本 安装模块 pip install pywinrm 脚本如下 #!/usr/bin/env python3 # coding=utf-8 # author:LJX # describe: ...

  9. QT(9)-QStyleOption及其子类

    1 QStyleOption QStyleOption及其子类包含QStyle函数绘制图形元素所需的所有信息. 出于性能考虑,成员函数很少,对成员变量的访问是直接的(即使用.或者->运算符).这 ...

  10. webview是什么?作用是什么?和浏览器有什么关系?

    Webview 是一个基于webkit的引擎,可以解析DOM 元素,展示html页面的控件,它和浏览器展示页面的原理是相同的,所以可以把它当做浏览器看待.(chrome浏览器也是基于webkit引擎开 ...