-1

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")
martineau
  • 119,623
  • 25
  • 170
  • 301
ueir
  • 101
  • 3

2 Answers2

1

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

There are some problems with your code:

  1. The main one:

    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
    
  2. 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)

  3. 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

  4. Argument validation should come 1st

CristiFati
  • 38,250
  • 9
  • 50
  • 87
  • Note that `.restype` should be set or a 64-bit HMODULE could be truncated. – Mark Tolonen Jun 30 '21 at 17:01
  • @MarkTolonen: thanks for the suggestion, that should have been covered by the answer referenced by the 2nd bullet. Anyway I added that piece of info in order to be explicit. – CristiFati Jun 30 '21 at 17:11
1

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
Mark Tolonen
  • 166,664
  • 26
  • 169
  • 251