查找二进制文件的版本

3

有人知道如何查找已传递给我的函数的二进制文件的版本号吗?

我从这个页面获取了以下代码:

def version(fpath):
    f = open(fpath, 'rb')

    s = f.read(1024)
    print s

    f.close()

然而,这并没有给我提供类似于上述网站显示的有用输出。

编辑: @BoazYaniv 告诉我,文件格式在这个问题中起着重要作用。这是一个Windows可执行文件。


2
哪种类型的二进制文件?这完全取决于格式,你知道的。 - undefined
我不知道这个!格式如何影响功能? - undefined
1
你的文件是xft文件吗?如果不是,那个教程就无关紧要了。但你可以用它作为一个从二进制文件中读取指定数量数据的例子,根据你的格式进行编辑。 - undefined
1
@inspectorG4dget:因为每种二进制文件格式都将其版本存储在不同的位置和不同的方式中,甚至可能根本没有存储版本信息。 - undefined
无论如何,编辑你的问题以包含你想要解析的格式。目前,我可以建议你尝试一下Python自带的struct模块。它非常适用于读取二进制文件。如果你想要更强大的功能,还有一个叫做construct的包,它更加灵活,但是如果你需要使用它,可能需要更多关于二进制格式的经验。 - undefined
2
一个Windows的EXE?那么这个格式被称为PE(可移植可执行文件),它又是COFF的一种变体。 - undefined
2个回答

12

您可以使用一个现成的模块来解析EXE文件:http://code.google.com/p/pefile/

您可以使用以下代码读取它:

import pefile

pe = pefile.PE(r'C:\Windows\notepad.exe')
FileVersion    = pe.FileInfo[0].StringTable[0].entries['FileVersion']
ProductVersion = pe.FileInfo[0].StringTable[0].entries['ProductVersion']

正如您所看到的,Windows EXE(和DLL)文件存储两种不同类型的版本,即FileVersion和ProductVersion。很多时候它们是相同的,但有时它们可能不同 - 这完全取决于制作EXE的人。

编辑:

为了使事情更加复杂,这些PE字符串表中的两个字符串并不是Windows编译器保存版本的唯一位置。在EXE中还有另外两个FileVersion和ProductVersion值,只是它们以32位整数对的形式存储,每个整数再分别分成两个16位整数(在Windows API术语中称为WORDs)。总体上,每个版本值(FileVersion和ProductVersion)都有4个16位的WORDs,表示版本号的点分隔部分。您也可以使用pefile获取它们:

pe = pefile.PE(r'C:\Windows\notepad.exe')
FileVersionLS    = pe.VS_FIXEDFILEINFO.FileVersionLS
FileVersionMS    = pe.VS_FIXEDFILEINFO.FileVersionMS
ProductVersionLS = pe.VS_FIXEDFILEINFO.ProductVersionLS
ProductVersionMS = pe.VS_FIXEDFILEINFO.ProductVersionMS

FileVersion = (FileVersionMS >> 16, FileVersionMS & 0xFFFF, FileVersionLS >> 16, FileVersionLS & 0xFFFF)
ProductVersion = (ProductVersionMS >> 16, ProductVersionMS & 0xFFFF, ProductVersionLS >> 16, ProductVersionLS & 0xFFFF)

print 'File version:    %s.%s.%s.%s' % FileVersion 
print 'Product version: %s.%s.%s.%s' % ProductVersion

但是!这还不是全部:你至少还有一个地方可以查找版本号:在名为OPTIONAL_HEADER的另一个结构内,你可以找到另外两个值,分别称为MajorImageVersion和MinorImageVersion。它们代表了整个版本号的前两部分,因此,一个具有ProductVersion或FileVersion为6.1.7600.150的文件通常会具有MajorImageVersion为6,MinorImageVersion为1。你可以使用pe.OPTIONAL_HEADER.MajorImageVersionpe.OPTIONAL_HEADER.MinorImageVersion来获取它们。

所有这些值(如果我算得对的话,有5个不同的值)通常是等价的(如果忽略掉字符串表中那些额外的自由格式字符串值),但看到不同的FileVersions和ProductVersions也很常见,你也应该准备好面对其他的“惊喜”。


2
+1 这是一个非常好的技巧。可惜我的经理不让我使用它。 - undefined
这个答案比win32api有一个优势。pefile模块可以很容易地通过pip安装,而pywin32则不行。用户需要下载pywin32的whl文件来进行安装。 - undefined
2
稍作修改,pe.VS_FIXEDFILEINFO.FileVersionLS 应该是 pe.VS_FIXEDFILEINFO[0].FileVersionLS 等等。因为它们是列表。在这个旧版本中可能不是这样的! - undefined
除了@Rots的轻微修改外,只有“编辑”部分对我有效,pe.FileInfo[0].StringTable[0].entries['FileVersion']pe.FileInfo[0].StringTable[0].entries['ProductVersion']对我来说都会出现AttributeError: 'list' object has no attribute 'StringTable'(使用Python 3.10.5和pefile 2022.5.30)。 - undefined

5
我们使用此代码从一个可执行文件中提取版本,以在其他程序中使用。
import win32api

try:
    info = win32api.GetFileVersionInfo('rpmsrv.exe', "\\")
    ms = info['FileVersionMS']
    ls = info['FileVersionLS']
    __version__ = "%d.%d.%d.%d" % (win32api.HIWORD(ms), win32api.LOWORD (ms),
                                 win32api.HIWORD (ls), win32api.LOWORD (ls))
except:
    __version__ = '5.1.1.000' # some appropriate default here.

--- 包含注释 ---

这需要安装Python的Windows绑定。可以在此处获取:http://starship.python.net/~skippy/win32/。这也限制了该解决方案仅适用于Windows平台(这可能是最终项目中重要因素或不重要因素)。


2
好的替代方案,但你应该添加一个注释,说明这需要Python的Windows扩展,并且它只能在Windows上运行(因为它使用Windows API而不是直接解析文件)。 - undefined
@Boaz Yaniv - 说得对。我对你的回答中提到的这个工具不太熟悉,需要去阅读一些资料。谢谢! - undefined
1
它还将从PE文件中稍微不同的位置读取版本信息(该结构在pefile中称为VS_FIXEDFILEINFO)。这是可以的,但它可能会遗漏一些有时添加到版本信息中的字符串值,因为该结构仅允许4个16位整数值(表示版本部分),而不是自由格式字符串。 - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接