My Remote Desktop Session Hosts (RDSHs) show the following warning in the System event log at boot time:
Event ID: 11
Description: Custom dynamic link libraries are being loaded for every application. The system administrator should review the list of libraries to ensure they are related to trusted applications.
Task Category: None
First of all, the event source Wininit (although not configured through the “eventlog” registry key (HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\eventlog\System)) refers to a Windows component (Windows Startup Application) implemented by wininit.exe (in %windir%\system32). Without analyzing the whole boot flow, I would like to explain very shortly a piece of the boot process (only since Vista/WS08), so you know what we are talking about. First the system loads very low-level stuff. After a while the first user-mode process is created: the Session Manager (smss.exe). This Session Manager creates another Session Manager instance to configure session 0. This 2nd Session Manager starts up the Windows Startup Application (wininit.exe) and Client/Server Runtime Subsystem (csrss.exe). As you perhaps knows, session 0 is only meant for system processes, so a user can never connect to this session. The Windows Startup Application is one of those system processes and is not be found back in other (user) sessions (although they have a variant for winit.exe, i.e. userinit.exe (Userinit Logon Application)). Anyway, wininit.exe continues with the boot process by launching the Service Control Manager (SCM) (services.exe) and the Local Security Authority (LSA) (lsass.exe). Wininit.exe continues to exist, while userinit.exe processes terminate after a while. Windows Startup Application and Userinit Logon Application can be considered as the “session 0 initializer” and “session (non-0) initializer” respectively, the first staying alive, while the 2nd runs temporarily in every session. Oh by the way, session 0 does not contain a Winlogon (winlogon.exe), which isn’t that weird, as interactive user logon isn’t allowed for this session.
Now let’s step back and discuss something else. Take a look at the registry key HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Windows:
Do you see the REG_SZ named value AppInit_DLLs? In my case the value is “pngdi32.dll pnuphk32.dll” (without the quotes). This named value contains a list of dynamic link libraries (DLLs), separated by spaces (or commas). In my case the value refers to those DLLs:
- pngdi32.dll (Quest 32-bit GDI Client DLL)
- PNUPHk32.dll (Quest Universal Printer x64 32-bit Hook)
Both DLLs are part of a vWorkspace component from Quest Software (in the past it belonged to Provision Networks, but Quest Software took them over). vWorkspace is an extension to Microsoft’s RDS infrastructure: extra broker functionality, enhanced web access, more redirection options, etc. It is similar to Citrix’ XenApp/XenDesktop. Part of vWorkspace has to be installed on a TS/RDSH and those 2 DLLs belong to a component of that part. I think the first DLL takes care of the 32 bit GDI, while the second DLL is a hook DLL so 32 bit processes can use the 64 bit Print-IT, the vWorkspace component for printer redirection, which uses the “Quest Universal Printer EMF Driver” driver (I’m not going to explain EMF, as that’s definitely outside the scope of this article J). “PN” stands for “Provision Networks”, “UP” for “Universal Printer” and “Hk” for “Hook”.
Now, every DLL mentioned in the AppInit_DLLs named value will be loaded in *every* user-mode process on the system (except for smss.exe and csrss.exe), including wininit.exe, for 32 bit Windows or 64 bit processes on 64 bit Windows. For 32 bit processes on 64 bit Windows this key contains another AppInit_DLLs with DLLs to load into those processes: HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Windows NT\CurrentVersion\Windows; This value can of course be different from the first AppInit_DLLs (for 64 bit processes on 64 bit Windows).
On Windows 7 all the DLLs from AppInit_DLLs should be code-signed, but it’s not enforced by default. On WS08R2 this is enforced by default though. The named value that actually determines this behavior is RequireSignedAppInit_DLLs (a DWORD) and resides under the same key as AppInit_DLLs. On Windows 7 this value is 0 by default, while it’s 1 on WS08R2. As you can see in my screenshot it’s 0; that’s because vWorkspace has changed it, because its DLLs code-signed, but expired… Without this change the vWorkspace DLLs wouldn’t be able to be loaded. So non-code-signed or code-signed-but-expired DLLs can only be loaded through this AppInit_DLLs mechanism if the code signing requirement isn’t enforced (so if RequireSignedAppInit_DLLs is 0).
When Windows Startup Application loads those explicitly configured and non-default loaded ( so “custom”) DLLs, it logs this event in the System event log. It has nothing to do with code signing being enabled or disabled, non-codesigned DLLs or codesigned DLLs with expired certificates. The message is just a warning that should be considered as not negative and wants to make you check the AppInit_DLLs named values, so you can determine if you trust the DLLs or not (even if they are codesigned, as codesigning doesn’t automatically mean you can trust them!). If neither AppInit_DLLs named value (on 64 bit Windows there are of such named values, as just explained) contains a “custom” DLL, nothing is logged. So even if I have shown you an example of disabled code-signing and an expired certificate, the warning has nothing to do with that. The bottom line is this warning only tells you at least 1 custom DLL is loaded through the described mechanism.
Side note 1: it doesn’t make sense for every process to log this event. That’s why you only see Wininit doing this.
Side note 2: don’t forget that if RequireSignedAppInit_DLLs has been changed to 0 on WS08R2 this also affects other DLLs in the AppInit_DLLs list. vWorkspace didn’t ask the administrator to allow this change and didn’t even warn or inform the install user! If another, non-code-signed DLL would be included in AppInit_DLLs and it’s a bad one, it could harm your system… I think applications should inform the install user of this security reduction.
Side note 3: at the same level as AppInit_DLLs another named value could be important, i.e. LoadAppInit_DLLs. A value of 0 means the whole mechanism to load DLLs in “every” process is disabled. By default this value is 1.
Side note 4: Take a look at the following screenshot, taken with Process Explorer on one of my RDSHs:
Do you see something special? Yup, pngdi32.dll is loaded in mmc.exe (a 64 bit process on 64 bit WS08R2). But what about PNUPHk32.dll? Nope, it’s missing, even while it’s registered to be loaded in AppInit_DLLs in HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Windows. The last DLL seems to be a 32 bit DLL because it’s located in %windir%SysWOW64. Ok, I admit, that’s not a proof, but I can check this out for sure with a tool called dumpbin. And that’s what I did. Yup, it’s a 32 bit DLL. Then why is this registered to be loaded in a 64 bit process? This should fail and indeed, you don’t see it loaded in any process at all… BTW, if it’s okay with you, I won’t explain all the dumpbin stuff here. I just want to show you my particular case in this blog post and I would like to point out I have a problem with one of those DLLs. That’s all. Anyway, I would expect a 64 process here, located in %windir%\system32, as the counterpart for a 32 bit process, located in %windir%\SysWOW64, i.e. pnuphk.dll, which is registered for 32 bit processes. It is weird though to find PNUPHk32.dll in the “wrong” folder, but also in the “wrong” architecture; and especially: of course it doesn’t work if you register such a DLL for 64 bit processes! Perhaps I don’t understand something, but I think there is a problem here too… Or otherwise this DLL isn’t needed at all and it’s something old from older tests, but if that’s the case, it’s not very clean from Quest Software…
For completeness I would like to stress the fact that the warning can also be logged if vWorkspace is not installed. My case is just one particular scenario. The bottom line is some applications can use AppInit_DLLs to load DLLs in processes and those DLLs may be non-code-signed (and on WS08R2 RequireSignedAppInit_DLLs is changed to 0); in that scenario the warning we have described here is logged.