1
votes

I am using dliNotePreLoadLibrary in my own delay loading hook to verify the code signature of a DLL to be loaded before actually loading it. In order to avoid it to execute any code whatsoever, I load it by means of LoadLibraryExA(...,...,LOAD_LIBRARY_AS_DATAFILE) (the hook only provides the ANSI name, so that's okay) and unload it after verification so that it can be loaded as a DLL with code.

Stepping through the code in the debugger I can see that I receive a handle and that handle is <baseaddress>+1 as expected for a "data module". However, once I attempt to pass this handle to GetModuleFileName inside a library function (that is also the reason why I can't pass the name, only the module handle), the function returns 0 and GetLastError gives me ERROR_MOD_NOT_FOUND. However, the module got loaded, so it was definitely found. Also, this is in the current process, so access to the "target process" is no issue here.

So I thought why not use VirtualQuery to retrieve the actual base address (MEMORY_BASIC_INFORMATION::BaseAddress) of the DLL I just loaded (in case the <baseaddress>+1 is an issue), but the result remains the same: ERROR_MOD_NOT_FOUND.

I'm out of ideas. Does anyone have any ideas what is going on here?

Platform of the tests: Windows 7 SP1, x64 (latest patches)

Here's the code of the:

FARPROC WINAPI MyDliHook(unsigned dliNotify, PDelayLoadInfo pdli)
{
    switch(dliNotify)
    {
    case dliNotePreLoadLibrary:
        if(0 == lstrcmpiA(pdli->szDll, "DLLNAME.dll"))
        {
            HMODULE hVerifiedDll = LoadLibraryExA(pdli->szDll, NULL, LOAD_LIBRARY_AS_DATAFILE);
            if(hVerifiedDll)
            {
                MEMORY_BASIC_INFORMATION mbi;
                if(0 != VirtualQuery(hVerifiedDll, &mbi, sizeof(mbi)));
                {
                    VerifyModuleSignature((HMODULE)mbi.BaseAddress, pdli->szDll);
                }
                FreeLibrary(hVerifiedDll);
            }
        }
        break;
    default:
        break;
    }
    return NULL;
}
PfnDliHook __pfnDliNotifyHook2 = MyDliHook;

The function VerifyModuleSignature calls first of all GetModuleFileName to retrieve the file name and it fails at that step. I verified that with the .exe that creates the process, the code signature verification works fine.

Side-note: I have verified that the ERROR_MOD_NOT_FOUND error comes from GetModuleFileName and not, for example, from the earlier call to LoadLibraryExA. In order to make sure I don't get a "polluted" last error code I called SetLastError(ERROR_SUCCESS) right before the call to GetModuleFileName.

1
GetModuleFileName() cannot work for DLLs loaded with the LOAD_LIBRARY_AS_DATAFILE option. That option just loads a blob of bytes, the loader doesn't otherwise keep track of it.Hans Passant

1 Answers

3
votes

As explained in MSDN, you cannot retrieve the Module using GetModuleHandle when LOAD_LIBRARY_AS_DATAFILE is used:

If this value is used, the system maps the file into the calling process's virtual address space as if it were a data file. Nothing is done to execute or prepare to execute the mapped file. Therefore, you cannot call functions like GetModuleFileName, GetModuleHandle or GetProcAddress with this DLL.

Edit: Actually Hans Passant was a bit closer to the reason than this answer. While this answer reiterates what MS states, it doesn't give a reason. The reason however, is that GetModuleFileName basically walks the LDR_MODULE list of the PEB, and that is only populated with the details when you "load code".