2010-08-24 138 views
11

如您所知,如果LoadLibrary的调用指定了一个DLL模块已经映射到调用进程的地址空间中,该函数只是返回DLL的句柄并递增模块的引用计数。如何检查dll的引用计数?如何知道dll的加载位置?

某处,我需要得到一个DLL的引用计数。如何获得dll的引用计数?如何知道dll的加载位置?谢谢。

+1

有趣的问题,但为什么你要去做这个?我敢打赌,有一种更简单的方法可以实现你的目标。 – 2010-08-24 03:22:18

+1

我想通过调用FreeLibrary来卸载dll,但它仍然被加载。我猜在某处引用它,所以我想检查参考计数调试。 – ldlchina 2010-08-24 03:32:04

+0

为此,请使用Dependency Walker。它比一些插入的代码更强大。 – MSalters 2010-08-24 06:42:23

回答

0

该信息不适用于通过公共API afaik。你的场景是什么?运行AppVerifier将捕获您使用模块(或任何其他)手柄所犯的任何错误。

5

我把它搜索了一下,发现这个article声称提供了答案。 抱歉,我不能提供更多的帮助:

+1

+1对于你的观点,以编程方式获得计数 – Chubsdad 2010-08-24 03:22:01

+1

@C Johnson,你试过了吗?此解决方案取决于未记录的功能,这些功能无法在未来版本的Windows中使用。 – 2010-08-24 04:27:33

+2

实际上,它们甚至不能保证能在Windows的当前版本中工作:-) – paxdiablo 2010-08-24 04:58:07

3

如果它是一个非编程的方式(感谢C.Johnson给了这一观点),WinDBG的可帮助

http://windbg.info/doc/1-common-cmds.html#10_modules

看的dll!它是变种。 !

DLL - 负载 计数

编辑所有加载的模块2:

如果你想从所有正在从进程中加载​​的DLL哪里知道,有两种方法:

a。看命令

“BU KERNEL32 LoadLibraryExW!”;如/亩 $ {/ V:MyAlias} POI(@ ESP + 4); .if( $ spat(\“$ {MyAlias} \”,\“MYDLL \”) != 0){kn; }的.else {G}”,“

在上述URL

b

。在WinDBG下运行该进程。 Debug-> Even Filter并选择“Load Module”并将其设置为“Execution”下的“Enabled”。在“继续”下将其设置为“未处理”。

其中一个应该可以帮助你。

+0

@ jack2000:如果它是用于调试的目的,正如您在其他地方提到的那样,WinDBG和它的每一个不断增加的强大功能应该肯定会让你头痛不已。 – Chubsdad 2010-08-24 04:05:28

+0

@ jack2000:检查编辑2下的信息是否有帮助 – Chubsdad 2010-08-24 06:43:19

1

我不确定您完全了解LoadLibrary/FreeLibrary是如何工作的。当你完成它时,你可以调用FreeLibrary,并减少加载时增加的引用计数。如果您的流程的其他部分仍在使用它,那可能不是您的担心。

引用计数可能会告诉你它已被“加载”了多少次,但无助于弄清楚是谁加载了它。

+0

进程管理器可以告诉谁正在使用给定的DLL。 – Chubsdad 2010-08-24 03:54:24

+0

@chubsdad,它会告诉你哪个进程正在使用它,但它会告诉你它是从一个进程中加载​​的。我的理解是,这一切都发生在一个单独的过程中:'FreeLibrary'是一个进程内事物,引用计数不跨越进程边界,它们仅用于映射到本地地址空间。 – paxdiablo 2010-08-24 04:17:47

+0

当然,最好知道它在哪里加载。:) – ldlchina 2010-08-24 05:12:15

0

您可以在Module32First()/Module32Next()的进程中枚举加载的模块,然后使用MODULEENTRY32.GlblcntUsage来检查它的引用计数。我不确定这是多么可靠。

2
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...”)。

要坏...

0

请在下面显示代码。 注:我在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; 
} 

For more info go to below url

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);