如何判断 Windows 模块句柄是否仍然有效?

发布于 2024-07-26 11:17:30 字数 143 浏览 7 评论 0原文

模块可以被卸载,那么我如何确定它是否仍在内存中? 我有一个从 GetModuleHandle 获得的句柄。 当我尝试对其调用 GetHandleInformation 时,我看到错误 0xc0000008 - “指定了无效的 HANDLE。” 这发生在它被卸载之前。

A module can be unloaded, so how can I tell for sure if it is still in memory? I have a handle to it, obtained from GetModuleHandle. When I tried calling GetHandleInformation on it I see error 0xc0000008 - "An invalid HANDLE was specified." This happened before it could have been unloaded.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

清音悠歌 2024-08-02 11:17:30

“句柄”这个术语在这里有点重载 - Win32 API 中许多不同类的对象都称为“句柄”。

GetHandleInformation 用于处理内核对象 - 文件、注册表项、互斥体等。

GetModuleHandle 返回的 HMODULE 由加载程序使用,不是实际的内核对象,因此 GetHandleInformation 失败。 不过,您在 GetHandleInformation 中获得的两个标志对于 HMODULE 都没有意义。

如果你想检查 HMODULE 是否仍然加载在内存中,你可以调用 GetModuleHandle - 这个 API 应该足够快,可以多次调用。 但是,GetModuleHandle 的结果在返回时可能无效 - 另一个线程可能调用了 FreeLibrary。 最好确保 DLL 确实保持加载状态。 您可以通过自己调用 LoadLibrary 或调用 GetModuleHandleEx 来完成此操作,这将增加 DLL 的引用计数。

The term "handle" is a bit overloaded here - lots of different classes of objects in the Win32 API are called "Handles".

GetHandleInformation is used for handles to kernel objects - files, registry keys, mutexes, etc.

The HMODULE returned by GetModuleHandle is used by the loader and is not an actual kernel object, hence GetHandleInformation fails. Neither of the flags you get in GetHandleInformation makes sense for HMODULE though.

If you want to check if the HMODULE is still loaded in memory, you can just call GetModuleHandle - this API should be quick enough to call many times. However, the result of GetModuleHandle can be invalid the moment it returns - another thread could have called FreeLibrary. It is better to ensure that the DLL does stay loaded. You can do this by calling LoadLibrary yourself, or by calling GetModuleHandleEx which will increment the reference count of the DLL.

别挽留 2024-08-02 11:17:30

两种解决方案:

1

在 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

2

调用 VirtualQuery(),传递 HMODULE 作为要查询的地址。 作为实验,在已加载的库和您知道要释放的库上执行此操作。 您会发现它们对于返回的 MEMORY_BASIC_INFORMATION 有非常不同的结果。 我让您制定一个合适的算法来确定两者之间的差异。

警告

当然,当您运行这些测试中的任何一个时,另一个线程可能会卸载库,这一警告适用。 根据我的经验,这种情况极不可能发生,但这在很大程度上取决于您在做什么、为什么这样做以及何时执行程序的执行路径。 小心使用。

Two solutions:

1

Call GetModuleFileName() on the HMODULE. If the module is loaded you will get a valid filename. If it is not loaded, you won't get a valid filename. Be sure to either set the first byte of the returned filename array to '\0' before you call GetModuleFileName() or to check the return value. If you set the first byte before the call you can effectively ignore the return value and just treat the zero length string as a "not loaded" signal.

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

2

Call VirtualQuery() passing the HMODULE as the address to query. As an experiment do this on a loaded library and on a library you know to be freed. You will find they have very differentl results for the returned MEMORY_BASIC_INFORMATION. I leave it to you to work out a suitable algorithm to determine the difference between the two.

Caveat

Of course, the caveat that another thread may unload the library while you are running eiher of these tests applies. In my experience, this is highly unlikely to happen, but that depends very much on what you are doing, why you are doing it, and when you are doing it the program's execution path. Use with care.

苏大泽ㄣ 2024-08-02 11:17:30

这是非常简单的 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

It's very simple API.

PIMAGE_NT_HEADERS (NTAPI* _RtlImageNtHeader)

Sample program:

(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
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文