在Windows系统上,确定一个可执行文件(或库文件)是32位还是64位。

12
我试图找出一个给定的可执行文件(或库)是否是编译为32位或64位的,并从Python中确定它。我正在运行Vista 64位,并希望确定某个目录中的特定应用程序是否针对32位或64位编译。
是否有一种简单的方法只使用标准Python库(当前使用2.5.4)来实现这一点?
5个回答

24

在Windows中,获取二进制文件类型的API是GetBinaryType。您可以使用pywin32从Python调用此函数:

import win32file
type=GetBinaryType("myfile.exe")
if type==win32file.SCS_32BIT_BINARY:
    print "32 bit"
# And so on

如果你不想使用 pywin32,那么你需要自己阅读 PE header。这里有一个 C# 的示例,这是一个快速翻译成 Python 的版本:

import struct

IMAGE_FILE_MACHINE_I386=332
IMAGE_FILE_MACHINE_IA64=512
IMAGE_FILE_MACHINE_AMD64=34404

f=open("c:\windows\explorer.exe", "rb")

s=f.read(2)
if s!="MZ":
    print "Not an EXE file"
else:
    f.seek(60)
    s=f.read(4)
    header_offset=struct.unpack("<L", s)[0]
    f.seek(header_offset+4)
    s=f.read(2)
    machine=struct.unpack("<H", s)[0]

    if machine==IMAGE_FILE_MACHINE_I386:
        print "IA-32 (32-bit x86)"
    elif machine==IMAGE_FILE_MACHINE_IA64:
        print "IA-64 (Itanium)"
    elif machine==IMAGE_FILE_MACHINE_AMD64:
        print "AMD64 (64-bit x86)"
    else:
        print "Unknown architecture"

f.close()

如果可以不使用pywin32模块获取这些信息,那就太好了。 - pkit
1
刚刚编辑了答案,展示了如何在没有pywin32的情况下完成此操作。 - Martin B
@Martin。感谢提供的链接,我会看看能否组织一些东西。 - pkit
1
文件不应该以二进制模式打开吗? - unwind
1
我的错 - IMAGE_FILE_MACHINE_IA64 是 Itanium。-31132(或34404无符号)是AMD64(也称为64位x86)。我没有一个64位系统可以测试这个,但我希望现在应该可以工作了。 - Martin B
显示剩余4条评论

5
如果您在Windows上运行Python 2.5或更高版本,则还可以使用ctypes而不是pywin32来使用Windows API。
from ctypes import windll, POINTER
from ctypes.wintypes import LPWSTR, DWORD, BOOL

SCS_32BIT_BINARY = 0 # A 32-bit Windows-based application
SCS_64BIT_BINARY = 6 # A 64-bit Windows-based application
SCS_DOS_BINARY = 1 # An MS-DOS-based application
SCS_OS216_BINARY = 5 # A 16-bit OS/2-based application
SCS_PIF_BINARY = 3 # A PIF file that executes an MS-DOS-based application
SCS_POSIX_BINARY = 4 # A POSIX-based application
SCS_WOW_BINARY = 2 # A 16-bit Windows-based application

_GetBinaryType = windll.kernel32.GetBinaryTypeW
_GetBinaryType.argtypes = (LPWSTR, POINTER(DWORD))
_GetBinaryType.restype = BOOL

def GetBinaryType(filepath):
    res = DWORD()
    handle_nonzero_success(_GetBinaryType(filepath, res))
    return res

然后,您可以像使用win32file.GetBinaryType一样使用GetBinaryType。

请注意,您需要实现handle_nonzero_success函数,该函数基本上会在返回值为0时抛出异常。


3

我已经编辑了Martin B的答案,使其可以在Python 3中使用,并添加了with语句和ARM/ARM64支持:

import struct

IMAGE_FILE_MACHINE_I386 = 332
IMAGE_FILE_MACHINE_IA64 = 512
IMAGE_FILE_MACHINE_AMD64 = 34404
IMAGE_FILE_MACHINE_ARM = 452
IMAGE_FILE_MACHINE_AARCH64 = 43620

with open('foo.exe', 'rb') as f:
    s = f.read(2)
    if s != b'MZ':
        print('Not an EXE file')
    else:
        f.seek(60)
        s = f.read(4)
        header_offset = struct.unpack('<L', s)[0]
        f.seek(header_offset + 4)
        s = f.read(2)
        machine = struct.unpack('<H', s)[0]

        if machine == IMAGE_FILE_MACHINE_I386:
            print('IA-32 (32-bit x86)')
        elif machine == IMAGE_FILE_MACHINE_IA64:
            print('IA-64 (Itanium)')
        elif machine == IMAGE_FILE_MACHINE_AMD64:
            print('AMD64 (64-bit x86)')
        elif machine == IMAGE_FILE_MACHINE_ARM:
            print('ARM eabi (32-bit)')
        elif machine == IMAGE_FILE_MACHINE_AARCH64:
            print('AArch64 (ARM-64, 64-bit)')
        else:
            print(f'Unknown architecture {machine}')

1

在做了以下调整后,我成功地在Python 3.5程序中使用了Martin B的答案:

s=f.read(2).decode(encoding="utf-8", errors="strict")

最初在Python 2.7中运行我的程序时,它正常工作。但在进行其他必要更改后,我发现程序返回了b'MZ',解码似乎可以解决这个问题。


0
使用Python 3.7,在64位Win 7上的32位系统中,顶部答案中的第一个代码片段无法运行。它失败了,因为GetBinaryType是一个未知的符号。解决方案是使用win32file.GetBinaryType
此外,即使将其重命名为.dll,也无法在.pyd文件上运行它。请参见下面的内容:
import shutil

import win32file
from pathlib import Path

myDir = Path("C:\\Users\\rdboylan\\AppData\\Roaming\\Python\\Python37\\site-packages\\pythonwin")
for fn in ("Pythonwin.exe", "win32ui.pyd"):
    print(fn, end=": ")
    myf = myDir / fn
    if myf.suffix == ".pyd":
        mytemp = myf.with_suffix(".dll")
        if mytemp.exists():
            raise "Can not create temporary dll since {} exists".format(mytemp)
        shutil.copyfile(myf, mytemp)
        type = win32file.GetBinaryType(str(mytemp))
        mytemp.unlink()
    else:
        type=win32file.GetBinaryType(str(myf))
    if type==win32file.SCS_32BIT_BINARY:
        print("32 bit")
    else:
        print("Something else")
    # And so on 

结果如下:
Pythonwin.exe: 32 bit
win32ui.pyd: Traceback (most recent call last):
  File "C:/Users/rdboylan/Documents/Wk devel/bitness.py", line 14, in <module>
    type = win32file.GetBinaryType(str(mytemp))
pywintypes.error: (193, 'GetBinaryType', '%1 is not a valid Win32 application.')

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