Occasionally I come across DLL load problems:
The verbosity of the error messages varies greatly. In their raw form these include at least the DLL name, but as various frameworks come into play (for the error message above, it’s .net) – native exceptions are caught and re-thrown, and more often than not helpful information is lost on the way.
Turns out there’s a built in way to get verbose windows-loader output: the Show Loader Snaps flag. The easiest way to mark it is with the GFlags utility, bundled with debugging tools for windows:
Under the hood, it merely adds a FLG_SHOW_LDR_SNAPS flag (0x00000002), to a DWORD value in the relevant IFEO registry key. This in turn causes Windows Loader to set the _ShowSnaps variable in the ntdll copy specific to the named process.
And now, behold the new and shiny loader trace (dumped to the debugger output window):
…
2724:245c @ 11813487 – LdrpFindOrMapDll – RETURN: Status: 0x00000000
2724:245c @ 11813487 – LdrpLoadImportModule – RETURN: Status: 0x00000000
2724:245c @ 11813487 – LdrpLoadImportModule – RETURN: Status: 0x00000000
2724:245c @ 11813487 – LdrpLoadImportModule – RETURN: Status: 0x00000000
2724:245c @ 11813487 – LdrpSnapThunk – WARNING: Hint index 0x70a for procedure “?Revert@CStreamMemory@@UAGJXZ” in DLL “YaddaYadda.dll” is invalid
2724:245c @ 11813487 – LdrpSnapThunk – ERROR: Procedure “?Revert@CStreamMemory@@UAGJXZ” could not be located in DLL “YaddaYadda.dll”
First-chance exception at 0x77321d32 (ntdll.dll) in Strategist.exe: 0xC0000139: Entry Point Not Found.
Bam! There’s the offending DLL and the offending imported function, right there in the debugger.
Like many other useful features – it is documented, but very low on discoverability. Which is a fancy way of saying you can find it only if you already know exactly what you are looking for. I personally got around to it after digging around in ntdll assembly (just like Matt Pietrek, 14 years ago), trying to get to a string containing the name of an offending DLL.
The windows-copycat-opensource ReactOS source gives a nice view of the internal usage of this flag – called ShowSnaps in their source. The ‘snapping’ verb in this context refers to one of the actions performed by the loader: after rebasing the loaded DLL in the loading process memory space, the DLL’s exported function addresses are updated and must be copied to the importing process (or other dll) Import Address Table. This – in this context – is called snapping, and that’s where the extra tracing is hooked.
hi Ofek, greate discovery.
however, in case this happens in a deploy machine, with no debugger, how can I log the trace to a file instead of the not installed Visual-Studio’s output window.
M>
Use DebugView, a nifty lightweight tool by sysinternals intended to achieve just that: http://technet.microsoft.com/en-us/sysinternals/bb896647.aspx
in that specific case, what have you done to achieve the missing method (Revert@CStreamMemory)?
had to code it youself?
find the dll version that had it already?
The culprit here was indeed a wrong version of the dll.
Update: DebugView doesn’t intercept these loader messages after all – apparently they don’t use the standard tracing API.
a
b!
Saved my bacon, many thanks!
Pingback: On API-MS-WIN-XXXXX.DLL, And Other Dependency Walker Glitches | 神刀安全网
It’s probably only me that is an idiot, but in the Image field you should only put the EXE name, not full path. Otherwise it won’t work.
I’m not sure how the launch button is suppose to work.
Indeed you should put only the executable name. What is the launch button? where exactly?
On the right of the image field?
Ahh I see. It seems the launch button just invokes the executable name as a shell command – so it would work only if the executable folder is on the system path.
The debug log is going to a function named vDbgPrintExWithPrefix in ntdll.dll.
So detouring this function can give you the messages.
ULONG NTAPI vDbgPrintExWithPrefix(PCH Prefix, ULONG ComponentId, ULONG Level, PCH Format, va_list arglist)
I detoured all [v]DbgPrint* API in ntdll.dll, but still not work (on Windows 10). Can you share more information about how you get the messages?
I successfully capture those debug log using WaitForDebugEvent(). Basically, I create another process to act like a debugger attaching original process and get debug output for original process. Then I can use my own way to pass those message back to original process
Basically, this should work for all user-mode DbgPrint() messages.
ShowSnaps does not call OutputDebugString, but LdrpLogDbgPrint – which I believe doesn’t use vDbgPrintExWithPrefix. Years ago Mark Russinovic declined my request to support LdrpLogDbgPrint in DebugView.
Pingback: 更多信息如下0xc0000139错误在windows上的应用。 – 运维实战侠
Pingback: 更多信息如下0xc0000139错误在windows上的应用。 – 实战宝典