Как проверить счетчик ссылок DLL? Как узнать, где была загружена dll?

Как вы знаете, если вызов LoadLibrary указывает DLL-модуль, уже отображенный в адресное пространство вызывающего процесса, функция просто возвращает дескриптор DLL и увеличивает количество ссылок на модуль.

Где-то мне нужно получить ссылочный счет dll. Как получить счетчик ссылок DLL? Как узнать, где была загружена dll? Спасибо.

Ответ 1

Я искал его и нашел эту статью , которая утверждает, что дает ответ. Извините, я не могу быть более полезным:

Ответ 2

Если это не программный способ (благодаря C.Johnson для предоставления этой перспективы), WinDBG может быть полезным

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

Посмотрите на! dlls и его варианты.

! dll - все загруженные модули с нагрузкой кол

ИЗМЕНИТЬ 2:

Если вы хотите узнать, откуда все DLL загружается из процесса, есть два способа:

а. Посмотрите на команду

"bu kernel32! LoadLibraryExW"; as/mu ${/v: MyAlias} poi (@esp + 4);.если ( $spl (\ "$ {MyAlias} \", \ "MYDLL \" ) != 0) {kn; }.else {g} ""

в приведенном выше URL

б. Запустите процесс под WinDBG. Debug- > Even Filter и выберите "Load Module" и установите "Enabled" в "Execution". В разделе "Продолжить" установите значение "Не обрабатывается".

Один из них должен помочь вам определенно.

Ответ 3

   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 Маттиас

hmmm Удерживать abit... в 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 я снова проверил использование структуры PEB_LDR_DATA, определенной USER. Система генерирует неточность. Некоторые члены LDR_MODULE становятся ненужными. Зачем? Я не знаю. ( "Det fixar båtklubben..." ).

Плохо...

Ответ 4

Я не уверен, что вы полностью понимаете, как LoadLibrary/FreeLibrary должен работать. Вы вызываете FreeLibrary, когда вы закончите с ним, и это уменьшает счетчик ссылок, который был увеличен при его загрузке. Если какая-то другая часть вашего процесса все еще использует его, возможно, это не ваша проблема.

Счетчик ссылок может рассказать вам, сколько раз он был "загружен", но не поможет выяснить, кто его загрузил.

Ответ 5

Эта информация недоступна через публичный API afaik. Каков ваш сценарий? Запуск AppVerifier будет устранять любые ошибки, которые вы совершили с помощью модулей (или любых других).

Ответ 6

Вы можете перечислить загруженные модули в процессе с помощью Module32First()/Module32Next(), а затем использовать MODULEENTRY32.GlblcntUsage, чтобы проверить его количество ссылок. Я не уверен, насколько это надежно.

Ответ 7

Пожалуйста, введите код ниже. Примечание. Я написал код ниже в 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;
}

Для получения дополнительной информации перейдите по ссылке ниже

Ответ 8

Протестировано в 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 force us to shutdown.
while( GetModuleLoadCount( dll ) > 1 )
    FreeLibrary(dll);

FreeLibraryAndExitThread(dll, 0);