Earlier this year I demoed iOS 6 running on an iPod touch 3 – a device that Apple never gave iOS 6 to, making iOS 5.1.1 the latest build it can run

A few months later I also released a script that generates an iOS 6 restore image installable on that iPod touch model

This article describes technical details behind this work. Certain proficiency in iOS internals is assumed

iPhone 3GS was released the same year as iPod touch 3 (2009), and has a very similar hardware (S5L8920X SoC vs. S5L8922X). But the most important part is that it actually got iOS 6 officially

Before doing anything on the iPod I decided to try to boot iOS 6.0 with iOS 5.1.1 iBoot & DeviceTree on the iPhone and see what’s gonna break and how

The most broken thing was DeviceTree – iOS 6 added a lot of new nodes and properties. To fix it in automated manner I wrote a stupid Python script that decodes and computes a diff between 2 DeviceTrees. Such diff can also be applied to another DeviceTree

As I mentioned above a lot of things in a DeviceTree is filled by iBoot at runtime. One of such new properties is nvram-proxy-data in chosen node

The property must contain a raw NVRAM dump – leaving it empty will make kernel get stuck somewhere very early

For iPod touch 3 I also had to clean-up the diff out of iPhone-specific things before applying it to iPod’s 5.1.1 DeviceTree

iBoot didn’t require any major changes in this case. Just typical Image3 signature check patch, boot-args injection and debug-enabled patch so kernel is going to actually respect AMFI boot-args

The most complex part. iPod touch 3 never got iOS 6 officialy, yes, but it was rumored that initially it was meant to have it, but Apple’s marketing team said no. Either way, almost every internal iOS 6 build got both standalone S5L8922X kernel and even standalone kexts (including ones specific to iPod touch 3)

The question is how to load them all simultaneously. My initial idea was to do it just as older Mac OS X could do – load all kexts dynamically on bootloader level. Long story short, my strategy was the following:

So creating a legit kernelcache is the only way after all. I was already imagining all the horrors of writing software to parse and apply LINKEDIT and etc., but then it occured to me! Mac OS X (before Apple Silicon) was generating such kernelcaches somehow! What if we use that logic to build our iOS kernelcache?

I used /usr/local/bin/kcgen from internal Sierra build (can be found online as “Phoenix A1708.dmg”), but it seems that even latest macOS kextcache can do it (included by default)

The little thing to do is to remove fat header. For some reason, it creates a fat Mach-O with a single slice. iBoot doesn’t like it, so let’s strip it:

Once again I compared iPhone 3GS’ iOS 5.1.1 vs. 6.0 – some kexts were added, some removed, some changed their bundle IDs, some were irrelevant for iPod touch 3

In this specific case I had to patch up Info.plist of the Wi-Fi kext. As always there is a sample in the repo

Pretty cannonical here. I patched asr as usual and also had to move options.n88.plist to options.n18.plist so it can lay out partitions properly

iOS 5 iBoot had a bug in HFS+ filesystem driver. I did make an exploit many years ago but it was bad. Like, truly bad. I reimplemented it from scratch for this project making it deterministic (hopefully…)

There was another device that Apple dropped support for in that year – iPad 1. I will try that soon enough as well

I hope that the information from this write-up will help you making other crazy combinations, like iOS 4 on iPhone 4S or iOS 5 on iPad mini 1

DeviceTree – structured list of hardware used by specific device model + some parameters that specify software behavior. The copy included in an IPSW is more of a template that is heavily modified by iBoot before jumping into kernel

Userspace filesystem – tiny restore ramdisk used purely for OS installation or the actual root filesystem of iOS installed persistently

Various firmwares for coprocessors, be they internal or external to the main SoC – like, baseband, Wi-Fi, Bluetooth, multitouch and etc.

$(cat n18.10A403.kextlist | sed ‘s/^/–bundle-id /’) – this weird expression appends –bundle-id to every line from the file at n18.10A403.kextlist. This is to specify which kexts we’d like to include. How I created such list is described below

-all-personalities – very important flag that prevents irrelevant IOKit personalities to be stripped. “Irrelevant” as in “irrelevant to current machine”, meaning everything relevant to iPod touch 3 is going to be stripped

-strip-symbols – strips unnecessary symbols. This flag can be omitted theoretically, but I recommend keeping it to make resulting kernelcache smaller

-uncompressed – do not apply compression. Since we’ll have to change one little thing later, compression would have to be reapplied anyway

If restore was completed properly, I add a third partition, write the exploit there and set boot-partition to 2

Add matching SpringBoard’s hardware feature plist (/System/Library/CoreServices/SpringBoard.app/N18AP.plist in this case)

Luckily, they can also be overriden by files in /etc/bluetool – as always check my code for reference

This trick will be harder to pull off on iOS 6.1+ because they load LaunchDaemons from a signed cache. Still can be bypassed in many ways – for instance, patching launchd or forcefully loading another plist via launchctl

First of all, let’s recap what software components iOS consists of:

One important thing is to actually populate nvram-proxy-data dynamically, at least for normal boots (aka non-restore). Restore boot will be fine with some random NVRAM hardcoded into DeviceTree, but normal one will overwrite your actual NVRAM with the random one if it decides to sync it at some point

I do it by replacing a call to UpdateDeviceTree() with my own little function that calls the real UpdateDeviceTree(), but also populates actual nvram-proxy-data and random-seed (this one shouldn’t be of any importance)

For boot-args I always add amfi=0xff to disable code-signing, but that’s pretty cannonical as well

Please note that other iBoot+kernel combos might require more changes – if you ever try something and it doesn’t work, I recommend looking into DeviceTree differences (both the initial template and how iBoot fills it) and also boot_args structure iBoot passes to kernel (not to be confused with boot-args string, the boot_args structure is a different thing)

The kernel has all the code to pick them up, but not to actually link…

The kernel cache is ready now! Just needs to be compressed and packaged into Image3 container

Do not forget to include the pseudo-extensions as well!

However, I also have to install the iBoot exploit. To do that I reimplement rc.boot binary:

My implementation is available guess where? Yes, in the repository

This was not easy to do, and yet easier than I expected initially

iBoot – the bootloader. Has 4 different types for different scenarios – iBSS, iBEC, LLB and iBoot

Kernelcache – the OS kernel + kernel extensions (drivers) built into a single binary blob

-c output.bin – output file to write resulting kernelcache to

— means the rest of the args will point to directories to grab kexts from

kernels_kexts_10A63970m/Extensions is a path to a folder containing kexts

Remount ramdisk and set umask just like the original one does

Call restored_external, but with -server argument, so it doesn’t reboot after finishing restore

I took the iOS 5.1.1 variant as a base and added iOS 6 specific capabilities

This is more complicated, as those are all hardcoded into /usr/sbin/BlueTool

It has LimitLoadToHardware key in its’ LaunchDaemon plist

But if we simply remove the key, it works on iPod touch 3 as well

This is important, because otherwise we cannot activate device through Apple’s servers

I extracted both firmware and scripts from 5.1.1 BlueTool

This is the xdefiance Online Web Shop.

A True Shop for You and Your Higher, Enlightnened Self…

Welcome to the xdefiance website, which is my cozy corner of the internet that is dedicated to all things homemade and found delightful to share with many others online and offline.

You can book with Jeffrey, who is the Founder of the xdefiance store, by following this link found here.

Visit the paid digital downloads products page to see what is all available for immediate purchase & download to your computer or cellphone by clicking this link here.

Find out more by reading the FAQ Page for any questions that you may have surrounding the website and online sop and get answers to common questions. Read the Returns & Exchanges Policy if you need to make a return on a recent order. You can check out the updated Privacy Policy for xdefiance.com here,

If you have any unanswered questions, please do not hesitate to contact a staff member during office business hours:

Monday-Friday 9am-5pm, Saturday 10am-5pm, Sun. Closed

You can reach someone from xdefiance.online directly at 1(419)-318-9089 via phone or text.

If you have a question, send an email to contact@xdefiance.com for a reply & response that will be given usually within 72 hours of receiving your message.

Browse the shop selection of products now!

Reaching Outwards