PE文件资源解析(九)版本信息资源的解析

版本信息资源,在这里指的是资源类型为RT_VERSION的资源信息。通过ResHacker看到的效果图如下:

 版本信息资源存储编码格式是UNICODE,解析代码如下: 

HRSRC hResrc = ::FindResourceEx((HMODULE)hModule, lpType, lpName, wLanguage);
DWORD dwSize = ::SizeofResource((HMODULE)hModule, hResrc);
HGLOBAL hGlobal = ::LoadResource((HMODULE)hModule, hResrc);
if (hGlobal == NULL)
	return;

BYTE* lpResrc = (BYTE*)LockResource(hGlobal);
if (lpResrc == NULL)
	return;

HGLOBAL hAllocMem = GlobalAlloc(GMEM_FIXED, dwSize);
char* pMem = (char*)GlobalLock(hAllocMem);
memcpy(pMem, lpResrc, dwSize);
std::wstring swVersion = GetVersionInfo((char*)pMem, dwSize);
GlobalUnlock(hAllocMem);
GlobalFree(hAllocMem);
//swVersion就是解析的最终结果

其中GetVersionInfo函数的实现代码如下:

#define DWORDUP(x) (((DWORD)(LPBYTE)(x)+3)&~03)
std::wstring GetVersionInfo(char* lpszVersinon, int size)
{
	//第一部分是一个 VS_FIXEDFILEINFO 对象,包含简要版本信息。
	//第二部分是一个 VarFileInfo 对象,该部分可能不存在。
	//第三部分是一个 StringFileInfo 对象,该部分可能不存在。
	VS_VERSIONINFO* pVersionInfo = (VS_VERSIONINFO*)lpszVersinon;
	VS_FIXEDFILEINFO* pFileInfo = (VS_FIXEDFILEINFO*)((char*)lpszVersinon + 40);
	std::wstring wsResult = L"1 VERSIONINFO\r\n";
	CStringW wStr;
	wStr.Format(L"FILEVERSION %d,%d,%d,%d",
		(pFileInfo->dwFileVersionMS >> 16) & 0xFF,
		(pFileInfo->dwFileVersionMS) & 0xFF,
		(pFileInfo->dwFileVersionLS >> 16) & 0xFF,
		(pFileInfo->dwFileVersionLS) & 0xFF);
	wsResult += wStr.GetBuffer(0);
	wsResult += L"\r\n";
	wStr.Format(L"PRODUCTVERSION %d,%d,%d,%d",
		(pFileInfo->dwProductVersionMS >> 16) & 0xFF,
		(pFileInfo->dwProductVersionMS) & 0xFF,
		(pFileInfo->dwProductVersionLS >> 16) & 0xFF,
		(pFileInfo->dwProductVersionLS) & 0xFF);
	wsResult += wStr.GetBuffer(0);
	wsResult += L"\r\n";
	wStr.Format(L"FILEOS 0x%X", pFileInfo->dwFileOS);
	wsResult += wStr.GetBuffer(0);
	wsResult += L"\r\n";
	wStr.Format(L"FILETYPE 0x%X", pFileInfo->dwFileType);
	wsResult += wStr.GetBuffer(0);
	wsResult += L"\r\n{";

	VS_VARSTRINGTABLE* pbVersionInfoStrings = (VS_VARSTRINGTABLE*)((char*)pFileInfo + sizeof(VS_FIXEDFILEINFO));
	VS_VARBLOCK* pbVersionInfoString = (VS_VARBLOCK*)pbVersionInfoStrings;
	int nRef = 1;
	while ((DWORD_PTR)pbVersionInfoString < (DWORD_PTR)lpszVersinon + size)
	{
		VS_VARBLOCK* pbBlocks = (VS_VARBLOCK*)pbVersionInfoString;
		std::wstring wsBlock = L"\r\nBLOCK \""+ std::wstring((WCHAR*)pbBlocks->szKey) + L"\"";
		wsBlock += L"\r\n{\r\n";
		if (nRef == 1) // StringFileInfo
		{
			VS_VARSTRING* pbBlock = (VS_VARSTRING*)DWORDUP(pbBlocks->szKey + lstrlenW(pbBlocks->szKey) + 1);
			while ((DWORD_PTR)pbBlock < (DWORD_PTR)pbBlocks + pbBlocks->wLength)
			{
				wsBlock += L"\tBLOCK \"" + std::wstring((WCHAR*)pbBlock->szKey) + L"\"";

				//////////////////////////////////////////////////////////////////////////
				VS_VARSTRINGTABLE* pbStringTable = (VS_VARSTRINGTABLE*)pbBlock;
				wsBlock += L"\r\n\t{";
				BOOL bResult = FALSE;
				VS_VARSTRING* pbString = (VS_VARSTRING*)DWORDUP(pbStringTable->szKey + lstrlenW(pbStringTable->szKey) + 1);
				while ((DWORD_PTR)pbString < (DWORD_PTR)pbStringTable + pbStringTable->wLength)
				{
					if (pbString->wType == 1)
						wsBlock += L"\r\n\t\tVALUE \"" + std::wstring((WCHAR*)pbString->szKey) + L"\"" + L", \"" + std::wstring((WCHAR*)DWORDUP(pbString->szKey + lstrlenW(pbString->szKey) + 1)) + L"\"";
					else
					{
						VS_VARSTRING* pbStringValue = (VS_VARSTRING*)DWORDUP(pbString->szKey + lstrlenW(pbString->szKey) + 1);
						WORD dw1 = *(WORD*)pbStringValue;
						WORD dw2 = *(WORD*)((WORD*)pbStringValue + 1);
						wStr.Format(L"0x%04X 0x%04X", dw1, dw2);
						wsBlock += L"\r\n\t\tVALUE \"" + std::wstring((WCHAR*)pbString->szKey) + L"\"" + L", " + std::wstring((WCHAR*)wStr.GetBuffer(0));
					}

					pbString = (VS_VARSTRING*)DWORDUP((DWORD_PTR)pbString + pbString->wLength);
				}
				//////////////////////////////////////////////////////////////////////////
				wsBlock += L"\t\r\n\t}";
				pbBlock = (VS_VARSTRING*)DWORDUP((DWORD_PTR)pbBlock + pbBlock->wLength);
			}
		}
		else if (nRef == 2) // VarFileInfo
		{
			wsBlock = L"\r\n" + wsBlock;
			VS_VARSTRING* pbBlock = (VS_VARSTRING*)DWORDUP(pbBlocks->szKey + lstrlenW(pbBlocks->szKey) + 1);
			wsBlock += L"\tBLOCK \"" + std::wstring((WCHAR*)pbBlock->szKey) + L"\"";

			//////////////////////////////////////////////////////////////////////////
			VS_VARSTRINGTABLE* pbStringTable = (VS_VARSTRINGTABLE*)pbBlock;
			wsBlock += L"\r\n\t{";
			BOOL bResult = FALSE;
			VS_VARSTRING* pbString = (VS_VARSTRING*)pbStringTable;
				
			if (pbString->wType == 1)
				wsBlock += L"\r\n\t\tVALUE \"" + std::wstring((WCHAR*)pbString->szKey) + L"\"" + L", \"" + std::wstring((WCHAR*)DWORDUP(pbString->szKey + lstrlenW(pbString->szKey) + 1)) + L"\"";
			else
			{
				VS_VARSTRING* pbStringValue = (VS_VARSTRING*)DWORDUP(pbString->szKey + lstrlenW(pbString->szKey) + 1);
				WORD dw1 = *(WORD*)pbStringValue;
				WORD dw2 = *(WORD*)((WORD*)pbStringValue + 1);
				wStr.Format(L"0x%04X 0x%04X", dw1, dw2);
				wsBlock += L"\r\n\t\tVALUE \"" + std::wstring((WCHAR*)pbStringTable->szKey) + L"\"" + L", " + std::wstring((WCHAR*)wStr.GetBuffer(0));
			}				

			wsBlock += L"\t\r\n\t}";
			pbBlock = (VS_VARSTRING*)DWORDUP((DWORD_PTR)pbBlock + pbBlock->wLength);
		}
		else
			break;	// 按道理这里不会进来
			
		wsBlock += L"\r\n}";
		wsResult += wsBlock;
		pbVersionInfoString = (VS_VARSTRING*)DWORDUP((DWORD_PTR)pbVersionInfoString + pbVersionInfoString->wLength);
		nRef++;
	}
	
	wsResult += L"\r\n}";
	return wsResult;
}

解析结果一致。

文件所用结构定义如下:

typedef struct tagVS_FIXEDFILEINFO
{
	DWORD   dwSignature;            // 文件填充信息标识,固定值0xFEEF04BD
	DWORD   dwStrucVersion;         // 结构体版本号,当前值0x10000,高2字节代表主版本号,低2字节代表副版本号
	DWORD   dwFileVersionMS;        // 4段文件版本号的前2段,每段2字节,不如3.8
	DWORD   dwFileVersionLS;        // 4段文件版本号的后2段,每段2字节
	DWORD   dwProductVersionMS;		// 4段产品版本号的前2段,每段2字节
	DWORD   dwProductVersionLS;     // 4段产品版本号的后2段,每段2字节
	DWORD   dwFileFlagsMask;        /* = 0x3F for version "0.42" */
	DWORD   dwFileFlags;            /* e.g. VFF_DEBUG | VFF_PRERELEASE */
	DWORD   dwFileOS;               /* e.g. VOS_DOS_WINDOWS16 */
	DWORD   dwFileType;             /* e.g. VFT_DRIVER */
	DWORD   dwFileSubtype;          /* e.g. VFT2_DRV_KEYBOARD */
	DWORD   dwFileDateMS;           // 文件创建日期高4字节
	DWORD   dwFileDateLS;           // 文件创建日期低4字节
} VS_FIXEDFILEINFO;

typedef struct tagVS_VERSIONINFO 
{
	WORD  wLength;			// 结构体总长度
	WORD  wValueLength;		// 后面Value字段的长度
	WORD  wType;			// 资源类型,0代表二进制数据,1代表字符串数据
	WCHAR szKey[ANYSIZE_ARRAY];			// 标识字符串: “VS_VERSION_INFO”
	WORD  Padding1[ANYSIZE_ARRAY];		// 填充字节串(以0填充),使后面字段按4字节对齐
	VS_FIXEDFILEINFO Value;				// VS_FIXEDFILEINFO对象,存储简要版本信息 offset=40字节
	WORD  Padding2[ANYSIZE_ARRAY];		// 填充字节串(以0填充),使后面字段按4字节对齐
	WORD  Children[ANYSIZE_ARRAY];		// 里面最多存放两个对象,要么是 VarFileInfo 要么是 StringFileInfo
} VS_VERSIONINFO;

typedef struct tagVS_VAR
{
	WORD        wLength;		// 该结构体长度
	WORD        wValueLength;	// Value字段长度
	WORD        wType;			// 0代表二进制数据,1代表字符串数据。此值为0
	WCHAR	    szKey[ANYSIZE_ARRAY];		// 标识字符串: “Translation”
	WORD        Padding[ANYSIZE_ARRAY];		// 填充字节串(以0填充),使后面字段按4字节对齐
	DWORD		Value;			// 区域语言值
}VS_VAR;

typedef struct tagVS_VARFILEINFO
{
	WORD        wLength;		// 该结构体长度
	WORD        wValueLength;	// Value字段长度
	WORD        wType;			// 0代表二进制数据,1代表字符串数据。此值为0
	WCHAR*      szKey;			// 标识字符串: “Translation”
	WORD*       Padding;		// 填充字节串(以0填充),使后面字段按4字节对齐
	VS_VAR		Children;		// 包含区域语言列表信息
}VS_VARFILEINFO;

typedef struct tagVS_STRING
{
	WORD        wLength;		// 该结构体长度
	WORD        wValueLength;	// 后面Value字段占用的WORD大小
	WORD        wType;			// 0代表二进制数据,1代表字符串数据。此值为0
	WCHAR       szKey[ANYSIZE_ARRAY];		// “Comments” “CompanyName” “FileDescription” “FileVersion”等等
	WORD        Padding[ANYSIZE_ARRAY];		// 填充字节串(以0填充),使后面字段按4字节对齐
	WORD		Value[ANYSIZE_ARRAY];		// 值的内容,注意:填充Value的值要使得后续的对象按4字节对齐
}VS_STRING;

typedef struct tagVS_STRINGTABLE
{
	WORD        wLength;		// 该结构体长度
	WORD        wValueLength;	// Value字段长度
	WORD        wType;			// 0代表二进制数据,1代表字符串数据。此值为0
	TCHAR       szKey[ANYSIZE_ARRAY];		// 语言和编码中文字符一般为Unicode “000004b0”
	WORD        Padding[ANYSIZE_ARRAY];		// 填充字节串(以0填充),使后面字段按4字节对齐
	VS_STRING	Children[ANYSIZE_ARRAY];	// String对象列表,版本字段全部存放在这个列表中
}VS_STRINGTABLE;

typedef struct tagVS_STRINGFILEINFO
{
	WORD        wLength;		// 该结构体长度
	WORD        wValueLength;	// Value字段长度
	WORD        wType;			// 0代表二进制数据,1代表字符串数据。此值为0
	WCHAR       szKey[ANYSIZE_ARRAY];		// 标识字符串: “Translation”
	WORD        Padding[ANYSIZE_ARRAY];		// 填充字节串(以0填充),使后面字段按4字节对齐
	VS_STRINGTABLE Children[ANYSIZE_ARRAY];	// 版本字段列表
}VS_STRINGFILEINFO;
#include <fstream>

typedef struct tagVS_VARBLOCK
{
	WORD  wLength;			// 该结构体长度
	WORD  wValueLength;		// Key字段长度
	WORD  wType;			// 0代表二进制数据,1代表字符串数据。此值为0
	WCHAR szKey[ANYSIZE_ARRAY];
	WORD  Padding[ANYSIZE_ARRAY];
}VS_VARBLOCK;

typedef struct tagVS_VARSTRING:
	public VS_VARBLOCK
{
	WORD   Value[ANYSIZE_ARRAY];
}VS_VARSTRING;

typedef struct tagVS_VARSTRINGTABLE:
	public VS_VARBLOCK
{
	VS_VARSTRING Children[ANYSIZE_ARRAY];
}VS_VARSTRINGTABLE;

typedef struct tagVS_VARSTRINGFILEINFO:
	public VS_VARBLOCK
{
	VS_VARSTRINGTABLE Children[ANYSIZE_ARRAY];
}VS_VARSTRINGFILEINFO;

猜你喜欢

转载自blog.csdn.net/u012156872/article/details/105677488