Linux环境下使用Python pefile库获取PE文件产品名称的问题咨询
问题分析与解决方案
你的代码忽略了VS_VERSIONINFO结构的嵌套层次——在pefile中,StringTable并不是直接挂在FileInfo条目下的,而是嵌套在StringFileInfo子结构里。Notepad.exe的版本信息正是按照这个标准结构存储的,所以你的遍历逻辑跳过了关键的StringFileInfo层,导致找不到目标数据。
另外还要注意,pefile返回的版本信息字符串可能是字节类型,需要根据Windows版本资源的标准编码(UTF-16LE)解码成Unicode字符串,避免出现乱码问题。
修正后的完整代码
下面是可以正确获取Notepad.exe(以及绝大多数Windows PE文件)详细信息的代码,包含你需要的文件描述、产品名称、原始文件名等字段:
from pefile import PE from typing import Optional, Dict def get_pe_version_info(pe_path: str) -> Optional[Dict[str, str]]: try: pe = PE(pe_path) except Exception as e: print(f"解析PE文件失败: {e}") return None # 检查是否存在版本信息结构 if not hasattr(pe, 'VS_VERSIONINFO') or not hasattr(pe, 'FileInfo'): return None version_info = {} # 遍历VS_VERSIONINFO结构 for entry in pe.FileInfo: # 只处理包含StringFileInfo的条目 if hasattr(entry, 'StringFileInfo'): for string_file_info in entry.StringFileInfo: # 遍历每个语言/代码页对应的StringTable for string_table in string_file_info.StringTable: # 解码字节串为Unicode字符串 for key, value in string_table.entries.items(): if isinstance(value, bytes): try: # Windows版本信息通常使用UTF-16LE编码 decoded_value = value.decode('utf-16le') except UnicodeDecodeError: # 解码失败时回退到系统默认编码 decoded_value = value.decode('mbcs') else: decoded_value = value version_info[key] = decoded_value return version_info # 示例用法 if __name__ == "__main__": info = get_pe_version_info("notepad.exe") if info: print("文件描述:", info.get("FileDescription")) print("产品名称:", info.get("ProductName")) print("原始文件名:", info.get("OriginalFilename")) print("文件版本:", info.get("FileVersion")) print("产品版本:", info.get("ProductVersion"))
关键改进点说明
- 修正结构遍历层次:新增了
entry.StringFileInfo的遍历,这是访问StringTable的必要中间层,完全符合Windows PE版本信息的标准结构。 - 编码处理:针对pefile返回的字节串,优先用UTF-16LE解码(Windows版本资源的标准编码),解码失败时回退到系统默认的MBCS编码,避免出现乱码。
- 返回完整字典:一次性返回所有版本信息字段,方便你按需提取需要的属性。
额外说明:关于「文件类型」的获取
你提到的「详细信息」选项卡中的「类型」(比如Notepad.exe显示为「应用程序」),这个信息并不在StringTable里,而是需要从PE头的Subsystem字段判断:
def get_pe_file_type(pe_path: str) -> Optional[str]: try: pe = PE(pe_path) except Exception as e: print(f"解析PE文件失败: {e}") return None subsystem_map = { 1: "原生应用程序(不使用Windows子系统)", 2: "GUI应用程序", 3: "控制台应用程序", 5: "OS/2应用程序", 7: "POSIX应用程序", 8: "Windows CE应用程序", 9: "EFI应用程序", 10: "EFI驱动程序", 11: "EFI ROM镜像", 12: "Xbox应用程序" } return subsystem_map.get(pe.OPTIONAL_HEADER.Subsystem, "未知类型")
调用这个函数就能得到对应文件的类型描述,和Windows属性窗口里的「类型」完全一致。
内容的提问来源于stack exchange,提问作者Larytet
相关产品推荐
相关产品推荐

