拡張カーネルの DLL参照数 / LoadCount のバグ

Microsoft Safety Scanner がクラッシュするという報告があったので調べてみたところ…。

ADVAPI32.DLL のVista以降の関数をロードして失敗したときに処理される FreeLibrary で、
ADVAPI32.DLL が解放されることが判明。n

あれ、そもそも、 静的ロードされたDLLってアンロードできないんじゃ?
というわけで、スペシャルねこまんまで確認してみたところ…。

spm
あれ…ADVAPI32.DLL の参照カウントが途中から 2になってる!?

もしかして、GetModuleHandleEx のバグ?!


c++ – DLL LoadCount on Windows 8 – Stack Overflow

int GetModuleLoadCount()
{
    DWORD dwBytesRead = 0;
    PROCESS_BASIC_INFORMATION PBI;
    HANDLE ProcessHandle = GetCurrentProcess();
    if (MyZwQueryInformationProcess(ProcessHandle, 0, &PBI, sizeof(PROCESS_BASIC_INFORMATION), &dwBytesRead) >=  0) {
        PEB_LDR_DATA LdrData;
        LDR_MODULE LdrModule;
        PPEB_LDR_DATA pLdrData = NULL;
        PLDR_MODULE pLdrModule = NULL;

        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 && LdrModule.BaseAddress)
                {
                    if(LdrModule.FullDllName.Buffer)
                        printf(“Name: %ws(%ws)\n”,LdrModule.BaseDllName.Buffer,LdrModule.FullDllName.Buffer);
                    printf(“BaseAddress: %x  EnrtyPoint: %x\n”,LdrModule.BaseAddress,LdrModule.EntryPoint);
                    printf(“ImageSize: %x  Reference Count: %x\n”,LdrModule.SizeOfImage,LdrModule.LoadCount);
                    printf(“\n”);
                }

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

これは良いプログラム・ω・

GetModuleHandleEx
でGET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT フラグを指定した場合は問題ないものの…。
指定しなかった場合、 参照カウンタが FFFF からインクリメントされて0になってしまうことが判明ww

あー、これはだめだw

>loadcount2.exe

Name: ntdll.dll(D:\WINNT\system32\ntdll.dll)
BaseAddress: 77f80000  EnrtyPoint: 0
ImageSize: 7f000  Reference Count: ffff

Name: KERNEL32.dll(D:\WINNT\system32\KERNEL32.dll)
BaseAddress: 77e50000  EnrtyPoint: 77eaaa11
ImageSize: a8000  Reference Count: ffff

Name: ADVAPI32.dll(D:\WINNT\system32\ADVAPI32.dll)
BaseAddress: 79480000  EnrtyPoint: 794e61c9
ImageSize: 6d000  Reference Count: 2

Name: RPCRT4.dll(D:\WINNT\system32\RPCRT4.dll)
BaseAddress: 78780000  EnrtyPoint: 78787840
ImageSize: 71000  Reference Count: ffff

という訳で続きます・ω・;

おすすめ

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です