Building iBoot
Created on 14.07.18
Important note: this article discusses Apple internal software. This
information is provided for educational purposes only. Also playing
with low-level software directly may lead to a hardware damage. You
have been warned
In February 2018 someone leaked Apple iBoot's source code to a
general public. According to timestamps in files and various signs in
the code (string obfuscation, missing support for anything older than
A5, four PRODUCTS (LLB      LLB, iBoot
                                  iBoot, iBSS
                                         iBSS, iBEC
                                               iBEC) instead of two
(iBootStage1
 iBootStage1, iBootStage2
                iBootStage2) like in iOS 10) we can freely affirm that
this code belongs to some late iOS 9 build. More information about a
story of the leak is available here
What can or cannot be built
For a pretty long time it has been known that the leak is incomplete
and therefore it's impossible to build a working copy of iBoot from it.
As far as I know, two security researchers on Twitter tried to do that.
One of them, @xerub, actually managed to build bootloaders, but
according to himself he simply re-created missing files. I highly doubt
that a bootloader built in such way would actually work. Especially if
we take on an account, that missing files are most likely related to a
power management
I performed my own research and found out that:
   iBoot for A5 targets (s5l8940x
                         s5l8940x, s5l8942x
                                   s5l8942x, s5l8945x
                                             s5l8945x, s5l8947x
                                                         s5l8947x)
   and s5l8747x (used in Haywire
                           Haywire) can be built, but modifications
   are required in device_map (we'll talk about this later)
   iBoot for A6 targets (both s5l8950x and s5l8955x
                                           s5l8955x) can be built
   iBoot for A7 (s5l8960x
                   s5l8960x), A8 (t7000
                                   t7000, t7001
                                          t7001), A9 (s8000
                                                       s8000, s8003
                                                               s8003,
   s8001
   s8001), S1 (s7002
                s7002) and S1P
                            S1P/S2
                                S2 (t8002
                                     t8002) targets can not be built
   due to a lot of missing headers
Also DEBUG
     DEBUG-fused bootloaders don't work for some unobvious
reason. There's a special technique to solve it, but it wasn't found by
me, so I cannot share it
Building
First step is pretty obvious:
 cd iboot
Second one, however, isn't so obvious:
 sudo make APPLICATIONS="iBoot" TARGETS="n41 n42" BUILDS="DEVE
Let's define what it all means:
   APPLICATIONS argument defines applications to be built,
   obviously. Valid values: iBoot
                            iBoot, SecureROM (bootrom) and
   EmbeddedIOP (something loaded by kernel and situated in its
   cache)
   TARGETS defines device models to be built for (without
   "ap"/"dev" part)
   BUILDS defines BUILD_STYLE
                       BUILD_STYLEs to be built of. Valid values for
   iBoot application: RELEASE (just as normal iBoot supplied with
   IPSWs), DEVELOPMENT (untrusted image execution on
   Image3-compatible devices, amazing level of verbosity on newer
   versions and a lot of additional commands), DEBUG (same as
   DEVELOPMENT
   DEVELOPMENT, but even more verbosity and even more
   additional commands) and SECRET (most likely just an easter
   egg, this build style isn't defined in device_map
                                          device_map, so you can't build
   it)
For sure it won't work out of the box. You'll run into several
problems. For environment I highly recommend to use OS X El
Capitan with Xcode 7 installed. Higher SDKs should work too,
lower are highly not recommended
Problem 1: missing SDK
Embedded mechanisms of finding a path to a SDK usually fail:
 %%% building on OS     darwin xcodebuild: error: SDK "iPhoneOS" c
 xcodebuild: error:     SDK "ProductName" cannot be located.
 xcodebuild: error:     SDK "iPhoneOS" cannot be located.
 xcodebuild: error:     SDK "iPhoneOS" cannot be located.
 Makefile:86: *** A     path to a component of the SDK specifies a
This can easily be fixed by editing main makefile. In my case, for
example, it's enough to set SDK_PLATFORM variable to "iOS 9.3"
Problem 2: missing executive permissions for
tools
The next issue you might get is something looking like this:
 make: execvp: ./tools/generate_debug_hashes.py: Permission de
This is because executive permissions were lost for everything in
tools/ directory. Can easily be fixed:
 sudo chmod +x tools/*
Problem 3: missing embedded_device_map
The next thing you'll have to do is to add embedded_device_map to
/usr/local/bin or /usr/bin :
 %%%%%% library_list iBoot
 makefiles/device_map.mk:15: *** Cannot locate embedded_device
 make: *** [library_list-iBoot] Error 2
embedded_device_map is a tiny shell script that makes queries from
device_map.db
device_map.db. Very important thing. Can be found in
HomeDiagnostics.pkg
HomeDiagnostics.pkg. This is internal stuff
It also wants image3maker and img4payload
                              img4payload, but they aren't
important
Problem 4: missing device_map.db
Obviously, embedded_device_map is useless without a database it
will make queries from. If it's missing, you'll get quite unobvious
messages:
 %%%%%% library_list iBoot
 apps/iBoot/iBoot.mk:162: *** multiple target patterns. Stop.
 make: *** [library_list-iBoot] Error 2
device_map.db can be found in HomeDiagnostics.pkg as well. You
can find out where to put it by reading DEVICEMAP_DATABASE variable in
makefiles/device_map.mk or by trying to build SecureROM
                                               SecureROM, it will
print where it should be
device_map.db is SQLite 3 database that defines targets' properties
(since most of them are useless for building iBoot, most likely it's used
somewhere else. For example, there's plist version of it in Purple
Restore
Restore) and which PRODUCTS of which BUILD_STYLE
                                               BUILD_STYLEs can
be built for it
Problem 5: unused variable
For 2nd-stage bootloaders there'll be error:
 CC build/n41-iBEC-DEBUG/lib/macho/macho.o
 lib/macho/macho.c:29:17: error: unused variable 'gkalsr_debug
Solution is very easy: just remove or comment out this variable in
lib/macho/macho.c
Problem 6: -lcompiler_rt-static
When everything is almost built, when it's time to assemble all
components in a single image, this is what you'll get:
 LD build/n42-iBEC-DEVELOPMENT/iBEC.sys using -L/Applications/
 ld: warning: directory not found for option '-L/Applications/
 ld: library not found for -lcompiler_rt-static
 clang: error: linker command failed with exit code 1 (use -v
 make[2]: *** [build/n42-iBEC-DEVELOPMENT/iBEC.sys] Error 1
 make[1]: *** [build-n42-iBEC-DEVELOPMENT] Error 2
This can be easily solved as well: just remove -lcompiler_rt-static
flag from _RUNTIME_FLAGS variable in makefiles/build.mk
In the end, if everything's fine, you should see something like this:
 STRIP build/n41-iBEC-DEBUG/iBEC.stripped
 dSYM build/n41-iBEC-DEBUG/iBEC.sys.dSYM
 SIZE build/n41-iBEC-DEBUG/iBEC.size
 STRIP build/n42-iBEC-DEVELOPMENT/iBEC.stripped
 dSYM build/n42-iBEC-DEVELOPMENT/iBEC.sys.dSYM
 STRIP build/n41-iBEC-DEVELOPMENT/iBEC.stripped
 SIZE build/n42-iBEC-DEVELOPMENT/iBEC.size
 dSYM build/n41-iBEC-DEVELOPMENT/iBEC.sys.dSYM
 SIZE build/n41-iBEC-DEVELOPMENT/iBEC.size
 STRIP build/n42-iBEC-DEBUG/iBEC.stripped
 dSYM build/n42-iBEC-DEBUG/iBEC.sys.dSYM
 SIZE build/n42-iBEC-DEBUG/iBEC.size
 __TEXT __DATA __OBJC others dec hex
 380928 73728 0 0 454656 6f000
 __TEXT __DATA __OBJC others dec hex
 344064 73728 0 0 417792 66000
 BIN build/n41-iBEC-DEBUG/iBEC.bin
 BIN build/n41-iBEC-DEVELOPMENT/iBEC.bin
 __TEXT __DATA __OBJC others dec hex
 344064 73728 0 0 417792 66000
 0+0 records in
 0+0 records out
 0 bytes transferred in 0.000011 secs (0 bytes/sec)
 0+0 records in
 0+0 records out
 0 bytes transferred in 0.000010 secs (0 bytes/sec)
 BIN build/n42-iBEC-DEVELOPMENT/iBEC.bin
 0+0 records in
 0+0 records out
 0 bytes transferred in 0.000008 secs (0 bytes/sec)
 __TEXT __DATA __OBJC others dec hex
 380928 73728 0 0 454656 6f000
 BIN build/n42-iBEC-DEBUG/iBEC.bin
 0+0 records in
 0+0 records out
 0 bytes transferred in 0.000009 secs (0 bytes/sec)
 348160+0 records in
 348160+0 records out
 348160 bytes transferred in 1.518022 secs (229351 bytes/sec)
 348160+0 records in
 348160+0 records out
 348160 bytes transferred in 1.523777 secs (228485 bytes/sec)
 385024+0 records in
 385024+0 records out
 385024 bytes transferred in 1.682545 secs (228834 bytes/sec)
 385024+0 records in
 385024+0 records out
 385024 bytes transferred in 1.622805 secs (237258 bytes/sec)
In build/ directory you'll find sub-directories with your compiled
iBoots. *.sys is non-stripped Mach-O
                               Mach-O, it's very nice in disassembler,
since every function and even some variables have their native names.
*.bin   is a binary you can load on your device
Tweaking device_map.db to support A5
devices
As mentioned above, device_map.db is SQLite3 database. Its schema
can easily be gotten using embedded_device_map
                           embedded_device_map:
 embedded_device_map -db device_map.db -schema
As you can see, it consists of three TABLEs:
   Targets is most important TABLE, defines properties of every
   supported device. There're a lot of properties, but only some of
   them seem to matter for building iBoot: Target
                                             Target, TargetType
                                                       TargetType,
   Platform
   Platform, ChipID
              ChipID, SecurityEpoch
                         SecurityEpoch, CryptoHashMethod
                                          CryptoHashMethod,
   ProductID (seems to be not important) and ImageFormat
                                                   ImageFormat; look
   into makefiles/device_map.mk to check. Duplicate one of the
   Targets or just take one of existing and fill up these properties
   with data. Every of them is public knowledge
   Manifests                   manifestIds for devices from Targets
               TABLE defines manifestId
   of manifestType
      manifestTypes (valid values are Debug
                                       Debug, Development
                                                 Development,
   Production
   Production, FactoryFA and VendorInstall
                                  VendorInstall). Replace Target
   property of some unimportant device with TargetType property
   of target you created in Targets table for every manifestType
                                                    manifestType:
Filestable defines manifests for files with specified manifestId
                                                      manifestId.
No need to touch it