一个模块可以被卸载,那么我如何确定它是否还在内存中?我有一个句柄,从GetModuleHandle获得。当我尝试调用GetHandleInformation时,我看到错误0xc 0000008-“指定了一个无效的HANDLE”。
67up9zun1#
术语“句柄”在这里有点多了--Win32 API中的许多不同类的对象都被称为“句柄”。GetHandleInformation用于内核对象的句柄-文件、注册表项、互斥锁等。GetModuleHandle返回的HMODULE由加载程序使用,并且不是实际的内核对象,因此GetHandleInformation失败。不过,GetHandleInformation中的两个标志对HMODULE都没有意义。如果你想检查HMODULE是否仍然加载在内存中,你可以调用GetModuleHandle --这个API应该足够快,可以调用很多次。然而,GetModuleHandle的结果在返回时可能是无效的--另一个线程可能已经调用了FreeLibrary。最好确保DLL保持加载状态。您可以通过自己调用LoadLibrary或调用GetModuleHandleEx来实现此操作,后者将递增DLL的引用计数。
xqnpmsa82#
两种解决方案:
在HMODULE上调用GetModuleFileName()。如果加载了模块,您将获得一个有效的文件名。如果它没有被加载,你将不会得到一个有效的文件名。请确保在调用GetModuleFileName()之前将返回的文件名数组的第一个字节设置为“\0”,或者检查返回值。如果在调用前设置第一个字节,则可以有效地忽略返回值,并将零长度字符串视为“未加载”信号。
TCHAR szModName[MAX_PATH + 1]; szModName[0] = _T('\0'); GetModuleFileName(hMod, szModName, MAX_PATH); // zero length string if not loaded, valid DLL name if still loaded
调用VirtualQuery(),传递HMODULE作为查询地址。作为一个实验,在一个已加载的库和一个您知道要释放的库上执行此操作。您会发现它们对于返回的MEMORY_BASIC_INFORMATION有非常不同的结果。我把它留给你来制定一个合适的算法来确定两者之间的差异。
当然,在您运行这些测试的同时,另一个线程可能会卸载库的警告也适用。根据我的经验,这是极不可能发生的,但这在很大程度上取决于你在做什么,为什么要这样做,以及当你这样做时,程序的执行路径。小心使用。
t8e9dugd3#
这是一个非常简单的API。
PIMAGE_NT_HEADERS (NTAPI* _RtlImageNtHeader)
示例程序:
(PVOID)typedef PIMAGE_NT_HEADERS (NTAPI *RTLIMAGENTHEADER)(PVOID); RTLIMAGENTHEADER RtlImageNtHeader; HMODULE hDll = GetModuleHandle("ntdll.dll"); HMODULE hDllTmp = LoadLibrary("ws2_32.dll"); RtlImageNtHeader = (RTLIMAGENTHEADER)GetProcAddress(hDll,"RtlImageNtHeader"); struct _IMAGE_NT_HEADERS *r,*r2; r= RtlImageNtHeader(hDllTmp); FreeLibrary(hDllTmp); r2= RtlImageNtHeader(hDllTmp); //r = NULL //r2 = return ws2_32 PE Header address
3条答案
按热度按时间67up9zun1#
术语“句柄”在这里有点多了--Win32 API中的许多不同类的对象都被称为“句柄”。
GetHandleInformation用于内核对象的句柄-文件、注册表项、互斥锁等。
GetModuleHandle返回的HMODULE由加载程序使用,并且不是实际的内核对象,因此GetHandleInformation失败。不过,GetHandleInformation中的两个标志对HMODULE都没有意义。
如果你想检查HMODULE是否仍然加载在内存中,你可以调用GetModuleHandle --这个API应该足够快,可以调用很多次。然而,GetModuleHandle的结果在返回时可能是无效的--另一个线程可能已经调用了FreeLibrary。最好确保DLL保持加载状态。您可以通过自己调用LoadLibrary或调用GetModuleHandleEx来实现此操作,后者将递增DLL的引用计数。
xqnpmsa82#
两种解决方案:
1
在HMODULE上调用GetModuleFileName()。如果加载了模块,您将获得一个有效的文件名。如果它没有被加载,你将不会得到一个有效的文件名。请确保在调用GetModuleFileName()之前将返回的文件名数组的第一个字节设置为“\0”,或者检查返回值。如果在调用前设置第一个字节,则可以有效地忽略返回值,并将零长度字符串视为“未加载”信号。
2
调用VirtualQuery(),传递HMODULE作为查询地址。作为一个实验,在一个已加载的库和一个您知道要释放的库上执行此操作。您会发现它们对于返回的MEMORY_BASIC_INFORMATION有非常不同的结果。我把它留给你来制定一个合适的算法来确定两者之间的差异。
注意事项
当然,在您运行这些测试的同时,另一个线程可能会卸载库的警告也适用。根据我的经验,这是极不可能发生的,但这在很大程度上取决于你在做什么,为什么要这样做,以及当你这样做时,程序的执行路径。小心使用。
t8e9dugd3#
这是一个非常简单的API。
示例程序: