AppInit_DLLs should be renamed Deadlock_Or_Crash_Randomly_DLLs


I have no idea why the window manager team added this feature to Windows NT. It basically says, "Hi, use this key to violate all the rules known to mankind about what can legitimately be done in a DllMain function. Oh, and be an attractive malware attack vector, too."

I've debugged a few crashes that were traced back to the AppInit_DLLs key. What makes them particularly fun is that the offending DLL is usually not on the stack. Rather, the fact that a foreign DLL is being loaded inside USER32's initialization code means that you're violating the rule against calling LoadLibrary inside a DllMain function. The result of this madness is that DLLs get initialized out of order, and typically manifests itself in some DLL crashing trying to use an object (often a critical section) that it is supposed to have initialized in its DLL_PROCESS_ATTACH handler. It crashed because the loader got tricked into initializing DLLs out of order. The dependent DLL received its DLL_PROCESS_ATTACH before the prerequisite DLL.

I end up looking at these failures because the victim DLL is often a DLL that my group is responsible for.

The window manager folks came to the same conclusion about AppInit_DLLs, and it doesn't work any more in Windows Vista by default. (Nick Kramer describes how to re-enable it.)

Comments (26)
  1. John says:

    Sounds like The Daily WTF material.  Seriously, is there even one legitimate use for this?

  2. Stefan Kuhr says:

    John: Using this registry value it is very easy to automatically inject your code into lots of processes on the user’s desktop (virtually all that load user32.dll). Otherwise you would need a separate process that injects DLLs into users’ processes. So at least there is a use case for this registry value.

  3. cmov says:

    Since the KB article says "The AppInit_DLLs value is found in the following registry key: HKEY_LOCAL_MACHINE…" and even explicitly states "Typically, only the Administrators group and the LocalSystem account have write access to the key that contains the AppInit_DLLs value.", the malware argument is moot. There are worse things a program can do when it’s run with such privileges.

  4. DriverDude says:

    "Typically, only the Administrators group and the LocalSystem account have write access to the key that contains the AppInit_DLLs value.", the malware argument is moot."

    That would be the case if users didn’t run with admin privs all the time (pre-Vista) and vendors did their part writing software to runs with minimal privs.

    Vista’s UAC is annoying but if it forces developers to think seperation of privs, then all the better.

    Actually, this ranks up there as a pretty sneaky attack, at least when it was discovered. Do spyware scanners check this now?

  5. mikeb says:

    > That would be the case if users didn’t run with admin privs all the time (pre-Vista) and vendors did their part writing software to runs with minimal privs.

    What cmov is saying is that in that case you don’t need AppInit_DLLs to perform an exploit – why not just install a service or a device driver?  It’s just another example of Raymond’s "It rather involved being on the other side of this airtight hatchway" set of ‘exploits’.

  6. Ben Hutchings says:

    It’s like the ELF dynamic linker’s LD_PRELOAD, only implemented in the wrong place. LD_PRELOAD may be used for good or evil, but it can be made reliable (in so far as injection of code into another process can be).

  7. Doug says:

    This just extends the insanity that can happen in DllInit functions.  I don’t know why it wasn’t just removed, rather than limited.  The above mentioned "use case" is not a strong enough reason to allow this.

  8. Mike Dimmick says:

    I recently discovered that some shovelware shipped with my Dell laptop uses AppInit_DLLs to hook itself into the file APIs. See my blog entry "Calling out EMBASSY Trust Suite" at http://mikedimmick.blogspot.com/2007/12/calling-out-embassy-trust-suite.html, with apologies for the bad language.

  9. GreaseMonkey says:

    The moral of the story: make sure that your team doesn’t add stupid crap without checking first.

    [That’s not particularly helpful advice since nobody considers what they’re doing to be “stupid crap”. -Raymond]
  10. poochner says:

    Nobody may consider what they’re doing "stupid crap," but adding features to Windows NT that don’t support long file names should have raised an eyebrow or two.

  11. John says:

    The moral of the story: make sure that your team doesn’t add stupid crap without checking first.

    [That’s not particularly helpful advice since nobody considers what they’re doing to be "stupid crap". -Raymond]

    Actually, it’s quite easy.  Just ask Raymond.  If he says it’s stupid crap, the odds are quite good that it’s stupid crap.  On the other hand, Raymond would probably lose his voice after 15 minutes of telling people how stupid their crap is.

  12. Triangle says:

    [That’s not particularly helpful advice since nobody considers what they’re doing to be "stupid crap". -Raymond]

    That’s what peer review was created for.

  13. meh says:

    Even peer reviews don’t include time machines. Trinagle, why are you reading this blog anyway? I’ve seen nothing but what others would call trolling from you.

  14. AJ says:

    "Sounds like The Daily WTF material.  Seriously, is there even one legitimate use for this?"

    The Wise Installer products (formerly of Wise Solutions, then Altiris, now Symantec) use this to monitor installation processes in-memory to capture machine changes without using the more traditional method of machine snapshots.  Whether this is legitimate or not is up for debate.  I have found that is causes more problems than anything else, so I would say no.

  15. Dan says:

    Program A and Program B are the two legitimate programs I know of that use Appinit DLLs. Program A probably hooks file operations or something, Program B likely uses it to inject a window-painting DLL.

  16. Dan says:

    Oh yeah… and I recall once when Program B‘s DLL, when injected into Program A, ate up 2gb memory (which was all I had at the time including swap space) and hung my computer.

    It was probably Program B‘s fault, but it didn’t happen with the next version of Program A.

  17. Tyler says:

    Injecting code into arbitrary processes that with WriteProcessMemory is hardly safe either, is it?

  18. Igor Levicki says:

    Tyler, AppInit mechanism automatically injects your DLL in every running process which imports from user32.dll.

    That means if your DLL goes down, whole system goes down with it.

    I really do not see any legitimate uses for this feature. It can be easily emulated by other means anyway so nobody will miss it, especially not the malware writers.

  19. Dean Harding says:

    "That’s what peer review was created for."

    Peer reviews do not catch every possible problem.

    I’m sure at the time, the feature WAS peer-reviewed, and the developer who wanted the feature included probably argued vehemently for his (or her) feature, perhaps eventually winning out over the "detractors".

    With properly constructed DLLs, AppInit_DLLs should work without problems. You just need to craft your DLL *knowing* that it will be included in the AppInit_DLLs registry key, and be very careful about what dependencies you drag in (e.g. kernel32 and nothing else).

  20. poef says:

    IIRC, Program B adds a DLL which depends on 2 more DLL’s of its own. It can totally break common controls, and nags you to return the favor by registering.

  21. Steve Loughran says:

    I have to defend the AppInit team here- it probably did help some fancy things like plug-in themed GUIs. Furthermore, they were working in a pre-internet era when malware was kind of hard to get on. So in a scale of design errors where activeX is at 10, Sun’s NFS is at 8 (unsecured LAN filesharing), appinit is probably a 5. It doesnt help malware onto the system, just provides a way for it to live.

    but if you want to lock down everything, what about all those CBT hooks?

  22. Omega Red says:

    You can even nicely BSOD the machine/prevent it from booting using this key:

    http://www.openrce.org/blog/view/966/Null_pointer_dereference_in_win32k

  23. Michiel says:

    I’ll have to second Mike Dimmick’s rant. [Remainder of comment deleted as off topic; feel free to respond to Mike’s rant on his blog.]

  24. Marc Sherman says:

    “… and typically manifests itself in some DLL crashing trying to use an object (often a critical section) that it is supposed to have initialized in its DLL_PROCESS_ATTACH handler. It crashed because the loader got tricked into initializing DLLs out of order. The dependent DLL received its DLL_PROCESS_ATTACH before the prerequisite DLL.”

    As long as your dll is not dependent on any other in the AppInit_DLLs list, it’s fine to create synchronization objects such as critical sections in your DllMain and then use them later in the *same* dll.

    [As noted in the article, the crash was in some other DLL, not in the AppInit DLL. -Raymond]
  25. Introduction Hi everyone, this is Bob again. I recently worked on an issue where the interaction of two

Comments are closed.