2013-03-17 3 views
4

누구든지 LDR_MODULE.LoadCount가 Windows 8에있는 위치를 알고 있습니까?Windows 8의 DLL LoadCount

다음 코드는 참조 수에 대해 항상 6을 인쇄합니다. S RemoteDLLTool을 사용하여 검사했으며 baseaddress 및 기타 모든 정보가 올바른지 확인합니다. 그러나 LoadCount는 항상 6이므로 잘못되었습니다. 6이면 DLL이 동적으로로드되고 -1이면 정적이라는 것을 알았습니다.

끊임없이 ReadProcessMemory를 사용하지 않고도 링크 된 목록을 반복 할 수있는 방법이 있습니까?

어떻게 든 참조 카운트를 알아 내야합니다. 기본적으로 Windows 7의 아래 코드는 DLL이로드 된 횟수 (일명 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 - 그러나 설명서에 따라 작동한다) 주입 .DLL 년대에 대한

#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 

사용법 :

// Someone reserved us, let's force us to shutdown. 
while(GetModuleLoadCount(dll) > 1) 
    FreeLibrary(dll); 

FreeLibraryAndExitThread(dll, 0); 

(2016년 3월 12일 갱신) 그러나이 기능을 주 스레드에서 사용하는 것이 좋습니다. 주요 문제는 dll을 반복 할 때입니다. dll도 해제 될 수 있습니다. 이후에는 "while 루프"가 무한히 끊어집니다.

그런 놀라운 dll 제거는 사이드 스레드가 dll을 해제하면 메인 스레드에서도 발생할 수 있지만, 드물게 발생합니다.

+1

내 견해로는이 질문에 대한 대답이 아니며 다른 대답이 아닙니다. – user2120666

+0

이제 더 좋아 보이십니까? – TarmoPikaro

+0

어때? :-) – TarmoPikaro