Call to GetModuleHandle on kernel32 using Python C-types
Question:
I’m trying to use Python’s C-Types to call GetModuleHandleA on the kernel32 library. I’d like to get a handle to the library so I can use it to call GetProcAddress for LoadLibraryA. Below is my code…
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)))
I’m getting an error, “ERROR: 126 – The specified module could not be found”. I’ve also tried “C:/Windows/System32/kernel32.dll” and just “kernel32”. I’m using Python 3.2 and this is on a Windows 7 machine. I’ve verified that the dll is there and in the path that I have set in the code above. I’ve been doing some research and can’t seem to find out what the issue is. Any help is greatly appreciated. Thanks!
Answers:
The handle is stored in kernel32._handle
. Calling GetModuleHandle
should return the same value, but make sure you set restype
and argtypes
for type safety [*]:
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')
Notice the ‘W’ suffix instead of ‘A’. Python 3 uses Unicode strings, for which ctypes creates a c_wchar_p
(LPCWSTR
). There’s no reason to call the [A]NSI version since it’s just a wrapper around the [W]ide string version. But if you must, then you need to use bytes:
kernel32.GetModuleHandleA.restype = wintypes.HMODULE
kernel32.GetModuleHandleA.argtypes = [wintypes.LPCSTR]
hMod = kernel32.GetModuleHandleA(b'kernel32.dll')
[*] I recommend using kernel32 = WinDLL('kernel32', use_last_error=True)
instead of windll.kernel32
. This avoids conflicts with other modules that use windll
. It also enables protection for the thread’s LastErrorValue
. In this case, use ctypes.get_last_error()
and ctypes.set_last_error(err)
instead of directly calling WinAPI GetLastError
and SetLastError
.
As for how it’s done internally, ctypes.windll.kernel32
is WinDLL("kernel32")
. WinDLL inherits CDLL, whose __init__
opens a handle to kernel32.dll using self._handle = ctypes._dlopen
(from _ctypes import LoadLibrary as _dlopen
), and LoadLibrary
is bound to the load_library
C function in the runtime, which calls LoadLibraryExW
, and then returns a call to PyLong_FromVoidPtr
, which creates a PyObject
(PyLong
) from a C void pointer (HMODULE
) and returns it, and just like a regular function implemented in python, it now internally has a PyObject
that it uses to assign to self._handke
). The CDLL __getattr__
is called by the runtime the first time "GetModuleHandle"
is used on kernel32
, and this python code instantiates an object of _FuncPtr
type for it, which inherits _CFuncPtr
, which is a _ctypes.CFuncPtr
(from _ctypes import _CFuncPtr as CFuncPtr
).
The type identifier _ctypes.CFuncPtr
is bound to a C object (PyCFuncPtr_Type
of type PyTypeObject
) in the definition of said C object in the runtime library; the identifier string is a member of the object. Remember that under the hood the runtime creates PyObject
s for all python objects (including python functions), and a PyTypeObject
for all python types, this is usually done implicitly by the runtime but in this case the python code explicitly creates a function object that can be used to make the native call. It now uses the constructor PyCFuncPtr_new
set in the type object (PyCFuncPtr_Type
) in C to instantiate the actual function object from the function type object, which takes the args, in this case the kernel32 WinDLL object and "GetModuleHandle"
, and calls PyCFuncPtr_FromDll
(because the very fact there are arguments means it’s not a regular function) to create a new function object and associate it with the actual function address using GetProcAddress
on the handle to the module in WinDLL set up in the CDLL __init__
.
A call performed on this function object will cause python to call the address in this object, which will be GetProcAddress
instead of an address of a function that interprets the bytecode at the bytecode address… I assume.
Next time the __getattr__
is not called because the attribute now exists.
I’m trying to use Python’s C-Types to call GetModuleHandleA on the kernel32 library. I’d like to get a handle to the library so I can use it to call GetProcAddress for LoadLibraryA. Below is my code…
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)))
I’m getting an error, “ERROR: 126 – The specified module could not be found”. I’ve also tried “C:/Windows/System32/kernel32.dll” and just “kernel32”. I’m using Python 3.2 and this is on a Windows 7 machine. I’ve verified that the dll is there and in the path that I have set in the code above. I’ve been doing some research and can’t seem to find out what the issue is. Any help is greatly appreciated. Thanks!
The handle is stored in kernel32._handle
. Calling GetModuleHandle
should return the same value, but make sure you set restype
and argtypes
for type safety [*]:
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')
Notice the ‘W’ suffix instead of ‘A’. Python 3 uses Unicode strings, for which ctypes creates a c_wchar_p
(LPCWSTR
). There’s no reason to call the [A]NSI version since it’s just a wrapper around the [W]ide string version. But if you must, then you need to use bytes:
kernel32.GetModuleHandleA.restype = wintypes.HMODULE
kernel32.GetModuleHandleA.argtypes = [wintypes.LPCSTR]
hMod = kernel32.GetModuleHandleA(b'kernel32.dll')
[*] I recommend using kernel32 = WinDLL('kernel32', use_last_error=True)
instead of windll.kernel32
. This avoids conflicts with other modules that use windll
. It also enables protection for the thread’s LastErrorValue
. In this case, use ctypes.get_last_error()
and ctypes.set_last_error(err)
instead of directly calling WinAPI GetLastError
and SetLastError
.
As for how it’s done internally, ctypes.windll.kernel32
is WinDLL("kernel32")
. WinDLL inherits CDLL, whose __init__
opens a handle to kernel32.dll using self._handle = ctypes._dlopen
(from _ctypes import LoadLibrary as _dlopen
), and LoadLibrary
is bound to the load_library
C function in the runtime, which calls LoadLibraryExW
, and then returns a call to PyLong_FromVoidPtr
, which creates a PyObject
(PyLong
) from a C void pointer (HMODULE
) and returns it, and just like a regular function implemented in python, it now internally has a PyObject
that it uses to assign to self._handke
). The CDLL __getattr__
is called by the runtime the first time "GetModuleHandle"
is used on kernel32
, and this python code instantiates an object of _FuncPtr
type for it, which inherits _CFuncPtr
, which is a _ctypes.CFuncPtr
(from _ctypes import _CFuncPtr as CFuncPtr
).
The type identifier _ctypes.CFuncPtr
is bound to a C object (PyCFuncPtr_Type
of type PyTypeObject
) in the definition of said C object in the runtime library; the identifier string is a member of the object. Remember that under the hood the runtime creates PyObject
s for all python objects (including python functions), and a PyTypeObject
for all python types, this is usually done implicitly by the runtime but in this case the python code explicitly creates a function object that can be used to make the native call. It now uses the constructor PyCFuncPtr_new
set in the type object (PyCFuncPtr_Type
) in C to instantiate the actual function object from the function type object, which takes the args, in this case the kernel32 WinDLL object and "GetModuleHandle"
, and calls PyCFuncPtr_FromDll
(because the very fact there are arguments means it’s not a regular function) to create a new function object and associate it with the actual function address using GetProcAddress
on the handle to the module in WinDLL set up in the CDLL __init__
.
A call performed on this function object will cause python to call the address in this object, which will be GetProcAddress
instead of an address of a function that interprets the bytecode at the bytecode address… I assume.
Next time the __getattr__
is not called because the attribute now exists.