Tooling Thursday: AppCompatCacheParser

Zelter Challenge Update

Thanks to everyone who has read and given me feedback thus far. Please don’t stop, and keep being honest with me! For Thursdays, my goal is to focus on tools within the DFIR community. I am going to do my best to make sure that these are open source and freely-available tools, so that readers may incorporate them into their arsenal immediately. If a rare case comes along where I discuss or review a proprietary or purchased tool, then there will be a corresponding reason as to why.

Tooling Thursday: AppCompatCacheParser

This post comes on the heels of yesterday’s discussion, where I focused on the Application Compatibility Cache (“AppCompatCache”), also referred to as the Shim Cache. I provided an example output using Mandiant’s ShimCacheParser.py, but wanted to make sure I mentioned the other tool I commonly use to parse this artifact.

Today I’ll be focusing on the tool AppCompatCacheParser, currently at version 0.9.4.0. This tool is provided to the DFIR community from my colleague and fellow SANS instructor @EricRZimmerman. If you’re not familiar with Eric’s work, I highly recommend checking out his blog when you get a chance. He explores quite a few Windows aritfacts in immense detail, and publishes tools to automate the same type of introspection.

One Key Difference

Before digging into the output options and use of the tool, it’s first important to note that Eric publishes his tools to be used in Windows environments. While the ShimCacheParser.py script can obviously also be run in Windows, having a Windows executable gives analysts a flexible option if they cannot install or do not want to install Python. Eric also maintains his source code on GitHub, so feel free to suggest ways he can improve the tools!

Tool Options

AppCompatCacheParser contains really simple output options to help analysts manipulate their output data. Here’s a screenshot of the help menu, listing all the available options:

Help options from AppCompatCacheParser v0.9.4.0

By default, the tool will save the results to a directory of choice, and the output file will contain the operating system and the hostname. This output format makes it really easy to script against a bunch of extracted hives and let the tool help with sorting later on.

A few key options to discuss:

  • h — This flag allows us to extract AppCompatCache data from an extracted SYSTEM hive. By default, the tool will look at the local, live system.
  • t — Sorts timestamps in descending order. Be careful with this option! Remember, analysts, AppCompatCache data is typically relevant because of the order of execution. The tool output does also include a CacheEntryPosition, which you can use to reset the order if you want. See the screenshot below:
Output from AppCompatCacheParser using the -t option

Notice that while my timestamps are in order, my CacheEntryPosition (column 2) shows that the files were not executed sequentially.

  • dt — Allows you to set a custom date/time format. The tool’s default timestamp format of yyyy-MM-dd HH:mm:ss is how I like my timestamps, so I don’t have a better suggestion. However, note the case-sensitivity if you wanted to define your own output.
  • d — Eric has brilliantly also built in a ‘debug’ mode, that actually allows you to get extremely granular with your data. Take a look at some sample output:
Output from AppCompatCacheParser using debug mode

Notice that if we were having issues parsing the data, we could go entry by entry and try to figure out the issue. I love this mode!

  • c — The ‘c’ option allows the analyst to choose which ControlSet to parse. By default, it detects and parses all ControlSets. Let me spend a minute on this to stress the forensic importance:

As I mentioned yesterday, the registry path for the AppCompatCache data is stored within the SYSTEM registry hive, and the top-level key is CurrentControlSet. If you take a look at a SYSTEM registry hive on a live system, you may see the following:

  • ControlSet001
  • ControlSet002
  • CurrentControlSet

While you can browse all three, CurrentControlSet is actually a pointer to either 001 or 002. What determines this? Well, under SYSTEM, you also have a key named Select. Within this key, there are the following values:

  • Current
  • Default
  • Failed
  • LastKnownGood

Take a look at a screenshot from my system:

Contents of the HKLM\SYSTEM\Select key

With a value of 1 for the Current, I can be confident that my CurrentControlSet points to ControlSet001. Note that I also don’t have a ControlSet002. In hives where both are present, 001 may be listed as the Current while 002 is listed as the LastKnownGood, in case Windows runs into any boot issues and needs to revert to a last known good configuration.

Default is often the same value as Current, and Failed will point to a ControlSet that was unable to successfully boot (if you’re troubleshooting a recent boot failure, this value will most likely be set).

During Eric’s testing, he found that the AppCompatCache data within each ControlSet can contain different data; and rightfully so, if one is meant to be a known good backup, while the other is the current set. Remember, by default the tool parses both. Take a look at the following output from running the tool against a sample SYSTEM hive:

Sample AppCompatCacheParser output from a system with two control sets

The break in column 1 indicates which ControlSet the data was extracted from (notice the jump from 1 to 2, as well as the CacheEntryPosition order being reset).

Note that Mandiant’s ShimCacheParser.py tool also examines both control sets, and de-dupes between the two.

Wrap-Up

As previously mentioned, I’m a huge fan of this tool and use it quite frequently to parse data. In line with Eric’s tests, I have also found differences between CurrentControl001 and CurrentControl002, and appreciate being able to select granularity with the tool. If you are looking for different methods to parse AppCompatCache data, I hope you consider adding this tool to your DFIR arsenal.

Until tomorrow, Happy Forensicating!