从没有此类信息的 pyd 中检索 Python 版本
Retrieve Python version from pyd built without such an information
在 Windows 上,我有一个 Python 库 (*.pyd),我需要检查链接的 Python 版本。可以是 Python 2.7.x 或 3.x.
当我 运行 使用 win32api
这样的东西时(改编自此处:):
def get_pyd_python_version(pyd_path):
"""
Get the python version required by the passed pyd library
"""
import win32api
print("- pyd path: %s" % str(pyd_path))
try:
info = win32api.GetFileVersionInfo(pyd_path, '\')
except win32api.error as e:
print(str(e.strerror) + " > " + pyd_path)
return ""
python_version = "%s.%s.%s.%s" % (
str(win32api.HIWORD(info['FileVersionMS'])),
str(win32api.LOWORD(info['FileVersionMS'])),
str(win32api.HIWORD(info['FileVersionLS'])),
str(win32api.LOWORD(info['FileVersionLS'])))
return python_version
我得到:The specified resource type cannot be found in the image file.
相同的函数与其他 "properly" 构建的 pyd 库(例如,win32api.pyd
)一起按预期工作。
由于 Dependency Walker 与 incomplete pyd 一起使用正确显示了 DLL,我想知道是否有办法以编程方式(使用 Python)获取版本信息从这样一个事实。
--- 编辑 ---
基于 pefile
库和@vyktor 的回答,我通过下载这个叉子得到了这个工作:https://github.com/BlackXeronic/pefile_py3
并使用这种方法(也检查架构):
from __future__ import absolute_import, print_function
import sys
sys.path.append('./pefile_py3-master')
import pefile
print("python env: v.%s.%s" % (sys.version_info.major, sys.version_info.minor))
print("pefile lib: v.%s" % pefile.__version__)
dll_path = r'C:/Python27/DLLs/bz2.pyd'
print("path to pyd: %s" % dll_path)
pe = pefile.PE(dll_path)
if pe.is_dll():
for entry in pe.DIRECTORY_ENTRY_IMPORT:
if "python" in entry.dll:
if pe.FILE_HEADER.Machine == 0x14C:
arch = "x86"
elif pe.FILE_HEADER.Machine == 0x8664:
arch = "x64"
else:
arch = "unknown"
print(">>> importing %s: v.%s [%s] <<<" % (entry.dll, entry.dll[6:8], arch))
这是我使用 Python 3.4.3 解释器得到的:
python env: v.3.4
pefile lib: v.1.2.10-139
path to pyd: C:/Python27/DLLs/bz2.pyd
>>> importing python27.dll: v.27 [x86] <<<
我在 C:\Python32\DLLs\bz2.pyd
上对此进行了测试,但我没有看到任何 python 的详细信息(文件刚刚重命名为 .dll
):
python 版本的唯一相关信息在 IAT 中:
所以你只需要解析 PE 文件并查找导入的 DLL 名称。关于loading IAT from file and I did this using pefile
extension (suggested by 的问题很少):
C:\Python27>python.exe
Python 2.7.2 (default, Jun 12 2011, 15:08:59) [MSC v.1500 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import pefile
>>> p = pefile.PE(r'C:\Python32\DLLs\bz2.pyd')
>>> p.is_dll()
True
>>> for entry in p.DIRECTORY_ENTRY_IMPORT:
... print entry.dll
...
python32.dll
MSVCR90.dll
KERNEL32.dll
>>> p = pefile.PE(r'C:\Python27\DLLs\bz2.pyd')
>>> p.is_dll()
True
>>> for entry in p.DIRECTORY_ENTRY_IMPORT:
... print entry.dll
...
python27.dll
MSVCR90.dll
KERNEL32.dll
而您只需简单地编写一个查找 pythonXX.dll
字符串的检查。
不幸的是,这只适用于 python 2.7(也许有人可以找到 pefile 的 3.2 分支)。
据我所知,WinAPI 本身不提供在文件中查找导入的简单方法,因此使用嵌入了所有结构的第 3 方扩展是执行此操作的最佳方法。
在 Windows 上,我有一个 Python 库 (*.pyd),我需要检查链接的 Python 版本。可以是 Python 2.7.x 或 3.x.
当我 运行 使用 win32api
这样的东西时(改编自此处:):
def get_pyd_python_version(pyd_path):
"""
Get the python version required by the passed pyd library
"""
import win32api
print("- pyd path: %s" % str(pyd_path))
try:
info = win32api.GetFileVersionInfo(pyd_path, '\')
except win32api.error as e:
print(str(e.strerror) + " > " + pyd_path)
return ""
python_version = "%s.%s.%s.%s" % (
str(win32api.HIWORD(info['FileVersionMS'])),
str(win32api.LOWORD(info['FileVersionMS'])),
str(win32api.HIWORD(info['FileVersionLS'])),
str(win32api.LOWORD(info['FileVersionLS'])))
return python_version
我得到:The specified resource type cannot be found in the image file.
相同的函数与其他 "properly" 构建的 pyd 库(例如,win32api.pyd
)一起按预期工作。
由于 Dependency Walker 与 incomplete pyd 一起使用正确显示了 DLL,我想知道是否有办法以编程方式(使用 Python)获取版本信息从这样一个事实。
--- 编辑 ---
基于 pefile
库和@vyktor 的回答,我通过下载这个叉子得到了这个工作:https://github.com/BlackXeronic/pefile_py3
并使用这种方法(也检查架构):
from __future__ import absolute_import, print_function
import sys
sys.path.append('./pefile_py3-master')
import pefile
print("python env: v.%s.%s" % (sys.version_info.major, sys.version_info.minor))
print("pefile lib: v.%s" % pefile.__version__)
dll_path = r'C:/Python27/DLLs/bz2.pyd'
print("path to pyd: %s" % dll_path)
pe = pefile.PE(dll_path)
if pe.is_dll():
for entry in pe.DIRECTORY_ENTRY_IMPORT:
if "python" in entry.dll:
if pe.FILE_HEADER.Machine == 0x14C:
arch = "x86"
elif pe.FILE_HEADER.Machine == 0x8664:
arch = "x64"
else:
arch = "unknown"
print(">>> importing %s: v.%s [%s] <<<" % (entry.dll, entry.dll[6:8], arch))
这是我使用 Python 3.4.3 解释器得到的:
python env: v.3.4
pefile lib: v.1.2.10-139
path to pyd: C:/Python27/DLLs/bz2.pyd
>>> importing python27.dll: v.27 [x86] <<<
我在 C:\Python32\DLLs\bz2.pyd
上对此进行了测试,但我没有看到任何 python 的详细信息(文件刚刚重命名为 .dll
):
python 版本的唯一相关信息在 IAT 中:
所以你只需要解析 PE 文件并查找导入的 DLL 名称。关于loading IAT from file and I did this using pefile
extension (suggested by
C:\Python27>python.exe
Python 2.7.2 (default, Jun 12 2011, 15:08:59) [MSC v.1500 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import pefile
>>> p = pefile.PE(r'C:\Python32\DLLs\bz2.pyd')
>>> p.is_dll()
True
>>> for entry in p.DIRECTORY_ENTRY_IMPORT:
... print entry.dll
...
python32.dll
MSVCR90.dll
KERNEL32.dll
>>> p = pefile.PE(r'C:\Python27\DLLs\bz2.pyd')
>>> p.is_dll()
True
>>> for entry in p.DIRECTORY_ENTRY_IMPORT:
... print entry.dll
...
python27.dll
MSVCR90.dll
KERNEL32.dll
而您只需简单地编写一个查找 pythonXX.dll
字符串的检查。
不幸的是,这只适用于 python 2.7(也许有人可以找到 pefile 的 3.2 分支)。
据我所知,WinAPI 本身不提供在文件中查找导入的简单方法,因此使用嵌入了所有结构的第 3 方扩展是执行此操作的最佳方法。