This contains the artifacts for our ACM CCS 2025 paper: "Pixnapping: Bringing Pixel Stealing out of the Stone Age”. Checkout our website for more information.
Disclaimer: this is a research repository and is released to support more research. DO NOT use this code for malicious purposes.
Pixnapping is a new Android pixel stealing framework that bypasses all browser mitigations and can even steal secrets from non-browser apps. Our key observation is that Android APIs enable an attacker to create an analog to Stone-style attacks outside of the browser. Specifically, a malicious app can force victim pixels into the rendering pipeline via Android intents and compute on those victim pixels using a stack of semi-transparent Android activities. Crucially, our framework enables stealing secrets only stored locally (e.g., 2FA codes and Google Maps Timeline), which have never before been in reach of pixel stealing attacks.
We instantiate our pixel stealing framework on Google and Samsung phones—which differ in both hardware and graphical software. On the Google phones, we additionally provide evidence that the pixel color-dependent timing measured in our attack is due to GPU graphical data compression. We demonstrate end-to-end attacks that steal pixels from both browser and non-browser victims, including accounts.google.com, gmail.com, Google Maps, Google Messages, and Venmo. Finally, we demonstrate an end-to-end attack capable of stealthily stealing security-critical and ephemeral2FA codes from Google Authenticator in under 30 seconds.
Please cite our work if you use it! Thanks :D!
@inproceedings{wang2025pixnapping,
author = {Alan Wang and Pranav Gopalkrishnan and Yingchen Wang and Christopher W. Fletcher and Hovav Shacham and David Kohlbrenner and Riccardo Paccagnella},
title = {Pixnapping: Bringing Pixel Stealing out of the Stone Age},
booktitle = {CCS},
year = {2025}
}
Phone Versions: Pixel 6, Pixel 7, Pixel 8, Pixel 9, and Galaxy S25 Android Versions: 13, 14, 15, and 16 (up to BP3A.250905.014)
This entire repo is just one large Android Studio project, so you can just import the entire repo into Android Studio. The breakdown of specific Java/C++ files is as follows:
java/com.example.pixnapping/: houses all the Java code for the project.MainActivity.java: first activity that appears when you open our app. Has all the logic to launch and configure our attacks.PixnappingFramework.java: most of the logic for our attacks are located in this file. Most notably, this activity launches our attacks activity stack. All our attacks from Section 5 of our paper are located in this file.GoogleAuthStealer.java: all of the Google Authenticator 2FA attack logic (Section 6 of our paper) are located in this file.ActivityController.java: helper file to launch activities.StackedActivity.java: this implements the transmitting activities and encoding activity of the activity stack.MaskingActivity.java: this implements the masking activity of the activity stack.TestVictim.java: this is a fake victim with the 48x48 checkerboard.InternalFileWriter.java: this contains helper functions for logging.GraphicsManipulator.java: this contains code to manipulate activity graphics. Most notably, this contains our enlargement technique.CustomTabs.java: helper functions to open Chrome custom tabs.CoordFinder.java: this houses the coordinate finder logic.CompressionRcaActivity.java: contains the logic for our RCA that attributes the observed rendering time difference to GPU compression on Pixel devices (Section 4.1 of our paper).
cpp/*: houses all the lower-level code (C++) for the project. No functionality is really implemented here, it is just to demonstrate how you can get execute native code in Android apps.res/layout/activity_main.xml: layout for the main activity.coord_finder.xml: layout for the coordinate finder activity.hiding.xml: layout for the hiding activity.surfaceview.xml: layout used by the enlargement activity on the S25.transparent.xml: transparent layout for most of the activities in the stack.
disclosures/: this folder contains PoCs we submitted to Google- Right now this folder only contains the app list disclosure in
appListBypass.zip
- Right now this folder only contains the app list disclosure in
- Future releases
- We plan to release additional versions of our Pixnapping code base in the future
Simply import the project into Android Studio and then it should automatically build.
This section details the instructions to run the attacks we have in the project.
- Install Android Studio on your device
- Clone the repo somewhere:
git clone https://github.com/TAC-UCB/pixnapping.git. - In Android Studio open
file -> new -> import projectand import the entire repo as the project. - Enable developer options on the target Android phone and enable USB debugging .
- Connect the phone to the computer with Android Studio.
- Ensure the phone is connected to wifi.
- Ensure the phone is vertical and stays in vertical mode throughout the duration of the attacks.
- Ensure the phone is in light mode (Go to settings and search for the "Dark theme" setting, turn it off). Our attack is not dependent on the phone being in light mode, however, our PoC is specifically tuned to light mode.
- Depending on the attack, certain apps will need to be installed (e.g., Google Chrome, Venmo, etc.). The specific apps needed are discussed below.
- (Optional) Ensure your screen off time is set to a long duration (think >1 hour).
- Run the app on the phone, you see a screen with a bunch of buttons appear (like in the image below).
- Click one of the bottom buttons to change the “Phone Version Selected” to your device version.
- Hit a button with the test you want to run (detailed below).
- Make sure to have log cat open to see the output (debug reasons) (it is also helpful to add
package:mineto the package filter to the right of the phone drop down menu in log cat). 13) Log cat can be opened by hitting the cat on the bottom right. - Do not mess with the phone after starting the attack/experiment. Disturbances will lead to errors in the exacted pixels.
- Each attack/experiment will log data into a specific file under
/data/data/com.example.pixnapping/filesin the “Device Explorer” menu. These locations are also detailed below. - All done :)
It is important to note that the coordinates each of these PoCs steal from is hard coded and could vary at any time! Therefore, we highly recommend you check the coordinates the PoC is leaking from ahead of time with the coordinate finding utility discussed below.
This image depicts what you should see when you open our app.
The following details what each upper button maps to:
- Attacks from Section 5 of our paper. The leaked pixels for these attacks are dropped in
/data/data/com.example.pixnapping/files/pixel_stealer/recordedPixels.png.accounts.google.com: This attack leaks the name from the Google Account logged in on the phone.accounts.google.com address: This attack leaks the home address from the Google Account logged in on the phone.gmail.com: This attack leaks the top most email in the Gmail account logged in on the phone.Perplexity: This leaks the top most AI chat thread from the Perplexity account logged in on the phone.Timeline: This leaks the top most Timeline entry on 1/1/2025 from Google Maps.SMS Messages: This leaks the most recent message from the number 111-111-1111 on the phone. Note: if you run this attack please change the target number inPixnappingFramework.javato the number you actually wish to target.Venmo: This leaks the Venmo account balance of the logged in user on the phone.Signal: This leaks the most recent message from the number 111-111-1111 on the phone. Note: if you run this attack please change the target number inPixnappingFramework.javato the number you actually wish to target.
2FA Test: This will continuously leak the top most 6-digit 2FA code from Google Authenticator. This corresponds to Section 6 of our paper. The leaked codes are displayed in Log Cat or in/data/data/com.example.pixnapping/files/googleAuthData/log.txt.Simple: This is a simple test that uses our framework to distinguish between a black/white pixel. This is used for Figures 4 & 6 of our paper. Note, this test does not produce arecordedPixels.pngfile and instead logs the raw timing values incalibrationData.csv.Checkerboard: This is a simple test which leaks the pixels in the 48x48 checkerboard used by Andrysco et al. This corresponds to Section 4.3 of our paper. The leaked checkerboard is shown in/data/data/com.example.pixnapping/files/pixel_stealer/recordedPixels.png.RCA: This is the root cause analysis experiment which attributes the observed rendering time difference to GPU graphical data compression. This is used to create Figures 5 and Section 4.1 of our paper.Coordinate finding utility: A simple tool to allow users to manually find coordinate positions on the screen. Instructions for use are below.
The following details how to configure the attacks (lower buttons):
Pixel 6: sets the attack configuration for Pixel 6 devices.Pixel 7: sets the attack configuration for Pixel 7 devices.Pixel 8: sets the attack configuration for Pixel 8 devices.Pixel 9: sets the attack configuration for Pixel 9 devices.S25: sets the attack configuration for Galaxy S25 devices.- Note: the selected device is displayed in a TextView on screen so you can see what the current configuration is.
Note: the coordinates we leak are specific for our specific secrets! The coordinate positions will be different for the secrets that you attempt to leak! To find the coordinate positions refer to the Coordinate Finder Utility section below.
This details what setup you need to do for each attack (Section 5 and Section 6 of our paper)
accounts.google.com: make sure you install Google Chrome and log in to your Google account. Ensure your account has a name which is displayed when you go tohttps://accounts.google.com(should be “Welcome, YOUR NAME”).accounts.google.com address: make sure you install Google Chrome and log in to your Google account. Ensure you fill out the home address field of the google account. When you navigate tohttps://myaccount.google.com/personal-info#:~:text=chevron_right-,Addresses,-Your%20home%20andyou should see the home address field filled in.gmail.com: make sure you install Google Chrome and log in to your Gmail account. Note: this attack requires the top most email to stay constant for several hours (10-25 hours).Perplexity: make sure you install Google Chrome and log in to your Perplexity account. Ensure you have some chat history by navigating tohttps://www.perplexity.ai/library.Timeline: make sure you install Google Maps and are logged into your Maps account. The attack will leak an entry from the date 1/1/2025 so make sure that there is a timeline entry there, add one there yourself, or change the target date to a different date.SMS MessagesandSignal: ensure Google Messages is installed. Modify the target SMS conversation from 111-111-1111 to one of your choosing. To do so modifyPixnappingFramework.javain the functionopenTargetAndOverlay.Venmo: ensure Venmo is installed and that you are logged into Venmo on your phone.2FA test: ensure Google Authenticator is installed and you are logged into your Google Authenticator account. Ensure at least one 2FA code exists in your account. If you want you can load a dummy 2FA code entry into Google Authenticator. If you do so, fill in theSECRETstring variable insideGoogleAuthStealer.java. Otherwise, ignore the "correct 2FA code” and accuracy measurements outputted into Log Cat and just focus on the “extracted 2FA code”.simpleandcheckerboard: if you are using the S25 please ensure Google Chrome is installed which is used to help with those tests. For Pixel devices, no setup is needed.
This section details how to run our root cause analysis experiments. Note, we only do RCA on the Pixels (not the S25). The steps are detailed below:
- Specific device configurations don’t work for this experiment. Instead you manually need to adjust the number of transmitting activities used in
CompressionRcaActivity.java. Specifically, change the lineActivityController.launchStackedActivity(CompressionRcaActivity.this, ActivityController.stackedActivityConfigs.STACKED_BLUR_ACTIVITIES.ordinal(), 0, 60, 0);toActivityController.launchStackedActivity(CompressionRcaActivity.this, ActivityController.stackedActivityConfigs.STACKED_BLUR_ACTIVITIES.ordinal(), 0, <TRANSMITTING ACTIVITIES>, 0);. - Install our app on the target device.
- Open Arm Performance Studio’s Streamline tool.
- You should see our app and the target device in the Streamline menu. Select the MainActivity of the app in the menu.
- Make sure to also select the “Capture Arm GPU profile” option.
- Hit start capture. This should launch the app.
- Once the app starts hit the RCA experiment button, launching the experiment.
- During the experiment you want to collect results from the “Mali Core External Memory Reads” monitor.
- Rendering time results are reported in Log Cat and under
/data/data/com.example.pixnapping/files/compression_re/ - You can see the device thermal state in Streamline as well.
- Refer to our paper (Section 4.1) for how to additionally rule out Hertzbleed/Hot pixel effects.
Our framework will leak from a region of screen dictated by the (left, top, right, bottom) coordinates. For our attacks we have preprogrammed the coordinates (which you may want to slightly adjust). However, if you want to leak from other positions of the screen we also provide a utility to manually find the coordinate positions on the screen.
To use this utility, first open the target window you wish to find coordinates in.
Next, start the Pixnapping app and hit the “Coordinate finding utility” button.
Hit anywhere on the screen to open a semi-transparent blue rectangle which is the region you wish to leak.
You can use the buttons to adjust the height, width, and its position on the screen.
You can also just tap anywhere on the screen to move the rectangle where you tapped.
The coordinates of the blue rectangle are then outputted in Log Cat.
I recommend changing the starting width and height in CoordFinder.java so you don’t have to hit the width/height adjustment buttons often.
