我尝试使用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)))
我收到错误,&#34;错误:126 - 无法找到指定的模块&#34;。我也试过&#34; C:/Windows/System32/kernel32.dll"并且只是&#34; kernel32&#34;。我使用的是Python 3.2,这是在Windows 7机器上。我已经验证了dll在那里以及我在上面的代码中设置的路径。我一直在做一些研究,似乎无法找出问题所在。任何帮助是极大的赞赏。谢谢!
答案 0 :(得分:5)
句柄存储在kernel32._handle
中。调用GetModuleHandle
应返回相同的值,但请确保为类型安全[*]设置restype
和argtypes
:
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()
和ctypes.set_last_error(err)
,而不是直接调用WinAPI GetLastError
和SetLastError
。
答案 1 :(得分:0)
至于如何在内部完成,ctypes.windll.kernel32
是 WinDLL("kernel32")
。 WinDLL 继承了 CDLL,它的 __init__
打开了 kernel32 的句柄。当您在 __getattr__
上使用它时,CDLL"GetModuleHandle"
查找字符串化属性 kernel32
并为其创建一个 _FuncPtr
,它继承了 _CFuncPtr
,它是一个 { {1}}。
_ctypes.CFuncPtr
类型对象 (_ctypes.CFuncPtr
) 是直接在 C 中创建的,而不是通过定义 python 类(运行时将为其创建类型对象)间接创建的。请记住,运行时为 Python 中的所有对象(包括函数)创建 PyTypeObject
,并为所有类型创建 PyObject
。因为 PyTypeObject
是继承的,所以它在 CFuncPtr
类型对象中定位构造函数,当类型对象初始化时,它在 C 中设置为 CFuncPtr
,它接受 args,在这种情况下kernel32 WinDLL 对象和 PyCFuncPtr_new
并调用 "GetModuleHandle"
以使用在 CDLL PyCFuncPtr_FromDll
中设置的模块句柄上的 GetProcAddress
来获取地址。在我看来,CDLL __init__
中的 _dlopen
从内部创建的类型对象为 kernel32 创建了一个句柄对象,该对象调用内部 C 构造函数来执行类似 __init__
的操作,并通过python代码将相关的LoadLibrary
赋值给kernel32 WinDLL PyObject中的PyObject
,然后self._handle
使用传入的kernel32 WinDLL对象从PyCFuncPtr_FromDll
中获取句柄对象,即对象将包含来自 _handle
的地址,它将调用 LoadLibrary
,最终 GetProcAddress
类型的对象构造函数返回 CFuncPtr
用于从 CDLL 返回的函数指针实例PyObject
,对其执行的调用将导致python调用此对象中的地址,该地址将是__getattr__
而不是在字节码地址处解释字节码的函数的地址?。我现在无法验证细节,但对我来说,这就是我看到从 Python 运行时与 Windows API 接口的可能性的方式。
下次不会调用 GetProcAddress
,因为该属性现在存在。