我试图找出一个给定的可执行文件(或库)是否是编译为32位或64位的,并从Python中确定它。我正在运行Vista 64位,并希望确定某个目录中的特定应用程序是否针对32位或64位编译。
是否有一种简单的方法只使用标准Python库(当前使用2.5.4)来实现这一点?
是否有一种简单的方法只使用标准Python库(当前使用2.5.4)来实现这一点?
在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()
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时抛出异常。
我已经编辑了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}')
在做了以下调整后,我成功地在Python 3.5程序中使用了Martin B的答案:
s=f.read(2).decode(encoding="utf-8", errors="strict")
最初在Python 2.7中运行我的程序时,它正常工作。但在进行其他必要更改后,我发现程序返回了b'MZ',解码似乎可以解决这个问题。
win32file.GetBinaryType
。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.')