zoukankan      html  css  js  c++  java
  • 取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。

  • 相关阅读:
    windows10使用记录
    DevOps理论与实践总结
    工资调整
    Node程序debug小记
    基于游标的分页接口实现
    util.promisify 的那些事儿
    如何编写 Typescript 声明文件
    async语法升级踩坑小记
    使用TS+Sequelize实现更简洁的CRUD
    使用 TypeScript 改造构建工具及测试用例
  • 原文地址:https://www.cnblogs.com/Quincy/p/1713800.html
Copyright © 2011-2022 走看看