Magic Tricks with DLL Forwarders


Thought I would share a DLL trick we used in the VS 2003 debugger that illustrates how a DLL with no real code or data can be very useful, especially if your exe is pretending to be something it is not.

VS 2003 has the ability to load windbg extension DLLs, though we only guarantee that one particular one will work (sos.dll). In order for a windbg DLL to load, it has a static reference to an export from dbgeng.dll which is the real 'guts' of windbg. So if you dumpbin -exports sos.dll you will see this:

    dbgeng.dll
              602711A4 Import Address Table
              602B5F54 Import Name Table
                     0 time date stamp
                     0 Index of first forwarder reference

                    1 DebugCreate

The VS debugger doesnt use or include dbgeng.dll, but we have to supply one in order to load extension DLLs. It's easy enough to create our own dbgeng.dll and give it an export of the right name. However all of the native debugger code really lives in natdbgde.dll, and it would be great if somehow we could get our DebugCreate function to live there instead of dbgeng.dll. And so we can using the magic of DLL Forwarders.

A DLL forwarder is an export that doesnt have any actual code at the end of it. Instead it has some magic goo that the Windows loader uses to automatically forward the call to the "real" DLL, natdbgde.dll in our case. If you run dumpbin -exports on our dbgeng.dll you will see

    ordinal hint RVA      name

          1    0          DebugCreate (forwarded to natdbgde.DebugCreate)

which shows that the DebugCreate function is forwarded to the same export in natdbgde.dll. (We could have used a different name in for the export from natdbgde but to keep things simple we did not). How did we do this magic? Firstly I coded up a fake DebugCreate function thus:

extern "C" __cdecl DebugCreate()
{
    return 0;
}

This was compiled as usual but the key is in the DEF file passed to the linker:

EXPORTS

   DebugCreate=natdbgde.DebugCreate

And that is it. You may find this technique useful any time you want to load a DLL that expects a dependent DLL to be there but is not, such as when loading other application's add-in DLLs.

Comments (1)

  1. smidgeonsoft says:

    Hi. If you check-out my article in MSDN, "Windows 2000 Loader: What Goes On Inside Windows 2000: Solving the Mysteries of Loader", msdn.microsoft.com/msdnmag/issues/02/03/Loader/default.aspx

    you will find an explanation for some of the "goo" as well as pseudo-code. Also, you can avoid the "fake DebugCreate" function with the following (also in the article’s sample code):

    #pragma comment(linker, "/EXPORT:DebugCreate=natdbgde.DebugCreate")

Skip to main content