本文介绍了Windows 8上的DLL LoadCount的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有人知道Windows 8上LDR_MODULE.LoadCount在哪里吗?

Does anyone know where LDR_MODULE.LoadCount is on windows 8?

以下代码始终打印6作为参考计数:S我用RemoteDLLTool和基地址检查了所有其他信息是否正确.但是,LoadCount始终是6,这是错误的.我读到,如果它是6,则意味着DLL是动态加载的;如果它是-1,则它是静态的.

The following code always prints 6 for the reference count :SI checked with a RemoteDLLTool and the baseaddress and all other information is correct. However, LoadCount is wrong as it is always 6. I read that if it is 6, it means the DLL is loaded dynamically and if it is -1, it is static.

还有没有一种方法可以让我迭代链接列表,而不必不断读取ReadProcessMemory?

Also is there a way I can just iterate the linked list without having to constantly ReadProcessMemory?

我需要以某种方式弄清楚引用计数..基本上,Windows 7上的以下代码将告诉我DLL被加载了多少次..也就是DLL的引用计数.

I need to figure out the reference count somehow.. Basically the code below on Windows 7 will tell me how many times a DLL is loaded.. aka the reference count to the 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上执行相同操作的任何想法?

Any ideas on how to do the same on Windows 8?

推荐答案

在Windows 8.1上进行了测试.无法保证此功能将在较新的Windows上运行(例如,不过10个-根据文档,应该可以正常工作)

Tested on Windows 8.1. Will not guarantee that this will work on newer windows (e.g. 10, however - according to documentation should be working)

#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的用途:

Usage for injected .dll's:

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

FreeLibraryAndExitThread(dll, 0);

(2016年12月31日更新)但是请注意-建议从主线程使用此功能.主要问题是当您迭代dll时-DLL也可以释放,此后无限循环挂起"while-loop".

(Update 3.12.2016) Please notice however - that it's recommended to use this function from main thread. The main problem is when you're iterating dll's - dll's can be freed as well, after which "while-loop" hungs infinitely.

如果侧线程正在释放dll,那么也可能从主线程中发生这种令人惊讶的dll删除,但是这种情况很少发生.

Such surprise dll removal can happen also from main thread as well, if side thread is freeing dll, but this happens more rarely.

这篇关于Windows 8上的DLL LoadCount的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

07-16 23:07
查看更多