Extracting Bitmaps from a Firmware Binary

As a side trip within the firmware reversing project, I’ve been looking for the font and image files inside the Electribe firmware. Initially, I just thought it would be neat to grab the startup logo, but as I considered it, the presence of images at all actually has significance. The key goal became proving that the update process completely rewrites the firmware, rather than just diff’ing the existing memory and updating selective regions. The other approach to this would be to see if the code makes sense, but until I get my hands on IDA, that’s not going to happen.

The first step was finding something that would browse raw bitmap data.The idea for this whole thing came to mind when I found Hexplorer’s “pixel view” option. Unfortunately, Hexplorer is a pretty bad program all around, and the pixel view was even less configurable than the already limited hex view, so I searched for more options.pixelview

Lucky for me, GIMP already has this feature built-in, with plenty of options including offset and dimensions. Used the open command and set the format to “raw image data” in order to search for familiar shapes. It’s important to use “index” mode here, not because the images are actually indexed (they’re monochrome) but because everything else turns the view into a mess of colors. Unfortunately, there is no way to set the mode to monochrome in GIMP, and we know the display is strictly monochrome from observation, which was going to make things difficult. At some point, I think I realized this but was really enjoying watching the dancing pixels, so I kept scrolling down until a certain 128-wide chunk caught my attention.

GimpRaw

Look familiar? Maybe not. I don’t know if you’re familiar with the Electribe, but that white band near the middle looks suspiciously like the negative of the Electribe Sampler’s loading screen. If you squint, you can just kind of make out the letters. The truth is, this was a lucky break, since they decided to display the text in negative and GIMP has the monochrome reversed. Instead of being a black box with white text, which would have hidden pretty well, this block stuck out like a sore thumb. I opened the region and zoomed in to check it out, and this is what I saw:

ElectribeCropped

Clearly, something’s missing here. First of all, the image has gray levels, which I could assume it shouldn’t. Second, the entire banner is only 8 pixels tall, not the 64 available on the screen. Strangely, the width was right, which didn’t make a lot of sense to me. I wasn’t thinking very creatively, so I didn’t even bother to check the height here. Doing so would have made things easier. Instead, I went to the datasheets.

With no clues as to who makes the display or how it communicates with the processor, I just went to the first manufacturer’s website I could think of (Newhaven display) and grabbed datasheets for their 128×64 graphic displays, plus the associated driver chips. Disappointingly, there was very little information about the image input format in the Newhaven sheets, but the driver chip was exceedingly well-defined in this respect. It even had little graphics explaining the way things are loaded and read from the framebuffer.

Displayorder

This was immensely helpful, because it essentially removed all of the guesswork about the typical display format. D0 through D7 are parallel inputs used to load 8 pixels at a time (presumably from left to right), which means the optimal arrangement of data is in 8-pixel-tall strips.

Looking back at the GIMP extracted image, I finally decided to measure the height. Unsurprisingly, it’s 8 pixels tall with some noise at the top and bottom. It was a factor of 8 shorter that it should have been. I should have checked this much earlier. The problem was that just reading it as a 1-bit-per-pixel file with width 128 yielded no results. The region became garbled when read this way. I started writing out the needed transformations as a kind of matrix transposition thing, but the solution looked like it was overwhelmingly iterative. At this point, I wasn’t thinking clearly. If I had been, I would have realized that the best way to extract 8-pixel-wide strips isn’t as a 128-pixel-wide image.

Of course, the answer was to just use an 8-bit wide header. As I realized this, I also realized that nothing I had would allow me to set both raw image width and arbitrary bit depth. I dug around on the GIMP wiki looking for the libraries it uses, and by a very roundabout chain of links arrived at ImageMagick. ImageMagick is just great, it lets you do every conceivable thing to every conceivable format as long as you’re willing to do some trial and error and wait for results.

By running the explicit format convert command (and tweaking a few times) I finally got a folder full of 8×128 image samples representing all the possible image “strips” within the firmware. At the same offset as the image was found in GIMP, there was a much clearer picture of my target:

SlicedLogo

Actually, about 8 pictures of my target. It was now backwards and no longer centered in the frame, and also sliced into 8 pieces, but it was finally showing all the pixels correctly. At this point, the ImageMagic commands could do most of the work. I used the +append option to stack a small subset of the strips together and did some offsets and shifting in GIMP to arrive at the final product. Also visible are some system glyphs for small text objects and icons.

appendedlogo

I believe the fonts are loaded into the display driver’s sprite/font memory which frees them from the strip format of the other graphics. Impressively, the Electribe uses proportional fonts for most of the menu text, which may make the letters very difficult to find using this extraction technique.

And that’s how to find monochrome bitmaps in embedded firmware. Hopefully this will save someone the time it took me trying and failing to interpret this data the first few times.

Next in this series: Electribe 2 Firmware Disassembly (pt 1)

3 comments

  1. Pingback: Electribe 2 Sampler Firmware Examination | Profanity Filter Testing Domain

  2. Q840av's avatar
    Q840av

    Awesome post, would you mind sharing the ImageMagic explicit format convert commands you finally used?

    • jergling's avatar

      Oh man, I wish I remembered. I want to say it was just specifying bitmap format, 1bpp, 8×128 frames and an offset to the location of the image, but I’m afraid to try to dig through those manpages again. I made a lot of mistakes until I got a reasonable result.

      Check here for the basics: http://www.imagemagick.org/script/command-line-processing.php and look at the “-depth” setting for the main stuff.

      Also read up on “frames”, which are stored the same way as the slices.

Leave a comment