Depix is a PoC for a technique to recover plaintext from pixelized screenshots.
This implementation works on pixelized images that were created with a linear box filter. In this article I cover background information on pixelization and similar research.
- 24 dec '24: Made repo private, changed the name and made it public again. It just had a ridiculous amount of stars because of the media hype, which didn't feel right. I made this as a quick PoC for a company back in the day, because someone pixelated part of a password for an account with Domain Admin rights. The hype got running by the catchy image and eventually this repo had 26152 stars. If I ever get this much stars again, I want it to be for a project that I'm that hyped about as well.
- 27 nov '23: Refactored and removed all this pip stuff. I like scripts I can just run. If a package can't be found, just install it. Also added
tool_show_boxes.py
to show how bad the box detector is (you have to really cut out the pixels exactly). Made a TODO to create a version that just cuts out boxes of static size.
- Install the dependencies
- Run Depix:
python3 depix.py \
-p /path/to/your/input/image.png \
-s images/searchimages/debruinseq_notepad_Windows10_closeAndSpaced.png \
-o /path/to/your/output.png
- Depixelize example image created with Notepad and pixelized with Greenshot. Greenshot averages by averaging the gamma-encoded 0-255 values, which is Depix's default mode.
python3 depix.py \
-p images/testimages/testimage3_pixels.png \
-s images/searchimages/debruinseq_notepad_Windows10_closeAndSpaced.png
- Depixelize example image created with Sublime and pixelized with Gimp, where averaging is done in linear sRGB. The backgroundcolor option filters out the background color of the editor.
python3 depix.py \
-p images/testimages/sublime_screenshot_pixels_gimp.png \
-s images/searchimages/debruin_sublime_Linux_small.png \
--backgroundcolor 40,41,35 \
--averagetype linear
- (Optional) You can view if the box detector thingie finds your pixels with
tool_show_boxes.py
. Consider a smaller batch of pixels if this looks all mangled. Example of good looking boxes:
python3 tool_show_boxes.py \
-p images/testimages/testimage3_pixels.png \
-s images/searchimages/debruinseq_notepad_Windows10_closeAndSpaced.png
- (Optional) You can create pixelized image by using
tool_gen_pixelated.py
.
python3 tool_gen_pixelated.py -i /path/to/image.png -o pixed_output.png
- For a detailed explanation, please try to run
$ python3 depix.py -h
andtool_gen_pixelated.py
.
- Cut out the pixelated blocks from the screenshot as a single rectangle.
- Paste a De Bruijn sequence with expected characters in an editor with the same font settings as your input image (Same text size, similar font, same colors).
- Make a screenshot of the sequence.
- Move that screenshot into a folder like
images/searchimages/
. - Run Depix with the
-s
flag set to the location of this screenshot.
- Cut out the pixelized blocks exactly. See the
testimages
for examples. - It tries to detect blocks but it doesn't do an amazing job. Play with the
tool_show_boxes.py
script and different cutouts if your blocks aren't properly detected.
The algorithm uses the fact that the linear box filter processes every block separately. For every block it pixelizes all blocks in the search image to check for direct matches.
For some pixelized images Depix manages to find single-match results. It assumes these are correct. The matches of surrounding multi-match blocks are then compared to be geometrically at the same distance as in the pixelized image. Matches are also treated as correct. This process is repeated a couple of times.
After correct blocks have no more geometrical matches, it will output all correct blocks directly. For multi-match blocks, it outputs the average of all matches.
- The algorithm matches by integer block-boundaries. As a result, it has the underlying assumption that for all characters rendered (both in the de Brujin sequence and the pixelated image), the text positioning is done at pixel level. However, some modern text rasterizers position text at sub-pixel accuracies.
- You need to know the font specifications and in some cases the screen settings with which the screenshot was taken. However, if there is enough plaintext in the original image you might be able to use the original as a search image.
- This approach doesn't work if additional image compression is performed, because it messes up the colors of a block.
- Implement more filter functions
Create more averaging filters that work like some popular editors do.
- Create a new tool that utilizes HMMs
After creating this program, someone pointed me to a research document from 2016 where a group of researchers managed to create a similar tool. Their tool has better precision and works across many different fonts. While their original source code is not public, an open-source implementation exists at DepixHMM.
Edit 16 Feb '22: Dan Petro created the tool UnRedacter (write-up, source) to crack a challenge that was created as a response to Depix!
Still, anyone who is passionate about this type of depixelization is encouraged to implement their own HMM-based version and share it.