如您所知,如果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