Как проверить количество ссылок DLL?Как узнать где была загружена dll? - PullRequest
12 голосов
/ 24 августа 2010

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

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

Ответы [ 8 ]

5 голосов
/ 24 августа 2010

Если это не программный способ (спасибо 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);.if ($ spat (\ "$ {MyAlias} \", \ " MYDLL \")! = 0) {kn;} .else {g} ""

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

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

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

5 голосов
/ 24 августа 2010

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

2 голосов
/ 18 сентября 2015
   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;
        }

Это «скрытый» способ получения информации о загруженных библиотеках любого процесса. Он работает на Windows 10. Обратите внимание, что ustring - это моя личная специальная реализация строк, которую можно заменить соответствующим образом. Стоит обратить внимание на peb_ldr_data.InMemoryOrderModuleList.Flink . Это связанный список со всеми загруженными библиотеками. В документации MSDN говорится, что при достижении последней записи он будет указывать на себя. ЭТО НЕ ОТНОСИТСЯ К ДЕЛУ. Это хорошо вернуться к первой записи в списке. По крайней мере в Win10 Pro. Я считаю, что LDR_MODULE :: LoadCount - это то, что вы ищете.

MVH Маттиас

хммм Держись 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.

Кстати, я снова проверил использование определенной пользователем структуры PEB_LDR_DATA. Система один порождает неточность. Некоторые члены в LDR_MODULE становятся ненужными. Зачем? Я не знаю. ("Det fixar båtklubben ...").

К плохому ...

1 голос
/ 24 августа 2010

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

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

0 голосов
/ 25 ноября 2016

Проверено на 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);
0 голосов
/ 28 апреля 2016

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

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

0 голосов
/ 10 декабря 2010

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

0 голосов
/ 24 августа 2010

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...