Wednesday, December 9, 2020

Windows compatibility shim logs

One of the ways Windows provides backward compatibility with applications targeted to older OS versions is by loading compatibility shims into their processes to intercept and alter various Windows API calls. apphelp.dll provides most of the machinery for this, at least for user mode. Interestingly, that DLL and the shim DLLs it can load are capable of logging some information about what they're doing or errors they encounter, though those log entries don't go anywhere by default. Out of curiosity I poked around in IDA to figure out how to enable them.

The SepApplyDebugPolicy function, called early in SE_InitializeEngine, is responsible for initializing some global variables related to logging. It reads two environment variables, SHIM_DEBUG_LEVEL and SHIMENG_DEBUG_LEVEL, into global variables controlling the verbosity of shims' logs and AppHelp itself's logs respectively. Level 5 produces messages of all detail levels including "trace." These logs seem to be designed for consumption via ETW Trace Logging, but I was unable to record any relevant events with WPR. 

They can also, however, output to files. For shim logs, AppHelp also consults a SHIM_FILE_LOG environment variable which specifies a filename under %WINDOWS%\Temp to save the log as. The code tries to take just the filename - the segment after the last backslash - but ../ sequences can be used to traverse up the directory tree and place the log anywhere you have write access to. For AppHelp (the shim engine) itself, there is no environment variable to set filenames; logs are always saved in that temp directory with a name starting with AslLog_ApphelpDebug. The shim engine state (?) is saved as an XML document in an adjacent file with a name starting with AslLog_shimengstate. These logs have to be enabled with a LogFlags DWord value in HKLM\Software\Microsoft\Windows NT\CurrentVersion\AppCompatFlags in the Registry. Setting that to 0xFF (255) does the job nicely.

For completeness' sake: SepApplyDebugPolicy also looks for a DWord value named ShowDebugInfo in that key, but the effect is not clear to me from the disassembly and I did not notice any difference in behavior.

No comments:

Post a Comment