Определите, является ли исполняемый файл (или библиотека) 32- или 64-битным (в Windows)

Я пытаюсь выяснить, скомпилирован ли данный исполняемый файл (или библиотека) для 32-битной или 64-битной версии Python. Я использую 64-разрядную версию Vista и хочу определить, скомпилировано ли определенное приложение в каталоге для 32-разрядной или 64-разрядной версии.

Есть ли простой способ сделать это, используя только стандартные библиотеки Python (в настоящее время использующие 2.5.4)?


person pkit    schedule 28.08.2009    source источник


Ответы (5)


API Windows для этого - GetBinaryType. Вы можете вызвать это из Python, используя pywin32:

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

Если вы хотите сделать это без pywin32, вам придется самостоятельно прочитать PE-заголовок. Вот пример на 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()
person Martin B    schedule 28.08.2009
comment
Было бы неплохо, если бы я мог получить эту информацию без использования модуля pywin32. - person pkit; 28.08.2009
comment
Просто отредактировал ответ, чтобы показать, как это можно сделать без pywin32. - person Martin B; 28.08.2009
comment
@Мартин. Спасибо за ссылки, посмотрю, смогу ли что-нибудь собрать. - person pkit; 28.08.2009
comment
Просто добавил порт примера C # на Python. - person Martin B; 28.08.2009
comment
Не следует ли открывать файл в двоичном режиме? - person unwind; 28.08.2009
comment
Это печатает Неизвестную архитектуру на моей машине. Машинная переменная сообщает -31132. Какие-либо предложения? - person pkit; 28.08.2009
comment
Моя беда - IMAGE_FILE_MACHINE_IA64 это Itanium. -31132 (или 34404 без знака) - это AMD64 (он же 64-битный x86). У меня нет 64-битной системы, на которой я могу это протестировать, но я надеюсь, что теперь она должна работать. - person Martin B; 28.08.2009
comment
Я смог использовать это решение (Python 3.5) после внесения изменений, предложенных в ответе, представленном ниже Джейсоном Р. Кумбсом. - person Vada Poché; 31.01.2019

Если вы используете Python 2.5 или более позднюю версию в Windows, вы также можете использовать Windows API без pywin32, используя ctypes.

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

Затем используйте GetBinaryType так же, как и с win32file.GetBinaryType.

Обратите внимание: вам придется реализовать handle_nonzero_success, который в основном выдает исключение, если возвращаемое значение равно 0.

person Jason R. Coombs    schedule 29.08.2009

Я отредактировал ответ Мартина Б. для работы с 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}')
person iFarbod    schedule 05.01.2021

Я смог успешно использовать ответ Мартина Б в программе Python 3.5 после внесения этой корректировки:

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

Первоначально он отлично работал с моей программой на Python 2.7, но после внесения других необходимых изменений я обнаружил, что получаю b'MZ, и его декодирование, похоже, исправляет это.

person thesis    schedule 29.09.2016

  1. Используя 32-битный Python 3.7 на 64-битной Win 7, первый фрагмент кода в верхнем ответе у меня не работает. Это не удается, потому что GetBinaryType - неизвестный символ. Решение - использовать win32file.GetBinaryType.
  2. Также запуск его с файлом .pyd не работает, даже если он переименован в .dll. См. Далее:

    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.')
    
person Ross Boylan    schedule 18.12.2018