September 23, 2024
Article

When is an app not an app? Investigating WebAPKs on Android

In his new blog, Principal Analyst Alex Caithness dives into progressive web apps and WebAPKs and comes up to ask “When is an app not an app”? And more importantly, what data can possibly be extracted from them if you know where to look?

Recently while catching up on some interesting blogs, CCL’s R&D team happened across this write-up by ESET documenting a novel phishing attack using two technologies: progressive web apps and WebAPKs. This got us thinking more widely about how these technologies operate on Android and how we could detect their use and extract the data they might store on a device. What we found highlighted a number of areas where, unless you know what to look for, opportunities to maximise the meaning of this data could be missed.

Progressive Web Apps and WebAPK

A Progressive Web App (PWA) is an application which is built using web technologies (HTML, CSS, JavaScript) but is designed to give the look and feel of a native application. It is, in essence, just another website – it still needs a browser to be viewed and used. Depending on the browser being used, it may be launched in a special window without any of the usual browser controls (e.g., address bar, navigation controls, etc.). This is done so that it may have the look and feel of being a “fully fledged” native application with its own window, launcher icon, etc.

On modern versions of Android, when PWAs are installed by Chrome they are further enhanced by Chrome generating a WebAPK. A WebAPK wraps the PWA as a “real” app, allowing it to appear on the device’s app launcher, register intents with the operating system, and so on. To the user, this “application” appears to be a “first class citizen” of the operating system, on a par with any other native application; but to a digital forensics practitioner the story is somewhat more complex. Let’s try to unpick this tangled web …

WebAPK
Figure 1 Is this an app? Or just a website?

Sidenote: How does this differ from Electron/WebView2?

Electron (along with similar technologies like WebView2) is a framework that can “wrap” an application based on web technologies so that it can be presented to the user in a way that mirrors a native application. This sounds a lot like a PWA, and not by accident – in many cases these frameworks may just be wrapping a PWA. There are a few key, important differences though:

  • An Electron application is wrapped in its own “browser”. It is separate from other browsers (or other Electron apps) installed on the system. A PWA, gives the appearance of being a separate entity but is launched by the browser that installed it.
  • The Electron framework provides a web application further access to the host operating system, e.g., access to the host’s file system, whereas a PWA running in the browser would be sandboxed and only able to perform operations that a “normal” website could.
  • The Electron framework also packages node.js in order to build a local web server for the application to use; a PWA running in the browser would need to reach out to the web for many operations (although it may still offer offline operations using browser technologies such as service workers).

How do you know you’ve got a WebAPK application?

From a user’s perspective

The “point” of a WebAPK application for a user is that it looks and acts like a “real” application. From the perspective of the device’s UI, the app appears to have a normal icon, it appears in the app launcher alongside other apps, it appears in the settings alongside other apps for uninstalling, and so on.

WebAPK application
Figure 2 A WebAPK application in the launcher - note the "Site settings" option

One clue can be spotted by “long-pressing” the application’s icon in the launcher: an additional option for “Site settings” that sits alongside the standard “App info” and “Pause app” menu items, which leads to a settings dialog which allows the user to manage the data stored by and the permissions granted to the application.

Depending on the version of Android, another indication may be found in the “App info” screen for the application, or this screen may straight up lie to you! We tested this behaviour both on version 14 of Android (the most recent version available to most users at the time of writing), and a beta of the upcoming version 15.

In version 15, the “App info” screen will show that the application was installed by Chrome rather than another store app (typically this would be the Play Store), which helps to confirm its status as a PWA or WebAPK – this is a useful indicator for us.

In version 14 (which is much more likely to be the version encountered at the time of writing), we observed that the “App info” screen incorrectly identified the app as being installed by the Play Store (which is a lie - deeply unhelpful for us as digital investigators, and a timely reminder that we need to validate our findings always). We assume that this behaviour is a bug in Android as tapping the button to go to the (alleged) Play Store page for this app results in an error dialog.

WebAPK's App Info dialog
Figure 3 A WebAPK's App Info dialog. On the left Android 15 correctly identifies the source of the app as Chrome; on the right Android 14 erroneously states the app is from the Play Store.

If the app is installed as a “basic” progressive web application (the default on earlier versions of Android and Chrome) then there is a far more obvious visual cue, as the icon on the home screen will be superimposed with the browser’s icon. In this case, the PWA will also be absent from the app drawer and will not be listed as an installed application in the Settings app.

WebAPK App
Figure 4 A "basic" progressive web app on the Android home screen – note the superimposed Chrome icon.

From a file system perspective

The primary indication of a WebAPK application being present on a device is its package name. The package name is used by Android as an identifier for the application. They generally take a form along the lines of “com.example.abc123”; so for example, the Chrome browser application on Android has the package name “com.android.chrome”. The package name is found throughout the file system, most notably as the application’s folder in “/data/data” and in the “packages.xml” (not actually an XML file anymore, rather an ABX file) and “packages.list” files which list installed packages on the device.

The package name for a WebAPK will take the form: “org.chromium.webapk.[an identifier]”, for example, one of the apps we tested was assigned the package name: “org.chromium.webapk.a4241cb488be5dc45_v2”. This package name could well be misleading if you weren’t on the lookout for the “webapk” portion of the name, as “org.chromium” could reasonably be assumed to be related to some official component of the Chrome/Chromium browser.

This package name is found in all of the expected locations (as a folder in “data/data”, in the two packages files, etc.), however what isn’t clear at all from that package name is which app it is.

Given  its ubiquity when it comes to seeing which packages are installed on a device, the “packages.xml” file might be a good place to go searching for more details on our WebAPK application. As expected, the “package” element related to this app only shows   the package name (in Android 15, the package element also lists the “installer” and “updater” as being Chrome, unlike other applications which typically show “com.android.vending”; in Android 14 it incorrectly showed the default vending value). By searching for a corresponding “package-state” element, we can find an indication of the friendly name for the application   which is displayed to the user.

WebAPK file system perspective
Figure 5 A WebAPK "package" element in packages.xml (Android 15, so the installer is correctly shown to be Chrome)

Figure 6 The same WebAPK's "package-state" element, showing a more useful identifier for the application

There are other locations we identified which can be used to correlate the package name to the friendly name:

  • In the APK: the WebAPK is a real APK file, so it can be typically be located in “/data/app” (the actual path is listed in packages.xml). An APK file is a ZIP archive, and one of the files you can find inside the archive is “AndroidManifest.xml”. The “activity-alias” element in this XML document   contains an attribute named “android:label” which contains the friendly name of the WebAPK (as with “packages.xml”, this is not actually an XML document as it’s stored using another, different Binary XML format – not ABX this time; it can be converted using any number of APK reverse engineering tools, such as APKTool or the “Profile or Debug APK” feature of Android Studio).
  • Vending: although the application isn’t installed via a “store” as such, its installation still appears to be managed by the default vending system, so there are records in the SQLite databases “/data/data/com.android.vending/databases/download_service” and "/data/data/com.android.vending/databases/install_queue.db” which correlate the package name and the friendly name.
  • Launcher: the launcher is a special app that is responsible for the home screen on Android, where users can organise icons and widgets and from which apps are launched. On our Pixel test device, the launcher is “com.google.android.apps.nexuslauncher” and we identified 2 databases which contained records correlating the package and friendly names: “/data/data/com.google.android.apps.nexuslauncher/databases/launcher_4_by_5.db” and “/data/data/com.google.android.apps.nexuslauncher/databases/app_icons.db”. Other launchers come pre-installed with other devices, and further launchers may be installed via an app store, so these databases won’t be present on all devices, but it would seem likely that other launchers store similar information.
  • The Digital Wellbeing application keeps track of the device usage habits of an Android user. It can make suggestions on the basis of usage patterns, but also provides features to help users adjust how they interact with apps, notifications etc. The friendly name of an application and its package name are recorded in an SQLite database: “/data/data/com.google.android.apps.wellbeing/databases/app_config”.

Where the data isn’t.

Conventional knowledge suggests that the first place to go looking for an app’s data is its package folder in “/data/data”. For a WebAPK if we head over there, we find… not much.    Some basic preferences, but little related to user activity.

During testing we were making use of NowSecure’s extremely useful fsmon to keep tabs on where data was being sent as we performed actions in the application. And, well…

Of course, it’s all in Chrome.

The activity related to using the WebAPK based application was all hitting the data folder for the device’s installation of Chrome. On the one hand this should be of little surprise sense given that the PWA is being run by Chrome, but what was slightly jarring was how little separation there was between the PWA’s data and the rest of Chrome.

We’ve written previously about the types of technologies used by websites to persist data on users’ machines, such as IndexedDB and WebStorage, and these data stores are, of course, used by PWAs too. To process data for this application, we would be looking to artefacts in these data stores, as well as data held in the web cache, history, cookies etc., and bringing them together to give a picture of the user’s activities on the web app - exactly the approach we have been advocating when dealing with browser artefacts, and the reason that these data formats are supported directly in CCL’s data exploration tool RabbitHole and why we created our browser forensics tool Mister Skinnylegs.

This does raise a question: how do we differentiate “app” usage from general browser usage? And the answer is… for the most part it doesn’t appear that we can. The WebAPK application is just running in Chrome, even if it doesn’t look like it to the user. Data stores like Local Storage, Session Storage and IndexedDB appear no different to if the site had been used through the “real” browser and we can find no clues in cache entries either.

There are a few indications that we have identified that show that browser data might be connected to a WebAPK/PWA though, which luckily all have timestamps associated with them.

The first indicator is in the History database. Initially accessing a WebAPK is just a visit to a website and using it might also involve web navigation (although many progressive web apps are single-page sites), these all generate records in the History database.

Visits in the history database have a “transition” field, which is stored as an integer value, but is actually storing a set of binary flags. When these flag values are parsed (the flags are defined in page_transition_types.h), the visit which represents the WebAPK application being opened will contain the transition flag “PAGE_TRANSITION_FROM_API” which is distinct from normal browsing records (but could feasibly be present for other reasons). Other navigation events that take place within the PWA do not have this flag however, but it should be able to be identified as part of the app activity by way of the “from_visit” field which shows chains of navigations. Be aware that different tools parse and show this information in differing levels of detail (and some tools may not show it at all); the screenshot below is from our free research tool for Chrome artefacts and you can see the app launches where the Transition field includes “from_api”.

Parsed History database
Figure 7 Parsed History database showing WebAPK launches where the transition includes "from_api".

The next, and arguably best indicator (if it is present) comes from the “custom_tabs” artefact. This resides outside of the Chrome profile folder in “/data/data/com.android.chrome/app_tabs/custom_tabs” and contains tab and tab state files for the special “featureless” browser instances that the PWA/WebAPK runs in. These files are the same structure as those found in the main numbered folder, and the “tab” files contain navigation events (encoded as a pickle, structure documented here and supported in our Chromium Python library) which include a timestamp for when the navigation took place.

The presence of these files alone is a good indication that PWAs or WebAPKs have been used, and they do appear to persist for some time after the application has been closed (including between restarts), but we would expect to see these purged at some point, in line with Chrome’s “main” tab state files.

Summing up

CCL’s R&D department have long been banging the drum with regards to the richness of evidence that can be uncovered by treating browser artefacts related to particular websites and Web apps holistically: bringing together data from all of the various data stores in the browser to get the full picture. With progressive web apps and their new elevated status as WebAPKs in Android, we have applications which otherwise appear to be native to the OS whose data can only be considered in this fashion.

Being able to identify the presence of a WebAPK application, understanding what it is and knowing where its data is likely to be stored (and where its data will not be stored) will be important skills for any DFIR practitioner working with Android devices.

We're here to help

Our experts are on hand to learn about your organisation and suggest the best approach to meet your needs. Contact an expert today.

Get in touch