144 lines
7.2 KiB
Markdown
144 lines
7.2 KiB
Markdown
|
# iBoot RE (64 bits)
|
||
|
|
||
|
We focus on 64 bit iBoot cause we should:)
|
||
|
|
||
|
## In the beginning
|
||
|
|
||
|
### The Loading Address
|
||
|
|
||
|
Bootloaders in general and iBoot in particular expect to run at a specific, predefined, addresses.
|
||
|
Such an address called the __loading address__ (reset vector) of a bootloader.
|
||
|
When loading the bootloader into IDA you need to supply the loading address, so IDA will be able to resolve data and code references properly.
|
||
|
|
||
|
Most Apple bootloaders start with a relocation code which compares the loading address with the current address and moves the bootloader if needed.
|
||
|
Looking at this relocation code we can extract the loading address of the particular bootloader.
|
||
|
|
||
|
So, we start by using 0 as the loading address until we know better.
|
||
|
|
||
|
Here is an iBoot 64 bit example loaded at 0:
|
||
|
~~~ data
|
||
|
ROM:000 loc_0
|
||
|
ROM:000
|
||
|
ROM:000 ADRP X0, #loc_0@PAGE
|
||
|
ROM:004 ADD X0, X0, #loc_0@PAGEOFF <=== X0 has the current page address
|
||
|
ROM:008 LDR X1, =0x83D37B000 <=== this is the loading address
|
||
|
ROM:00C BL sub_17634
|
||
|
ROM:010 CMP X1, X0 <=== are we running at loading address
|
||
|
ROM:014 B.EQ loc_44 <=== if yes: continue booting normally
|
||
|
ROM:018 MOV X30, X1 <=== else: set LR to loading address
|
||
|
ROM:01C LDR X2, =0x83D413440
|
||
|
ROM:020 LDR X3, =0x83D37B000
|
||
|
ROM:024 SUB X2, X2, X3 <=== calculate len
|
||
|
ROM:028
|
||
|
ROM:028 loc_28 <=== copy loop
|
||
|
ROM:028 LDP X3, X4, [X0]
|
||
|
ROM:02C STP X3, X4, [X1]
|
||
|
ROM:030 ADD X0, X0, #0x10
|
||
|
ROM:034 ADD X1, X1, #0x10
|
||
|
ROM:038 SUBS X2, X2, #0x10
|
||
|
ROM:03C B.NE loc_28
|
||
|
ROM:040 RET <=== done copying -> return to loading address (LR)
|
||
|
ROM:044 ; -------------------------------------------------------------
|
||
|
ROM:044
|
||
|
ROM:044 loc_44 <=== rest of the iboot
|
||
|
ROM:044 MSR #6, #0xF ; MSR DAIFSET, #0XF
|
||
|
ROM:048 ADRP X30, #loc_AC8@PAGE
|
||
|
ROM:04C ADD X30, X30, #loc_AC8@PAGEOFF
|
||
|
ROM:050 ADRP X10, #loc_1F000@PAGE
|
||
|
ROM:054 ADD X10, X10, #loc_1F000@PAGEOFF
|
||
|
ROM:058 MSR #6, c12, c0, #0, X10 ; MSR VBAR_EL3, X10
|
||
|
~~~
|
||
|
|
||
|
So, the __loading address__ in this example is: __0x83D37B000__.
|
||
|
With this knowledge we can load the iboot to IDA with a proper loading address.
|
||
|
|
||
|
For 32 bits iboot the relocation code works the same, but it's not the first code.
|
||
|
The iboot starts with an exception vector.The first vector (reset) branches to the relocation code and it's the same from there.
|
||
|
|
||
|
Other bootloader: LLB, iBEC, IBSS have the same relocation code and hence the loading address available for grabbing.
|
||
|
|
||
|
|
||
|
### Beyond the loading address
|
||
|
|
||
|
After relocation of the iBoot to the proper running place, the boot continues.
|
||
|
Setting SP pointers, exception tables, etc.
|
||
|
Below is the rest of the first function that runs on boot.
|
||
|
Between the comments and the labels you should have no troubles following the code flow.
|
||
|
|
||
|
|
||
|
~~~ data
|
||
|
......... [ relocation code as shown above ]
|
||
|
ROM:83D07B044
|
||
|
ROM:83D07B044 ; mask exceptions
|
||
|
ROM:83D07B044 MSR #6, #0xF ; MSR DAIFSET, #0XF
|
||
|
ROM:83D07B048 ; set the next function to be executed on return
|
||
|
ROM:83D07B048 ADRP X30, #_start@PAGE
|
||
|
ROM:83D07B04C ADD X30, X30, #_start@PAGEOFF
|
||
|
ROM:83D07B050 ; setup exceptions table base address
|
||
|
ROM:83D07B050 ADRP X10, #exception_table@PAGE
|
||
|
ROM:83D07B054 ADD X10, X10, #exception_table@PAGEOFF
|
||
|
ROM:83D07B058 MSR #6, c12, c0, #0, X10 ; MSR VBAR_EL3, X10
|
||
|
ROM:83D07B05C ; clear 512K of memory
|
||
|
ROM:83D07B05C LDR X10, =base_addr_for_stack_and_stuff
|
||
|
ROM:83D07B060 LDR X11, =0x80000 ; 512K
|
||
|
ROM:83D07B064 ADD X11, X11, X10
|
||
|
ROM:83D07B068 MOV X12, #0
|
||
|
ROM:83D07B06C loop__clear_512K
|
||
|
ROM:83D07B06C STP X12, X12, [X10]
|
||
|
ROM:83D07B070 ADD X10, X10, #0x10
|
||
|
ROM:83D07B074 CMP X10, X11
|
||
|
ROM:83D07B078 B.NE loop__clear_512K
|
||
|
ROM:83D07B07C ; set base address for stack and stuff
|
||
|
ROM:83D07B07C LDR X10, =base_addr_for_stack_and_stuff
|
||
|
ROM:83D07B080 ADD X10, X10, #1,LSL#12 ; (base + 4K)
|
||
|
ROM:83D07B084 ; set EL3 SP to (base + 4K)
|
||
|
ROM:83D07B084 MOV SP, X10
|
||
|
ROM:83D07B088 MSR #5, #0 ; MSR SPSEL, #0
|
||
|
ROM:83D07B08C ADD X10, X10, #2,LSL#12 ; ((base + 4K) + 8K)
|
||
|
ROM:83D07B090 ; set EL0 SP to (base + 12K)
|
||
|
ROM:83D07B090 MOV SP, X10
|
||
|
ROM:83D07B094 ADD X20, X10, #2,LSL#12 ; (((base + 4K) + 8K) + 8K)
|
||
|
ROM:83D07B098 ; zero additional space
|
||
|
ROM:83D07B098 LDR X10, =_iboot_end ; from this addr
|
||
|
ROM:83D07B09C LDR X11, =fb_mbe ; to this addr
|
||
|
ROM:83D07B0A0 MOV X12, #0xF
|
||
|
ROM:83D07B0A4 BIC X12, X11, X12 ; end addr aligned to 16
|
||
|
ROM:83D07B0A8 MOV X13, #0
|
||
|
ROM:83D07B0AC ; clear more space, aligned 16
|
||
|
ROM:83D07B0AC loop__clear_more__aligned
|
||
|
ROM:83D07B0AC STP X13, X13, [X10],#0x10
|
||
|
ROM:83D07B0B0 CMP X10, X12
|
||
|
ROM:83D07B0B4 B.NE loop__clear_more__aligned
|
||
|
ROM:83D07B0B8 CMP X11, X12
|
||
|
ROM:83D07B0BC B.EQ loc_83D07B0CC
|
||
|
ROM:83D07B0C0 ; clear more space, the rest (unaligned)
|
||
|
ROM:83D07B0C0 loop__clear_more__unaligned
|
||
|
ROM:83D07B0C0 STR W13, [X10],#4
|
||
|
ROM:83D07B0C4 CMP X10, X11
|
||
|
ROM:83D07B0C8 B.NE loop__clear_more__unaligned
|
||
|
ROM:83D07B0CC
|
||
|
ROM:83D07B0CC loc_83D07B0CC
|
||
|
ROM:83D07B0CC ; set Exception handlers SP to (base + 20K)
|
||
|
ROM:83D07B0CC ADRP X11, #sp_for_exception_handlers@PAGE
|
||
|
ROM:83D07B0D0 ADD X11, X11, #sp_for_exception_handlers@PAGEOFF
|
||
|
ROM:83D07B0D4 STR X20, [X11]
|
||
|
ROM:83D07B0D8 RET
|
||
|
~~~
|
||
|
|
||
|
|
||
|
Notes:
|
||
|
- MSR DAIFSET, #0XF (mask all exceptions)
|
||
|
This is very early stage and we don't want to be interrupted before we can handle exceptions properly.
|
||
|
- _start
|
||
|
We are running a kind of a 'reset vector' code now and this is the next
|
||
|
function we execute by setting its address in the LR register and running with the RET instruction.
|
||
|
- exception_table
|
||
|
The address that goes into the VBAR_EL3 register is the beginning of the EL3 exception table.
|
||
|
ARMv8 is very different from ARMv7 in how the exception table looks and works.
|
||
|
Some of the differences are:
|
||
|
- Instead of vector of dwords it has 0x80 bytes of code for each exception
|
||
|
- There are multiple entries for the same exception depending on the circumstances of where the exception is taken from
|
||
|
|
||
|
|
||
|
|