Windows Wednesday: Application Compatibility Cache

Zeltser Challenge Update

For Wednesdays, I’ve decided on the theme of “Windows Wednesday”. I was torn between Windows Wednesday and Microsoft Mondays, but was happy to settle on malware for Mondays. I think there’s plenty of Windows to go around for its own day :)

Windows Wednesday: The Application Compatibility Cache, or Shim Cache

Today’s post is going to focus on The Application Compatibility Cache (“AppCompatCache”), also known as the Shim Cache. As I just wrapped up a webcast on fileless malware, it got me thinking about Windows artifacts that contain evidence of program execution; and how certain malware may avoid these artifacts. As one of my favorite artifacts, AppCompatCache naturally bubbled up to the top.

The Purpose of the AppCompatCache

When working with students in FOR508, I often remind them that many of our forensic artifacts in Windows operating systems, especially older versions, are actually byproducts of tools meant to offer a seamless customer experience and/or assist developers in troubleshooting. I have always viewed the AppCompatCache as one of these forensic gems — with this consideration in mind, the perilous timestamps found in AppCompatCache output all of a sudden make sense.

To understand how the AppCompatCache works, we must first remember that one strength of Microsoft Windows is backwards compatibility (see how we get to ‘Application Compatibility’?). As the Windows operating system went through updates, both major and minor, Microsoft realized it couldn’t make frequent updates that broke applications each time. Instead of forcing application developers to either constantly rewrite code or maintain an insurmountable number of source code branches, Microsoft instead developed the Shim Infrastructure.

The Shim Infrastructure essentially intercepts API calls — it actually is a form of API hooking — and loads the alternate “shimmed” code. Through examining the Import Address Table, Windows can actually replace the pointer to a function with the shimmed code. Take a look at the following examples from a Microsoft TechNet post that explains the concept:

Application Execution without a Shim; credit to Microsoft TechNet
Application Execution with a Shim; credit to Microsoft TechNet

I often like to remind myself that a traditional shim is something used to align parts or make something fit. In fact, if you’ve ever folded up a cocktail napkin to stop a table from wobbling, congrats, you’ve shimmed something :) I think it’s also prudent to mention that all of this seamless redirection and backwards compatibility happens with no impact to the user.

While I’ve severely simplified the purpose and function of the AppCompatCache, I hope it gets the general point across. After all, the majority of DFIR analysis is not to understand what code needed to be shimmed, but rather look at the list of executables that resulted from shim introspection.

The Actual Cache

The artifact that DFIR analysts examine and are concerned with is the list of file metadata from executables that were recently executed, and thus examined for shimming, or executables examined for “the need to shim” but not executed. More on this later.

The location of this “list” exists in one of two primary locations:

  • Windows XP-ish: HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\AppCompatibility\AppCompatCache
  • Not Windows XP-ish (potentially including 2003):HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\AppCompatCache\AppCompatCache

That’s right — they’re stored in the SYSTEM registry hive. Let’s look at some key differences between operating systems and what is stored in this cache:

Windows XP

  • Cache will contain a maximum of 96 entries.
  • Entries are 552 bytes in length.
  • The entry has a header that begins with 0xDEADBEEF, and contains the number of entries in the record, as well as the indices used.

Entries contain:

  • The full path of the executable
  • The $SI Last Modified Time
  • File Size
  • Last File Execution Time

Windows Server 2003

  • Registry path changes to AppCompatCache\AppCompatCache (see example above).
  • Cache contains a maximum of 512 entries.
  • Entries are 24 or 32 bytes in length, depending on system architecture.
  • Entry has an 8-byte header that begins with 0xBADC0FFE and contains the number of entries.

Windows Vista/Server 2008

  • Cache contains a maximum of 1024 entries.
  • Entries are 24 or 32 bytes in length, depending on system architecture.
  • Two 4-byte flags were added and the File Size metadata was removed.
  • Updated format now contains a flag denoting whether the file was executed or not.
  • Applications are now added to the cache without execution.

Windows 7/Server 2008 R2

  • Cache contains a maximum of 1024 entries.
  • Entries are 32 or 48 bytes in length, depending on system architecture.
  • Entry has a 128-byte header that begins with 0xBADC0FEE and contains number of entries.

True/False

Note above that in newer operating systems, AppCompatCache data includes a true/false flag denoting program execution. In a majority of output, this flag will be set to True. This is typically indicative that an executable was..well, executed! Seems fairly straightforward.

In instances where we have a False flag, this may indicate that Windows was “exposed” to the executable, and decided to examine it for “the need to shim”. Typically, I have seen this in cases where a user is browsing a directory containing executables that haven’t been executed yet, and are not executed before the data is written to the key.

EDIT: On older operating systems that do not have the execution flag, the value for this field may be set to ‘FALSE’ in some script output files. Take a note of your host’s operating system, and determine whether you have the execution flag or not before interpreting all the executables recorded were not executed.

One great case study was when I was performing an examination on an ex-employee who was abusing his still-active AD credentials to remote back into the environment and steal sensitive data. When the user connected via RDP, he actually mapped his D: drive to copy data to. Inside the root of D:, he had an executable for an IP scanner and a password dumper. Both of these executables were added to the AppCompatCache registry keys, but were actually never executed. Talk about a smoking gun!

Sometimes, .DLL files may also be represented with a false execution flag. These files are often not run directly, however do have MZ headers.

The Importance of Rebooting

Another important consideration of the AppCompatCache registry key is that it is only written upon a system reboot. The data is stored in memory until a system shutdown or reboot, at which point the data is written by winlogon.exe.

For incident responders and threat hunters, this is an important thing to note if you’re pulling AppCompatCache from live systems. Be wary that if you’re not seeing data you’d expect to see, take a look at system uptime and see how old the records may be.

Of course, I’m not suggesting we reboot a system. Instead, grab a copy of system memory (as is a blanket suggestion for volatile data from compromised or suspected systems), and we can parse AppCompatCache data from memory. We’ll cover more on this in the next section.

Parsing AppCompatCache Data

When the AppCompatCache artifact was first discovered and discussed, there were only a couple of parsing tools. Now, we have multiple. One of the original tools, and one of my top recommendations, is the Python ShimCacheParser.py script from Mandiant. Here’s a link to the Github page:

Mandiant’s script allows you to examine an offline hive — from say, a disk image — or a live system. The script can be executed against a multitude of data types.

As I mentioned above, we can also parse the yet-to-be-written AppCompatCache data from memory. The folks over at Mandiant also wrote the volatility plugin “shimcachemem”, which can parse the stored data from kernel memory. This allows us to maintain evidence collection based on artifact volatility, but still gain valuable data that is often dependent on a restart to be in the expected location.

Analyzing AppCompatCache Data

For the first part of this post, I’m going to briefly discuss analyzing AppCompatCache data. I don’t mean to dismiss an important part of interpreting the evidence, but I’d rather point to other posts that have context to help illustrate the point. Not to provide a personal plug, but a post I put up a few weeks ago about PsExec artifacts provides insight on examining AppCompatCache data.

First, after parsing the data, an analyst must be wary of the order in which data is output. Take a look at the following snippet, borrowed from our SANS FOR508 material:

Output from the shimcachemem volatility plugin; taken from SANS FOR508

Many analysts want to immediately sort the output data by date and find data that sits within their timeframes of interest. However, remember that the timestamp recorded by Windows is the $SI Modification Time. This file is not only easily time-stompable, but may also be a much, much earlier date. Instead, focus on the order in which the executables are listed.

The order of executables output places the most recently executed file at the top. In the particular snippet provided above, that would indicate that a.exe was the most recently-executed file. Prior to that, it was SearchFilterHost.exe. In this arbitrary example, there’s not much of a sequence of interest. However, for incident responders and threat hunters, I would certainly recommend looking for patterns that resemble attacker internal recon or privilege escalation events. This may include basic Windows “information gathering” executables, such as net.exe, whoami.exe, ipconfig.exe, ping.exe, etc.

The real power of AppCompatCache analysis comes when analysts can combine the data from the registry with the data stored in memory. This provides a list of executed programs longer than the usual limits, and may even give you a peek back in time! Be sure to involve this artifact in your next analysis.

If you are quite familiar with performing AppCompatCache analysis, you no doubt have a sense of how valuable this artifact can be. If not, then I hope this post put forward some new information. This is always a really fun portion to teach during FOR508, as this is still an underutilized artifact. Here’s to hoping this is has helped some analysts find the missing piece of the puzzle.

Until tomorrow, Happy Forensicating!