A library loaded via LOAD_LIBRARY_AS_DATAFILE (or similar flags) doesn’t get to play in any reindeer module games

If you load a library with the LOAD_LIBRARY_AS_DATA­FILE flag, then it isn't really loaded in any normal sense. In fact, it's kept completely off the books.

If you load a library with the LOAD_LIBRARY_AS_DATA­FILE, LOAD_LIBRARY_AS_DATA­FILE_EXCLUSIVE, or LOAD_LIBRARY_AS_IMAGE_RESOURCE flag (or any similar flag added in the future), then the library gets mapped into the process address space, but it is not a true module. Functions like Get­Module­Handle, Get­Module­File­Name, Enum­Process­Modules and Create­Toolhelp32­Snapshot will not see the library, because it was never entered into the database of loaded modules.

These "load library as..." flags don't actually load the library in any meaningful sense. They just take the file and map it into memory manually without updating any module tracking databases. This functionality was overloaded into the Load­Library­Ex function, which in retrospect was probably not a good idea, because people expect Load­Library­Ex to create true modules, but these flags create pseudo-modules, a term I made up just now.

It would have been less confusing in retrospect if the "load library as..." functionality were split into another function like Load­File­As­Pseudo­Module. Okay, that's a pretty awful name, but that's not the point. The point is to put the functionality in some function that doesn't have the word library in its name.

Okay, so now that we see that these pseudo-modules aren't true modules, and they don't participate in any reindeer module games. So what use are they?

Basically, the only thing you can do with a pseudo-module is access its resources with functions like Find­Resource, Load­Resource, and Enum­Resource­Types. Note that this indirectly includes functions like Load­String, and Format­Message which access resources behind the scenes.

So maybe a better name for the function would have been Load­File­For­Resources, since that's all the pseudo-module is good for.

Comments (23)
  1. Markus says:

    The hardest part with programming is not writing bug free fast and scalable code it is the naming of functions/classes…

  2. Danny says:

    So you do have it in memory, right? Well, how hard can be to do a bit of calculation and find the functions addresses the library exports? I used exactly this but with memory mapped file, and I mapped a .dll, then zbang!! call it from there. Well, was part of a self-modifying code in order to obfuscate the real code from the existing disk file, but still you can use it. Write a wrapper and you can have MyAwesomeLoadLibrary to fiddle with these files. After all, you wrote the library, you know what is inside.

  3. Azarien says:

    @Danny: you have to remember about relocations and what not, which basically means you are writing your own module loader. And what's the point?

  4. Evan says:

    @Markus: "it is the naming of functions/classes…"

    Probably everyone has heard this, but there's the old quote (in a modified version I like):

    There are only two difficult problems in computer science: cache coherence, naming things, and counting.

  5. skSdnW says:

    Is the loader not able to upgrade a LOAD_LIBRARY_AS_IMAGE_RESOURCE loaded module to a "normal" module? I guess this scenario is rare and would slow down regular loading slightly?

    [You can't upgrade it in place because RVAs are rarely compatible with direct mapping. -Raymond]
  6. dave says:

    I have problems with talking about "loading" anything on a virtual memory system.

  7. Gabe says:

    xor88: The reason you would use LOAD_LIBRARY_AS_DATAFILE alone is just to use the loader to find the file.

    The reason you would use LOAD_LIBRARY_AS_IMAGE_RESOURCE is to get the proper memory alignment.

    Both are things that you can't do just by mapping a file yourself.

  8. alegr1 says:

    [You can't pass a manually mapped file to Load­String, for example. -Raymond]

    I bet you could. The module handle is just a pointer to its header. LoadString just goes from the header to the resource section. You may have to map it with COPY_ON_WRITE, though.

    [But the resource section is not mapped where the header said it would be. -Raymond]
  9. Joshua says:

    [You can't pass a manually mapped file to Load­String, for example. -Raymond]

    The worst part of this one is it probably works in 32 bit Windows because HINSTANCE == (load address). However, IT WILL BREAK on 64 bit Windows.

  10. Tom says:

    Thanks for that wonderful "reindeer games" reference; nice to put a name to the disease

  11. Koro says:

    What's the exact difference between that and using CreateFileMapping with the SEC_IMAGE flag? If I recall, that's what the NT loader does underneath anyway.

  12. Killer{R} says:

    if requested dll is already loaded as normal executable module then LOAD_LIBRARY_AS_DATAFILE will return that already loaded HINSTANCE.

    This introduces a bit of mess for caller, since that mean that LoadLibraryEx(..LOAD_LIBRARY_AS_DATAFILE..) can return either plain data of file, either its image loaded just like PE image usually loaded for execution… And returned HINSTANCE tagged with less significant bit to let resources API know what they have as input…

  13. Rick C says:

    Why would you load the library a second time, as a data file, when you've already got it in memory?

  14. Darran Rowe says:

    @Rick C:

    You may not know that it is loaded (i.e. indirect dependency), it may be optionally loaded (dynamically through a call to LoadLibrary(Ex)) or you may just want to bump the reference count so it isn't unloaded until you free it.

  15. Killer{R} says:

    why not?:) See what happens in win2003's explorer.exe when I check version info of shell32.dll:

    0:017> bp kernel32!LoadLibraryExW

    0:017> g

    Breakpoint 0 hit

    eax=00000001 ebx=00000001 ecx=0277ee48 edx=7c82845c esi=77e6c2bc edi=00000001

    eip=77e41b14 esp=0277ee64 ebp=0277eeb0 iopl=0         nv up ei pl zr na pe nc

    cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246


    77e41b14 6a34            push    34h

    0:017> kv

    ChildEBP RetAddr  Args to Child              

    0277ee60 77b91879 0277ef90 00000000 00000002 kernel32!LoadLibraryExW (FPO: [Non-Fpo])

    0277eeb0 7c9ab2fe 0277ef90 0277eec8 01d2b5d0 VERSION!GetFileVersionInfoSizeW+0x31 (FPO: [Non-Fpo])

    0277f19c 7ca37ab7 0277f200 7c9a9a16 0277fc74 SHELL32!AddVersionPage+0x75 (FPO: [Non-Fpo])

    0277fb74 7c9f0ad9 0017a410 7c9a9a16 0277fc74 SHELL32!FileSystem_AddPages+0x157 (FPO: [Non-Fpo])

    0277fb88 7c9a9abc 02159638 7c9a9a16 0277fc74 SHELL32!CShellExecMenu::AddPages+0x14 (FPO: [Non-Fpo])

    0277fbb0 7c9a9ef4 01c90df8 0000082e 02159630 SHELL32!DCA_AppendClassSheetInfo+0x78 (FPO: [Non-Fpo])

    0277fccc 7c9ffec7 0215a488 0277fcfc 00000003 SHELL32!SHOpenPropSheetW+0x131 (FPO: [Non-Fpo])

    0277ff40 7c9bfe5e 020f1bd8 00000000 00000000 SHELL32!CFSFolder::_PropertiesThread+0xba (FPO: [Non-Fpo])

    0277ff54 7d183f12 020f1bd8 00000000 00000000 SHELL32!_PropSheetThreadProc+0x18 (FPO: [Non-Fpo])

    0277ffb8 77e6484f 00000000 00000000 00000000 SHLWAPI!WrapperThreadProc+0x94 (FPO: [Non-Fpo])

    0277ffec 00000000 7d183ea5 0254ec1c 00000000 kernel32!BaseThreadStart+0x34 (FPO: [Non-Fpo])

    0:017> du 0277ef90

    0277ef90  "C:WINDOWSsystem32shell32.dll"

    0:017> gu; r eax


    so… Version info dialog implemented in SHELL32.dll, since I requested version info of shell32's file – it called LoadLibraryEx to load it (itself actually) with LOAD_LIBRARY_AS_DATAFILE flag (3rd arg that equals 00000002). And – finally it gets its own base.

  16. Killer{R} says:

    Not exactly speaked.. its version.dll loaded shell32.dll in this stack, but not shell32.dll itself.. however this doesn't change anything in this context, btw also when I check properties of version.dll – then version.dll calls LoadLibraryExW for version.dll.

  17. xor88 says:

    Is there *any* difference to manually mapping the file?

    [You can't pass a manually mapped file to Load­String, for example. -Raymond]
  18. Neil says:

    @Evan: The quote I'm used to just calls it off-by-one errors.

  19. Boris says:

    In other words, a library thus loaded isn't like the ones I used to know?

  20. DebugErr says:

    Am I the only one understanding the hint the flag names give on first sight?

    Use them only for DLLs in which you stuff ressources. Not functionality.

    Or did I misunderstand something?

  21. foo says:

    I saw that movie. Who would want to play mind games with a bunch of psychopaths? Well… Charlize Theron…

  22. DWalker says:

    @Boris:  You win the Internets with that quote.

  23. One difference between opening it as a file vs. using LoadLibraryEx is that the latter does not add a handle to the process' handle table.  In Sysinternals Process Explorer, open DLL View and add the Mapping Type column.  It distinguishes between "Image" and "Data" modules, where the former has executable code, relocations, DLL dependencies, etc., and the latter is just data like icons, localized text, bitmaps, …

    (FWIW, I've never been confused about LOAD_LIBRARY_AS_DATA­FILE or been surprised about what I could or could not do with the resulting module handle…)

Comments are closed.

Skip to main content