为什么在Python中调用kernel32.GetModuleHandleA()会失败?

1 投票
4 回答
3046 浏览
提问于 2025-04-16 10:49

我在用Python调用 GetModuleHandleA() 的时候遇到了一些问题。我有一个模块,它作为调试器附加到某个进程上。我正在写一个函数,目的是返回特定DLL模块中某个函数的地址。但是 GetModuleHandleA("msvcr100") 总是失败。

from ctypes import *
kernel32 = windll.kernel32

这个函数是一个更大 debug 类的一部分。以下是函数声明的部分内容:

   def resolve_function(self,dll,function): 
        handle = kernel32.GetModuleHandleA(dll)
        if handle == False:
            print "kernel32.GetModuleNameA() failed!!!"
            return False
        address = kernel32.GetProcAddress(handle, function)
        if address == False:
            print "kernel32.GetProcAddress() failed!!!"
            return False
        kernel32.CloseHandle(handle)
        return address

调用这个函数的方式是:

function_address = debug.resolve_function("msvcr100", "printf")

我运行一个单独的进程,里面使用了printf(),然后再附加到这个进程上。一切都很顺利,直到我调用 GetModuleHandleA(),它总是返回 False

运行 printf() 的代码是:

from ctypes import *
import time
msvcr100 = cdll.msvcr100
counter = 0
while 1:
    msvcr100.printf("Counter = %d\n" % counter)
    time.sleep(1)
    counter += 1

有什么想法吗?

4 个回答

0

使用 GetLastError() (或者 WinError)来自 ctypes 来找出为什么你会得到一个 NULL 的返回值,然后把这个信息加到你的错误信息里。即使你解决了这个具体的问题,你也会希望有更强大的错误报告功能。

想了解更多细节,可以查看 ctypes 的文档: http://docs.python.org/library/ctypes.html

1

...

在修改之后:

handle = kernel32.GetModuleHandleA(dll) if handle == False: error = GetLastError() print "错误: %d - %s" % (error, FormatError(error)) return False

...

我得到的结果是:错误: 126 - 找不到指定的模块

其实我把代码中的msvcr100.dll替换成了msvcrt.dll,结果运行得非常好。我发现msvcrt.dll是系统自带的动态链接库,而msvcr100.dll是2010版Studio自带的。它们都在C:\Windows\system32这个文件夹里。至于为什么msvcr100.dll不工作,我还是搞不明白。

5

你已经找到了问题的解决办法,但我还是想解释一下你最开始的尝试为什么失败了,以及你修复的原因。

首先,msvcrt和msvcr100是微软的C运行库的两个不同版本。其实还有其他版本,它们每个都有自己对printf()的定义。一个程序可能加载了其中的某一个版本,也可能加载了多个版本,甚至可能一个版本都没有加载——实际上,你可以只用WinAPI函数来产生控制台输出!简单来说,如果这个程序不是你写的,你就不能指望它能找到某个特定版本的C运行库。

其次,GetModuleHandle()并不会加载任何东西。它只会在指定的模块已经被加载的情况下,返回一个指向该模块的句柄。如果msvcr100.dll文件就放在硬盘上,但程序还没有加载它,GetModuleHandle就不会给你这个句柄。如果你想同时加载一个模块并获取它的句柄,你应该使用LoadLibrary()这个函数……不过你可能不想在一个你不拥有的程序中这样做。

顺便提一下,Process Explorer是一个很方便的工具,可以用来查看一个程序已经加载的DLL。

撰写回答