如您所知,如果LoadLibrary的调用指定了一个DLL模块已经映射到调用进程的地址空间中,该函数只是返回DLL的句柄并递增模块的引用计数。如何检查dll的引用计数?如何知道dll的加载位置?
某处,我需要得到一个DLL的引用计数。如何获得dll的引用计数?如何知道dll的加载位置?谢谢。
如您所知,如果LoadLibrary的调用指定了一个DLL模块已经映射到调用进程的地址空间中,该函数只是返回DLL的句柄并递增模块的引用计数。如何检查dll的引用计数?如何知道dll的加载位置?
某处,我需要得到一个DLL的引用计数。如何获得dll的引用计数?如何知道dll的加载位置?谢谢。
该信息不适用于通过公共API afaik。你的场景是什么?运行AppVerifier将捕获您使用模块(或任何其他)手柄所犯的任何错误。
如果它是一个非编程的方式(感谢C.Johnson给了这一观点),WinDBG的可帮助
http://windbg.info/doc/1-common-cmds.html#10_modules
看的dll!它是变种。 !
DLL - 负载 计数
编辑所有加载的模块2:
如果你想从所有正在从进程中加载的DLL哪里知道,有两种方法:
a。看命令
在上述URL“BU KERNEL32 LoadLibraryExW!”;如/亩 $ {/ V:MyAlias} POI(@ ESP + 4); .if( $ spat(\“$ {MyAlias} \”,\“MYDLL \”) != 0){kn; }的.else {G}”,“
b
。在WinDBG下运行该进程。 Debug-> Even Filter并选择“Load Module”并将其设置为“Execution”下的“Enabled”。在“继续”下将其设置为“未处理”。
其中一个应该可以帮助你。
我不确定您完全了解LoadLibrary/FreeLibrary
是如何工作的。当你完成它时,你可以调用FreeLibrary
,并减少加载时增加的引用计数。如果您的流程的其他部分仍在使用它,那可能不是您的担心。
引用计数可能会告诉你它已被“加载”了多少次,但无助于弄清楚是谁加载了它。
您可以在Module32First()
/Module32Next()
的进程中枚举加载的模块,然后使用MODULEENTRY32.GlblcntUsage
来检查它的引用计数。我不确定这是多么可靠。
typedef struct _LDR_MODULE
{
LIST_ENTRY InLoadOrderModuleList;
LIST_ENTRY InMemoryOrderModuleList;
LIST_ENTRY InInitializationOrderModuleList;
PVOID BaseAddress;
PVOID EntryPoint;
ULONG SizeOfImage;
UNICODE_STRING FullDllName;
UNICODE_STRING BaseDllName;
ULONG Flags;
USHORT LoadCount;
USHORT TlsIndex;
LIST_ENTRY HashTableEntry;
ULONG TimeDateStamp;
} LDR_MODULE, *PLDR_MODULE;
struct LDR_MODULE_COMPARE
{
bool operator()(CONST LDR_MODULE& L, CONST LDR_MODULE& R) CONST {
ustring ul = L.BaseDllName.Buffer;
ustring ur = R.BaseDllName.Buffer;
ul.to_lower();
ur.to_lower();
int cmp = wcscmp(ul.c_wstr(), ur.c_wstr());
if (cmp == 0) {
ul = L.FullDllName.Buffer;
ur = R.FullDllName.Buffer;
cmp = wcscmp(ul.c_wstr(), ur.c_wstr());
}
return cmp < 0;
}
};
typedef std::set<LDR_MODULE, LDR_MODULE_COMPARE> LDR_MODULE_SET;
typedef std::map<ustring, LDR_MODULE, ustring::map_ustring_compare> LDR_MODULE_MAP;
DWORD get_process_id(LPCWSTR processname_z) {
DWORD aProcesses[1024], cbNeeded, cProcesses;
unsigned int i;
DWORD result = 0;
//Enumerate all processes
if (!EnumProcesses(aProcesses, sizeof(aProcesses), &cbNeeded))
return NULL;
// Calculate how many process identifiers were returned.
cProcesses = cbNeeded/(DWORD)sizeof(DWORD);
ustring fullpath(processname_z);
fullpath.to_lower();
ustring uprocess(processname_z);
uprocess = _UWC(uprocess.filename());
uprocess.to_lower();
size_t ext_pos = uprocess.find_last_of('.');
if (ext_pos != ustring::unpos) {
uprocess = uprocess.left(ext_pos);
}
TCHAR szEXEName[MAX_PATH];
//Loop through all process to find the one that matches
//the one we are looking for
for (i = 0; i < cProcesses; i++) {
// Get a handle to the process
HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION |
PROCESS_VM_READ, FALSE, aProcesses[i]);
// Get the process name
if (NULL != hProcess) {
HMODULE hMod;
DWORD cbNeeded;
if (EnumProcessModules(hProcess, &hMod,
sizeof(hMod), &cbNeeded)) {
//Get the name of the exe file
GetModuleBaseName(hProcess, hMod, szEXEName,
sizeof(szEXEName)/sizeof(TCHAR));
size_t len = _tcslen(szEXEName);
_tcscpy(szEXEName + len - 4, TEXT("\0"));
ustring uexename((TCHAR*)szEXEName);
uexename = _UWC(uexename.filename());
uexename.to_lower();
if (uexename == uprocess) {
result = aProcesses[i];
} else if (GetModuleFileNameEx(hProcess, 0, szEXEName, MAX_PATH)) {
uexename = (TCHAR*)szEXEName;
uexename.to_lower();
if (uexename == fullpath) {
result = aProcesses[i];
}
}
}
}
CloseHandle(hProcess);
if (result > 0) break;
}
return result;
}
HRESULT get_dll_references_or_count(LPCWSTR process_z, LPCWSTR dll_z,
_Out_ DWORD* count_ptr,
_Out_opt_ LDR_MODULE_SET* pdlls,
_Out_opt_ LDR_MODULE_SET* pnew_dlls,
BOOL append) {
HRESULT hr = E_FAIL;
PROCESS_BASIC_INFORMATION pbi;
PEB peb;
DWORD dwSize = 0;
SIZE_T stSize = 0;
DWORD process_id = 0;
HANDLE hProcess = NULL;
PEB_LDR_DATA peb_ldr_data;
ustring udll;
LDR_MODULE peb_ldr_module;
void *readAddr = NULL;
HMODULE hMod = NULL;
typedef NTSTATUS(WINAPI* ZwQueryInformationProcess)(HANDLE, DWORD, PROCESS_BASIC_INFORMATION*, DWORD, DWORD*);
ZwQueryInformationProcess MyZwQueryInformationProcess = NULL;
//
if (count_ptr == NULL && pdlls == NULL) return hr;
if (count_ptr != NULL) *count_ptr = 0;
if (pdlls != NULL && !append) pdlls->clear();
//
process_id = get_process_id(process_z);
if (process_id == 0) return hr;
//
hProcess = OpenProcess(PROCESS_QUERY_INFORMATION |
PROCESS_VM_READ, FALSE, process_id);
if (hProcess == NULL) goto Exit;
//
hMod = GetModuleHandle(L"ntdll.dll");
MyZwQueryInformationProcess = (ZwQueryInformationProcess)GetProcAddress(hMod, "ZwQueryInformationProcess");
if (MyZwQueryInformationProcess == NULL) goto Exit;
//
if (MyZwQueryInformationProcess(hProcess, 0, &pbi, sizeof(PROCESS_BASIC_INFORMATION), &dwSize) < 0) {
goto Exit;
}
//
if (!ReadProcessMemory(hProcess, pbi.PebBaseAddress, &peb, sizeof(PEB), &stSize)) goto Exit;
//
if (!ReadProcessMemory(hProcess, peb.Ldr, &peb_ldr_data, sizeof(peb_ldr_data), &stSize)) goto Exit;
//
_LIST_ENTRY* pmodule = peb_ldr_data.InMemoryOrderModuleList.Flink;
_LIST_ENTRY* pstart = pmodule;
readAddr = (void*)pmodule;
// Go through each modules one by one in their load order.
udll = dll_z;
udll.to_lower();
while (ReadProcessMemory(hProcess, readAddr, &peb_ldr_module, sizeof(peb_ldr_module), &stSize)) {
// Get the reference count of the DLL
if (pdlls == NULL) {
ustring utmp(peb_ldr_module.FullDllName.Buffer);
utmp.to_lower();
if (utmp == udll) {
*count_ptr = (int)(signed short)peb_ldr_module.LoadCount;
break;
}
utmp = peb_ldr_module.BaseDllName.Buffer;
utmp.to_lower();
if (utmp == udll) {
*count_ptr = (int)(signed short)peb_ldr_module.LoadCount;
break;
}
} else {
if (append) {
if (pdlls->find(peb_ldr_module) == pdlls->end()) {
pdlls->insert(peb_ldr_module);
if (pnew_dlls != NULL) {
pnew_dlls->insert(peb_ldr_module);
}
}
#ifdef _DEBUG
else {
ATLTRACE("%s already loaded\n", peb_ldr_module.FullDllName.Buffer);
}
#endif
} else {
pdlls->insert(peb_ldr_module);
}
}
_LIST_ENTRY* pprevmodule = pmodule;
pmodule = pmodule->Flink;
if (pprevmodule == pmodule || pmodule == pstart) {
break;
}
readAddr = (void *)(pmodule);
}
if (pdlls == NULL) {
if (*count_ptr == 0) {
hr = E_NOINTERFACE;
} else {
hr = S_OK;
}
} else {
if (pdlls->size() == 0) {
hr = E_NOINTERFACE;
} else {
if (count_ptr != NULL) {
*count_ptr = (DWORD)pdlls->size();
}
hr = S_OK;
}
}
Exit:
SAFE_CLOSEHANDLE(hProcess);
return hr;
}
这是一种“秘密”的方式来获取有关任何进程的加载DLL的信息。它可以在Windows 10上运行。请注意,ustring是我个人特殊的字符串实现,可以相应地进行替换。 值得注意的是peb_ldr_data.InMemoryOrderModuleList.Flink。它的链接列表与所有加载的DLL。它在MSDN文档中说,当到达最后一个条目时它将指向它自己。事实并非如此。它很好地恢复到列表中的第一个条目。至少在Win10 Pro中。 LDR_MODULE :: LoadCount是你正在寻找我相信。
MVH 马蒂亚斯
嗯上升技保持...它可能无法正常在Win10工作...生病回来。
3件事情是相关的。它在Win 10中可以工作,但LoadCount不显示参考计数。只有其动态(6)或静态(-1)
PEB_LDR_DATA:有不同的结构浮动。该系统中的一个:
typedef struct _PEB_LDR_DATA {
BYTE Reserved1[8];
PVOID Reserved2[3];
LIST_ENTRY InMemoryOrderModuleList;
} PEB_LDR_DATA, *PPEB_LDR_DATA;
而在一些用户的例子用户定义:
typedef struct _PEB_LDR_DATA2
{
ULONG Length;
UCHAR Initialized;
PVOID SsHandle;
LIST_ENTRY InLoadOrderModuleList;
LIST_ENTRY InMemoryOrderModuleList;
LIST_ENTRY InInitializationOrderModuleList;
PVOID EntryInProgress;
} PEB_LDR_DATA2, *PPEB_LDR_DATA2;
这开始变得一团糟。他们都似乎工作,但怀疑。内存在某种程度上被抵消了。尽管如此,您可以通过这种方式获得有关进程(任意Exe程序)加载的模块的信息,但LoadCount在Windows中不显示实际的引用计数> 7.
Btw我再次检查使用USER定义的PEB_LDR_DATA结构。该系统会产生不准确。 LDR_MODULE中的一些成员变成垃圾。为什么?我不知道。 (“Det fixarbåtklubben...”)。
要坏...
请在下面显示代码。 注:我在Visual Studio中写下面的代码2010
#include <iostream>
#include <ntstatus.h>
#include <Windows.h>
#include <winternl.h>
#include <string>
#include <tchar.h>
#include <excpt.h>
#include <fstream>
using namespace std;
struct _PROCESS_BASIC_INFORMATION_COPY
{
PVOID Reserved1;
PPEB PebBaseAddress;
PVOID Reserved2[2];
ULONG_PTR UniqueProcessId;
PVOID Reserved3;
} PROCESS_BASIC_INFORMATION_COPY;
struct _LDR_MODULE_COPY
{
LIST_ENTRY InLoadOrderModuleList;
LIST_ENTRY InMemoryOrderModuleList;
LIST_ENTRY InInitializationOrderModuleList;
PVOID BaseAddress;
PVOID EntryPoint;
ULONG SizeOfImage;
UNICODE_STRING FullDllName;
UNICODE_STRING BaseDllName;
ULONG Flags;
USHORT LoadCount;
USHORT TlsIndex;
LIST_ENTRY HashTableEntry;
ULONG TimeDateStamp;
} LDR_MODULE_COPY , *PLDR_MODULE_COPY;
struct _PEB_LDR_DATA_COPY
{
ULONG Length;
UCHAR Initialized;
PVOID SsHandle;
LIST_ENTRY InLoadOrderModuleList;
LIST_ENTRY InMemoryOrderModuleList;
LIST_ENTRY InInitializationOrderModuleList;
PVOID EntryInProgress;
} PEB_LDR_DATA_COPY , *PPEB_LDR_DATA_COPY;
typedef ULONG (WINAPI * ZwQueryInformationProcess)(HANDLE ProcessHandle,
ULONG ProcessInformationClass,
PVOID ProcessInformation,
ULONG ProcessInformationLength,
PULONG ReturnLength);
char *w2c(char *pcstr,const wchar_t *pwstr, size_t len)
{
int nlength=wcslen(pwstr);
//Gets converted length
int nbytes = WideCharToMultiByte(0, 0, pwstr, nlength, NULL,0,NULL, NULL);
if(nbytes>len) nbytes=len;
// Through the above obtained results, convert Unicode character for the ASCII character
WideCharToMultiByte(0,0, pwstr, nlength, pcstr, nbytes, NULL, NULL);
return pcstr ;
}
int filter(unsigned int code, struct _EXCEPTION_POINTERS *ep) {
puts("in filter.");
if (code == EXCEPTION_ACCESS_VIOLATION) {
puts("caught AV as expected.");
return EXCEPTION_EXECUTE_HANDLER;
}
else {
puts("didn't catch AV, unexpected.");
return EXCEPTION_CONTINUE_SEARCH;
};
}
int main()
{
_PROCESS_BASIC_INFORMATION_COPY stProcessBasicInformation = { 0 };
_PEB_LDR_DATA_COPY peb_ldr_data = { 0 };
_LDR_MODULE_COPY peb_ldr_module = { 0 };
PEB peb = { 0 };
USHORT loadCount = 0;
//ofstream outputfile;
//outputfile.open("dllNameAndTheirCount.txt", ios::app||ios::beg);
HMODULE hModule = LoadLibrary((const char*)"NTDLL.dll");
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, GetCurrentProcessId()); /* Get current prcess handle */
ZwQueryInformationProcess ZwQueryInformationProcessPtr = (ZwQueryInformationProcess)GetProcAddress(hModule, "ZwQueryInformationProcess");
if(ZwQueryInformationProcessPtr){
ZwQueryInformationProcessPtr(hProcess, 0, &stProcessBasicInformation, sizeof(stProcessBasicInformation), 0);
}
DWORD dwSize = 0;
bool bStatus;
/* Get list of loaded DLLs from PEB. */
bStatus = ReadProcessMemory(hProcess, stProcessBasicInformation.PebBaseAddress, &peb, sizeof(peb), &dwSize);
bStatus = ReadProcessMemory(hProcess, peb.Ldr, &peb_ldr_data, sizeof(peb_ldr_data), &dwSize);
void *readAddr = (void*) peb_ldr_data.InLoadOrderModuleList.Flink;
// Go through each modules one by one in their load order.
while(ReadProcessMemory(hProcess, readAddr, &peb_ldr_module, sizeof(peb_ldr_module), &dwSize))
{
__try{
// Get the reference count of the DLL
loadCount = (signed short)peb_ldr_module.LoadCount;
//outputfile << "DLL Name: " << peb_ldr_module.BaseDllName.Buffer << endl;
//outputfile << "DLL Load Count: " << peb_ldr_module.LoadCount << endl;
wcout << "DLL Name: " << peb_ldr_module.BaseDllName.Buffer << endl;
cout << "DLL Load Count: " << peb_ldr_module.LoadCount << endl;
cout << endl << endl;
}_except(filter(GetExceptionCode(), GetExceptionInformation())){
//outputfile << "DLL Name: " << "No Name Found" << endl;
//outputfile << "DLL Load Count: " << peb_ldr_module.LoadCount << endl;
readAddr = (void *) peb_ldr_module.InLoadOrderModuleList.Flink;
continue;
}
readAddr = (void *) peb_ldr_module.InLoadOrderModuleList.Flink;
}
FreeLibrary(hModule);
return 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);
有趣的问题,但为什么你要去做这个?我敢打赌,有一种更简单的方法可以实现你的目标。 – 2010-08-24 03:22:18
我想通过调用FreeLibrary来卸载dll,但它仍然被加载。我猜在某处引用它,所以我想检查参考计数调试。 – ldlchina 2010-08-24 03:32:04
为此,请使用Dependency Walker。它比一些插入的代码更强大。 – MSalters 2010-08-24 06:42:23