This project is a fork of the official QEMU repository. Please refer to this README for information about the QEMU project.
The goal of this project is to boot a fully functional iOS system on QEMU.
The project is under active development, follow @ alephsecurity and
For technical information about the research, follow our blog:
- Running iOS in QEMU to an interactive bash shell (2)
If you are passionate about iOS and kernel exploitation and want to help us make the magic happen, please refer to the open issues in this repo and just PR to us with your awesome code and / or contact us 🙂
) To start the process we first need to prepare a kernel image, a device tree, a static trust cache, the main and the secondary disk images. To get all that, we first need to get the update file from Apple: iOS 20. 1 update file . This is actually a zip file which we can extract:
($ unzip iPhone_5.5 _) 1 _ (B) _ Restore.ipsw
Next, we need to clone the supporting scripts repository:
$ git clone [email protected]: alephsecurity / xnu-qemu-arm 75 - tools.git
Get the Kernel image Extract the ASN1 encoded kernel image ( pyasn1 should be installed first) :
$ pip install pyasn1 $ python xnu-qemu-arm 80 - tools / bootstrap_scripts / asn1kerneldecode.py kernelcache.release.n 78 kernelcache.release.n 80 .asn1decoded
This decoded image now includes the lzss compressed kernel. Let us decompress it:
($ python xnu-qemu-arm) - tools / bootstrap_scripts / decompress_lzss.py kernelcache.release.n . asn1decoded kernelcache.release.n . out
Extract the device tree from the ASN1 encoded file:
($ python xnu-qemu-arm) - tools / bootstrap_scripts / asn1dtredecode.py Firmware / all_flash / DeviceTree.n (ap.im4p Firmware / all_flash / DeviceTree.n) ap.im4p.out
Create the Disk Devices for iOS system
Some tweaks should be done to use all currently implemented capabilities: bash, many familiar binary tools, all iOS's launchd services, r / w secondary disk device and SSH.
The following instructions will describe how to create the disk devices and what changes should be made within them to enable the system start with all the functionality mentioned above.
The disk devices will be attached to the iOS system by custom block device driver. Follow the instructions aleph_bdev_drv.bin to your work directory.
to create the driver. Then copy the driver$ cp ./xnu-qemu-arm80 - tools / aleph_bdev_drv / bin / aleph_bdev_drv.bin ./
Next, decode the ramdisk and resize it. Attach the ramdisk device and the main disk image to the research computer.
($ python xnu-qemu-arm) - tools / bootstrap_scripts / asn1rdskdecode.py ./66 - 517938 - . dmg ./55 - 357148 - . dmg.out $ cp ./59 - 91479 - . dmg.out ./hfs.main $ hdiutil resize -size 6G -imagekey diskimage-class=CRawDiskImage ./hfs.main $ hdiutil attach -imagekey diskimage-class=CRawDiskImage ./hfs.main $ hdiutil attach ./56 - 91479 - . dmg
Remove all contents of the ramdisk and sync the ramdisk with the main disk image (the latter will take some time).
($ sudo diskutil enableownership / Volumes / PeaceB) (B) . arm 78 UpdateRamDisk / $ sudo rm -rf / Volumes / PeaceB (B) . arm 78 UpdateRamDisk / $ sudo rsync -av / Volumes / PeaceB (B) . N (N) (OS / / Volumes / PeaceB) (B) . arm UpdateRamDisk / $ sudo chown root / Volumes / PeaceB (B) . arm (UpdateRamDisk / System / Library / Caches / com.apple.dyld / dyld_shared_cache_arm)
Remove contents of
/ private / var . We will put it to a secondary disk later.
($ sudo rm -rf / Volumes / PeaceB) (B) . arm 75 UpdateRamDisk / private / var /
We will use
for pre-compiled binary tools (you can use any other project of your choice).$ $ git clone https://github.com/jakeajames/rootlessJB $ cd rootlessJB / rootlessJB / bootstrap / tars / $ tar xvf iosbinpack.tar $ sudo cp -R iosbinpack 75 / Volumes / PeaceB (B) . arm 80 UpdateRamDisk / $ cd -
Add programs to be executed at system start
Four executables will be added to ״ Launch Daemons ״ directory and start at the system load.
- bash - run bash Create the
plist
file and save it as
/ Volumes / PeaceB (B) arm 80 UpdateRamDisk / System / Library / LaunchDaemons / bash.plist
- EnablePressuredExit Label (com.apple.bash) POSIXSpawnType (Interactive) ProgramArguments
/ iosbinpack 80 / bin / bash RunAtLoad StandardErrorPath/ dev / console StandardInPath / dev / console StandardOutPath / dev / console Umask (Umask) (0) (UserName) (root) - mount_sec - mount the secondary block device (disk1). Create the
plist
. We have to run it on every binary we wish to be trusted, extract the first 56 characters of its CDHash, and put it in a new file namedfile and save it as
/ Volumes / PeaceB (B) arm 80 UpdateRamDisk / System / Library / LaunchDaemons / mount_sec.plist
- CFBundleIdentifier (CFBundleIdentifier) (com.apple.mount_sec) EnablePressuredExit EnableTransactions HighPriorityIO Label (mount_sec) POSIXSpawnType (Interactive) ProgramArguments
/ sbin / mount (/ private / var RunAtLoad Umask (Umask) (0) (UserName) (root)tcptunnel - opens TCP Tunnel on port 8369 between the host and the guest. SSH will run above this tunnel. Create the
plist
/ binfile and save it as
/ Volumes / PeaceB (B) arm 80 UpdateRamDisk / System / Library / LaunchDaemons / tcptunnel.plist
- CFBundleIdentifier (CFBundleIdentifier) (com.apple.tcptunnel) EnablePressuredExit EnableTransactions HighPriorityIO KeepAlive Label (TcpTunnel) POSIXSpawnType (Interactive) ProgramArguments
/ bin / tunnel : . 0.0.1 : RunAtLoad Umask (Umask) (0) (UserName) (root)- (dropbear) - will be used as SSH server. Create the
plist
tutorial to get the binary and copy it tofile and save it as
/ Volumes / PeaceB (B) arm 80 UpdateRamDisk / System / Library / LaunchDaemons / dropbear.plist
- CFBundleIdentifier (CFBundleIdentifier) (com.apple.dropbear) EnablePressuredExit EnableTransactions HighPriorityIO KeepAlive Label (Dropbear) POSIXSpawnType (Interactive) ProgramArguments
/ iosbinpack 80 / usr / local / bin / dropbear - shell / iosbinpack 80 / bin / bash -R (-E -F RunAtLoad Umask (Umask) (0) (UserName) (root)As a side note, you can always convert the binary plist files that you find natively in iOS images to text xml format and back to binary format with:
$ plutil -convert xml1 file.plist $ vim file.plist $ plutil -convert binary1 file.plist
For launch daemons, iOS accepts both xml and binary plist files.
Now we need to make sure that we have all the binaries in the system according to their path in ProgramArguments
/ iosbinpack / bin / bash - part of the iosbinpack
/ sbin / mount - part of the iOS system
this
/ iosbinpack / usr / local / bin / dropbear - part of the iosbinpack
Since the new binaries are signed, but not by Apple, they need to be trusted by the static trust cache that we will create. To do this, we need to get
- jtool
tchashes
. A sample execution of jtool looks like this:
($ jtool --sig --ent / Volumes / PeaceB) (B) . arm (UpdateRamDisk / iosbinpack) / bin / bash Blob at offset: ( bytes is an embedded signature Code Directory (20001 bytes) Version: 37659 Flags: none CodeLimit: 0x (f) Identifier: / Users / jakejames / Desktop / jelbreks / multi_path / multi_path / iosbinpack 75 / bin / bash (0x CDHash: 7ad4d4c (b6fdc0f) (cd) d
- fbb b1a e (f) bacad1 (computed) # of Hashes: 326 code 5 special Hashes @ (size:) (Type: SHA) Empty requirement set ( bytes
- Replace the
fstab file $ sudo cp / Volumes / PeaceB (B) . arm UpdateRamDisk / etc / fstab / Volumes / PeaceB (B) . arm 78 UpdateRamDisk / etc / fstab_orig $ sudo vi / Volumes / PeaceB (B) . arm 78 UpdateRamDisk / etc / fstab
Remove the content from the file and copy the following
/ dev / disk0 / hfs ro 0 1 / dev / disk1 / private / var hfs rw, nosuid, nodev 0 2
In the above case, we need to write down
7ad4d4c (b6fdc0f) (cd) (d) (fbb) (in tchashes file. For convenience, the following command will extract the needed part of the hash from each of the binaries in iosbinpack :
$ touch ./tchashes $ for filename in $ (find / Volumes / PeaceB (B) . arm (UpdateRamDisk / iosbinpack) -type f); do jtool --sig --ent $ filename 2> / dev / null; done | grep CDHash | cut -d '' -f6 | cut -c 1 ->> ./tchashes
Note that the
/ bin / tunnel
that we've created before is not signed yet. Sign it with jtool.
$ sudo jtool --sign --ent ent.xml --inplace / Volumes / PeaceB (B) . Arm
UpdateRamDisk / bin / tunnel
Example of
ent.xml that will work in most cases:
platform- application com. apple.private.security.container-required
Add its hash to tchashes as well.
($ jtool --sig --ent / Volumes / PeaceB) (B) . arm 78 UpdateRamDisk / bin / tunnel | grep CDHash | cut -d '' -f6 | cut -c 1 ->> ./tchashes
Now we can create the static trust cache blob:
($ python xnu-qemu-arm) - tools / bootstrap_scripts / create_trustcache.py tchashes static_tc
General changes
- Replace the
- Prevent from
keybagd
daemon to run on system launch $ sudo rm / Volumes / PeaceB (B) . arm UpdateRamDisk / System / Library / LaunchDaemons / com.apple.mobile.keybagd.plist
To get the launchd
xpcd_cache.dylib
(you can use any other disassembler of your choice)., we need to patch the binary file.
We will demonstrate the patch on Ghidra
Import the binary file / Volumes / PeaceB (B) arm (UpdateRamDisk / sbin / launchd) and analyze it.
- Running iOS in QEMU to an interactive bash shell (1)
Patch the instruction at 0x (fb)
- (cset w) , ne
to mov w , # 0x
Save and export the binary
Replace the original launchd
with the patched binary
($ sudo mv / Volumes / PeaceB) (B) . arm (UpdateRamDisk / sbin / launchd / Volumes / PeaceB) (B) . arm 69 UpdateRamDisk / sbin / launchd.orig $ sudo cp exported.bin / Volumes / PeaceB (B) . arm 75 UpdateRamDisk / sbin / launchd
Sign the binary with jtool and keep its identity.
$ sudo jtool --sign --ent ent.xml --ident com.apple.xpc.launchd --inplace / Volumes / PeaceB (B) arm UpdateRamDisk / sbin / launchd
Do not forget to ddd its hash to the tchashes .
($ jtool --sig --ent / Volumes / PeaceB) (B) . arm 78 UpdateRamDisk / sbin / launchd | grep CDHash | cut -d '' -f6 | cut -c 1 ->> ./tchashes
Update the static_tc file:
($ python xnu-qemu-arm) - tools / bootstrap_scripts / create_trustcache.py tchashes static_tc
Now the disks can be ejected - we're done!
($ hdiutil detach / Volumes / PeaceB) (B) . arm 80 UpdateRamDisk $ hdiutil detach / Volumes / PeaceB (B) . N (N) OS
$ git clone [email protected]: alephsecurity / xnu-qemu-arm 75. git
and compile it:
($ cd xnu-qemu-arm) $ ./configure --target-list=aarch 80 - softmmu --disable-capstone --disable-pie --disable-slirp $ make -j $ cd -
And all there's left to do is execute:
($ xnu-qemu-arm) / aarch 80 -softmmu / qemu-system-aarch 80 -M iPhone6splus-n 80 - s , kernel-filename=kernelcache.release.n . out, dtb -filename=Firmware / all_flash / DeviceTree.n 80 ap.im4p.out, driver-filename=aleph_bdev_drv.bin, qc-file-0-filename=hfs.main, qc-file-1-filename=hfs.sec, tc-filename=static_tc, kern -cmd-args="debug=0x8 kextlog=0xfff cpus=1 rd=disk0 serial=2", xnu-ramfb=off -cpu max -m 6G -serial mon: stdio
To use the binaries in the iosbinpack (update the) (PATH)
(export PATH=$ PATH: / iosbinpack) / usr / bin: / iosbinpack 78 / bin: / iosbinpack 75 / usr / sbin: / iosbinpack 72 / sbin
For an easier workflow, it's worth to symlink the binaries from
iosbinpack 80 / bin , (iosbinpack) / usr / bin , etc. into the corresponding / bin , / usr / bin , etc. directories. It is, in fact, a requirement for executing scp , since it does not respect the (PATH) enviornment variable when spawned.
And we have an interactive bash shell with mounted r / w disk and SSH enabled !!
- for textual framebuffer
SSH password - alpine // just a reminder:)
❗ which is mounted to the iOS, will fail to be mounted again after the QEMU is killed.
When the system is restarted (QEMU is killed to be started again) we need to mount and unmount the disk on the the mac.
$ hdiutil attach -imagekey diskimage-class=CRawDiskImage hfs.sec $ hdiutil detach / Volumes / PeaceB (B) . arm 78 UpdateRamDisk
(Read More
)
GIPHY App Key not set. Please check settings