5

我正在尝试使用 Python 的 C-Types 在 kernel32 库上调用 GetModuleHandleA。我想获得该库的句柄,以便可以使用它为 LoadLibraryA 调用 GetProcAddress。下面是我的代码...

import sys
from ctypes

kernel32 = windll.kernel32
print("The kernel32 is %s" % kernel32)
#The kernel32 is <WinDLL 'kernel32', handle 765b0000 at 1c2a9f0>

h_kernel32 = kernel32.GetModuleHandleA("C:\\Windows\\System32\\kernel32.dll")
if h_kernel32 == False:
        error = GetLastError()
        print("ERROR: %d - %s" % (error, FormatError(error)))

我收到一个错误,“错误:126 - 找不到指定的模块”。我也试过“C:/Windows/System32/kernel32.dll”和“kernel32”。我正在使用 Python 3.2,这是在 Windows 7 机器上。我已经验证了 dll 存在并且在我在上面的代码中设置的路径中。我一直在做一些研究,似乎无法找出问题所在。任何帮助是极大的赞赏。谢谢!

4

2 回答 2

7

句柄存储在kernel32._handle. 调用GetModuleHandle应该返回相同的值,但请确保您设置了restypeargtypes类型安全 [*]:

import ctypes
from ctypes import wintypes

kernel32 = ctypes.WinDLL('kernel32', use_last_error=True)

kernel32.GetModuleHandleW.restype = wintypes.HMODULE
kernel32.GetModuleHandleW.argtypes = [wintypes.LPCWSTR]

hMod = kernel32.GetModuleHandleW('kernel32.dll')

注意“W”后缀而不是“A”。Python 3 使用 Unicode 字符串,ctypes 为其创建一个c_wchar_p( LPCWSTR)。没有理由调用 [A]NSI 版本,因为它只是 [W]ide 字符串版本的包装。但如果你必须,那么你需要使用字节:

kernel32.GetModuleHandleA.restype = wintypes.HMODULE
kernel32.GetModuleHandleA.argtypes = [wintypes.LPCSTR]

hMod = kernel32.GetModuleHandleA(b'kernel32.dll')

[*] 我建议使用kernel32 = WinDLL('kernel32', use_last_error=True)而不是windll.kernel32. 这避免了与其他使用windll. 它还可以保护线程的LastErrorValue. 在这种情况下,使用ctypes.get_last_error()andctypes.set_last_error(err)而不是直接调用 WinAPIGetLastErrorSetLastError.

于 2013-06-10T23:02:51.240 回答
0

至于它是如何在内部完成的,ctypes.windll.kernel32WinDLL("kernel32"). WinDLL 继承 CDLL,后者__init__打开 kernel32 的句柄。当你使用它时,CDLL 会__getattr__查找 stringified 属性并为其创建一个继承.的."GetModuleHandle"kernel32_FuncPtr_CFuncPtr_ctypes.CFuncPtr

_ctypes.CFuncPtr类型PyTypeObject对象(请记住,运行时PyObject为 python 中的所有对象(包括函数)创建 s,并PyTypeObject为所有类型创建 a。因为CFuncPtr是继承的,所以它将构造函数定位在CFuncPtr类型对象中,该类型对象在 C 中设置为在PyCFuncPtr_new初始化类型对象时设置,它接受 args,在本例中为 kernel32 WinDLL 对象,"GetModuleHandle"并调用PyCFuncPtr_FromDll以获取GetProcAddress句柄上使用的地址在 CDLL 中设置的模块__init__。在我看来,_dlopen在 CDLL 中__init__从内部创建的类型对象中为LoadLibrarykernel32创建一个句柄对象,该类型对象调用内部 C 构造函数来执行类似对象 from并且该对象将包含它将调用的地址 from ,最终类型对象构造函数返回要从 CDLL 返回的函数指针实例,并且对其执行的调用将导致 python 调用此地址对象,这将是PyObjectself._handlePyCFuncPtr_FromDll_handleLoadLibraryGetProcAddressCFuncPtrPyObject__getattr__GetProcAddress而不是解释字节码地址处的字节码的函数的地址?我现在无法验证细节,但对我来说,这就是我如何看待从 Python 运行时与 Windows API 交互的可能性。

下次__getattr__不调用 ,因为该属性现在存在。

于 2021-04-19T02:38:21.953 回答