kernel32.GetModuleHandleA returning strange value - python

By running the code of python below with python main.py wmi.dll, I want to get the loading address of DLL. However, the value of loadAddr is 0. What is wrong in the code?
from ctypes import *
import sys
import string
kernel32 = windll.kernel32
print(kernel32)
if len(sys.argv)!=2:
print("Usage : dll.py<DLL to resolve>")
sys.exit(0)
windll.LoadLibrary(sys.argv[1])
loadAddr = kernel32.GetModuleHandleA(sys.argv[1])
print(str(loadAddr)+"\n")
print(sys.argv[1])
print(hex(loadAddr) + " Load Address")
print(hex(loadAddr + int("0x1000",16)) + " Text segment")

Make sure to define the .argtypes and .restype of the functions you are using with ctypes. GetModuleHandleA takes a LPCSTR (equivalent to a bytes object in Python), and GetModuleHandleW takes a LPCWSTR (equivalent to a str object in Python). Additionally, they both return HDMODULE, which is a 64-bit value of 64-bit systems, but the default .restype if unspecified is c_int (32-bit).
Here's correct code to call either version:
import ctypes as ct
from ctypes import wintypes as w
k32 = ct.WinDLL('kernel32')
k32.GetModuleHandleA.argtypes = w.LPCSTR,
k32.GetModuleHandleA.restype = w.HMODULE
k32.GetModuleHandleW.argtypes = w.LPCWSTR,
k32.GetModuleHandleW.restype = w.HMODULE
wmi = ct.WinDLL('wmi')
print(k32.GetModuleHandleA(b'wmi')) # byte string
print(k32.GetModuleHandleW('wmi')) # Unicode string
print(k32.GetModuleHandleA('wmi')) # calling with wrong type
Sample output below. Note this value is larger than a 32-bit value could hold (>4294967295) and would be truncated and incorrect if .restype wasn't set, and the error message would not occur if .argtypes wasn't set.
1864530853888
1864530853888
Traceback (most recent call last):
File "C:\test.py", line 15, in <module>
print(k32.GetModuleHandleA('wmi'))
ctypes.ArgumentError: argument 1: <class 'TypeError'>: wrong type

Listing [Python.Docs]: ctypes - A foreign function library for Python.
There are some problems with your code:
The main one:
[MS.Docs]: GetModuleHandleA function (libloaderapi.h) (or any ANSI function variant from WinAPI) takes a 8bit string (char*) as argument
In Python 3 (I assume that's what you are using) strings are 16bit (wchar_t*)
To get past this you should use: kernel32.GetModuleHandleW. Example:
>>> import ctypes as ct
>>> # kernel32 is alsready loaded
>>> ct.windll.kernel32.GetModuleHandleA("kernel32")
0
>>> ct.windll.kernel32.GetModuleHandleW("kernel32")
-1613692928
Check [SO]: C function called from Python via ctypes returns incorrect value (#CristiFati's answer) for details on calling functions from .dlls via CTypes (in particular, you should set restype to a 64bit value, e.g. wintypes.HMODULE)
There's no need for GetModuleHandle (making the previous 2 bullets moot for this particular case, but I left them because they contain useful general info). You could simply use load_addr = windll.LoadLibrary(sys.argv[1])._handle
Argument validation should come 1st

Related

Can ints be passed where a Windows Handle is expected in Python ctypes

I have the following code:
GetForegroundWindow = windll.user32.GetForegroundWindow
GetWindowTextLength = windll.user32.GetWindowTextLengthW
GetWindowText = windll.user32.GetWindowTextW
hwnd = GetForegroundWindow() # Get handle to foreground window. Here hwnd is a Python int.
length = GetWindowTextLength(hwnd) # Get length of the window text in title bar. Here hwnd is expected to be a Windows Handle.
buff = create_unicode_buffer(length + 1) # Create buffer to store the window title buff
GetWindowText(hwnd, buff, length + 1) # Get window title and store in buff
print(buff.value) # print the value of buff
On line 4, a handle is retrieved, which in ctypes is assumed to be a Python int. On the next line, it is passed where a Windows handle is expected. Is Python automatically converting it into the correct type? Don't we have to convert it explicitly?
No, don’t assume. Set .argtypes and .restype on each function to inform ctypes what the argument types and return type are. For example on 64-bit Python the handle is 64 bits and the assumed c_int return value will truncate it to 32 bits.
For example, extending your code using some predefined Windows types provided:
from ctypes import wintypes as w
...
GetForegroundWindow.argtypes = ()
GetForegroundWindow.restype = w.HWND
Now the correct value will be returned, regardless of OS. Repeat for other functions used and parameters will be type-checked and checked for number of arguments and return values will be correct.

Using d2xx.dll in python with ctypes

I'm trying to use d2xx.dll which is a library for interfacing FTDI's USB controller chips. I want to use this library in my python code. I decided to use ctypes library in python to call dll functions. I failed to call function from dll file appropriately and I think I have some problems with variable types that I pass to the functions in the dll library. I am not a professional programmer, so take it easy on me. :D
Here is what tried so far,
import ctypes
from ctypes import *
d2xxdll = ctypes.cdll.LoadLibrary('ftd2xx.dll') #Load the dll library
d2xxdll.FT_CreateDeviceInfoList.argtypes =[ctypes. c_ulong] # specify function's input type
d2xxdll.FT_CreateDeviceInfoList.restype = ctypes.c_ulong # specify function's return type
numDevs = ctypes.c_ulong()
p_numDevs = POINTER(numDevs)
FT_STATUS = d2xxdll.FT_CreateDeviceInfoList(p_numDevs)
print(FT_STATUS)
print(numDevs)
I am just trying to detect how many D2XX devices are connected with FT_CreateDeviceInfoList() function. FT_CreateDeviceInfoList is described in d2xx.dll documentation page 6. The function has one input parameter which is a pointer to an unsigned long and it returns the state of the USB device. I declare an unsigned long with "numDevs = ctypes.c_ulong()" and declare its pointer in "p_numDevs = POINTER(numDevs)", and I get the following error when I run the code.
Traceback (most recent call last):
File "C:\Users\asus\Desktop\dokümanlar\Python_Ogren\Ctypes_cll\d2xx_dll.py", line 9, in <module>
p_numDevs = ctypes.POINTER(numDevs)
TypeError: must be a ctypes type
I also tried using byref to pass the address of numDevs:
import ctypes
from ctypes import *
d2xxdll = ctypes.cdll.LoadLibrary('ftd2xx.dll') #Load the dll library
d2xxdll.FT_CreateDeviceInfoList.argtypes =[ctypes. c_ulong] # specify function's input type
d2xxdll.FT_CreateDeviceInfoList.restype = ctypes.c_ulong # specify function's return type
numDevs = ctypes.c_ulong()
FT_STATUS = d2xxdll.FT_CreateDeviceInfoList(ctypes.byref(numDevs))
print(FT_STATUS)
print(numDevs)
This time I get the following:
Traceback (most recent call last):
File "C:\Users\asus\Desktop\dokümanlar\Python_Ogren\Ctypes_cll\d2xx_dll.py", line 10, in <module>
FT_STATUS = d2xxdll.FT_CreateDeviceInfoList(ctypes.byref(numDevs))
ArgumentError: argument 1: <type 'exceptions.TypeError'>: wrong type
How should I pass the input parameter? I know there are some wrappers for d2xx.dll in python like pyusb, but for some reason I couldn't got them working. I wrote some C code with d2xx.dll they worked like charm. Right now I am looking for a way to get them working in python.
Thanks in advance.
The C definition of the function is:
typedef ULONG FT_STATUS;
FTD2XX_API
FT_STATUS WINAPI FT_CreateDeviceInfoList(
LPDWORD lpdwNumDevs
);
ctypes has a library of Windows types to help you map them correctly. The parameter type is not a c_ulong but a POINTER(c_ulong). The wintypes module defines LPDWORD correctly as this type. Then you create a DWORD and pass it byref().
Below is a complete wrapper:
import ctypes
from ctypes import wintypes
FT_STATUS = wintypes.ULONG
FT_OK = 0
# Note: WINAPI is __stdcall so if using 32-bit Windows you want WinDLL().
# Use CDLL() for __cdecl calling convention.
# On 64-bit Windows there is only one calling convention and either works.
ftd2xx = ctypes.WinDLL('ftd2xx')
_FT_CreateDeviceInfoList = ftd2xx.FT_CreateDeviceInfoList
_FT_CreateDeviceInfoList.argtypes = wintypes.LPDWORD,
_FT_CreateDeviceInfoList.restype = FT_STATUS
def FT_CreateDeviceInfoList():
num_devs = wintypes.DWORD()
if _FT_CreateDeviceInfoList(ctypes.byref(num_devs)) != FT_OK:
raise RuntimeError('failed')
return num_devs.value

ctypes call GetProcAddress() failed with error code 127,but win32api.GetProcAddress successed

When I call GetProcAddress() by win32api, I get the handle successfully but ctypes didn't.
The codes are:
from ctypes import windll
import win32api
KERNEL32 = windll.kernel32
h_kernel32 = KERNEL32.GetModuleHandleW('kernel32.dll')
print(hex(h_kernel32))
h_loadlib1=win32api.GetProcAddress(h_kernel32,'LoadLibraryW')
print(hex(h_loadlib1))
if not h_loadlib1:
print("NtCreateThreadEx Failed:",win32api.GetLastError())
h_loadlib2 = KERNEL32.GetProcAddress(h_kernel32,'LoadLibraryW')
print(hex(h_loadlib2))
if not h_loadlib2:
print("NtCreateThreadEx Failed:",win32api.GetLastError())
And the outputs:
0x77250000
0x77266f80
0x0
NtCreateThreadEx Failed: 127
SYSTEM INFO:
windows7 64, python 3.43
You need to use a char string rather than the default Unicode string provided by python 3.x, as hinted by the GetProcAddress documentation (the 2nd parameter is a LPCSTR, not LPCTSTR or LPCWSTR):
h_loadlib2 = KERNEL32.GetProcAddress(h_kernel32,'LoadLibraryW'.encode(encoding='ascii'))
Alternatively, you can pass a byte:
h_loadlib2 = KERNEL32.GetProcAddress(h_kernel32, b'LoadLibraryW')
Note: The above code won't work on a python 64-bit interpreter (the most significant 32-bit of the 64-bit module handle are zeroed). In this case you'll need to use argtypes and restype as explained in the tutorial (for example by defining a 64-bit HMODULE type).

calling a dll function that takes a pointer to a handle (win32) from python

I'm trying to write a very simple controller for a camera on a WinXP machine. Instead of writing c code, I thought I would simply use ctypes to access the dll.
To start the camera, you have to call:
BeginHVDevice(int nDevice, HHV *pHandle)
*pHandle is a pointer to a camera handle, which in the.h file is simply defined as
typedef HANDLE HHV;
I had thought that the following should work
from ctypes import *
from ctypes.wintypes import *
ailt_lib = cdll.LoadLibrary("HVDAILT")
load_camera = ailt_lib.BeginHVDevice
load_camera.restype = c_int
load_camera.argtypes = [c_int, POINTER(HANDLE)]
def initDev(res=(800,600)):
cam_int = c_int(1)
cam_handle_type = POINTER(HANDLE)
print cam_handle_type
cam_handle = cam_handle_type()
print cam_handle
cam_stat = load_camera(cam_int, cam_handle )
print cam_stat
return cam_handle
but, when I call initDev(), I get a ValueError: Procedure called with not enough arguments (8 bytes missing) or wrong calling convention. I'm pretty sure this means that I have not produced a compatible pointer to pass, but I can't figure out what the function actually wants to receive.
I've spent a couple of days search stackoverflow, looking at ctypes documentation and trying all sorts of permutations, but I have not found the answer.
It seems the function is using stdcall instead of the cdecl calling convention, i.e. use ctypes.WinDLL instead of ctypes.CDLL. Also, it wants a pointer to a memory location where it can store the handle, but you passed it a NULL pointer. Instead pass it a reference to a wintypes.HANDLE.
from ctypes import *
from ctypes.wintypes import *
ailt_lib = WinDLL("HVDAILT")
load_camera = ailt_lib.BeginHVDevice
load_camera.restype = c_int
load_camera.argtypes = [c_int, POINTER(HANDLE)]
def initDev(res=(800,600)):
cam_int = 1
cam_handle = HANDLE()
cam_stat = load_camera(cam_int, byref(cam_handle))
print 'cam_stat:', cam_stat
print 'cam_handle:', cam_handle
return cam_handle

Using NI-VISA with Python: error code -1073807343 in viFindRsrc

I'm working in Python and have installed the lastest version of NI-VISA. I'm using the ctypes package in order to load the visa32.dll installed with NI-VISA.
I used both the NI-VISA documentation, as well as the following page as a base for my code.
I already know of the pyVisa wrapper and using their find_resources function does return the instruments connected. However, I do not wish to use this wrapper and would rather use the VISA DLL file directly.
I've also been browsing the pyVisa code to see how they do it, and tried to learn from it, but it seems I still don't get it.
Here is my current unfinished code:
import sys
from ctypes import *
visa = windll.LoadLibrary("visa32.dll")
resourceManagerHandle = c_int(0)
visa.viOpenDefaultRM(byref(resourceManagerHandle))
instr_list = c_ulong(0)
nb = c_ulong(0)
desc = create_string_buffer(128)
print(visa.viFindRsrc(resourceManagerHandle,
"?*INSTR",
byref(instr_list),
byref(nb),
byref(desc)))
# The previous line prints: -1073807343
print(instr_list)
# The previous line prints: c_ulong(0)
I've been trying to find the meaning of the error code -1073807343 (4000FFEF in hex) on the Internet and though I have found some forum threads about it on the National Instruments forums, I still don't quite understand what it means.
I would welcome any advice, guidance or link towards relevant information.
The literal "?*INSTR" creates an str object, which is Unicode in Python 3. ctypes converts a unicode string to a wchar_t *. On Windows, wchar_t is 2 bytes, so ctypes passes a pointer to the UTF-16 encoded buffer "?\x00*\x00I\x00N\x00S\x00T\x00R\x00". Bear in mind that the function expects a null-terminated string.
To pass a byte string instead, prefix the literal with b to create a bytes object, i.e. use b"?*INSTR".
To prevent a mistake like this from passing unnoticed, define the function pointer's argtypes. ctypes will raise an ArgumentError if a unicode str argument is passed for a parameter that's defined to be c_char_p.
from ctypes import *
visa = WinDLL("visa32.dll") # or windll.visa32
def vi_status_check(vi_status, func, args):
if vi_status < 0:
raise RuntimeError(hex(vi_status + 2**32))
return args
visa.viOpenDefaultRM.errcheck = vi_status_check
visa.viOpenDefaultRM.argtypes = [POINTER(c_uint32)]
visa.viFindRsrc.errcheck = vi_status_check
visa.viFindRsrc.argtypes = [c_uint32, # sesn
c_char_p, # expr
POINTER(c_uint32), # findList
POINTER(c_uint32), # retcnt
c_char_p] # desc
rm_session = c_uint32()
visa.viOpenDefaultRM(byref(rm_session))
expr = b"?*INSTR"
instr_list = c_uint32()
nb = c_uint32()
desc = create_string_buffer(256)
visa.viFindRsrc(rm_session,
expr,
byref(instr_list),
byref(nb),
desc)
The NI-VISA Programmer Reference Manual says on page 5-30 that instrDesc should be at least 256 bytes.

Categories