winapipngreverse-engineeringcodecuser32

What function does `CreateIconFromResourceEx()` use to decompress PNG resources?


Icons in .dll or .exe files are stored in the resources segment as Windows DIBs or PNGs since Windows Vista.

What function/library is used by the CreateIconFromResourceEx() WinAPI function in the user32.dll to read/decompress these PNG resources?

Does CreateIconFromResourceEx() use the WIC for this purpose ?


Solution

  • When a function like the CreateIconFromResourceEx() is called, user32.dll sometimes dynamically loads another DLL specified in the REG_SZ value HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Windows\IconServiceLib.

    This load can be triggered with a function like the one below:

    bool TriggerICSLoad()
    {
        if (PCHAR pc = (PCHAR)GlobalAlloc(GMEM_FIXED | GMEM_ZEROINIT, 40)) {
            strcpy_s(pc, 39, "‰PNG\r\n\x1a\n"); //89 50 4E 47 OD 0A 1A 0A
            CreateIconFromResourceEx((PBYTE)pc, 40, true, 0x00030000, 0, 0, LR_DEFAULTCOLOR);  //Trigger the loading of the ICS library
            GlobalFree(pc);
            return true;
        }
        return false;
    }
    

    This causes a private variable user32.dll!gpICSProc to be set to an address of a private function ConvertToDIBProc() residing inside the ...\IconServiceLib which is set by default to IconCodecService.dll.

    This is initiated by the IconCodecService.dll!DllMain() that calls the exported function user32.dll!PrivateRegisterICSProc() which looks like this:

    bool PrivateRegisterICSProc(PCONVERT_TO_DIB_PROC AddrOfFn)
    {
      if ( user32.dll!gpICSProc )
        return false;
    
      user32.dll!gpICSProc = AddrOfFn;
      return true;
    }
    

    From the above, you can see that checking whether the ...\IconServiceLib has already been loaded by user32.dll can be done at any time by calling the following function without any side effects:

    bool IsICSLoaded()
    {    
        if (HMODULE hModUSR = GetModuleHandle(L"user32.dll") )
        {
            if (PREGISTER_ICS_PROC pRegisterICSProc = (PREGISTER_ICS_PROC)GetProcAddress(hModUSR, "PrivateRegisterICSProc") )
                return !(pRegisterICSProc)(0);
        }
    
        return false;
    }
    

    The ConvertToDIBProc() residing in the IconCodecService.dll is not exported nor documented but I reverse engineered it and it looks like this:

    HGLOBAL ConvertToDIBProc(PBYTE pbBuffer, DWORD cbBufferSize, DWORD* pcbOutputSize, DWORD Flags)
    {
        if (CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_SPEED_OVER_MEMORY | COINIT_DISABLE_OLE1DDE) >=0)   // In the original this is actually called in USER32.DLL
            return 0;
    
        for (unsigned char* p = pbBuffer; (p < pbBuffer + cbBufferSize); *(volatile unsigned char*)p, p += 4096);  // Touch every page of the buffer
    
        IWICImagingFactory* pIWICImagingFactory = NULL;
        WICPixelFormatGUID PixelFormat = GUID_WICPixelFormat32bppBGRA;
        IWICStream* pStreamIn = NULL;
        IWICBitmapDecoder* instBitmapDecoder = NULL;
        IWICBitmapDecoderInfo* pBitmapDecoderInfo = NULL;
        IWICComponentInfo* ppDecoderIInfo = NULL;
        IWICComponentInfo* ppIInfoEncoder = NULL;
        IWICBitmapEncoderInfo* pBitmapEncoderInfo = NULL;
        IWICBitmapEncoder* instBitmapEncoder = NULL;
        IWICBitmapFrameEncode* pBitmapFrameEncoder = NULL;
        IWICBitmapFrameDecode* pBitmapFrameDecode = NULL;
        IWICPalette* pPalette = NULL;
        HGLOBAL phglobal = NULL;
        LPSTREAM pStreamOut = NULL;
        int ExtraMemory;
        WICRect rc;
        HRESULT hr;
    
        if ( !(Flags & 0x80000003) )
            goto CLEANUP;
    
        hr = CoCreateInstance(CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pIWICImagingFactory));
        if (hr < 0) goto CLEANUP;    
        hr = pIWICImagingFactory->CreateStream(&pStreamIn);
        if (hr < 0) goto CLEANUP;
        hr = pStreamIn->InitializeFromMemory(pbBuffer, cbBufferSize);   
        if (hr < 0) goto CLEANUP;
        hr = CreateStreamOnHGlobal(0, 0, &pStreamOut);
        if (hr < 0) goto CLEANUP;
    
        IID cls_WICDecoder;
        if (Flags & 1) 
            cls_WICDecoder = CLSID_WICPngDecoder;
        else
        {
            cls_WICDecoder = CLSID_WICJpegDecoder;
            if (!(Flags & 2))
                cls_WICDecoder = CLSID_NULL;
        }
        
        hr = pIWICImagingFactory->CreateComponentInfo(cls_WICDecoder, &ppDecoderIInfo);
        if (hr < 0) goto CLEANUP;   
        hr = ppDecoderIInfo->QueryInterface(IID_IWICBitmapDecoderInfo, (LPVOID*)(&pBitmapDecoderInfo));
        if (hr < 0) goto CLEANUP;    
        hr = pBitmapDecoderInfo->CreateInstance(&instBitmapDecoder);
        if (hr < 0) goto CLEANUP;
        hr = instBitmapDecoder->Initialize(pStreamIn, WICDecodeMetadataCacheOnDemand);   // IWICBitmapDecoder::Initialize
        if (hr < 0) goto CLEANUP;
    
        UINT FrameCount;
        hr = instBitmapDecoder->GetFrameCount(&FrameCount);             // IWICBitmapDecoder::GetFrameCount
        if ((hr < 0) || (!(FrameCount))) goto CLEANUP;
        hr = instBitmapDecoder->GetFrame(0, &pBitmapFrameDecode);       // IWICBitmapDecoder::GetFrame
        if (hr < 0) goto CLEANUP;
    
        UINT pixWidth;
        int pixHeight;
        hr = pBitmapFrameDecode->GetSize(&pixWidth, (UINT*)&pixHeight); // IWICBitmapFrameDecode::GetSize
        if (hr < 0) goto CLEANUP;
    
        double DPI_x;
        double DPI_y;
        hr = pBitmapFrameDecode->GetResolution(&DPI_x, &DPI_y);         // IWICBitmapFrameDecode::GetResolution
        if (hr < 0) goto CLEANUP;
    
        if (Flags & 2)
        {
            hr = pBitmapFrameDecode->GetPixelFormat(&PixelFormat);      // IWICBitmapFrameDecode::GetPixelFormat
            if (hr<0) goto CLEANUP;
    
            if (PixelFormat == GUID_WICPixelFormat8bppGray)
                PixelFormat = GUID_WICPixelFormat24bppBGR;
            else
                PixelFormat = GUID_WICPixelFormat32bppBGRA;
        }
    
        ExtraMemory = 0;
        if (Flags & 0x80000000)
        {
            UINT cbWidthColor;
            UINT cbWidthMono;
            UINT pixHeightAbs;
    
            if (PixelFormat == GUID_WICPixelFormat32bppBGRA)
                cbWidthColor = ((32 * pixWidth + 31) >> 3) & 0xFFFFFFFC;
            else if (PixelFormat == GUID_WICPixelFormat24bppBGR)
                cbWidthColor = ((24 * pixWidth + 31) >> 3) & 0xFFFFFFFC;
            else
                goto CLEANUP;
           
            cbWidthMono = ((pixWidth + 31) >> 3) & 0xFFFFFFFC;
            pixHeightAbs = pixHeight>=0 ? pixHeight : -pixHeight;
    
            if (pixHeightAbs && (cbWidthMono < 0xFFFFFFFF / pixHeightAbs) && (cbWidthColor < 0xFFFFFFFF / pixHeightAbs) )
                ExtraMemory = cbWidthMono * pixHeightAbs;
        }
    
        hr = pIWICImagingFactory->CreateComponentInfo(CLSID_WICBmpEncoder, &ppIInfoEncoder);            // IWICImagingFactory::CreateComponentInfo
        if (hr < 0) goto CLEANUP;
        hr = ppIInfoEncoder->QueryInterface(IID_IWICBitmapEncoderInfo, (LPVOID*)&pBitmapEncoderInfo);   // IWICComponentInfo::QueryInterface
        if (hr < 0) goto CLEANUP;   
        hr = pBitmapEncoderInfo->CreateInstance(&instBitmapEncoder);                // IWICBitmapEncoderInfo::CreateInstance
        if (hr < 0) goto CLEANUP;   
        hr = instBitmapEncoder->Initialize(pStreamOut, WICBitmapEncoderNoCache);    // IWICBitmapEncoder::Initialize
        if (hr < 0) goto CLEANUP;
        hr = instBitmapEncoder->CreateNewFrame(&pBitmapFrameEncoder, NULL);         // IWICBitmapEncoder::CreateNewFrame
        if (hr < 0) goto CLEANUP;
        hr = pBitmapFrameEncoder->Initialize(NULL);              // IWICBitmapFrameEncode::Initialize
        if (hr < 0) goto CLEANUP;
        hr = pBitmapFrameEncoder->SetSize(pixWidth, pixHeight);  // IWICBitmapFrameEncode::SetSize
        if (hr < 0) goto CLEANUP;
        hr = pBitmapFrameEncoder->SetPixelFormat(&PixelFormat);  // IWICBitmapFrameEncode::SetPixelFormat
        if (hr < 0) goto CLEANUP;
        hr = pBitmapFrameEncoder->SetResolution(DPI_x, DPI_y);   // IWICBitmapFrameEncode::SetResolution
        if (hr < 0) goto CLEANUP;
        hr = pIWICImagingFactory->CreatePalette(&pPalette);      // IWICImagingFactory::CreatePalette
        if (hr >= 0)
        {
            hr = pBitmapFrameDecode->CopyPalette(pPalette); // IWICBitmapFrameDecode::CopyPalette
    
            if (hr != WINCODEC_ERR_PALETTEUNAVAILABLE)
            {
                if (hr >= 0)
                {
                    hr = pBitmapFrameEncoder->SetPalette(pPalette);
                    if (hr < 0)
                        goto CLEANUP;
                }
                else
                    goto CLEANUP;
            }                     
        }
        
        rc = {0,0,(int)pixWidth,pixHeight};
    
        hr = pBitmapFrameEncoder->WriteSource(pBitmapFrameDecode, &rc); //IWICBitmapFrameEncode::WriteSource
        if (hr < 0) goto CLEANUP;
        hr = pBitmapFrameEncoder->Commit();  // IWICBitmapFrameEncode::Commit
        if (hr < 0) goto CLEANUP;
        hr = instBitmapEncoder->Commit();    // IWICBitmapEncoder::Commit
        if (hr < 0) goto CLEANUP;
        hr = GetHGlobalFromStream(pStreamOut, &phglobal);
        if (hr < 0) goto CLEANUP;                                                                                      
        
        if (phglobal)
        {
            size_t GlobSize = GlobalSize(phglobal);
            if (GlobSize > 54)
            {
                if (ExtraMemory)
                {
                    HGLOBAL hReAllocated = GlobalReAlloc(phglobal, ExtraMemory + GlobSize, 0);// HGLOBAL, Size, idDecoder
                    if (!hReAllocated)
                    {
                        GlobalFree(phglobal);
                        phglobal = 0;
                        goto CLEANUP;
                    }
                    phglobal = hReAllocated;
                }
                if (pcbOutputSize)
                    *pcbOutputSize = (DWORD)GlobSize;
            }
        }
    
    CLEANUP:
        if (pPalette)
            pPalette->Release();
        if (pBitmapFrameEncoder)
            pBitmapFrameEncoder->Release();
        if (pBitmapEncoderInfo)
            pBitmapEncoderInfo->Release();
        if (ppDecoderIInfo)
            ppDecoderIInfo->Release();
        if (ppIInfoEncoder)
            ppIInfoEncoder->Release();
        if (instBitmapEncoder)
            instBitmapEncoder->Release();
        if (pBitmapFrameDecode)
            pBitmapFrameDecode->Release();
        if (pBitmapDecoderInfo)
            pBitmapDecoderInfo->Release();
        if (instBitmapDecoder)
            instBitmapDecoder->Release();
        if (pIWICImagingFactory)
            pIWICImagingFactory->Release();
        if (pStreamIn)
            pStreamIn->Release();
        if (pStreamOut)
            pStreamOut->Release();
    
        CoUninitialize();   // In the original this is actually called in USER32.DLL
    
        return phglobal;
    }
    

    The function above takes a pointer to a memory buffer that contains a PNG or JPEG image and returns a memory handle (HGLOBAL) to a Windows Device Independent Bitmap (DIB) consisting of the BITMAPFILEHEADER, BITMAPINFOHEADER and pixel array. It does this by using the Windows Imaging component (WIC) extensively.

    This function also takes the Flags parameter which has the following meanings:

    0x00000000 : disallowed
    0x00000001 : Convert PNG to 32bppBGRA DIB
    0x00000002 : Convert 8bppGray JPEG to 24bppBGR DIB (convert all other JPEG formats to 32bppBGRA DIB).
    0x00000003 : Convert 8bppGray PNG to 24bppBGR DIB (convert all other PNG formats to 32bppBGRA DIB).
    0x80000000 : OR it (bitwise) with the remaining flags to allocate extra memory for a monochrome bitmap of the same dimensions (The extra memory count is not written to *pcbOutputSize but it is visible to GlobalSize(). This flag cannot be used alone).
    

    Because the address of the ConvertToDIBProc() is not exported, you can call it only by using extreme ways, as illustrated below:

    HGLOBAL ConvertToDIBProcEw(PBYTE pbBuffer, DWORD cbBufferSize, DWORD* pcbOutputSize, DWORD Flags)  
    {
        static PCONVERT_TO_DIB_PROC gpConvertToDIBProc = NULL;
    
        if (!(pbBuffer) || !(cbBufferSize) || !(pcbOutputSize) || !(Flags))
            return 0;
    
        if (gpConvertToDIBProc)
        {
            return (gpConvertToDIBProc)(pbBuffer, cbBufferSize, pcbOutputSize, Flags);
        }
        else
        {
            PDLL_NOTIFICATION_CONTEXT pContext = (PDLL_NOTIFICATION_CONTEXT)_alloca(sizeof(DLL_NOTIFICATION_CONTEXT));  //This must be allocated on the stack or it will fail the subsequent IsAddrOnStack() check.
            *pContext = { NULL, L"PrivateRegisterICSProc", L"user32.dll", &LocalRegisterICSProc }; 
            if (GetICSLibraryName(&pContext->pLibFileName))
            {
                if (IsICSLoaded())
                {                
                    if (HMODULE hModICS = GetModuleHandle(pContext->pLibFileName))
                    {
                        pContext->hMod = hModICS;
                        if (HMODULE hModUSR = GetModuleHandle(pContext->pImportedModuleName))
                        {
    
                            PCHAR pc = wctombs(pContext->pImportedFunctionName);
                            if (__int64* op = (__int64*)GetProcAddress(hModUSR, pc))
                            {
                                INT32 ofs;
                                if ((*op & 0x0000000000FFFFFF) == 0x00000000003d8348)  //check for the CMP [RIP+ofs],0 opcode
                                {
                                    ofs = (INT32)((*op & 0x00FFFFFFFF000000) >> 24) + 8;  //extract RIP relative offset of gpICSProc from the CMP qword ptr [RIP + ofs],0 opcode.
                                    PDWORD pFn = *(PDWORD*)((PBYTE)op + ofs);
                                    if (IsAddrInExecutableSection(hModICS, pFn))
                                    {
                                        if (((*pFn & 0xC7FFFB) == 0x00C48B48) || ((*pFn & 0xF8FFFE) == 0x00E08948)) // check for: MOV reg64,RSP (it has 2 synonymous encodings, sheesh!)
                                            gpConvertToDIBProc = (PCONVERT_TO_DIB_PROC)pFn;
                                    }
                                }
                            }
    
                            free(pc);
                        }
    
                        if (!gpConvertToDIBProc)   //Try an alternative method to obtain the address of ConvertToDIBProc() if the method above failed.
                        {
                            PMY_LDR_DATA_TABLE_ENTRY pLdrDataTableEntry = NULL;
                            if ((LdrFindEntryForAddress(hModICS, &pLdrDataTableEntry) == STATUS_SUCCESS) && (pLdrDataTableEntry) && (hModICS == pLdrDataTableEntry->DllBase))
                            {
                                pLdrDataTableEntry->Padding1 = MY_LODWORD(pContext);
                                pLdrDataTableEntry->Padding2 = MY_HIDWORD(pContext);
    
                                if (IsAddrInExecutableSection(hModICS, pLdrDataTableEntry->EntryPoint))
                                    pContext->pOrgDllEntryPoint = pLdrDataTableEntry->EntryPoint;
                                else
                                {
                                    PIMAGE_NT_HEADERS NtHeader = ImageNtHeader((PVOID)hModICS);
                                    if (NtHeader)
                                    {
                                        PLDR_INIT_ROUTINE AddressOfEntryPoint = (PLDR_INIT_ROUTINE)((PBYTE)hModICS + NtHeader->OptionalHeader.AddressOfEntryPoint);
                                        if (IsAddrInExecutableSection(hModICS, AddressOfEntryPoint))
                                        {
                                            pContext->pOrgDllEntryPoint = AddressOfEntryPoint;
    
                                            if ( (pContext->pOrgImpProcAddress = (PREGISTER_ICS_PROC)SetImpProcAddress((PBYTE)hModICS, pContext->pImportedFunctionName, pContext->pImportedModuleName, &LocalRegisterICSProc)))
                                            {
                                                (pContext->pOrgDllEntryPoint)(hModICS, DLL_PROCESS_DETACH, NULL);  //So the CRT is not initialized twice
                                                (pContext->pOrgDllEntryPoint)(hModICS, DLL_PROCESS_ATTACH, NULL);  //This causes LocalRegisterICSProc() to be called
    
                                                if (pContext->pOrgImpProcAddress) //Just in case the LocalRegisterICSProc() has not restored the imports
                                                {
                                                    SetImpProcAddress((PBYTE)hModICS, pContext->pImportedFunctionName, pContext->pImportedModuleName, pContext->pOrgImpProcAddress);  //Restore IAT
                                                    ((PREGISTER_ICS_PROC)pContext->pOrgImpProcAddress)((PCONVERT_TO_DIB_PROC)pContext->Result); //Call the original imported function (the PrivateRegisterICSProc() )
                                                }
    
                                                gpConvertToDIBProc = (PCONVERT_TO_DIB_PROC)pContext->Result;
                                            }
                                        }
                                    }
                                }
                            }
    
                            
                        }
                    }
                }
                else  //if (!IsICSLoaded())
                {
                    if (LdrRegisterDllNotification(0, &DllNotificationCallback, pContext, &pContext->cookie) == STATUS_SUCCESS)
                    {
                        TriggerICSLoad();
    
                        if (pContext->cookie) //In case LocalDllInitRoutine() did not clean it up
                            LdrUnregisterDllNotification(pContext->cookie);
    
                        if (pContext->pOrgImpProcAddress) //In case LocalRegisterICSProc() has not restored the imports
                        {
                            if (HMODULE hModICS = GetModuleHandle(pContext->pLibFileName))
                                SetImpProcAddress((PBYTE)hModICS, pContext->pImportedFunctionName, pContext->pImportedModuleName, pContext->pOrgImpProcAddress);
                        }
    
                        if (IsICSLoaded())
                            gpConvertToDIBProc = (PCONVERT_TO_DIB_PROC)pContext->Result;
                    }
                }
    
                free((PVOID)pContext->pLibFileName);
            }
        }
    
        if (gpConvertToDIBProc)
            return (gpConvertToDIBProc)(pbBuffer, cbBufferSize, pcbOutputSize, Flags);
        else
            return 0;
    }
    
    bool __declspec(noinline) LocalRegisterICSProc(PCONVERT_TO_DIB_PROC pConvertToDIBProc)    //If this function is inlined then IsAddrOnStack() may fail
    {
        PMY_LDR_DATA_TABLE_ENTRY pLdrDataTableEntry=NULL;
        if ((LdrFindEntryForAddress(_ReturnAddress(), &pLdrDataTableEntry) == STATUS_SUCCESS) && (pLdrDataTableEntry))
        {        
            PDLL_NOTIFICATION_CONTEXT pContext = (PDLL_NOTIFICATION_CONTEXT)((ULONGLONG)pLdrDataTableEntry->Padding1 | (((ULONGLONG)pLdrDataTableEntry->Padding2) << 32));
            HMODULE hModICS = (HMODULE)pLdrDataTableEntry->DllBase;
            if (IsAddrOnStack(pContext) && (pContext->hMod == hModICS))  //Sanity check
            {
                pContext->Result = pConvertToDIBProc;
    
                if (PREGISTER_ICS_PROC pOrgImpProcAddress = (PREGISTER_ICS_PROC)pContext->pOrgImpProcAddress)
                {
                    pContext->pOrgImpProcAddress = NULL;
    
                    if (IsAddrInExecutableSection(GetModuleHandle(pContext->pImportedModuleName), pOrgImpProcAddress))
                    {
                        SetImpProcAddress((PBYTE)hModICS, pContext->pImportedFunctionName, pContext->pImportedModuleName, pOrgImpProcAddress);  //Restore import
                        return (pOrgImpProcAddress)(pConvertToDIBProc);
                    }
                
                }
            }
        }
    
        return false; // 
    }
    
    bool __declspec(noinline) LocalDllInitRoutine(_In_ PVOID DllHandle, _In_ ULONG Reason, _In_opt_ PVOID Context) //If this function is inlined then IsAddrOnStack() may fail
    {
        BOOLEAN res = false;
    
        PMY_LDR_DATA_TABLE_ENTRY pLdrDataTableEntry=NULL;
        if ((LdrFindEntryForAddress(DllHandle, &pLdrDataTableEntry) == STATUS_SUCCESS) && (pLdrDataTableEntry) && (pLdrDataTableEntry->DllBase == DllHandle))
        {
            PDLL_NOTIFICATION_CONTEXT pContext = (PDLL_NOTIFICATION_CONTEXT)((ULONGLONG)pLdrDataTableEntry->Padding1 | (((ULONGLONG)pLdrDataTableEntry->Padding2) << 32));        
            if (IsAddrOnStack(pContext) && (pContext->hMod == DllHandle))   //Sanity check
            {
                PLDR_INIT_ROUTINE pOrgDllEntryPoint = pContext->pOrgDllEntryPoint;
                if ((pOrgDllEntryPoint) && IsAddrInExecutableSection((HMODULE)DllHandle, pOrgDllEntryPoint))  //Sanity check
                {
                    if (Reason == DLL_PROCESS_ATTACH)
                    {
                        if (pContext->cookie)
                        {
                            LdrUnregisterDllNotification(pContext->cookie);
                            pContext->cookie = NULL;
                        }
    
                        pContext->pOrgImpProcAddress = SetImpProcAddress((PBYTE)DllHandle, pContext->pImportedFunctionName, pContext->pImportedModuleName, pContext->pNewImpProcAddress);
                    }
    
                    res = (*pOrgDllEntryPoint)(DllHandle, Reason, Context); //Call the original DLL Entry Point
                }                     
            }
        }
    
        return res;
    }
    
    
    VOID CALLBACK DllNotificationCallback(_In_ ULONG NotificationReason, _In_ PLDR_DLL_NOTIFICATION_DATA pNotificationData, _In_opt_ PDLL_NOTIFICATION_CONTEXT pContext)
    {
        if ( (pContext) && (NotificationReason == LDR_DLL_NOTIFICATION_REASON_LOADED) )
        {
            printf("LOAD NOTIFY: %ws\n", pNotificationData->Loaded.FullDllName->Buffer);
    
            if (!_wcsnicmp(pContext->pLibFileName, pNotificationData->Loaded.BaseDllName->Buffer, pNotificationData->Loaded.BaseDllName->Length) || !_wcsnicmp(pContext->pLibFileName, pNotificationData->Loaded.FullDllName->Buffer, pNotificationData->Loaded.FullDllName->Length ))
            {
                pContext->hMod = (HMODULE)pNotificationData->Loaded.DllBase;
    
                if (bitness(pContext->hMod) != 64)
                {
                    printf("ERROR: Handling non-64bit DLLs is not implemented\n");
                    pContext->Result = NULL;
                    return;
                }
    
                PMY_LDR_DATA_TABLE_ENTRY pLdrDataTableEntry = NULL;
                if ((LdrFindEntryForAddress(pContext->hMod, &pLdrDataTableEntry) == STATUS_SUCCESS) && (pLdrDataTableEntry) && (pContext->hMod == pLdrDataTableEntry->DllBase))
                {                
                    pLdrDataTableEntry->Padding1 = MY_LODWORD(pContext);
                    pLdrDataTableEntry->Padding2 = MY_HIDWORD(pContext);
                    pContext->pOrgDllEntryPoint = pLdrDataTableEntry->EntryPoint;
                    pLdrDataTableEntry->EntryPoint = &LocalDllInitRoutine;  // Needed because this dll notification is invoked BEFORE the imports are resolved in Windows 7.
                }
                else
                    pContext->Result = NULL;
            }
        }
    }
    
    typedef struct _DLL_NOTIFICATION_CONTEXT
    {
        LPCWSTR pLibFileName;
        LPCWSTR pImportedFunctionName;
        LPCWSTR pImportedModuleName;
        PVOID pNewImpProcAddress;
        HMODULE hMod;
        PVOID pOrgImpProcAddress;    
        PLDR_INIT_ROUTINE pOrgDllEntryPoint;
        PVOID cookie;
        PVOID Result;
    } DLL_NOTIFICATION_CONTEXT, * PDLL_NOTIFICATION_CONTEXT;
    

    The function listed above works only in 64-bit Windows. If you are interested in the various helper functions called by it, write me so in the comments.