如您所知,如果对LoadLibrary的调用指定DLL模块已映射到调用进程的地址空间,则该函数只返回DLL的句柄并递增模块的引用计数。
某处,我需要获取一个dll的引用计数。如何获取dll的引用计数?如何知道dll的加载位置?感谢。
答案 0 :(得分:5)
我用Google搜索,发现这个article声称提供了答案。 对不起,我无能为力:
答案 1 :(得分:4)
如果它是非编程方式(感谢C.Johnson给出了这个观点),WinDBG可能会有所帮助
http://windbg.info/doc/1-common-cmds.html#10_modules
看看!dlls和它的变种。
!dll - 所有加载的模块都有加载 计数
编辑2:
如果您想知道从进程中加载所有DLL的位置,有两种方法:
一个。看一下命令
“bu kernel32!LoadLibraryExW”;作为/ mu $ {/ v:MyAlias} poi(@ esp + 4); .if( $ spat(\“$ {MyAlias} \”,\“ MYDLL \”) != 0){kn; } .else {g}“”
在上面的网址
湾在WinDBG下运行该过程。 Debug-> Even Filter并选择“Load Module”并在“Execution”下将其设置为“Enabled”。在“继续”下,将其设置为“未处理”。
其中一个应该对你有所帮助。
答案 2 :(得分:1)
我不确定你是否完全理解LoadLibrary/FreeLibrary
的工作方式。完成后调用FreeLibrary
并减少加载时递增的引用计数。如果您的流程的其他部分仍在使用它,那可能不是您的担忧。
引用计数可能会告诉您已经“加载”了多少次,但无法确定是谁加载了它。
答案 3 :(得分:0)
此信息无法通过公共API afaik获得。你的情景是什么?运行AppVerifier将捕获您使用模块(或任何其他)句柄所犯的任何错误。
答案 4 :(得分:0)
您可以使用Module32First()
/ Module32Next()
枚举已加载的模块,然后使用MODULEENTRY32.GlblcntUsage
检查其引用计数。我不确定这是多么可靠。
答案 5 :(得分:0)
答案 6 :(得分:0)
在Windows 8.1上测试。不保证这将适用于较新的窗口(例如10,但是 - 根据文档应该正常工作)
#include <winternl.h> //PROCESS_BASIC_INFORMATION
// warning C4996: 'GetVersionExW': was declared deprecated
#pragma warning (disable : 4996)
bool IsWindows8OrGreater()
{
OSVERSIONINFO ovi = { 0 };
ovi.dwOSVersionInfoSize = sizeof( OSVERSIONINFO );
GetVersionEx(&ovi);
if( (ovi.dwMajorVersion == 6 && ovi.dwMinorVersion >= 2) || ovi.dwMajorVersion > 6 )
return true;
return false;
} //IsWindows8OrGreater
#pragma warning (default : 4996)
bool ReadMem( void* addr, void* buf, int size )
{
BOOL b = ReadProcessMemory( GetCurrentProcess(), addr, buf, size, nullptr );
return b != FALSE;
}
#ifdef _WIN64
#define BITNESS 1
#else
#define BITNESS 0
#endif
typedef NTSTATUS (NTAPI *pfuncNtQueryInformationProcess)(HANDLE,PROCESSINFOCLASS,PVOID,ULONG,PULONG);
//
// Queries for .dll module load count, returns 0 if fails.
//
int GetModuleLoadCount( HMODULE hDll )
{
// Not supported by earlier versions of windows.
if( !IsWindows8OrGreater() )
return 0;
PROCESS_BASIC_INFORMATION pbi = { 0 };
HMODULE hNtDll = LoadLibraryA("ntdll.dll");
if( !hNtDll )
return 0;
pfuncNtQueryInformationProcess pNtQueryInformationProcess = (pfuncNtQueryInformationProcess)GetProcAddress( hNtDll, "NtQueryInformationProcess");
bool b = pNtQueryInformationProcess != nullptr;
if( b ) b = NT_SUCCESS(pNtQueryInformationProcess( GetCurrentProcess(), ProcessBasicInformation, &pbi, sizeof( pbi ), nullptr ));
FreeLibrary(hNtDll);
if( !b )
return 0;
char* LdrDataOffset = (char*)(pbi.PebBaseAddress) + offsetof(PEB,Ldr);
char* addr;
PEB_LDR_DATA LdrData;
if( !ReadMem( LdrDataOffset, &addr, sizeof( void* ) ) || !ReadMem( addr, &LdrData, sizeof( LdrData ) ) )
return 0;
LIST_ENTRY* head = LdrData.InMemoryOrderModuleList.Flink;
LIST_ENTRY* next = head;
do {
LDR_DATA_TABLE_ENTRY LdrEntry;
LDR_DATA_TABLE_ENTRY* pLdrEntry = CONTAINING_RECORD( head, LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks );
if( !ReadMem( pLdrEntry , &LdrEntry, sizeof(LdrEntry) ) )
return 0;
if( LdrEntry.DllBase == (void*)hDll )
{
//
// http://www.geoffchappell.com/studies/windows/win32/ntdll/structs/ldr_data_table_entry.htm
//
int offDdagNode = (0x14 - BITNESS) * sizeof(void*); // See offset on LDR_DDAG_NODE *DdagNode;
ULONG count = 0;
char* addrDdagNode = ((char*)pLdrEntry) + offDdagNode;
//
// http://www.geoffchappell.com/studies/windows/win32/ntdll/structs/ldr_ddag_node.htm
// See offset on ULONG LoadCount;
//
if( !ReadMem(addrDdagNode, &addr, sizeof(void*) ) || !ReadMem( addr + 3 * sizeof(void*), &count, sizeof(count) ) )
return 0;
return (int)count;
} //if
head = LdrEntry.InMemoryOrderLinks.Flink;
}while( head != next );
return 0;
} //GetModuleLoadCount
注入.dll的用法:
// Someone reserved us, let's force us to shutdown.
while( GetModuleLoadCount( dll ) > 1 )
FreeLibrary(dll);
FreeLibraryAndExitThread(dll, 0);