2010-08-24 141 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);