【问题标题】:Determine if an executable (or library) is 32 -or 64-bits (on Windows)确定可执行文件(或库)是 32 位还是 64 位(在 Windows 上)
【发布时间】:2009-08-28 08:05:38
【问题描述】:

我试图找出给定的可执行文件(或库)是否从 Python 编译为 32 位或 64 位。我正在运行 64 位的 Vista,想确定目录中的某个应用程序是针对 32 位还是 64 位编译的。

有没有一种简单的方法可以仅使用标准 Python 库(目前使用 2.5.4)来做到这一点?

【问题讨论】:

    标签: python windows dll 64-bit executable


    【解决方案1】:

    用于此的 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# 中的 an example,这是 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 模块的情况下获得这些信息就好了。
    • 刚刚编辑了答案以展示如何在没有 pywin32 的情况下做到这一点。
    • @Martin。谢谢你的链接,我看看能不能把东西放在一起。
    • 文件不应该以二进制方式打开吗?
    • 我的错——IMAGE_FILE_MACHINE_IA64 是安腾。 -31132(或 34404 无符号)是 AMD64(又名 64 位 x86)。没有可以测试的 64 位系统,但我希望它现在可以工作。
    【解决方案2】:

    如果您在 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's 答案以使用 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}')
      

      【讨论】:

        【解决方案4】:

        进行此调整后,我能够在 Python 3.5 程序中成功使用 Martin B 的答案:

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

        最初它在我的 Python 2.7 程序中运行良好,但在进行了其他必要的更改后,我发现我得到了 b'MZ',并且解码它似乎可以解决这个问题。

        【讨论】:

          【解决方案5】:
          1. 在 64 位 Win 7 上使用 32 位 Python 3.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.')
            

          【讨论】:

            猜你喜欢
            • 2010-12-28
            • 2012-10-20
            • 2011-02-10
            • 2013-02-23
            • 2013-08-06
            • 2020-09-11
            • 1970-01-01
            • 2011-08-05
            • 2011-02-21
            相关资源
            最近更新 更多