OiO.lk Blog C++ Since when have the notifications registered by LdrRegisterDllNotification() started to work differently?
C++

Since when have the notifications registered by LdrRegisterDllNotification() started to work differently?


The Microsoft’s documentation about the function LdrRegisterDllNotification() states that DLL load notifications registered by this function:

Registers for notification when a DLL is first loaded.
This notification occurs before dynamic linking takes place.

I wrote the following test program to test this assertion and while these notifications act according to the documentation in Windows 7 x64, in Windows 10 x64 they act differently – namely, they occur after the DLL imports have been resolved and function entry points have been written to the Import Address Table ( IAT ) pointed to by the IMAGE_NT_HEADERS.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress->FirstThunk

VOID CALLBACK NotificationFunction(_In_ ULONG NotificationReason, _In_ PLDR_DLL_NOTIFICATION_DATA pNotificationData, _In_opt_ PVOID Context)
{
    if (NotificationReason == LDR_DLL_NOTIFICATION_REASON_LOADED)
    {
        printf(" ----------------------------------------------------------------------------------------------- \n");
        printf("LOADED: %wZ @ %p\n\n", pNotificationData->Loaded.FullDllName, pNotificationData->Loaded.DllBase);
        if (!_wcsicmp((wchar_t*)Context, pNotificationData->Loaded.FullDllName->Buffer) || !_wcsicmp((wchar_t*)Context, pNotificationData->Loaded.BaseDllName->Buffer))
            PrintImports((PBYTE)pNotificationData->Loaded.DllBase);
    }
}


int wmain(int argc, wchar_t* argv[])
{
    HMODULE hMod1 = LoadLibraryEx(argv[1], NULL, DONT_RESOLVE_DLL_REFERENCES); 
    if (hMod1)
    {

        printf(" ----------------------------------------------------------------------------------------------- \n");
        printf("LOADED UNRESOLVED %ls @ %p\n\n", argv[1], hMod1);
        if (PrintImports((PBYTE)hMod1)) 
            printf("\nWARNING: Some functions have pre-bound entry points / addresses\n");

        FreeLibrary(hMod1);

        PVOID cookie;
        NTSTATUS nts = LdrRegisterDllNotification(0, &NotificationFunction, argv[1], &cookie);            

        HMODULE hMod2 = LoadLibrary(argv[1]);
        if (hMod2) {
           printf(" ----------------------------------------------------------------------------------------------- \n");
           printf("LOADED RESOLVED %ls @ %p\n\n", argv[1], hMod2);
        }
       
        nts = LdrUnregisterDllNotification(&cookie);

        if (hMod2) {
            PrintImports((PBYTE)hMod2);
            FreeLibrary(hMod2);
        }    
    } else {
        printf("\nERROR: Loading library %ls\n", argv[1]);
        return -1;
    }

    return 0;
}

The full Visual Studio project with the entire source code is available under the following address: tinyurl.com/4RbMm123

In Windows 7 x64, this test program generates the following output:

 ----------------------------------------------------------------------------------------------- 
LOADED UNRESOLVED x.dll @ 000007FEF6030000

API-MS-Win-Core-LibraryLoader-L1-1-0.dll @ 000007FEFD680000
    DisableThreadLibraryCalls                  0000000000001230

API-MS-Win-Core-ProcessThreads-L1-1-0.dll @ 00000000772E0000
    GetCurrentProcessId                        000000000000128C
    GetCurrentThreadId                         0000000000001276

API-MS-Win-Core-Profile-L1-1-0.dll @ 000007FEFD680000
    QueryPerformanceCounter                    00000000000012CC

API-MS-Win-Core-SysInfo-L1-1-0.dll @ 000007FEFD680000
    GetSystemTimeAsFileTime                    000000000000131A
    GetTickCount                               000000000000130A

 ----------------------------------------------------------------------------------------------- 
LOADED: x.dll @ 000007FEF5FF0000

API-MS-Win-Core-LibraryLoader-L1-1-0.dll @ 000007FEFD680000
    DisableThreadLibraryCalls                  0000000000001230

API-MS-Win-Core-ProcessThreads-L1-1-0.dll @ 00000000772E0000
    GetCurrentProcessId                        000000000000128C
    GetCurrentThreadId                         0000000000001276

API-MS-Win-Core-Profile-L1-1-0.dll @ 000007FEFD680000
    QueryPerformanceCounter                    00000000000012CC

API-MS-Win-Core-SysInfo-L1-1-0.dll @ 000007FEFD680000
    GetSystemTimeAsFileTime                    000000000000131A
    GetTickCount                               000000000000130A

 ----------------------------------------------------------------------------------------------- 
LOADED RESOLVED x.dll @ 000007FEF6030000

API-MS-Win-Core-LibraryLoader-L1-1-0.dll @ 000007FEFD680000
    DisableThreadLibraryCalls                  0000000000001230 : 000007FEFD68B0B0

API-MS-Win-Core-ProcessThreads-L1-1-0.dll @ 00000000772E0000
    GetCurrentProcessId                        000000000000128C : 00000000772F32C0
    GetCurrentThreadId                         0000000000001276 : 00000000772F1CA0

API-MS-Win-Core-Profile-L1-1-0.dll @ 000007FEFD680000
    QueryPerformanceCounter                    00000000000012CC : 0000000077553BE0

API-MS-Win-Core-SysInfo-L1-1-0.dll @ 000007FEFD680000
    GetSystemTimeAsFileTime                    000000000000131A : 000007FEFD681760
    GetTickCount                               000000000000130A : 000007FEFD681120

However in Windows 10 x64, the same test program with the same x.dll generates the following output:

 ----------------------------------------------------------------------------------------------- 
LOADED UNRESOLVED x.dll @ 00007FF9005C0000

API-MS-Win-Core-LibraryLoader-L1-1-0.dll @ 00007FF905250000
    DisableThreadLibraryCalls                  0000000000001230

API-MS-Win-Core-ProcessThreads-L1-1-0.dll @ 00007FF906BC0000
    GetCurrentProcessId                        000000000000128C
    GetCurrentThreadId                         0000000000001276

API-MS-Win-Core-Profile-L1-1-0.dll @ 00007FF905250000
    QueryPerformanceCounter                    00000000000012CC

API-MS-Win-Core-SysInfo-L1-1-0.dll @ 00007FF905250000
    GetSystemTimeAsFileTime                    000000000000131A
    GetTickCount                               000000000000130A

 ----------------------------------------------------------------------------------------------- 
LOADED: x.dll @ 00007FF9005C0000

API-MS-Win-Core-LibraryLoader-L1-1-0.dll @ 00007FF905250000
    DisableThreadLibraryCalls                  0000000000001230 : 00007FF9052C6C70

API-MS-Win-Core-ProcessThreads-L1-1-0.dll @ 00007FF906BC0000
    GetCurrentProcessId                        000000000000128C : 00007FF906BE4BA0
    GetCurrentThreadId                         0000000000001276 : 00007FF906BD5860

API-MS-Win-Core-Profile-L1-1-0.dll @ 00007FF905250000
    QueryPerformanceCounter                    00000000000012CC : 00007FF907B70160

API-MS-Win-Core-SysInfo-L1-1-0.dll @ 00007FF905250000
    GetSystemTimeAsFileTime                    000000000000131A : 00007FF9052A4240
    GetTickCount                               000000000000130A : 00007FF9052A0F80

 ----------------------------------------------------------------------------------------------- 
LOADED RESOLVED x.dll @ 00007FF9005C0000

API-MS-Win-Core-LibraryLoader-L1-1-0.dll @ 00007FF905250000
    DisableThreadLibraryCalls                  0000000000001230 : 00007FF9052C6C70

API-MS-Win-Core-ProcessThreads-L1-1-0.dll @ 00007FF906BC0000
    GetCurrentProcessId                        000000000000128C : 00007FF906BE4BA0
    GetCurrentThreadId                         0000000000001276 : 00007FF906BD5860

API-MS-Win-Core-Profile-L1-1-0.dll @ 00007FF905250000
    QueryPerformanceCounter                    00000000000012CC : 00007FF907B70160

API-MS-Win-Core-SysInfo-L1-1-0.dll @ 00007FF905250000
    GetSystemTimeAsFileTime                    000000000000131A : 00007FF9052A4240
    GetTickCount                               000000000000130A : 00007FF9052A0F80

As you can see, the entry points to the imported functions are resolved in the "LOADED:" and "LOADED RESOLVED" sections in Windows 10 x64, however in Windows 7 x64 the imported functions are resolved only in the "LOADED RESOLVED" section, which agrees with the most current documentation.

Q: When exactly has this change happened ? i.e. in what version, service pack, update…



You need to sign in to view this answers

Exit mobile version