// read version information from pe file
#include <iostream>
#include <cstdio>
#include <iomanip>
#include "custom_winnt.h" // refer to part of <winnt.h>
using namespace std;
const char *fnout_ver(const char *buf, int ilayer = 0)
{
int idistance = 0;
int i = 0;
unsigned short *pvalue = NULL;
//¼ÆËã°æ±¾ÐÅÏ¢¿é´óС
struct _version_info
{
unsigned short wLength;//½á¹¹×ܳ¤¶È
unsigned short wValueLength;//ÐÅÏ¢³¤¶È
unsigned short wType;//ÐÅÏ¢ÀàÐÍ(1-×Ö·û´®,0-¶þ½øÖÆ)
unsigned short szKey[1];//Unicode ×Ö·û´® KEY Óò
} *head = (_version_info *)buf;
for(idistance = 0; head->szKey[idistance];idistance++);//skip 'VS_VERSION_INFO'
idistance = (char*)(head->szKey + idistance + 1) - buf;//distance.
idistance = (idistance + 3) /4*4;//4 bytes align.
pvalue = (unsigned short *)(buf + idistance);
idistance += head->wValueLength * (head->wType ? 2 : 1);// is string or binrary.
idistance = (idistance + 3) /4*4;//align.
//Êä³ö°æ±¾ÐÅÏ¢¿é
for(i=0;i<ilayer;i++)
cout<<"\t";
if(head->wValueLength == sizeof(VS_FIXEDFILEINFO))// 52
{
wcout<<head->szKey<<L" VERSIONINFO"<<endl;
VS_FIXEDFILEINFO *Info = (VS_FIXEDFILEINFO*)pvalue;
cout<<" FILEVERSION "
<<(Info->dwFileVersionMS>>16)<<", "<<(Info->dwFileVersionMS&0xFFFF)<<", "
<<(Info->dwFileVersionLS>>16)<<", "<<(Info->dwFileVersionLS&0xFFFF)
<<endl;
cout<<" PRODUCTVERSION "
<<(Info->dwProductVersionMS>>16)<<", "<<(Info->dwProductVersionMS&0xFFFF)<<", "
<<(Info->dwProductVersionLS>>16)<<", "<<(Info->dwProductVersionLS&0xFFFF)
<<endl;
cout<<" FILEFLAGSMASK 0x"<<Info->dwFileFlagsMask<<endl;
cout<<" FILEFLAGS 0x"<<Info->dwFileFlags<<endl;
cout<<" FILEOS 0x"<<Info->dwFileOS<<endl;
cout<<" FILETYPE 0x"<<Info->dwFileType<<endl;
cout<<" FILESUBTYPE 0x"<<Info->dwFileSubtype<<endl;
}
else if(idistance < head->wLength)
{
if(head->wType)
wcout<<L"BLOCK \""<<head->szKey<<L"\""<<endl;//unicode string
else
wcout<<L"BLOCK \""<<head->szKey<<L"\", 0x"<<std::hex<<pvalue[0]<<L", "<<std::dec<<pvalue[1]<<endl;
}
else
{//if( idestance >= head->wLength )
if(head->wType)
{
wcout<<L"VALUE \""<<head->szKey<<L"\", \"";
for(i=0;i<(head->wValueLength);i++)
wprintf(L"%c",pvalue[i]);
if(head->wValueLength == 0)
cout<<"\\0\""<<endl;
else
cout<<"\""<<endl;
}
else
{
wprintf(L"VALUE \"%s\", %#x, %d\n",head->szKey,pvalue[0],pvalue[1]);//value
}
return buf + head->wLength;
}
//µÝ¹éÊä³ö×ÓÐÅÏ¢¿é
for(i=0;i<ilayer;i++)
cout<<"\t";
ilayer++;
cout<<"BEGIN\n";
while(idistance < head->wLength)
{
idistance = fnout_ver(buf + idistance, ilayer) - buf;
idistance = (idistance + 3) /4*4;// align.
}
ilayer--;
for(i=0;i<ilayer;i++)
cout<<"\t";
cout<<"END\n";
//
return buf + head->wLength;
}
bool fnget_ver_from_file(const char *pfile)
{
unsigned long i = 0;
unsigned long j = 0;
IMAGE_DOS_HEADER idh = {0};
IMAGE_NT_HEADERS inh = {0};
IMAGE_SECTION_HEADER ish = {0};
FILE *pf = NULL;
bool bret = false;
unsigned long dwrs_rva = 0;//relative virtual address of resource data.
unsigned long dwrs_addr = 0;//file offset for resource.
IMAGE_RESOURCE_DIRECTORY rsd[3] = {0};//generally speeking, there are three layers.
IMAGE_RESOURCE_DIRECTORY_ENTRY rsd_entry[3] = {0};//directory entry.
IMAGE_RESOURCE_DATA_ENTRY rsdata = {0};//data entry.
pf = fopen(pfile,"rb");
if(pf == NULL)
return false;
rewind(pf);//goto begin.
//get dos header.///
fread(&idh,sizeof(IMAGE_DOS_HEADER),1,pf);
if(idh.e_magic != IMAGE_DOS_SIGNATURE)
{
cerr<<"is not a pe app file."<<endl;
return false;
}//cout<<std::hex<<std::showbase<<idh.e_magic<<endl;//
//get nt header.
fseek(pf,idh.e_lfanew,SEEK_SET);
fread(&inh,sizeof(IMAGE_NT_HEADERS),1,pf);//get nt header.
dwrs_rva = inh.OptionalHeader.DataDirectory[2].VirtualAddress;//rva of resource data.
for(i =0;i<inh.FileHeader.NumberOfSections;i++)
{
fread(&ish,sizeof(IMAGE_SECTION_HEADER),1,pf);//get section header.
char szsect_name[9] = {0};//8 bit length.
memcpy(szsect_name,ish.Name,8);// section name.
//cout<<i<<". section name: "<<szsect_name<<endl;
if(dwrs_rva >= (ish.VirtualAddress) && //rva for start section.
dwrs_rva < (ish.VirtualAddress + ish.SizeOfRawData) )//end section.
{//RVAµ½Îļþʵ¼ÊÆ«ÒƵÄת»»
dwrs_addr = dwrs_rva - ish.VirtualAddress + ish.PointerToRawData;// [section rva] - [data rva] + [file offset]
break;
}
}
//cout<<endl<<"offset of resouce data: "<<std::hex<<std::showbase<<dwrs_addr<<endl;
fseek(pf,dwrs_addr,SEEK_SET);//get resource
fread(&rsd[0],sizeof(IMAGE_RESOURCE_DIRECTORY),1,pf);
for(i=0;i< (rsd[0].NumberOfIdEntries + rsd[0].NumberOfNamedEntries);i++)
{
unsigned long dwoffset = dwrs_addr + sizeof(IMAGE_RESOURCE_DIRECTORY) + (i * sizeof(IMAGE_RESOURCE_DIRECTORY_ENTRY) );
fseek(pf,dwoffset,SEEK_SET);
fread(&rsd_entry[0],sizeof(IMAGE_RESOURCE_DIRECTORY_ENTRY),1,pf);
// cout<<std::dec<<i<<". name: "<<rsd_entry[0].Name<<endl;
if(rsd_entry[0].Name == 16)//verinfo.
{
for(j =1;j<3;j++)
{
dwoffset = dwrs_addr + rsd_entry[j -1].OffsetToDirectory;
fseek(pf,dwoffset,SEEK_SET);
fread(&rsd[j],sizeof(IMAGE_RESOURCE_DIRECTORY),1,pf);
fread(&rsd_entry[j],sizeof(IMAGE_RESOURCE_DIRECTORY_ENTRY),1,pf);
}
dwoffset = dwrs_addr + rsd_entry[j -1].OffsetToData;
fseek(pf,dwoffset,SEEK_SET);
fread(&rsdata,sizeof(IMAGE_RESOURCE_DATA_ENTRY),1,pf);
char *pbuffer = new char [rsdata.Size]();
if(pbuffer == NULL)
{
fclose(pf);
return false;
}
dwoffset = rsdata.OffsetToData - ish.VirtualAddress + ish.PointerToRawData;
fseek(pf,dwoffset,SEEK_SET);
fread(pbuffer,1,rsdata.Size,pf);
//cout<<"version offset: "<<dwoffset<<", size: "<<std::dec<<std::noshowbase<<rsdata.Size<<endl<<endl;
fnout_ver(pbuffer);
delete [] pbuffer;
}
}
fclose(pf);
return bret;
}
int main(void)
{
fnget_ver_from_file("debug\\test.exe");
return 0;
}
reference links:
PE文件解析-资源中的版本信息结构_zhyulo的博客-CSDN博客_pe文件版本
PE文件解析-文件头与整体介绍_zhyulo的博客-CSDN博客_pe文件头
PE文件解析-资源(Resource)_zhyulo的博客-CSDN博客_pe文件资源解析