Pages

Categories

Decoding Snapchat's MEDIA_CONTEXT_TYPE with JADX


Within the Digital Forensics Discord server, a user asked:

Does anyone know what MEDIA_CONTEXT_TYPE = "5" mean in Snapchat cache_controller.db?

Answer: TL;DR

MEDIA_CONTEXT_TYPE is a numeric field stored in Snapchat's cache_controller.db that categorises cached media by type. Here's how you can decode what each value represents. Tools required:

The main method of operation is:

  1. Verify source data
  2. Locate artefacts of interest and explore
  3. Identify and extract application base
  4. Decoding and searching
  5. Refining results

You'll need some sample data too. I found The Binary Hick's public images (in this case the Android 14 image) work well for testing. Don't forget to verify your file!

Pasted image 20260514194548.png

Matching SHA-256 hash of: 4e1698460550e20f3b334ae9df96ee1cd78314bdc0fe5de5183fd5d7e1c8967e

Now let's navigate to the cache_controller.db in question:

Folder Directory: \data\data\com.snapchat.android\databases\native_content_manager\

File Name MD5 Hash
cache_controller.db ee6558e18eb8d8ab6e8d00a3b04c1528
cache_controller.db-wal 02b01bdeea4d392553c57fb2ff753646
cache_controller.db-shm 4737ae3c24c4eac8e1a3a87b0d157980

Files of Interest with MD5 Hashes.

We're not too interested in carving data or seeing change commits staged in the write ahead log, so let's just open up the database in an SQLite browser and see what we are working with:

Pasted image 20260514194615.png

cache_controller.db - Tables of Interest

There are three tables that have the MEDIA_CONTEXT_TYPE field:

  • CACHE_FILE_CLAIM
  • CACHE_FILE_SAMPLED_TOMBSTONE
  • MEDIA_CONTEXT_TYPE_CACHE_POLICIES

A quick SQL query and we can see what tables we should look into further:

SELECT
    'CACHE_FILE_CLAIM' AS table_name,
    (SELECT COUNT(*) FROM CACHE_FILE_CLAIM) AS row_count
UNION ALL

SELECT
    'CACHE_FILE_SAMPLED_TOMBSTONE',
    (SELECT COUNT(*) FROM CACHE_FILE_SAMPLED_TOMBSTONE)
UNION ALL

SELECT
    'MEDIA_CONTEXT_TYPE_CACHE_POLICIES',
    (SELECT COUNT(*) FROM MEDIA_CONTEXT_TYPE_CACHE_POLICIES);

Results:

table_name row_count
CACHE_FILE_CLAIM 428
CACHE_FILE_SAMPLED_TOMBSTONE 23
MEDIA_CONTEXT_TYPE_CACHE_POLICIES 0

We can then see what MEDIA_CONTEXT_TYPE values we are working with:

SELECT
    *
FROM
    CACHE_FILE_CLAIM
GROUP BY
    MEDIA_CONTEXT_TYPE 

There are 12 sample points we can work from:

Pasted image 20260514194625.png

The EXTERNAL_KEY will be a good indicator for us later to validate the findings.

Now let's obtain the Snapchat APK file. There's a few methods, but I'll mention two:

  • Method 1: Extract the base.apk file directly from the forensic extraction.
  • Method 2: Download a (potentially untrusted) version from a 3rd party provider.

For method 1, if we open the \data\system\packages.xml we can see the Snapchat has the package name com.snapchat.android, installed under the directory /data/app/~~2OYI3NWAqov2Kgvu3KzgEw==/com.snapchat.android-LPpMfTzCI5PeRvfBpoFFrA==/, and inside this directory we can find the base.apk file (MD5 e87e1e308b72d209950f660a62dd5877). This is the primary android application package; the other apk files are supporting resources to the primary application, also referred to as a split APK. This is the best and most forensically sound way to analyse an Android package installed on a device. It's the exact evidence, no break in chain-of-custody, and repeatable.

The alternative method, but perfectly valid for research purposes, is to download a copy of the application's APK file from a 3rd party source such as from APKMirror. Be wary, the integrity of these files can not always be traced back to the original authors, and it may not exactly match the version installed on the device in question resulting in different features, modes of operations, and artefacts.

For this situation, we will stay with the base.apk version. Extract it out into a working directory, verifying of course, and let's continue.

File Name File Path Size (bytes) MD5
base.apk .\com.snapchat.android-LPpMfTzCI5PeRvfBpoFFrA==\base.apk 84713710 e87e1e308b72d209950f660a62dd5877
base.art .\com.snapchat.android-LPpMfTzCI5PeRvfBpoFFrA==\oat\arm64\base.art 3567616 cd989e4b8b4669afedb07a157dd7b051
base.odex .\com.snapchat.android-LPpMfTzCI5PeRvfBpoFFrA==\oat\arm64\base.odex 91676808 e1f30ed0c12260a0bed57a17f01b7d6b
base.vdex .\com.snapchat.android-LPpMfTzCI5PeRvfBpoFFrA==\oat\arm64\base.vdex 2160084 c0c26d08c48cee43d8614b4093718baf
app.metadata .\com.snapchat.android-LPpMfTzCI5PeRvfBpoFFrA==\app.metadata 8293 e9aa34e6f4a494db899a3a55e3c4c161
base.digests .\com.snapchat.android-LPpMfTzCI5PeRvfBpoFFrA==\base.digests 92 a378e32f90143ed6412d833d85f20139
base.dm .\com.snapchat.android-LPpMfTzCI5PeRvfBpoFFrA==\base.dm 2556198 cc2d1d00f3f5f3e8625d676f96365846
split_bloops_dynamic_sdk.apk .\com.snapchat.android-LPpMfTzCI5PeRvfBpoFFrA==\split_bloops_dynamic_sdk.apk 12721 43b338337aa698088906686450bd9585
split_bloops_dynamic_sdk.config.arm64_v8a.apk .\com.snapchat.android-LPpMfTzCI5PeRvfBpoFFrA==\split_bloops_dynamic_sdk.config.arm64_v8a.apk 2859481 1cf35495846403fcd0ae1a43d25122c9
split_config.arm64_v8a.apk .\com.snapchat.android-LPpMfTzCI5PeRvfBpoFFrA==\split_config.arm64_v8a.apk 73631145 5f7322c1a9318d588e0e402eebb7dc56
split_config.en.apk .\com.snapchat.android-LPpMfTzCI5PeRvfBpoFFrA==\split_config.en.apk 1319321 32eddfd5391d8ecf55df099c79afb4a1
split_config.xxhdpi.apk .\com.snapchat.android-LPpMfTzCI5PeRvfBpoFFrA==\split_config.xxhdpi.apk 2193095 646ae2b00bf590807f5f0678cf56d15c

Open Jadx, import the base.apk file, and then export out the source code:

jadx user interface and steps to export the source code.

Then import it into a text editor of your choice. We'll use VSCode:

Export of decoded base.apk loaded into VSCode.

Perform a global regex search for MEDIA.?CONTEXT.?TYPE (using .? to allow for variations in compiled code, such as camelCasing, snake_casing, kebab-casing, etc.) and we will see a collection of hits where the context type is referenced. One of them being a [enlighter lang="java"]public enum MediaContextType[/enlighter] in \sources\com\snapchat\client\mdp_common\MediaContextType.java:

Keyword search hits for the media context type.

Java enums are 0 indexed, so we can easily parse them out to determine what they represent in our original database:

Enum Value MediaContextType
0 BITMOJIIMAGES
1 LENSIMAGES
2 STICKERS
3 CHAT
4 FRIENDSTORYSNAP
5 TEMPUNASSIGNED
6 FRIENDSTORYTHUMBNAIL
7 RECOMMENDEDSTORYTHUMBNAIL
8 COGNACIMAGES
9 COMMERCEIMAGES
10 ADS
11 COMPOSERIMAGES
12 LENS
13 ONDEMAND
14 ONBOARDING
15 BLOOPS
16 RECOMMENDEDUSERSTORYSNAP
17 LOCALIZATIONSTRINGS
18 MUSIC
19 MEMORIESSNAP
20 PUBLISHERSTORYSNAP
21 GIPHYSTICKERS
22 UGCLENSASSETS
23 FRIENDSTORYFIRSTFRAME
24 RECOMMENDEDUSERSTORYFIRSTFRAME
25 GEOFILTER
26 MEMORIESTHUMBNAIL
27 LENSBITMOJI
28 PUBLISHERSTORYFIRSTFRAME
29 MAPS
30 SNAPSHOTS
31 SYSTEMTESTIMAGES
32 SYSTEMTESTVIDEOS
33 ARBUSINESS
34 PREVIEWSNAP
35 SPECTACLES
36 CHEERIOS
37 EXPORTEDMEDIASHARE
38 INCLUSIONPANELSURVEY
39 COMMUNITIES
40 SPOTLIGHTSNAP
41 TOSHTML
42 COMPOSERMODULESARCHIVE

Now we can create a simple SQL query to apply these enum values to our cache_controller.db file. Only a handful have been provided above to give an idea on how to do it:

SELECT
    CASE MEDIA_CONTEXT_TYPE
    WHEN 0 THEN "BITMOJIIMAGES"
    WHEN 1 THEN "LENSIMAGES"
    WHEN 2 THEN "STICKERS"
    WHEN 3 THEN "CHAT"
    WHEN 5 THEN "TEMPUNASSIGNED"
    WHEN 6 THEN "FRIENDSTORYTHUMBNAIL"
    WHEN 7 THEN "RECOMMENDEDSTORYTHUMBNAIL"
    WHEN 11 THEN "COMPOSERIMAGES"
    WHEN 12 THEN "LENS"
    WHEN 13 THEN "ONDEMAND"
    WHEN 25 THEN "GEOFILTER"
    WHEN 29 THEN "MAPS"
    ELSE MEDIA_CONTEXT_TYPE
    END AS "MediaContextTypeEnum",
    EXTERNAL_KEY
    --,*
FROM
    CACHE_FILE_CLAIM
GROUP BY
    MEDIA_CONTEXT_TYPE

See the results below:

MediaContextTypeEnum EXTERNAL_KEY
BITMOJIIMAGES bitmoji-ua-selfie.bitmoji-ua-selfie-100097697793_2-s5~10226021~2~webp~CIRCLE~ua
LENSIMAGES lens_icon.lens_icon-https://bolt-gcdn.sc-cdn.net/3/00jO6Ss9HD4aLmxkgB79g?bo=EhgaABoAMgF9OgEEQgYI8NvvmQZIAlASYAE%3D&uc=18
STICKERS ct_platform_item.ct_platform_item-33uTbBhpgLDvcw7O1RlcW
CHAT chat_media_thumbnail.chat_media_thumbnail-5AKwA9Y3n9MOeXVtLgnaQ.1020
TEMPUNASSIGNED 4809796c-65e1-e79b-f0a2-3d6b3b4d39ea
FRIENDSTORYTHUMBNAIL story_thumb.story_thumb-content://com.snapchat.android.provider//story_thumb/story_snap/08D481BD-B007-4D47-9E9F-10FD38F3DD0E~9283499e-a384-f094-47b5-ad2a7b3ea949/my_story_ads79sdf/2/DEFAULT/true
RECOMMENDEDSTORYTHUMBNAIL spotlight_thumb.spotlight_thumb-https://cf-st.sc-cdn.net/d/HgUVdyKAzbUdi5bp2cCEI.256.IRZXSOY?mo=Gk0aCxoAGgAyAQRQLmABWhBEZkxhcmdlVGh1bWJuYWlsogEUCIACIg8KAkgDEgAqB0lSWlhTT1miARQImgoiDwoCSAISACoHSVJaWFNPWQ%3D%3D&uc=46
COMPOSERIMAGES composer_animated_content.composer_animated_content-https://cf-st.sc-cdn.net/d/5vpAIaiDyVKWaLwcW4QVZ?bo=EhQaABoAMgIEfUgCUAhaBAjQqwFgAQ%3D%3D&uc=8
LENS lens_content_archive.lens_content_archive-05CAA6EF7CC3CC5579EE70062C37DFF82B945E0B2E7E63F433D5B23FF4F18A63
ONDEMAND PerceptionMl.PerceptionMl-fastdnn_fashion_classifier_default_BACKEND_LIBDNN_3
GEOFILTER external_geofilter.external_geofilter-https://cf-st.sc-cdn.net/d/0IHwOlnG7L7MyOeFCFDS8?mo=Gm4aIhIVMElId09sbkc3TDdNeU9lRkNGRFM4GgAaADIBBFAaYAFaDUdlb2ZpbHRlclByaW2iARUIASIRCg8yCwUHDQ8RcnR2d3t9SAGiASAI_gciGwoXOgsFBw0PEXJ0dnd7fUIGCMCZ5bQGSAISAA%3D%3D&uc=26
MAPS static-map-for-profile.static-map-for-profile-0.0+0.0+0+498+184+false+

So, to answer the original question - MEDIA_CONTEXT_TYPE = 5 in Snapchat's cache_controller.db represents TEMPUNASSIGNED: a cache bucket for media not yet assigned to a specific context type.

The above method of figuring out the media context can be applied to later versions of the application. This is also not just limited to the media context, or even just Snapchat, but can be applied to all Android applications for:

  • Database naming
  • Folder/file name conventions
  • Logic operations
  • URL parsing

TL;DR

With the current version of Snapchat (com.snapchat.android_14.10.0.47-293972, as of 13/06/2026) the MediaContextType enum maps to:

Enum Value MediaContextType
1 BITMOJIIMAGES
2 LENSIMAGES
3 STICKERS
4 CHAT
5 FRIENDSTORYSNAP
6 TEMPUNASSIGNED
7 FRIENDSTORYTHUMBNAIL
8 RECOMMENDEDSTORYTHUMBNAIL
9 COGNACIMAGES
10 COMMERCEIMAGES
11 ADS
12 COMPOSERIMAGES
13 LENS
14 ONDEMAND
15 ONBOARDING
16 BLOOPS
17 RECOMMENDEDUSERSTORYSNAP
18 LOCALIZATIONSTRINGS
19 MUSIC
20 MEMORIESSNAP
21 PUBLISHERSTORYSNAP
22 GIPHYSTICKERS
23 UGCLENSASSETS
24 FRIENDSTORYFIRSTFRAME
25 RECOMMENDEDUSERSTORYFIRSTFRAME
26 GEOFILTER
27 MEMORIESTHUMBNAIL
28 LENSBITMOJI
29 PUBLISHERSTORYFIRSTFRAME
30 MAPS
31 SNAPSHOTS
32 SYSTEMTESTIMAGES
33 SYSTEMTESTVIDEOS
34 ARBUSINESS
35 PREVIEWSNAP
36 SPECTACLES
37 CHEERIOS
38 EXPORTEDMEDIASHARE
39 INCLUSIONPANELSURVEY
40 COMMUNITIES
41 SPOTLIGHTSNAP
42 TOSHTML
43 VALDIMODULESARCHIVE
44 NOTIFICATIONS
45 TINSEL

Here's a SQL template to build from with the above values:

SELECT
    CASE MEDIA_CONTEXT_TYPE
      WHEN 1 THEN CONCAT(MEDIA_CONTEXT_TYPE, " - BITMOJIIMAGES")
      WHEN 2 THEN CONCAT(MEDIA_CONTEXT_TYPE, " - LENSIMAGES")
      WHEN 3 THEN CONCAT(MEDIA_CONTEXT_TYPE, " - STICKERS")
      WHEN 4 THEN CONCAT(MEDIA_CONTEXT_TYPE, " - CHAT")
      WHEN 5 THEN CONCAT(MEDIA_CONTEXT_TYPE, " - FRIENDSTORYSNAP")
      WHEN 6  THEN CONCAT(MEDIA_CONTEXT_TYPE, " - TEMPUNASSIGNED")
      WHEN 7 THEN CONCAT(MEDIA_CONTEXT_TYPE, " - FRIENDSTORYTHUMBNAIL")
      WHEN 8 THEN CONCAT(MEDIA_CONTEXT_TYPE, " - RECOMMENDEDSTORYTHUMBNAIL")
      WHEN 9 THEN CONCAT(MEDIA_CONTEXT_TYPE, " - COGNACIMAGES")
      WHEN 10 THEN CONCAT(MEDIA_CONTEXT_TYPE, " - COMMERCEIMAGES")
      WHEN 11 THEN CONCAT(MEDIA_CONTEXT_TYPE, " - ADS")
      WHEN 12 THEN CONCAT(MEDIA_CONTEXT_TYPE, " - COMPOSERIMAGES")
      WHEN 13 THEN CONCAT(MEDIA_CONTEXT_TYPE, " - LENS")
      WHEN 14 THEN CONCAT(MEDIA_CONTEXT_TYPE, " - ONDEMAND")
      WHEN 15 THEN CONCAT(MEDIA_CONTEXT_TYPE, " - ONBOARDING")
      WHEN 16 THEN CONCAT(MEDIA_CONTEXT_TYPE, " - BLOOPS")
      WHEN 17 THEN CONCAT(MEDIA_CONTEXT_TYPE, " - RECOMMENDEDUSERSTORYSNAP")
      WHEN 18 THEN CONCAT(MEDIA_CONTEXT_TYPE, " - LOCALIZATIONSTRINGS")
      WHEN 19 THEN CONCAT(MEDIA_CONTEXT_TYPE, " - MUSIC")
      WHEN 20 THEN CONCAT(MEDIA_CONTEXT_TYPE, " - MEMORIESSNAP")
      WHEN 21 THEN CONCAT(MEDIA_CONTEXT_TYPE, " - PUBLISHERSTORYSNAP")
      WHEN 22 THEN CONCAT(MEDIA_CONTEXT_TYPE, " - GIPHYSTICKERS")
      WHEN 23 THEN CONCAT(MEDIA_CONTEXT_TYPE, " - UGCLENSASSETS")
      WHEN 24 THEN CONCAT(MEDIA_CONTEXT_TYPE, " - FRIENDSTORYFIRSTFRAME")
      WHEN 25 THEN CONCAT(MEDIA_CONTEXT_TYPE, " - RECOMMENDEDUSERSTORYFIRSTFRAME")
      WHEN 26 THEN CONCAT(MEDIA_CONTEXT_TYPE, " - GEOFILTER")
      WHEN 27 THEN CONCAT(MEDIA_CONTEXT_TYPE, " - MEMORIESTHUMBNAIL")
      WHEN 28 THEN CONCAT(MEDIA_CONTEXT_TYPE, " - LENSBITMOJI")
      WHEN 29 THEN CONCAT(MEDIA_CONTEXT_TYPE, " - PUBLISHERSTORYFIRSTFRAME")
      WHEN 30 THEN CONCAT(MEDIA_CONTEXT_TYPE, " - MAPS")
      WHEN 31 THEN CONCAT(MEDIA_CONTEXT_TYPE, " - SNAPSHOTS")
      WHEN 32 THEN CONCAT(MEDIA_CONTEXT_TYPE, " - SYSTEMTESTIMAGES")
      WHEN 33 THEN CONCAT(MEDIA_CONTEXT_TYPE, " - SYSTEMTESTVIDEOS")
      WHEN 34 THEN CONCAT(MEDIA_CONTEXT_TYPE, " - ARBUSINESS")
      WHEN 35 THEN CONCAT(MEDIA_CONTEXT_TYPE, " - PREVIEWSNAP")
      WHEN 36 THEN CONCAT(MEDIA_CONTEXT_TYPE, " - SPECTACLES")
      WHEN 37 THEN CONCAT(MEDIA_CONTEXT_TYPE, " - CHEERIOS")
      WHEN 38 THEN CONCAT(MEDIA_CONTEXT_TYPE, " - EXPORTEDMEDIASHARE")
      WHEN 39 THEN CONCAT(MEDIA_CONTEXT_TYPE, " - INCLUSIONPANELSURVEY")
      WHEN 40 THEN CONCAT(MEDIA_CONTEXT_TYPE, " - COMMUNITIES")
      WHEN 41 THEN CONCAT(MEDIA_CONTEXT_TYPE, " - SPOTLIGHTSNAP")
      WHEN 42 THEN CONCAT(MEDIA_CONTEXT_TYPE, " - TOSHTML")
      WHEN 43 THEN CONCAT(MEDIA_CONTEXT_TYPE, " - VALDIMODULESARCHIVE")
      WHEN 44 THEN CONCAT(MEDIA_CONTEXT_TYPE, " - NOTIFICATIONS")
      WHEN 45 THEN CONCAT(MEDIA_CONTEXT_TYPE, " - TINSEL")
      ELSE CONCAT(MEDIA_CONTEXT_TYPE, " - UNKNOWN")
   END AS "MediaContextTypeEnumWithId"
    ,*
FROM
    CACHE_FILE_CLAIM