Office apps and the Mso::ChecksumRegistry::Data algorithm

Nearly all Microsoft apps have experimentation code built-in these days. This code is typically used to facilitate A/B testing externally but internally, it can problematic if left on. (Imagine trying to reproduce a bug in a feature that's turning itself on/off or behaving differently across machines.) This is why most apps also house a feature or experiment control panel, hidden to all except those typically on the owning team.

Story Remix has a panel, for example, that appears when a specifically named .json file is present on disk and populated with specific values. Groove Music relies instead on specialty registry values locked down to specific geographic markets. Office apps also use the registry, but with an added obfuscation twist.

I haven't fully mapped out how Office apps store all their experimental settings, but we're going to talk about one area today:

LocalState\HKCU\Software\Microsoft\Office\16.0\Common\ExperimentTas\[app]\Flights

The registry value names are straightforward -- they represent an arbitrary name assigned to an experiment or feature and hardcoded into the app. The registry value data represents a structure, serialized to a UTF-16 string, in the form [field]|[fieldType]|[fieldValue];[settingType]|[settingValue]. (This is then stuffed into a composite value, hence the 0x5f5e10c type and extra bits at the end that are out of scope for the blog post.)

A more concrete example:

  • Value: Microsoft.Office.Experimentation.ABC
  • Data: Mso::ChecksumRegistry::Data|uint64_t|9215221962101605702;bool|1

The signed (yes, despite the declaration) 64-bit checksum value is computed by taking the value name, setting type, and setting value, concatenating them together, and running it through the Fowler–Noll–Vo (variant 1a) hashing function.

Using our example data above, let's walk through this:

  1. Glue the pieces together: Microsoft.Office.Experimentation.ABCbool|1
  2. Run it through once with hardcoded initial offset basis: step2 = FNV1a(string_bytes, 0xCBF29CE484222325)
  3. Use that as the initial offset basis for another run, with a hardcoded chunk of data this time:
    hash = FNV1a([0xb7, 0x3c, 0x75, 0x96, 0xd5, 0x79, 0x13, 0xa5, 0xc8, 0xe5, 0xb2, 0xa2, 0xaf, 0x2b, 0x44, 0xff], step2)
  4. Serialize the hash and stuff it into the pattern above

If you implement this correctly, with say the Microsoft.Office.Experimentation.ShowExperimentSettings registry value, you'll end up with a hash of 2507011508917168823.

And a shiny new control panel to play with.

hxmail_experiments_panel

Registry values in the LocalState\HKEY_CURRENT_USER\Software\Microsoft\Office\16.0\Common\ExperimentEcs\[app]\Flights key use a different type of obfuscation that I'll cover in the next post.