使用Python C类型在kernel32上调用GetModuleHandle

时间:2013-06-10 22:16:48

标签: ctypes python-3.2

我尝试使用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在那里以及我在上面的代码中设置的路径。我一直在做一些研究,似乎无法找出问题所在。任何帮助是极大的赞赏。谢谢!

2 个答案:

答案 0 :(得分:5)

句柄存储在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_pLPCWSTR)。没有理由调用[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 GetLastErrorSetLastError

答案 1 :(得分:0)

至于如何在内部完成,ctypes.windll.kernel32WinDLL("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,因为该属性现在存在。