As a faithful user of NT5x it has become increasingly painful as much software has dropped support and requires vista or newer, hell even windows 7 support is waning now and I am still on xp/2k3. Anyway, over the years I have made various efforts to hack in newer apis such that I can run this newer software. I have never made much progress due to working on many projects at once and also the fact that I am a perfectionist. I can also never quite decided how to go about it so end up floundering around with a bunch of half implemented tests.
During my experiments I have discovered a number of ways in which NT5x is completely broken. The piece of brain damage I will discuss here today is one of several related to dynamically loaded libraries.
LoadLibrary:
When one would like to load a library at run-time, one can call this function. The specified module and all its dependencies will be loaded and a corresponding call to FreeLibrary will unload this module and any dependencies will also be unloaded if no longer needed. All nice a simple, there is just one major flaw in this system.
Export forwarders:
So a dll is able to forward an export onto another dll. This export forwarding has a number of performance advantages: 1. there needs be no thunks, the function pointer is fetched directly from the target dll. 2. The target dll is loaded on demand, if none of the forwarded functions are used then the target dll need not be loaded. There is one major problem with this mechanism however, dlls loaded by way of a forwarded export can never be unloaded, windows does not track these loads and has no way to determine when these dlls should be unloaded.
NT6x fix:
When a dll is unloaded its import table is walked and each dependent dll has its reference count decremented. Those dlls are then also unloaded if their ref-count drops to zero. This mechanism is completely incompatible with unloading of dlls loaded by forwarding so in vista a new mechanism was added to track just forwarder loaded dlls.
1. a new field was added to LDR_DATA_TABLE_ENTRY: ForwarderLinks
2. when a dll is loaded by fowarder the function
LdrpRecordForwarder(PLDR_DATA_TABLE_ENTRY LdrEntry, PLDR_DATA_TABLE_ENTRY ldrTarget)
is called, this function inserts the target dll into the ForwarderLinks list
3. The ForwarderLinks list structure
struct ForwarderLinks_t { LIST_ENTRY list;
PLDR_DATA_TABLE_ENTRY* target; int refCount; };
For each time the target dll is loaded LdrpRecordForwarder is called
and the ForwarderLinks list is inserted the first time, susequent times the refCount is incremented
The ref-count field is not really needed, it could have been implemented without a ref-count
But they decided to leave the existing call to LdrpLoadDll which always increments the dll ref-count
Allot of the changes made in vista feel very tacked on.
4. The LdrUnloadDll has been altered as necessary to make use of this new linked list to correctly unload this dll which where loaded by forwarded and are no-longer needed. Pretty simple fix, why on earth was this allowed to be broken like this for so long. It took them more then 10years to fix this since the first windows NT release.