2013-03-17 7 views
4

Кто-нибудь знает, где LDR_MODULE.LoadCount находится на окнах 8?DLL LoadCount на Windows 8

Следующий код всегда печатает 6 для подсчета ссылок: S Я проверил с RemoteDLLTool и базовым аддоном, и вся остальная информация верна. Однако LoadCount ошибочен, так как он всегда 6. Я читал, что если оно равно 6, это означает, что DLL загружается динамически, а если оно равно -1, оно является статичным.

Также есть способ, которым я могу просто перебирать связанный список, не имея постоянного ReadProcessMemory?

Мне нужно выяснить счетчик ссылок как-то .. В принципе, код ниже в Windows 7 скажет мне, сколько раз загружается DLL. Aka ссылка на DLL.

#include <winternl.h> 

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; 
    SHORT     LoadCount; 
    SHORT     TlsIndex; 
    LIST_ENTRY    HashTableEntry; 
    ULONG     TimeDateStamp; 
} LDR_MODULE, *PLDR_MODULE; 

int GetModuleLoadCount() 
{ 
    DWORD dwBytesRead = 0; 
    PROCESS_BASIC_INFORMATION PBI = {0}; 
    HANDLE ProcessHandle = GetCurrentProcess(); 

    if (NT_SUCCESS(NtQueryInformationProcess(ProcessHandle, ProcessBasicInformation, &PBI, sizeof(PBI), &dwBytesRead))) 
    { 
     PEB_LDR_DATA LdrData; 
     LDR_MODULE LdrModule; 
     PPEB_LDR_DATA pLdrData = nullptr; 
     PLDR_MODULE pLdrModule = nullptr; 

     char* LdrDataOffset = reinterpret_cast<char*>(PBI.PebBaseAddress) + offsetof(PEB, Ldr); 
     ReadProcessMemory(ProcessHandle, LdrDataOffset, &pLdrData, sizeof(pLdrData), &dwBytesRead); 
     ReadProcessMemory(ProcessHandle, pLdrData, &LdrData, sizeof(LdrData), &dwBytesRead); 

     LIST_ENTRY* Head = LdrData.InMemoryOrderModuleList.Flink; 
     LIST_ENTRY* Next = Head; 

     do 
     { 
      LDR_DATA_TABLE_ENTRY LdrEntry; 
      LDR_DATA_TABLE_ENTRY* Base = CONTAINING_RECORD(Head, LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks); 

      if (ReadProcessMemory(ProcessHandle, Base, &LdrEntry, sizeof(LdrEntry), &dwBytesRead)) 
      { 
       char* pLdrModuleOffset = reinterpret_cast<char*>(Head) - sizeof(LIST_ENTRY); 
       ReadProcessMemory(ProcessHandle, pLdrModuleOffset, &pLdrModule, sizeof(pLdrModule), &dwBytesRead); 
       ReadProcessMemory(ProcessHandle, pLdrModule, &LdrModule, sizeof(LdrModule), &dwBytesRead); 

       if (LdrEntry.DllBase) 
       { 
        std::cout<<"BaseAddress:  "<< LdrModule.BaseAddress<<std::endl; 
        std::cout<<"Reference Count: "<< LdrModule.LoadCount<<std::endl; 
       } 

       Head = LdrEntry.InMemoryOrderLinks.Flink; 
      } 
     } 
     while (Head != Next); 
    } 
    CloseHandle(ProcessHandle); 
    return 0; 
} 

Любые идеи о том, как сделать то же самое в Windows 8?

+0

В чем проблема, с которой вы сталкиваетесь, когда считаете, что чтение значения загрузки DLL является решением? –

+0

О, я просто хотел проверить, сколько раз DLL загружалась в процесс. Я делал инъекцию, и я хотел иметь возможность вызвать LdrUnloadDll, чтобы выгрузить DLL с большим количеством. – Brandon

+2

Ум, освобождая DLL, которую вы не загружали, не лучший инженерный дизайн. –

ответ

2

Протестировано на 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); 

(Обновление 3.12.2016) Обратите внимание, однако, что рекомендуется использовать эту функцию из основного потока. Основная проблема заключается в том, что вы итерации dll-dll также могут быть освобождены, после чего «while-loop» бесконечно зависает.

Такое неожиданное удаление dll может произойти также из основного потока, если боковая нить освобождает dll, но это происходит реже.

+1

С моей точки зрения, это не ответит на вопрос и не ответит на что-то другое. – user2120666

+0

Теперь это выглядит лучше? – TarmoPikaro

+0

Как насчет upvote? :-) – TarmoPikaro

Смежные вопросы