-
-
[旧帖] 如何解析出PE文件中的资源数据中的版本信息?(非硬盘PE文件) 0.00雪花
-
发表于: 2010-11-30 22:07 3680
-
//////////////////////////////////////////////////////////////////////////////////
/*
最近学习PE结构,想从已经读取到内存里的PE文件的数据里,直接从内存里解析出一些资源数据。
(当然,微软也已经提供了相关的API来直接操作,但为了加深PE结构了解,自己写了个蛋疼的程序来验证)
通过 GetFileVersionInfoSize GetFileVersionInfo VerQueryValue 这3个API, 我们很容易获取一个硬盘上的文件的详细的版本信息.
理论上, 加载到内存里的数据,只要知道对应数据结构和偏移,也能获取出正确的对应信息.
但是第一个想法就搁浅了,看了半天的PE的资源数据,居然就是不知道如何获取对应的版本信息。
所以特来请教各位PE帝,PE达人,如何从内存里直接获取对应的版本信息。请看下面的代码:
问题集中在GetVersionInfoFromMem函数中获取到对应的资源PIMAGE_RESOURCE_DIRECTORY_ENTRY后,
如果才能获取VS_VERSIONINFO这个数据结构是变长的版本信息呢?
*/
//////////////////////////////////////////////////////////////////////////////////
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
DWORD RVA2Offset(void *pImage, DWORD dwRVA)
{
PIMAGE_DOS_HEADER pDos = (PIMAGE_DOS_HEADER )pImage;
PIMAGE_NT_HEADERS pNtHeads = (PIMAGE_NT_HEADERS)((DWORD)pDos + pDos->e_lfanew);
DWORD NumOfSection = pNtHeads->FileHeader.NumberOfSections;
PIMAGE_SECTION_HEADER pSectionHead = (PIMAGE_SECTION_HEADER )(sizeof(IMAGE_FILE_HEADER) + 4 + pNtHeads->FileHeader.SizeOfOptionalHeader + (DWORD)pNtHeads);
DWORD RawOfEntryPoint = 0;
DWORD RawinSection = 0;
WORD count=0;
while(count<NumOfSection)
{
if((dwRVA >= pSectionHead->VirtualAddress)
&&(dwRVA < pSectionHead->VirtualAddress+pSectionHead->Misc.VirtualSize))
{
RawinSection=dwRVA-pSectionHead->VirtualAddress;
RawOfEntryPoint=pSectionHead->PointerToRawData+RawinSection;
break;
}
pSectionHead++;
count++;
}
if (RawOfEntryPoint == 0)
{
return 0;
}
return RawOfEntryPoint;
}
DWORD CheckFileSize(char *filename)
{
HANDLE hFile=NULL;
WIN32_FIND_DATA wfd;
if((hFile=FindFirstFile(filename,&wfd))==INVALID_HANDLE_VALUE)
{
FindClose(hFile);
return 0;
}
FindClose(hFile);
return wfd.nFileSizeHigh*MAXDWORD+wfd.nFileSizeLow;
}
//从内存里获取版本资源信息
//lpFileData: 存放dll数据的内存缓冲区
//nDataLength: dll文件的长度
BOOL GetVersionInfoFromMem(void* lpFileData, int nDataLength)
{
PIMAGE_DOS_HEADER m_pDosHeader;
PIMAGE_NT_HEADERS m_pNTHeader;
PIMAGE_SECTION_HEADER m_pSectionHeader;
//检查长度
if (nDataLength < sizeof(IMAGE_DOS_HEADER))
{
return FALSE;
}
m_pDosHeader = (PIMAGE_DOS_HEADER)lpFileData; // DOS头
//检查dos头的标记
if (m_pDosHeader->e_magic != IMAGE_DOS_SIGNATURE)
{
return FALSE; //0x5A4D : MZ
}
//检查长度
if ((DWORD)nDataLength < (m_pDosHeader->e_lfanew + sizeof(IMAGE_NT_HEADERS)))
{
return FALSE;
}
//取得pe头
m_pNTHeader = (PIMAGE_NT_HEADERS)((PBYTE)lpFileData + m_pDosHeader->e_lfanew); // PE头
//检查pe头的合法性
if (m_pNTHeader->Signature != IMAGE_NT_SIGNATURE)
{
return FALSE; //0x00004550 : PE00
}
if ((m_pNTHeader->FileHeader.Characteristics & IMAGE_FILE_DLL) == 0) //0x2000 : File is a DLL
{
return FALSE;
}
if ((m_pNTHeader->FileHeader.Characteristics & IMAGE_FILE_EXECUTABLE_IMAGE) == 0) //0x0002 : 指出文件可以运行
{
return FALSE;
}
if (m_pNTHeader->FileHeader.SizeOfOptionalHeader != sizeof(IMAGE_OPTIONAL_HEADER))
{
return FALSE;
}
//取得节表(段表)
m_pSectionHeader = (PIMAGE_SECTION_HEADER)((PBYTE)m_pNTHeader + sizeof(IMAGE_NT_HEADERS));
//验证每个节表的空间
for (int i=0; i< m_pNTHeader->FileHeader.NumberOfSections; i++)
{
if ((m_pSectionHeader[i].PointerToRawData + m_pSectionHeader[i].SizeOfRawData) > (DWORD)nDataLength)
{
return FALSE;
}
}
if(m_pNTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress != 0 &&m_pNTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].Size != 0 )
{
int nEntries;
DWORD dwOffset = RVA2Offset(lpFileData,m_pNTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress);
PIMAGE_RESOURCE_DIRECTORY pResRootDir = (PIMAGE_RESOURCE_DIRECTORY )((LPBYTE)lpFileData+dwOffset);
PIMAGE_RESOURCE_DIRECTORY_ENTRY pResTypeDirEnt = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)((LPBYTE)pResRootDir+sizeof(IMAGE_RESOURCE_DIRECTORY));
nEntries = pResRootDir->NumberOfNamedEntries+pResRootDir->NumberOfIdEntries;
for (i = 0; i < nEntries; i++)
{
if(!pResTypeDirEnt->NameIsString&&pResTypeDirEnt->Id==16)
{
//VS_FIXEDFILEINFO FixedInfo;
printf("\r\nFound Version Resouce\r\n");
//通过 GetFileVersionInfoSize GetFileVersionInfo VerQueryValue 这3个API, 我们很容易获取一个硬盘上的文件的详细的版本信息.
//理论上, 加载到内存里的数据,只要知道对应数据结构和偏移,也能获取出正确的对应信息.
//到了这步,看了半天PE资料,GOOGLE了一天,找了很久的资料,
//继续GOOGLE,VS_VERSIONINFO居然是个可变长结构体.到此彻底蒙了.
//该如何从内存里取出对应的版本信息? 就如同使用上面的3个API?
/*
?????????????????????????????????????????????
*/
}
// Reference next entry in directory entries array.
pResTypeDirEnt++;
}
}
return TRUE;
}
void main(int argc, char *argv[])
{
if(argc==2)
{
char* pFileMemBuffer;
DWORD dFileSize=CheckFileSize(argv[1]);
if(dFileSize)
{
pFileMemBuffer=new char[dFileSize];
if (!pFileMemBuffer)
{
return;
}
else
{
FILE* fp = fopen(argv[1], "rb");
int nLen = static_cast<int>(fread(pFileMemBuffer, 1, dFileSize, fp));
fclose(fp);
}
GetVersionInfoFromMem(pFileMemBuffer,dFileSize);
}
}
}
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!
赞赏
他的文章
看原图
赞赏
雪币:
留言: