取PE文件OriginalFilename-解析VERSION资源

 由于需要用到EXE文件的OriginalFilename这个值,原本微软提供了API可以取得PE文件的版本信息,通过VerQueryValue可以查询到这个值。

标准的取法是:

  1. 通过GetFileVersionInfoSize取得文件版本信息大小。
  2. 通过GetFileVersionInfo取得文件版本信息。
  3. 查找版本信息中的 languages and code pages列表。
  4. 根据相应 language and code page下对应的OriginalFilename的值。

代码如下:

1 BOOL GetOriginalFilename(LPCTSTR pszPath, CString& rOriginalFilename)
2 {
3 if (NULL==pszPath)
4 {
5 return FALSE;
6 }
7
8 /// Get the length for version information
9  
10 DWORD dwVersion = 0;
11 DWORD dwHandle = 0;
12 dwVersion = GetFileVersionInfoSize(pszPath, &dwHandle);
13 if (!dwVersion)
14 {
15 return FALSE;
16 }
17
18 /// Alloc the buffer for version information
19  
20 std::auto_ptr<BYTE> pbBuffer(new BYTE[dwVersion]);
21 PVOID pBlock = pbBuffer.get();
22 ZeroMemory(pBlock, dwVersion);
23
24 if (!GetFileVersionInfo(pszPath, dwHandle, dwVersion, pBlock))
25 {
26 return FALSE;
27 }
28
29 /// Structure used to store enumerated languages and code pages.
30  
31 struct LANGANDCODEPAGE
32 {
33 WORD wLanguage;
34 WORD wCodePage;
35 } *lpTranslate;
36
37 UINT cbTranslate = 0;
38
39 /// Read the list of languages and code pages.
40  
41 VerQueryValue(pBlock,
42 TEXT("\\VarFileInfo\\Translation"),
43 (LPVOID*)&lpTranslate,
44 &cbTranslate);
45 if (NULL==lpTranslate)
46 {
47 return FALSE;
48 }
49
50 /// Read the Original filename for 1st language and code page.
51  
52 TCHAR SubBlock[50] = {0};
53 StringCchPrintf(SubBlock, 50,
54 TEXT("\\StringFileInfo\\%04x%04x\\OriginalFilename"),
55 lpTranslate[0].wLanguage,
56 lpTranslate[0].wCodePage);
57
58 /// Retrieve file description for language and code page "i".
59  
60 BOOL bResult = FALSE;
61 UINT dwBytes = 0;
62 LPTSTR pszFileName = NULL;
63 if (VerQueryValue(pBlock,
64 SubBlock,
65 (LPVOID*)&pszFileName,
66 &dwBytes))
67 {
68 rOriginalFilename = pszFileName;
69 bResult = TRUE;
70 }
71
72 return bResult;
73 }

 

通过上面代码就可以取得EXE文件的OriginalFilename值。但是有时候EXE文件资源信息中没有对应的Translation值或者Translation的值不匹配,但是有对应的OriginalFilename,这时候通过标准的方法就取不到了,怎么办呢?

如这是WinRAR的版本信息,对应的就不对。

 

Length Of Struc: 02ACh
Length Of Value: 0034h
Type Of Struc:   0000h
Info:            VS_VERSION_INFO
Signature:       FEEF04BDh
Struc Version:   1.0
File Version:    3.90.5.0
Product Version: 3.90.5.0
File Flags Mask: 0.0
File Flags:     
File OS:         WINDOWS32
File Type:       APP
File SubType:    UNKNOWN
File Date:       00:00:00  00/00/0000

     Struc has Child(ren). Size: 592 bytes.

Child Type:         StringFileInfo
Language/Code Page: 1033/1252
ProductName:        WinRAR
CompanyName:        Alexander Roshal
FileDescription:    WinRAR archiver
FileVersion:        3.90.5
InternalName:       WinRAR
LegalCopyright:     Copyright ? Alexander Roshal 1993-2009
OriginalFilename:   WinRAR.exe

Child Type:         VarFileInfo
Translation:        0/0

 

这时通过之前的方法就不行了,只好自己解析了。下面代码参考了网上的VerInfoLib的代码,有兴趣的可以去下完整的代码http://packcab.googlecode.com/svn/trunk/VerInfoLib/

 

1 struct VarBlock
2 {
3 WORD wLength;
4 WORD wValueLength;
5 WORD wType;
6 WCHAR szKey[ANYSIZE_ARRAY];
7 WORD Padding[ANYSIZE_ARRAY];
8 };
9
10  struct VarString:
11 public VarBlock
12 {
13 WORD Value[ANYSIZE_ARRAY];
14 };
15
16  struct VarStringTable:
17 public VarBlock
18 {
19 VarString Children[ANYSIZE_ARRAY];
20 };
21
22  struct VarStringFileInfo:
23 public VarBlock
24 {
25 VarStringTable Children[ANYSIZE_ARRAY];
26 };
27
28  #define DWORDUP(x) (((DWORD)(LPBYTE)(x)+3)&~03)
29
30 BOOL GetOriginalFilename1(LPCTSTR pszPath, CString& rOriginalFilename)
31 {
32 if (NULL==pszPath)
33 {
34 return FALSE;
35 }
36
37 /// Get the length for version information
38  
39 DWORD dwVersion = 0;
40 DWORD dwHandle = 0;
41 dwVersion = GetFileVersionInfoSize(pszPath, &dwHandle);
42 if (!dwVersion)
43 {
44 return FALSE;
45 }
46
47 /// Alloc the buffer for version information
48  
49 std::auto_ptr<BYTE> pbBuffer(new BYTE[dwVersion]);
50 PVOID pBlock = pbBuffer.get();
51 ZeroMemory(pBlock, dwVersion);
52
53 if (!GetFileVersionInfo(pszPath, dwHandle, dwVersion, pBlock))
54 {
55 return FALSE;
56 }
57
58 /// Get StringFleInfo list in version information
59  
60 LPVOID* pbStringFileInfo = NULL;
61 UINT cbStringFileInfo = 0;
62 VerQueryValue(pBlock,TEXT("\\StringFileInfo"),
63 (LPVOID*)&pbStringFileInfo,&cbStringFileInfo);
64
65 if (NULL==pbStringFileInfo)
66 {
67 return FALSE;
68 }
69
70 VarStringTable* pbStringTable = (VarStringTable*)DWORDUP(pbStringFileInfo);
71
72 BOOL bResult = FALSE;
73 VarString* pbString = (VarString*)DWORDUP(pbStringTable->szKey + lstrlenW(pbStringTable->szKey) + 1);
74 while ((DWORD_PTR)pbString < (DWORD_PTR)pbStringTable + pbStringTable->wLength)
75 {
76 if (lstrcmpiW(pbString->szKey, L"OriginalFilename")==0)
77 {
78 rOriginalFilename = (WCHAR*)DWORDUP(pbString->szKey + lstrlenW(pbString->szKey) + 1);
79 bResult = TRUE;
80 break;
81 }
82
83 pbString = (VarString*)DWORDUP((DWORD_PTR)pbString + pbString->wLength);
84 }
85
86 return bResult;
87 }

 

上面代码取出第一个StringTable值,并从中解析出OriginalFilename。具体参考MSDN中的Version Information。

posted @ 2010-04-17 09:56  Quincy  阅读(1953)  评论(0编辑  收藏  举报