hackiosx r/hackios GitHub

How it works

If you have ever built a Hackintosh, the idea is similar: make Apple's software believe it runs on Apple hardware. On a phone the gap is much bigger, because nothing in an Android phone looks like an iPhone to iOS.

Where the drivers come from

An Android driver is part of the Linux kernel. It is written against Linux's own functions, memory management and device model. XNU, Apple's kernel, works differently and has its own driver system called IOKit, so Linux driver code can't run inside it directly.

The Android side is still the main source of information. Qualcomm and Xiaomi publish the Linux kernel source for the phone, and the phone carries a device tree that lists its hardware. Together they show where the touch controller sits, how the screen is set up and how the buttons are wired. ios-sweet uses that to write new, much smaller drivers for XNU that talk to the same chips. The hardware itself doesn't care which kernel is talking to it.

The second half of every driver is making iOS accept it. iOS doesn't want "a Goodix touchscreen". It wants an Apple-style touch device that sends the events Apple's own touch hardware sends. So the touch driver reads finger positions from the Goodix chip and then reports them to iOS the way an iPhone would. The same goes for the buttons, the battery and the screen.

The boot chain

An iPhone starts with Apple's boot ROM and iBoot, which only load software Apple signed. A Snapdragon phone has Qualcomm's chain instead, ending in Xiaomi's bootloader (ABL), which expects an Android boot image. ios-sweet doesn't replace any of it. It hands the stock bootloader something that looks like an Android kernel:

  1. Xiaomi bootloader (stock, unlocked). You run fastboot boot shim-boot.img from the PC. This boots the image once from RAM. Nothing is written to the boot partitions, so a normal reboot brings Android's boot chain back.
  2. The shim. A small program that the bootloader starts as if it were Linux. It sets up memory the way XNU expects, unpacks the payload and jumps into Apple's kernel. Think of it as a tiny stand-in for iBoot.
  3. XNU. Apple's kernel, built from Apple's public source (xnu-8796, the iOS 16 version) with about 80 patches for this phone. It gets a generated Apple Device Tree that describes the phone's hardware in Apple's format.
  4. Storage. A new UFS driver finds the phone's internal flash. iOS lives in the partition Android used for user data, formatted as HFS+.
  5. iOS. launchd starts, then the system daemons, then backboardd (input and display) and SpringBoard (the home screen). These are Apple's files from the iPhone X firmware.

Why an iPhone X?

Newer iPhones (XS and later) use a CPU feature called pointer authentication. Their whole system is compiled for it, and Snapdragon chips like this one don't have it. The iPhone X is the newest iPhone that runs iOS 16 without needing it. It also has no Home button, so iOS uses the swipe gestures, which suits a phone with a full touchscreen.

The kernel tells iOS it is an iPhone X (model iPhone10,3). Some identity data is copied from the real iPhone X device tree so that iOS picks the right layout and features.

The screen, without a GPU

When the bootloader shows its logo, it turns the display on and leaves an image buffer in memory that the panel keeps showing. ios-sweet reuses that buffer. iOS draws everything with its built-in software renderer on the CPU, and the kernel copies each finished frame into the bootloader's buffer.

The phone's screen is 1080 x 2400. iOS is told it has an iPhone X panel (1125 x 2436) because iOS only lays itself out properly on screen sizes it knows. The picture is centered on the real panel.

This is why it runs at roughly 20 to 30 frames per second. The Adreno GPU sits unused, because iOS would need a driver that speaks Apple's Metal graphics interface, and nobody has written one.

What had to be faked or switched off

Debugging a phone with no serial port

Most kernel ports start with a serial console. This phone doesn't have a usable one. The kernel prints its messages on the screen and also keeps the last 4 MB of its log at the end of the storage partition. After a crash you boot a recovery (OrangeFox) and pull that log to the PC. Newer kernels can also stream the log live over USB as a network connection.

Every boot, crash and fix is written down in NOTES.md, and every kernel change is its own numbered patch in xnu/patches.