Easter Egg in APK Files: What Is Frosting

BI.ZONE
6 min readDec 28, 2020

By Konstantin Molodyakov

A file structure is a whole fascinating world with its own history, mysteries and a home-grown circus of freaks, where workarounds are applied liberally. If you dig deeper into it, you can discover loads of interesting stuff.

In our digging we came across a particular feature of APK files — a special signature with a specific block of metadata, i.e. frosting. It allows you to determine unambiguously if a file was distributed via Google Play. This signature would be useful to antivirus vendors and sandboxes when analyzing malware. It can also help forensic investigators pinpoint the source of a file.

There’s hardly any information out there regarding this topic. The only reference appears to be in Security Metadata in Early 2018 on the Android Developers Blog, and there is also an Avast utility that allows this signature to be validated. I decided to explore the feature and check the Avast developers’ assumptions about the contents of the frosting block and share my findings.

Frosting and APK Signing Block

Google uses a special signature for APK files when publishing apps on Google Play. This signature is stored in the APK Signing Block, which precedes the central directory of ZIP files and follows its primary contents:

The magic APK Sig Block 42 can be used to identify the APK Signing Block. The signing block may contain other blocks, whose application can be determined by the 4-byte ID. Thus, we get a ZIP format extension with backward compatibility. If you are interested in reading more or seeing the source code, you can check out the description of the method ApkSigningBlockUtils.findSignature here.

Let us take some file as an example, for instance 2124948e2b7897cd6fbbe5fbd655c26d. You can use androguard to view the block identifiers within the APK Signing Block:

There are several types of blocks with various identifiers, which are officially described in the documentation:

Some of the blocks can be found in Android source codes:

Other types of blocks that may come up:

  • 0x504b4453 (DEPENDENCY_INFO_BLOCK_ID) — a block that apparently contains dependency metadata, which is saved by the Android Gradle plugin to identify any issues related to dependencies
  • 0x71777777 (APK_CHANNEL_BLOCK_ID) — a Walle (Chinese gizmo) assembler block, which contains JSON with a channel ID
  • 0xff3b5998 — a zero block, which I ran into in the file — I couldn't find any information on that
  • 0x2146444e — a block with the necessary metadata from Google Play

Frosting and Play Market

Let us get back to analyzing the 0x2146444e block. First off, we should explore the innards of the Play Market application.

The identifier of our interest is found in two locations. As we delve deeper, we quite quickly spot the class responsible for block parsing. This is the first time that the name of a frosting block pops up among the constants:

Having compared different versions of the Play Market application, I have made the following observation: the code responsible for the parsing of this type of signature appeared around January 2018 together with the release of the 8.6.X version. While the frosting metadata block already existed, it was during this period that it took on its current form.

In order to parse the data, we need a primitive for reading 4-byte numbers. The scheme is a standard varint without any tricks involving negative numbers.

Though simple, the block parsing function is fairly large. It allows you to gain an understanding of the data structure:

To validate the signature, the first-field hash and key from validation_sequence are used, where validation_strategy equals zero. The signature itself is taken from signature_sequence with the same ordinal number as the validation_sequence entry. The figure below presents the explanatory pseudocode:

The signing_key_index value indicates the index in the array finsky.peer_app_sharing_api.frosting_public_keys, which contains only one key so far as shown below:

The size_signed_data is signed with the ECDSA_SHA256 algorithm starting with the size_frosting variable. Note that the signed data contains SHA-256 of the file data:

1) data from the beginning of the file to the signing block

2) data from the central directory to the end of the central directory, with the field value ‘offset of start of central with respect to the starting disk number’ at the end of the central directory replaced with a signing block offset

The signature scheme version 2 block (if any) is inserted between the data from the above items 1 and 2 with APK_SIGNATURE_SCHEME_V2_BLOCK_ID preceding it.

The hash calculation function in the Play Market application is represented as follows:

Frosting and ProtoBuf

This information is sufficient for signature validation. Alas, I failed to figure out what is hidden in the frosting block data. The only thing I was able to discover was the data has a ProtoBuf format and varies greatly in size and the number of fields depending on the file.

Typical representation of decoded data without a scheme (4b005c9e9ea0731330a757fcf3abeb6e):

But you can come across some instances (471c589acc800135eb318057c43a8068) with around five hundred fields.

The data occasionally contains such curious strings as: android.hardware.ram.low, com.samsung.feature.SAMSUNG_EXPERIENCE, com.google.android.apps.photos.PIXEL_2018_PRELOAD. These strings are not explicitly declared feature names, which a device may have.

You can find the description of available features in the files on the device — in the /etc/sysconfig/ folder:

If we were to give an example of a declared feature, this could be checking the camera availability by calling the android.hardware.camera function through the method PackageManager hasSystemFeature. However, the function of these strings within this context is vague.

I could not guess, find or recover the data scheme for the Play Market APK classes. It would be great if anyone could tell us what is out there and how they managed to figure it out. Meanwhile, all we have now are the assumptions of the Avast utility developers about the ProtoBuf structure and the string com.google.android.apps.photos.PIXEL_2018_PRELOAD indicating a system or pre-installed app:

I would like to share some of my comments with respect to the above.

1. When it comes to the string com.google.android.apps.photos.PIXEL_2018_PRELOAD: you can easily prove that this assumption is incorrect. If we download a few Google factory images, we will realize that they have neither such strings nor a single app with a frosting block.

We can look into it in more detail using the image walleye for Pixel 2 9.0.0 (PQ3A.190801.002, Aug 2019). Having installed the image, we are not able to spot a single file with a frosting block among a total of 187 APK files. If we update all the apps, 33 out of the 264 APK files will acquire a frosting block. However, only 5 of them will contain these strings:

com.google.android.as:

  • com.google.android.feature.DPS
  • com.google.android.feature.PIXEL_EXPERIENCE
  • com.google.android.feature.PIXEL_2017_EXPERIENCE
  • com.google.android.feature.PIXEL_2019_EXPERIENCE
  • com.google.android.feature.ANDROID_ONE_EXPERIENCE
  • com.google.android.feature.PIXEL_2018_EXPERIENCE
  • com.google.android.feature.PIXEL_2020_EXPERIENCE

google.android.inputmethod.latin:

  • android.hardware.ram.low

google.android.dialer:

  • com.google.android.apps.dialer.GO_EXPERIENCE
  • com.google.android.feature.PIXEL_2020_EXPERIENCE

google.android.GoogleCamera:

  • android.hardware.camera.level.full

google.android.apps.photos:

  • com.google.android.feature.PIXEL_2020_EXPERIENCE

We can assume that these strings show the relevance of features to the device where the app is installed. However, requesting a full list of features on the updated device proves that the assumption is wrong.

2. I would disagree with the ‘frosting versions’ as you can find similar data, but with values other than 1. The maximum value of this field that I have come across so far is 26.

3. I would disagree with the ‘С timestamp of the frosting creation’: I have been monitoring a specific app and noticed that this field value does not necessarily increase with every new version. It tends to be unstable and can become negative.

4. MinSdkLevel and VersionCode appear plausible.

Conclusion

In summary, a frosting block in the signature helps to precisely ascertain if a file has been distributed through an official store. I wasn’t able to derive any other benefit from this signature.

For the finale, here is an illustration from the ApkLab mobile sandbox report of how this information is applied:

--

--

BI.ZONE

BI.ZONE: an expert in digital risks management. We help organizations around the world to develop their businesses safely in the digital age