It’s been over two years since I last published a blog, so I thought I’d give this another go in 2020 and kick it off by writing about an iOS-related project I’ve been working on over the last couple weeks – a reverse engineering task involving the iOS screen frame-buffer.

First of all, my inspiration to start looking at this came shortly after the release of the checkra1n jailbreak for the iPhone 5S – iPhone X. If you haven’t yet played with checkra1n, check it out here – https://checkra.in/.

One of the things checkra1n does during the jailbreaking process is display a series of debug messages on the phone’s screen to let the user know about the progress of the jailbreak, and allow them to see what went wrong in the event of the jailbreak failing.

These debug messages are written to the display over the top of the standard boot screen. I was intrigued by this and started to wonder how the checkra1n team had implemented it. I heard some phrases thrown around online mentioning the use of a “framebuffer” and that the jailbreak tool was somehow “writing” to it.

So I set myself the challenge of figuring out how this worked and how I could replicate this in order render some characters on the screen by directly manipulating the pixels.

Locating the iOS frame-buffer in kernel memory

The first step towards reaching my goal of writing custom characters to the screen was to find where in memory the screen pixel data was stored.

The checkra1n tool manipulates pixels in the framebuffer during the iBoot stage of the boot process, which is why we see the debug messages printed over the Apple boot-logo. I decided to take a different approach and focus on an already-booted iPhone.

The only difference meant dealing with kernel memory as opposed to iBoot memory, and dealing with the kernel memory seemed like the simpler approach as I could get started right away without having to construct a fully patched boot-chain etc.

I started digging around to find where the iOS kernel holds the screen pixel data in memory. Knowing this memory location would allow me to write to it (assuming I’m using a jailbroken device with a TFP0 patch) resulting in the colour of the pixels changing.

My first thought was to see if there was some kind of framebuffer symbol within the iOS kernel.

I opened a decrypted kernelcache file (for this, I’m using an iPhone3,1 iOS 7.1.2 kernel) in Hopper disassembler and searched for “framebuffer” but no luck :(

Despite not finding any symbols, Hopper did find a string containing “framebuffer”:

This string appeared to be some kind of debug message coming from the function initialize_screen . I went to the XNU source code to confirm this function actually existed and found it in the file https://github.com/apple/darwin-xnu/blob/a449c6a3b8014d9406c2ddbdc81795da24aa7443/osfmk/console/video_console.c.

Looking at the first few lines of code in this function it is clear that this function is responsible for setting up the device’s screen and assigning values for the width, height, colour depth etc.

The first argument to this function is a pointer to a PE_Video structure. I went to where this struct was defined (in https://github.com/apple/darwin-xnu/blob/master/pexpert/pexpert/pexpert.h) and found that it holds some information about the host’s screen, including the width, height, colour depth and a base address of where in memory the pixel data actually lies.

struct PE_Video {

unsigned long v_baseAddr; /* Base address of video memory */

unsigned long v_rowBytes; /* Number of bytes per pixel row */

unsigned long v_width; /* Width */

unsigned long v_height; /* Height */

unsigned long v_depth; /* Pixel Depth */

unsigned long v_display; /* Text or Graphics */

char v_pixelFormat[64];

unsigned long v_offset; /* offset into video memory to start at */

unsigned long v_length; /* length of video memory (0 for v_rowBytes * v_height) */

unsigned char v_rotate; /* Rotation: 0:normal, 1:right 90, 2:left 180, 3:left 90 */

unsigned char v_scale; /* Scale Factor for both X & Y */

char reserved1[2];

#ifdef __LP64__

long reserved2;

#else

long v_baseAddrHigh;

#endif

};

If I could find this structure sitting in the kernel memory I’d be able to follow the v_baseAddr pointer and find the raw pixel data.

I followed the first XREF from the debug string I had found in the iOS kernelcache and landed in the following code:

If this code was part of initialize_screen then I’d have a chance at finding the address of this PE_Video structure in here.