Python- GetProcAddress using ctypes returns NULL

1.6k Views Asked by At

Problem:

I am trying to get the address of LoadLibraryW but gets NULL.

Research effort:

The function successfully retrieves the kernel32.dll address that is mapped to the python process, but returns NULL for the LoadLibraryW address with 126 error code. When I check the function address in process hacker (under the python process) I see a valid address.

from ctypes import *
kernel32 = windll.kernel32

def resolve_function(dll, func):
    handle = kernel32.GetModuleHandleA(dll.encode("ascii"))
    address = kernel32.GetProcAddress(handle, func.encode("ascii"))
    kernel32.CloseHandle(handle)
    return address


address = resolve_function('kernel32.dll', 'LoadLibraryW')
print(address)

I tried other libraries and other functions but it always returns NULL.

2

There are 2 best solutions below

0
David Heffernan On BEST ANSWER

You need to set the argtypes and restype attributes on the functions you call so that ctypes is able to match the prototypes. I guess this is the main problem in your code.

You should also use the Unicode API as a general rule, in my view. And you must not call CloseHandle on the handle returned by GetModuleHandle.

Put it all together like so:

from ctypes import *
kernel32 = windll.kernel32

def resolve_function(dll, func):
    kernel32.GetModuleHandleW.argtypes = [c_wchar_p]
    kernel32.GetModuleHandleW.restype = c_void_p
    kernel32.GetProcAddress.argtypes = [c_void_p, c_char_p]
    kernel32.GetProcAddress.restype = c_void_p
    handle = kernel32.GetModuleHandleW(dll)
    address = kernel32.GetProcAddress(handle, func)
    return address

address = resolve_function('kernel32.dll', b'LoadLibraryW')
print(address)
0
CristiFati On

Listing [Python 3.Docs]: ctypes - A foreign function library for Python.

It looks like an XY Problem.
You don't need to call any of the 2 functions, ctypes does that for you.

Here's an alternative to your implementation (note that I did no exception handling):

import ctypes


def resolve_function(dll_name, func_name, dll_factory=ctypes.CDLL):
    dll = dll_factory(dll_name)
    return getattr(dll, func_name, None)

This is cross platform (will also work on Nix).