Difference between revisions of "Ultrasn0w"

From The iPhone Wiki
Jump to: navigation, search
(Added compatibility table.)
m
 
(83 intermediate revisions by 25 users not shown)
Line 1: Line 1:
  +
{{lowercase}}
The first [[iPhone 3G]] [[Unlock 2.0|unlock]]. Released on 01/01/09. [http://blog.iphone-dev.org/post/67797811/dont-eat-yellowsn0w]
 
  +
'''ultrasn0w''' (previously: yellowsn0w) is an [[N82AP|iPhone 3G]], [[N88AP|iPhone 3GS]] and [[N90AP|iPhone 4 (iPhone3,1)]] [[Unlock 2.0|unlock]] payload. yellowsn0w was released on [http://blog.iphone-dev.org/post/67797811 New Years Day 2009]. ultrasn0w was released on [http://blog.iphone-dev.org/post/128573459/ultras-now {{date|2009|06|23}}]. The official repository for ultrasn0w (repo666.ultrasn0w.com) has shut down.
   
  +
== Credit ==
A demo (of a console-only version of the app though) can be seen at http://qik.com/video/729275.
 
  +
[[User:MuscleNerd|MuscleNerd]] and [[iPhone Dev Team]]
   
==Credit==
+
== Exploit ==
  +
Relies on an unsigned code injection vulnerability.
[[geohot]] (injection exploit), MuscleNerd, and [[The dev team]] (payload).
 
 
==Exploit==
 
Relies on an unsigned code exploit.
 
   
 
The actual unlock works by a daemon patching the baseband's RAM on-the-fly, overriding the carrier lock code. It is not permanent because of the signature checks - the bootloader has to pass the sigchecks and the baseband has to pass them too, so any change to the baseband/bootloader cannot be made.
 
The actual unlock works by a daemon patching the baseband's RAM on-the-fly, overriding the carrier lock code. It is not permanent because of the signature checks - the bootloader has to pass the sigchecks and the baseband has to pass them too, so any change to the baseband/bootloader cannot be made.
   
  +
== Injection Vectors ==
The exploit itself is a buffer overflow in the at+stkprof cmd that devteam used to patch out the carrier checks in RAM.
 
  +
* [[AT+stkprof]] - used by yellowsn0w to unlock [[X-Gold 608]] baseband [[02.28.00]].
  +
* [[AT+XLOG Vulnerability]] - used by ultrasn0w to unlock [[X-Gold 608]] baseband [[04.26.08]].
  +
* [[AT+XAPP Vulnerability]] - used by ultrasn0w 1.0-1 and 1.2 to unlock public releases of [[X-Gold 608]] basebands [[04.26.08]] through [[05.13.04]] and [[06.15.00]] (ultrasn0w 1.2 only), and [[XMM 6180]] baseband [[01.59.00]])
  +
  +
== Compatible Basebands ==
  +
=== iPhone 3G/3GS ===
  +
* 02.28.00 (yellowsn0w only)
  +
* 04.26.08
  +
* 05.11.07
  +
* 05.12.01
  +
* 05.13.04
  +
* 06.15.00
  +
  +
=== iPhone 4 ===
  +
* 01.59.00 (if device is on iOS 5.x or lower)
  +
  +
== ultrasn0w payload with comments (by [[User:Oranav|Oranav]]) ==
  +
=== Code loader (incl. Stage2) ===
  +
<pre>
  +
ROM:00000000 ; =============== S U B R O U T I N E =======================================
  +
ROM:00000000
  +
ROM:00000000
  +
ROM:00000000 code_loader
  +
ROM:00000000 dest_addr = R1
  +
ROM:00000000 src_addr = R6
  +
ROM:00000000 MOVLS dest_addr, 0x110
  +
ROM:00000004 ADDS dest_addr, #6
  +
ROM:00000006 LSLS dest_addr, dest_addr, #8 ; unused ram to place code = 0x11600
  +
ROM:00000008 ADDS R2, dest_addr, #1 ; thumbing
  +
ROM:0000000A
  +
ROM:0000000A loop ; CODE XREF: code_loader+24�j
  +
ROM:0000000A MOVLS R0, 0x22 ; '"'
  +
ROM:0000000E LDRB R3, [src_addr] ; first nibble
  +
ROM:00000010 CMP R0, R3
  +
ROM:00000012 LDRB R0, [src_addr,#1] ; second nibble
  +
ROM:00000014 BEQ run ; branch if end of string
  +
ROM:00000016 SUBS R3, #0x41 ; subtract 'A'
  +
ROM:00000018 SUBS R0, #0x41 ; subtract 'A'
  +
ROM:0000001A LSLS R3, R3, #4 ; make room for next nibble
  +
ROM:0000001C ADDS R3, R3, R0 ; put them together as a byte
  +
ROM:0000001E STRB R3, [dest_addr]
  +
ROM:00000020 ADDS dest_addr, #1
  +
ROM:00000022 ADDS src_addr, #2
  +
ROM:00000024 B loop
  +
ROM:00000026 ; ---------------------------------------------------------------------------
  +
ROM:00000026
  +
ROM:00000026 run ; CODE XREF: code_loader+14�j
  +
ROM:00000026 BLX R2 ; handler_replace()
  +
ROM:00000028 MOVLS R0, 0 ; safe exit
  +
ROM:0000002C ADDS dest_addr, R0, #0
  +
ROM:0000002E BLX R4
  +
ROM:00000030 MOV SP, R5
  +
ROM:00000032 POP {R0-src_addr,PC}
  +
ROM:00000032 ; End of function code_loader
  +
</pre>
  +
  +
===Handler replace===
  +
<pre>
  +
RAM:00011600 ; =============== S U B R O U T I N E =======================================
  +
RAM:00011600
  +
RAM:00011600
  +
RAM:00011600 handler_replace
  +
RAM:00011600 PUSH {LR}
  +
RAM:00011602 LDR R0, =0x40492FC0 ; where to save task_loop_jmp + task_loop
  +
RAM:00011604 ADR R1, task_loop_jmp
  +
RAM:00011606 ADR R2, task_loop_end
  +
RAM:00011608 SUBS R2, R2, R1 ; size of task_loop + task_loop_jmp = 0x70
  +
RAM:0001160A LDR R3, =0x2040882C ; memcpy()
  +
RAM:0001160C BLX R3
  +
RAM:0001160E LDR R0, =0x40492C20 ; where to save task_creator_jmp + task_creator
  +
RAM:00011610 ADR R1, task_creator_jmp
  +
RAM:00011612 ADR R2, task_creator_end
  +
RAM:00011614 SUBS R2, R2, R1 ; size of task_creator + task_creator_jmp = 0xA0
  +
RAM:00011616 LDR R3, =0x2040882C ; memcpy()
  +
RAM:00011618 BLX R3
  +
RAM:0001161A LDR R0, =0x40492C20
  +
RAM:0001161C BLX R0 ; task_creator_jmp()
  +
RAM:0001161E POP {PC}
  +
RAM:0001161E ; End of function handler_replace
  +
</pre>
  +
  +
===Task creator (thanks Darkmen for the comments!)===
  +
<pre>
  +
RAM:40492C20 ; =============== S U B R O U T I N E =======================================
  +
RAM:40492C20
  +
RAM:40492C20
  +
RAM:40492C20 task_creator_jmp
  +
RAM:40492C20 STMFD SP!, {R1-R12,LR}
  +
RAM:40492C24 BLX task_creator
  +
RAM:40492C28 LDMFD SP!, {R1-R12,PC}
  +
RAM:40492C28 ; End of function task_creator_jmp
  +
RAM:40492C28
  +
RAM:40492C2C
  +
RAM:40492C2C ; =============== S U B R O U T I N E =======================================
  +
RAM:40492C2C
  +
RAM:40492C2C
  +
RAM:40492C2C task_creator ; CODE XREF: task_creator_jmp+4�p
  +
RAM:40492C2C PUSH {R4-R7,LR}
  +
RAM:40492C2E LDR R3, =0x401ED3B8 ; jumptable var
  +
RAM:40492C30 MOVLS R4, 0x800
  +
RAM:40492C34 SUB SP, SP, #0x24
  +
RAM:40492C36 STRH R0, [R3] ; task_creator_jmp addr
  +
RAM:40492C38 LDR R5, =0x201493F0 ; malloc
  +
RAM:40492C3A ADDS R0, R4, #0 ; 0x800
  +
RAM:40492C3C ADDS R7, R1, #0 ; R7 = resp_string
  +
RAM:40492C3E BLX R5 ; malloc(0x800)
  +
RAM:40492C40 ADDS R6, R0, #0 ; R6 = addr returned from malloc
  +
RAM:40492C42 MOVS R0, #0x98 ; sizeof(NU_TASK)
  +
RAM:40492C44 BLX R5 ; malloc(sizeof(NU_TASK))
  +
RAM:40492C46 MOVS R2, #0
  +
RAM:40492C48 MOVS R3, #0x44
  +
RAM:40492C4A LDR R1, =aDevteam1 ; char *name
  +
RAM:40492C4C STR R2, [R0,#0xC] ; task.field=0
  +
RAM:40492C4E STR R3, [SP,#0xC] ; priority = 0x44
  +
RAM:40492C50 MOVS R3, #0xA
  +
RAM:40492C52 STR R3, [SP,#0x14] ; preempt = NU_PREEMPT
  +
RAM:40492C54 MOVS R3, #0xC
  +
RAM:40492C56 STR R2, [SP] ; void *argv = 0
  +
RAM:40492C58 STR R4, [SP,#8] ; stack_size = 0x800
  +
RAM:40492C5A STR R2, [SP,#0x10] ; time_slice = 0
  +
RAM:40492C5C STR R3, [SP,#0x18] ; auto_start = NU_START
  +
RAM:40492C5E LDR R2, =0x40492FC0 ; task_loop_jmp address
  +
RAM:40492C60 STR R6, [SP,#4] ; void *stack_address = malloc(0x800)
  +
RAM:40492C62 MOVS R3, #0
  +
RAM:40492C64 LDR R4, =0x2043E5B4 ; NU_Create_Task
  +
RAM:40492C66 BLX R4 ; status = NU_Create_Task()
  +
RAM:40492C68 ADDS R2, R0, #0 ; R2 = status (for the %d reference in sprintf)
  +
RAM:40492C6A CMP R0, #0 ; success = zero
  +
RAM:40492C6C BNE status_error
  +
RAM:40492C6E LDR R1, =aOk ; "OK!"
  +
RAM:40492C70 ADDS R0, R7, #0 ; resp_string
  +
RAM:40492C72 LDR R3, =0x204B11F0 ; sprintf
  +
RAM:40492C74 BLX R3 ; sprintf(resp_string, "OK!")
  +
RAM:40492C76 B exit
  +
RAM:40492C78 ; ---------------------------------------------------------------------------
  +
RAM:40492C78
  +
RAM:40492C78 status_error ; CODE XREF: task_creator+40�j
  +
RAM:40492C78 LDR R1, =aErrorD ; "ERROR %d"
  +
RAM:40492C7A ADDS R0, R7, #0 ; resp_string
  +
RAM:40492C7C LDR R3, =0x204B11F0 ; sprintf
  +
RAM:40492C7E BLX R3 ; sprintf(resp_string, "ERROR %d", status)
  +
RAM:40492C80
  +
RAM:40492C80 exit ; CODE XREF: task_creator+4A�j
  +
RAM:40492C80 ADD SP, SP, #0x24 ; fixing stack
  +
RAM:40492C82 POP {R4-R7,PC}
  +
RAM:40492C82 ; End of function task_creator
  +
</pre>
  +
  +
===Unlock task loop (thanks Darkmen for the comments!)===
  +
<pre>
  +
RAM:00011630 ; =============== S U B R O U T I N E =======================================
  +
RAM:00011630
  +
RAM:00011630
  +
RAM:00011630 task_loop_jmp
  +
RAM:00011630 STMFD SP!, {R1-R12,LR}
  +
RAM:00011634 BLX task_loop
  +
RAM:00011634 ; ---------------------------------------------------------------------------
  +
RAM:00011638 LDMFD SP!, {R1-R12,PC}
  +
RAM:00011638 ; End of function task_loop_jmp
  +
RAM:00011638
  +
RAM:0001163C
  +
RAM:0001163C ; =============== S U B R O U T I N E =======================================
  +
RAM:0001163C
  +
RAM:0001163C
  +
RAM:0001163C task_loop
  +
RAM:0001163C PUSH {R4,R5,LR}
  +
RAM:0001163E LDR R5, =0x401E829C ; sec mailbox
  +
RAM:00011640 SUB SP, SP, #0x14
  +
RAM:00011642
  +
RAM:00011642 loop ; CODE XREF: task_loop+44�j
  +
RAM:00011642 LDR R3, =0x2042FFD8 ; NU_Receive_From_Mailbox
  +
RAM:00011644 ADDS R0, R5, #0 ; NU_MAILBOX *mailbox
  +
RAM:00011646 MOV R1, SP ; void *Message
  +
RAM:00011648 MOVS R2, #0xFF ; Timeout
  +
RAM:0001164A BLX R3 ; NU_Receive_From_Mailbox(sec_mailbox,SP,0xFF)
  +
RAM:0001164C LDR R3, [SP] ; Message[0]
  +
RAM:0001164E CMP R3, #0xD ; Message[0] = 0xD ?
  +
RAM:00011650 BNE skip
  +
RAM:00011652 LDR R1, [SP,#4] ; Message[1]
  +
RAM:00011654 LDR R3, =0x40301650
  +
RAM:00011656 LDR R2, [R1] ; Message[1].field0
  +
RAM:00011658 STR R2, [R3] ; sec_task_var1 = Message[1].field0
  +
RAM:0001165A ADDS R3, #4 ; 0x40301654
  +
RAM:0001165C LDR R2, [R1,#4] ; Message[1].field1
  +
RAM:0001165E STR R2, [R3] ; sec_task_var2 = Message[1].field1
  +
RAM:00011660 LDR R2, [R1,#8] ; Message[1].field2
  +
RAM:00011662 LDR R3, =0x100FF00
  +
RAM:00011664 STR R3, [R2] ; Message[1].field2[0] = 0x100FF00
  +
RAM:00011666 LDR R3, =0x4020401
  +
RAM:00011668 STR R3, [R2,#4] ; Message[1].field2[1] = 0x4020401
  +
RAM:0001166A LDR R3, =0x4040403
  +
RAM:0001166C STR R3, [R2,#8] ; Message[1].field2[2] = 0x4040403
  +
RAM:0001166E MOVS R3, #1
  +
RAM:00011670 STR R3, [R1,#0xC] ; Message[1].field3 = 1
  +
RAM:00011672 MOVS R3, #0x20 ; ' '
  +
RAM:00011674 STR R3, [SP] ; Message[0] = 0x20
  +
RAM:00011676
  +
RAM:00011676 skip ; CODE XREF: task_loop+14�j
  +
RAM:00011676 ADDS R0, R5, #0 ; sec mailbox
  +
RAM:00011678 MOV R1, SP ; void *Message
  +
RAM:0001167A MOVS R2, #0xFF ; timeout
  +
RAM:0001167C LDR R3, =0x20430040
  +
RAM:0001167E BLX R3 ; NU_Send_To_Mailbox()
  +
RAM:00011680 B loop
  +
RAM:00011680 ; End of function task_loop
  +
RAM:00011680
  +
RAM:00011680 ; ---------------------------------------------------------------------------
  +
</pre>
  +
  +
== Old yellowsn0w payload w/ comments (by Darkmen) ==
  +
  +
The exploit consists from 4 parts:
  +
=== Code loader ===
  +
<pre>
  +
ROM:00000000 ; =============== S U B R O U T I N E =======================================
  +
ROM:00000000
  +
ROM:00000000
  +
ROM:00000000 loader
  +
ROM:00000000 LDR R2, =0x11700 ; unused ram to place code
  +
ROM:00000002 ADDS R4, R2, #1 ; thumb switch
  +
ROM:00000004 LDR R3, =0x40159FBF ; at-handler buffer where stage2 binary and following hexdata are
  +
ROM:00000006
  +
ROM:00000006 copy.loop ; CODE XREF: loader+12�j
  +
ROM:00000006 LDRB R0, [R3] ; copying code+data until double quotes
  +
ROM:00000008 CMP R0, #0x22 ; '"'
  +
ROM:0000000A BEQ run ; jump thumb code
  +
ROM:0000000C STRB R0, [R2]
  +
ROM:0000000E ADDS R2, #1
  +
ROM:00000010 ADDS R3, #1
  +
ROM:00000012 B copy.loop ;
  +
ROM:00000014 run ; CODE XREF: loader+A�j
  +
ROM:00000014 BX R4 ; jump stage2 code
  +
ROM:00000014 ; End of function loader
  +
ROM:00000014
  +
ROM:00000014 ; ---------------------------------------------------------------------------
  +
</pre>
  +
  +
=== Stage2(tm) ===
  +
<pre>
  +
RAM:00000000 ; =============== S U B R O U T I N E =======================================
  +
RAM:00000000 stage2
  +
RAM:00000000 ADDS R2, #0x10 ; R2 = 0x11700 + stage2 size
  +
RAM:00000002 MOVS R7, #0xF
  +
RAM:00000004 BICS R2, R7 ; align offset by 0x10
  +
RAM:00000006 ADDS R7, R2, #0 ; saving address to jump
  +
RAM:00000008 ADR R4, 0x44 ; skipping Stage2 size and taking first char from at-string
  +
RAM:0000000A ADR R5, char2byte ; loading routine addr
  +
RAM:0000000C ADDS R5, #1 ; thumb
  +
RAM:0000000E
  +
RAM:0000000E loop ; CODE XREF: stage2+2C�j
  +
RAM:0000000E LDRB R1, [R4] ; at-string[index]
  +
RAM:00000010 CMP R1, #'x' ; end of line?
  +
RAM:00000012 BEQ jump_code
  +
RAM:00000014 BLX R5 ; char2byte first hakfbyte
  +
RAM:00000016 LSLS R3, R1, #4 ; <<4 0X becoming X0
  +
RAM:00000018 LDRB R1, [R4,#1] ; at-string[index+1]
  +
RAM:0000001A BLX R5 ; char2hex second halfbyte
  +
RAM:0000001C NOP
  +
RAM:0000001E NOP
  +
RAM:00000020 NOP
  +
RAM:00000022 NOP
  +
RAM:00000024 ADDS R1, R1, R3 ; R1 = complete byte
  +
RAM:00000026 STRB R1, [R2] ; storing byte to dst
  +
RAM:00000028 ADDS R4, #2 ; hexstr_index+=2
  +
RAM:0000002A ADDS R2, #1 ; dst++
  +
RAM:0000002C B loop ; at-string[index]
  +
RAM:0000002E jump_code
  +
RAM:0000002E NOP
  +
RAM:00000030 NOP
  +
RAM:00000032 ADDS R7, #1 ; thumbing
  +
RAM:00000034 BX R7 ; run Task creator code
  +
RAM:00000034 ; End of function stage2
  +
RAM:00000038
  +
RAM:00000038 ; =============== S U B R O U T I N E =======================================
  +
RAM:00000038 char2byte ; DATA XREF: stage2+A�o
  +
RAM:00000038 CMP R1, #0x41 ; 'A'
  +
RAM:0000003A BGE letter ; letter to number
  +
RAM:0000003C SUBS R1, #0x30 ; '0' ; digit to number
  +
RAM:0000003E BX LR
  +
RAM:00000040 letter ; CODE XREF: char2byte+2�j
  +
RAM:00000040 SUBS R1, #0x37 ; '7' ; letter to number
  +
RAM:00000042 BX LR ; ret
  +
RAM:00000042 ; End of function char2byte
  +
</pre>
  +
  +
===Task creator===
  +
<pre>
  +
RAM:000119A0 ; =============== S U B R O U T I N E =======================================
  +
RAM:000119A0
  +
RAM:000119A0
  +
RAM:000119A0 handler_replace
  +
RAM:000119A0 LDR R0, =0x4011714C ; soft reset handler addr
  +
RAM:000119A2 ADR R1, new_handler
  +
RAM:000119A4 ADDS R1, #1 ; thumbing
  +
RAM:000119A6 STR R1, [R0] ; setting new handler
  +
RAM:000119A8 POP {R0-R4,PC} ; safe exit fixing stack
  +
RAM:000119A8 ; End of function handler_replace
  +
  +
RAM:000119B0 ; =============== S U B R O U T I N E =======================================
  +
RAM:000119B0
  +
RAM:000119B0
  +
RAM:000119B0 new_handler ; DATA XREF: handler_replace+2�o
  +
RAM:000119B0 PUSH {R4-R7,LR}
  +
RAM:000119B2 LDR R3, =0x403BB344 ; jamptable var
  +
RAM:000119B4 MOVS R6, #0x80
  +
RAM:000119B6 SUB SP, SP, #0x2C
  +
RAM:000119B8 LSLS R6, R6, #4 ; 0x200
  +
RAM:000119BA STRH R0, [R3] ; saving R0 to mem var
  +
RAM:000119BC STR R1, [SP,#0x40+resp_string] ; saving responce prt to stack
  +
RAM:000119BE LDR R4, =0x201420AC ; malloc
  +
RAM:000119C0 ADDS R0, R6, #0
  +
RAM:000119C2 BLX R4 ; malloc(0x200)
  +
RAM:000119C4 MOVS R5, #0
  +
RAM:000119C6 STR R0, [SP,#0x40+ptr_200] ; saving pointer to stack
  +
RAM:000119C8 MOVS R0, #0x98 ; sizeof(NU_TASK)
  +
RAM:000119CA BLX R4 ; malloc(0x98)
  +
RAM:000119CC ADDS R7, R0, #0 ; R7 = task
  +
RAM:000119CE STR R5, [R0,#0xC] ; task.field=0
  +
RAM:000119D0 MOVS R0, 0x100
  +
RAM:000119D4 BLX R4 ; malloc(0x100)
  +
RAM:000119D6 MOVS R2, #0x80
  +
RAM:000119D8 LDR R1, =task_loop ; src
  +
RAM:000119DA LSLS R2, R2, #1 ; size to copy
  +
RAM:000119DC LDR R3, =0x203C58A0 ; bytecpy
  +
RAM:000119DE ADDS R4, R0, #0 ; R4 = dyn_task_loop
  +
RAM:000119E0 BLX R3 ; bytecpy(task_loop, dyn_task_loop, 0x100)
  +
RAM:000119E2 LDR R3, [SP,#0x40+ptr_200]
  +
RAM:000119E4 STR R3, [SP,#4] ; void *stack_address = malloc(0x200)
  +
RAM:000119E6 MOVS R3, #0x44
  +
RAM:000119E8 STR R3, [SP,#0xC] ; priority = 0x44
  +
RAM:000119EA MOVS R3, #0xA
  +
RAM:000119EC ADDS R4, #1 ; thumbing dyn_task_loop
  +
RAM:000119EE STR R3, [SP,#0x14] ; preempt = NU_PREEMPT
  +
RAM:000119F0 MOVS R3, #0xC
  +
RAM:000119F2 ADDS R2, R4, #0 ; void(*task_entry)
  +
RAM:000119F4 STR R3, [SP,#0x18] ; auto_start = NU_START
  +
RAM:000119F6 LDR R1, =devteam1 ; char *name
  +
RAM:000119F8 STR R5, [SP] ; void *argv = 0
  +
RAM:000119FA STR R6, [SP,#8] ; stack_size = 0x200
  +
RAM:000119FC STR R5, [SP,#0x10] ; time_slice = 0
  +
RAM:000119FE ADDS R0, R7, #0 ; NU_TASK *task
  +
RAM:00011A00 MOVS R3, #0 ; int argc = 0
  +
RAM:00011A02 LDR R4, =0x203FB540 ; NU_Create_Task
  +
RAM:00011A04 BLX R4 ; status = NU_Create_Task()
  +
RAM:00011A06 ADDS R2, R0, #0
  +
RAM:00011A08 CMP R0, #0 ; success = zero
  +
RAM:00011A0A BNE status_error
  +
RAM:00011A0C LDR R1, =OK
  +
RAM:00011A0E LDR R0, [SP,#0x40+resp_string]
  +
RAM:00011A10 LDR R3, =0x2046DD00 ; sprintf
  +
RAM:00011A12 BLX R3 ; sprintf(resp_string,"OK")
  +
RAM:00011A14 B exit ; fixing stack
  +
RAM:00011A16 ; ---------------------------------------------------------------------------
  +
RAM:00011A16
  +
RAM:00011A16 status_error ; CODE XREF: new_handler+5A�j
  +
RAM:00011A16 LDR R1, =ERROR
  +
RAM:00011A18 LDR R0, [SP,#0x40+resp_string]
  +
RAM:00011A1A LDR R3, =0x2046DD00 ; sprintf
  +
RAM:00011A1C BLX R3 ; sprintf(resp_string,"ERROR")
  +
RAM:00011A1E
  +
RAM:00011A1E exit ; CODE XREF: new_handler+64�j
  +
RAM:00011A1E ADD SP, SP, #0x2C ; fixing stack
  +
RAM:00011A20 POP {R4-R7,PC} ; bye
  +
RAM:00011A20 ; End of function new_handler
  +
RAM:00011A20
  +
RAM:00011A20 ; ---------------------------------------------------------------------------
  +
</pre>
  +
  +
=== Unlock task loop ===
  +
<pre>
  +
RAM:00011A64 ; =============== S U B R O U T I N E =======================================
  +
RAM:00011A64
  +
RAM:00011A64 task_loop ; DATA XREF: RAM:off_11A2C�o
  +
RAM:00011A64 PUSH {R4,R5,LR}
  +
RAM:00011A66 LDR R5, =0x40232754 ; sec mailbox
  +
RAM:00011A68 SUB SP, SP, #0x14
  +
RAM:00011A6A
  +
RAM:00011A6A loop ; CODE XREF: task_loop+44�j
  +
RAM:00011A6A LDR R3, =0x20165998 ; NU_Receive_From_Mailbox
  +
RAM:00011A6C ADDS R0, R5, #0 ; NU_MAILBOX *mailbox
  +
RAM:00011A6E MOV R1, SP ; void *Message
  +
RAM:00011A70 MOVS R2, #0xFF ; Timeout
  +
RAM:00011A72 BLX R3 ; NU_Receive_From_Mailbox(sec_mailbox,SP,0xFF)
  +
RAM:00011A74 LDR R3, [SP] ; Message[0]
  +
RAM:00011A76 CMP R3, #0xD ; Message[0] = 0xD ?
  +
RAM:00011A78 BNE skip ;
  +
RAM:00011A7A LDR R1, [SP,#4] ; Message[1]
  +
RAM:00011A7C LDR R3, =0x402F79BC
  +
RAM:00011A7E LDR R2, [R1] ; Message[1].field0
  +
RAM:00011A80 STR R2, [R3] ; sec_task_var1 = Message[1].field0
  +
RAM:00011A82 ADDS R3, #4 ; 0x402F79C0
  +
RAM:00011A84 LDR R2, [R1,#4] ; Message[1].field1
  +
RAM:00011A86 STR R2, [R3] ; sec_task_var2 = Message[1].field1
  +
RAM:00011A88 LDR R2, [R1,#8] ; Message[1].field2
  +
RAM:00011A8A LDR R3, =0x100FF00
  +
RAM:00011A8C STR R3, [R2] ; Message[1].field2[0] = 0x100FF00
  +
RAM:00011A8E LDR R3, =0x4020401
  +
RAM:00011A90 STR R3, [R2,#4] ; Message[1].field2[1] = 0x4020401
  +
RAM:00011A92 LDR R3, =0x4040403
  +
RAM:00011A94 STR R3, [R2,#8] ; Message[1].field2[2] = 0x4040403
  +
RAM:00011A96 MOVS R3, #1
  +
RAM:00011A98 STR R3, [R1,#0xC] ; Message[1].field3 = 1
  +
RAM:00011A9A MOVS R3, #0x20
  +
RAM:00011A9C STR R3, [SP] ; Message[0] = 0x20
  +
RAM:00011A9E
  +
RAM:00011A9E skip ; CODE XREF: task_loop+14�j
  +
RAM:00011A9E ADDS R0, R5, #0 ; sec mailbox
  +
RAM:00011AA0 MOV R1, SP ; void *Message
  +
RAM:00011AA2 MOVS R2, #0xFF ; timeout
  +
RAM:00011AA4 LDR R3, =0x203ED568
  +
RAM:00011AA6 BLX R3 ; NU_Send_To_Mailbox()
  +
RAM:00011AA8 B loop ; NU_Receive_From_Mailbox
  +
RAM:00011AA8 ; End of function task_loop
  +
</pre>
  +
  +
=== Explanation from [[User:planetbeing|planetbeing]] ===
  +
<pre>
  +
13:24:29 <crash-x_> especially how does ultra/yellow sn0w work
  +
13:24:40 <crash-x_> are you overwriting instructions
  +
13:24:48 <crash-x_> or some values in memory to make it accept the sim?
  +
13:24:48 <planetbeing> Nah.
  +
13:24:53 <planetbeing> It's a task.
  +
13:25:06 <planetbeing> That just waits for securiy messages to go through the inbox.
  +
13:25:13 <westbaer> planetbeing: btw, why isnt yellowsn0w/ultrasn0w not open-source anymore? like u posted an *oooold* version once
  +
  +
...
  +
  +
13:26:33 <planetbeing> The only thing I do for ys/us is the loader bit.
  +
13:26:39 <westbaer> so whats actually the loader stuff you've been talking about?
  +
13:26:46 <planetbeing> That uses the exploit to start MuscleNerd's payload.
  +
13:27:21 <westbaer> ah
  +
13:27:26 <planetbeing> Well, you have a vulnerability.
  +
13:27:30 <planetbeing> And you want to load a large chunk of code.
  +
13:27:39 <planetbeing> And you don't have much room to wriggle in for your overflow
  +
13:28:21 <westbaer> aah, makes sense
  +
13:28:50 <planetbeing> So the solution is a small loader that loads the rest of the code, and overcomes any restrictions there are on allowable characters.
  +
13:28:55 <ashikase> francis: pm
  +
13:28:59 <westbaer> yeah
  +
13:29:10 <crash-x_> planetbeing: the baseband is it like one process that runs there
  +
13:29:19 <crash-x_> or is it like a small os with process and stuff
  +
13:29:19 <planetbeing> Basically a good loader should turn a vulnerability into a reliable platform for the execution of arbitrary code, unrestricted by vulnerability-specific stuff.
  +
13:29:37 <planetbeing> Oh, it's a full-featured OS.
  +
13:29:38 <planetbeing> Nucleus.
  +
13:29:51 <planetbeing> http://www.mentor.com/products/embedded_software/nucleus_rtos/
  +
13:29:54 <crash-x_> and when you execute an at command
  +
13:30:06 <crash-x_> does that start another process that is crashed then
  +
13:30:21 <planetbeing> Ideally, you don't crash anything.
  +
13:30:21 <crash-x_> or does it crash like the main baseband program
  +
13:30:23 <planetbeing> And we don't.
  +
13:30:49 <crash-x_> so am i understand it right
  +
13:30:50 <westbaer> wait. is nucleus on the baseband already installed or do you actually inject it with ultrasn0w?
  +
13:30:51 <planetbeing> We load a bunch of code into certain memory locations, execute them, and then return safely back to the main command parser task.
  +
13:31:00 <planetbeing> Nucleus is what the baseband runs.
  +
13:31:04 <westbaer> ah ok
  +
13:31:29 <planetbeing> I mean, even the bootrom is an OS.
  +
13:31:36 <planetbeing> With one task, but it still has a scheduler. =P
  +
13:31:39 <crash-x_> ah thats how you do it
  +
13:31:42 <westbaer> heh
  +
13:31:44 <crash-x_> and about your payload
  +
13:31:57 <crash-x_> does it start a new process like using fork()
  +
13:32:03 <crash-x_> or does it all the work in the exploited process
  +
13:32:11 <planetbeing> It uses Nucleus-specific calls that create the new task.
  +
13:32:19 <planetbeing> Well, the payload has to create a new task
  +
13:32:22 <westbaer> I think they are documented on the wiki
  +
13:32:25 <planetbeing> To monitor for certain events.
  +
13:32:47 <planetbeing> Yeah, just read Darkmen's decompile.
  +
13:33:00 <planetbeing> us has the exact same payload as ys
  +
13:33:08 <planetbeing> Just different addresses for function calls and stuff.
  +
13:33:19 <planetbeing> And I had to rewrite the loader due to even tighter constraints.
  +
13:33:28 <crash-x_> thats cool, thanks for explaining
  +
13:33:34 <westbaer> yup, thanks
   
==Source Code==
 
The source code for yellowsn0w is now live [http://xs1.iphwn.org/releases/yellowsn0w.tar.bz2]
 
   
  +
From irc.saurik.com #iphone on Sunday {{date|2009|07|05}}.
==Compatibility==
 
  +
</pre>
yellowsn0w doesn't work with some carriers or stops working after a while.
 
   
  +
== Source Code ==
{| class="wikitable sortable" style="text-align: center; width: auto; table-layout: fixed; border-collapse: collapse;" border="1"
 
  +
The [http://xs1.iphwn.org/releases/yellowsn0w.tar.bz2 source code] for yellowsn0w 0.9.1 (old version) was released along with yellowsn0w release.
|-
 
! Country
 
! Provider
 
! SIM/USIM
 
! Calls?
 
! SMS?
 
! GPRS/EDGE?
 
! UMTS/HSDPA?
 
! Comments
 
|-
 
| Bermuda
 
| Mobility
 
| SIM
 
| {{no}}
 
| {{no}}
 
| {{no}}
 
| {{no}}
 
| Works for about ten minutes then "Sim Failure" occurs and yellowsn0w stops working.
 
|-}
 
   
==See Also==
+
== See Also ==
* [[Unlock 2.0]]
+
* [[X-Gold 608 Unlock]]
* [[Baseband]]
+
* [[X-Gold 608]]
  +
* [[Baseband Device]]
   
==External links==
+
== External Links ==
* [http://chronic-dev.org/blog/2008/12/props/ Chronic Dev's post about yellowsn0w]
+
* [http://chronic-dev.org/blog/2008/12/props/ Chronic Dev's post about Yellowsn0w]
* [http://blog.iphone-dev.org/post/65126957/tis-the-season-to-be-jolly yellowsn0w Announcement]
+
* [http://blog.iphone-dev.org/post/65126957/tis-the-season-to-be-jolly Yellowsn0w Announcement]
* [http://blog.iphone-dev.org/post/60599514/the-silicon-chip-inside-her-head What yellowsn0w relies on]
+
* [http://qik.com/video/729275 MuscleNerd's yellowsn0w Demo]
  +
* [http://www.youtube.com/watch?v=kd5vOy2m5uY MuscleNerd's ultrasn0w demo]
  +
* [https://gist.github.com/xerub/2b873a4ca08820a4d4de xerub code]
   
 
[[Category:Unlocking Methods]]
 
[[Category:Unlocking Methods]]
  +
[[Category:Baseband]]
  +
[[Category:Hacking Software]]

Latest revision as of 13:28, 17 September 2021

ultrasn0w (previously: yellowsn0w) is an iPhone 3G, iPhone 3GS and iPhone 4 (iPhone3,1) unlock payload. yellowsn0w was released on New Years Day 2009. ultrasn0w was released on 23 June 2009. The official repository for ultrasn0w (repo666.ultrasn0w.com) has shut down.

Credit

MuscleNerd and iPhone Dev Team

Exploit

Relies on an unsigned code injection vulnerability.

The actual unlock works by a daemon patching the baseband's RAM on-the-fly, overriding the carrier lock code. It is not permanent because of the signature checks - the bootloader has to pass the sigchecks and the baseband has to pass them too, so any change to the baseband/bootloader cannot be made.

Injection Vectors

Compatible Basebands

iPhone 3G/3GS

  • 02.28.00 (yellowsn0w only)
  • 04.26.08
  • 05.11.07
  • 05.12.01
  • 05.13.04
  • 06.15.00

iPhone 4

  • 01.59.00 (if device is on iOS 5.x or lower)

ultrasn0w payload with comments (by Oranav)

Code loader (incl. Stage2)

ROM:00000000 ; =============== S U B R O U T I N E =======================================
ROM:00000000
ROM:00000000
ROM:00000000 code_loader
ROM:00000000 dest_addr = R1
ROM:00000000 src_addr = R6
ROM:00000000                 MOVLS   dest_addr, 0x110
ROM:00000004                 ADDS    dest_addr, #6
ROM:00000006                 LSLS    dest_addr, dest_addr, #8 ; unused ram to place code = 0x11600
ROM:00000008                 ADDS    R2, dest_addr, #1 ; thumbing
ROM:0000000A
ROM:0000000A loop                                    ; CODE XREF: code_loader+24�j
ROM:0000000A                 MOVLS   R0, 0x22 ; '"'
ROM:0000000E                 LDRB    R3, [src_addr]  ; first nibble
ROM:00000010                 CMP     R0, R3
ROM:00000012                 LDRB    R0, [src_addr,#1] ; second nibble
ROM:00000014                 BEQ     run             ; branch if end of string
ROM:00000016                 SUBS    R3, #0x41       ; subtract 'A'
ROM:00000018                 SUBS    R0, #0x41       ; subtract 'A'
ROM:0000001A                 LSLS    R3, R3, #4      ; make room for next nibble
ROM:0000001C                 ADDS    R3, R3, R0      ; put them together as a byte
ROM:0000001E                 STRB    R3, [dest_addr]
ROM:00000020                 ADDS    dest_addr, #1
ROM:00000022                 ADDS    src_addr, #2
ROM:00000024                 B       loop
ROM:00000026 ; ---------------------------------------------------------------------------
ROM:00000026
ROM:00000026 run                                     ; CODE XREF: code_loader+14�j
ROM:00000026                 BLX     R2              ; handler_replace()
ROM:00000028                 MOVLS   R0, 0           ; safe exit
ROM:0000002C                 ADDS    dest_addr, R0, #0
ROM:0000002E                 BLX     R4
ROM:00000030                 MOV     SP, R5
ROM:00000032                 POP     {R0-src_addr,PC}
ROM:00000032 ; End of function code_loader

Handler replace

RAM:00011600 ; =============== S U B R O U T I N E =======================================
RAM:00011600
RAM:00011600
RAM:00011600 handler_replace
RAM:00011600                 PUSH    {LR}
RAM:00011602                 LDR     R0, =0x40492FC0 ; where to save task_loop_jmp + task_loop
RAM:00011604                 ADR     R1, task_loop_jmp
RAM:00011606                 ADR     R2, task_loop_end
RAM:00011608                 SUBS    R2, R2, R1      ; size of task_loop + task_loop_jmp = 0x70
RAM:0001160A                 LDR     R3, =0x2040882C ; memcpy()
RAM:0001160C                 BLX     R3
RAM:0001160E                 LDR     R0, =0x40492C20 ; where to save task_creator_jmp + task_creator
RAM:00011610                 ADR     R1, task_creator_jmp
RAM:00011612                 ADR     R2, task_creator_end
RAM:00011614                 SUBS    R2, R2, R1      ; size of task_creator + task_creator_jmp = 0xA0
RAM:00011616                 LDR     R3, =0x2040882C ; memcpy()
RAM:00011618                 BLX     R3
RAM:0001161A                 LDR     R0, =0x40492C20
RAM:0001161C                 BLX     R0              ; task_creator_jmp()
RAM:0001161E                 POP     {PC}
RAM:0001161E ; End of function handler_replace

Task creator (thanks Darkmen for the comments!)

RAM:40492C20 ; =============== S U B R O U T I N E =======================================
RAM:40492C20
RAM:40492C20
RAM:40492C20 task_creator_jmp
RAM:40492C20                 STMFD   SP!, {R1-R12,LR}
RAM:40492C24                 BLX     task_creator
RAM:40492C28                 LDMFD   SP!, {R1-R12,PC}
RAM:40492C28 ; End of function task_creator_jmp
RAM:40492C28
RAM:40492C2C
RAM:40492C2C ; =============== S U B R O U T I N E =======================================
RAM:40492C2C
RAM:40492C2C
RAM:40492C2C task_creator                            ; CODE XREF: task_creator_jmp+4�p
RAM:40492C2C                 PUSH    {R4-R7,LR}
RAM:40492C2E                 LDR     R3, =0x401ED3B8 ; jumptable var
RAM:40492C30                 MOVLS   R4, 0x800
RAM:40492C34                 SUB     SP, SP, #0x24
RAM:40492C36                 STRH    R0, [R3]        ; task_creator_jmp addr
RAM:40492C38                 LDR     R5, =0x201493F0 ; malloc
RAM:40492C3A                 ADDS    R0, R4, #0      ; 0x800
RAM:40492C3C                 ADDS    R7, R1, #0      ; R7 = resp_string
RAM:40492C3E                 BLX     R5              ; malloc(0x800)
RAM:40492C40                 ADDS    R6, R0, #0      ; R6 = addr returned from malloc
RAM:40492C42                 MOVS    R0, #0x98       ; sizeof(NU_TASK)
RAM:40492C44                 BLX     R5              ; malloc(sizeof(NU_TASK))
RAM:40492C46                 MOVS    R2, #0
RAM:40492C48                 MOVS    R3, #0x44
RAM:40492C4A                 LDR     R1, =aDevteam1  ; char *name
RAM:40492C4C                 STR     R2, [R0,#0xC]   ; task.field=0
RAM:40492C4E                 STR     R3, [SP,#0xC]   ; priority = 0x44
RAM:40492C50                 MOVS    R3, #0xA
RAM:40492C52                 STR     R3, [SP,#0x14]  ; preempt = NU_PREEMPT
RAM:40492C54                 MOVS    R3, #0xC
RAM:40492C56                 STR     R2, [SP]        ; void *argv = 0
RAM:40492C58                 STR     R4, [SP,#8]     ; stack_size = 0x800
RAM:40492C5A                 STR     R2, [SP,#0x10]  ; time_slice = 0
RAM:40492C5C                 STR     R3, [SP,#0x18]  ; auto_start = NU_START
RAM:40492C5E                 LDR     R2, =0x40492FC0 ; task_loop_jmp address
RAM:40492C60                 STR     R6, [SP,#4]     ; void *stack_address = malloc(0x800)
RAM:40492C62                 MOVS    R3, #0
RAM:40492C64                 LDR     R4, =0x2043E5B4 ; NU_Create_Task
RAM:40492C66                 BLX     R4              ; status = NU_Create_Task()
RAM:40492C68                 ADDS    R2, R0, #0      ; R2 = status (for the %d reference in sprintf)
RAM:40492C6A                 CMP     R0, #0          ; success = zero
RAM:40492C6C                 BNE     status_error
RAM:40492C6E                 LDR     R1, =aOk        ; "OK!"
RAM:40492C70                 ADDS    R0, R7, #0      ; resp_string
RAM:40492C72                 LDR     R3, =0x204B11F0 ; sprintf
RAM:40492C74                 BLX     R3              ; sprintf(resp_string, "OK!")
RAM:40492C76                 B       exit
RAM:40492C78 ; ---------------------------------------------------------------------------
RAM:40492C78
RAM:40492C78 status_error                            ; CODE XREF: task_creator+40�j
RAM:40492C78                 LDR     R1, =aErrorD    ; "ERROR %d"
RAM:40492C7A                 ADDS    R0, R7, #0      ; resp_string
RAM:40492C7C                 LDR     R3, =0x204B11F0 ; sprintf
RAM:40492C7E                 BLX     R3              ; sprintf(resp_string, "ERROR %d", status)
RAM:40492C80
RAM:40492C80 exit                                    ; CODE XREF: task_creator+4A�j
RAM:40492C80                 ADD     SP, SP, #0x24   ; fixing stack
RAM:40492C82                 POP     {R4-R7,PC}
RAM:40492C82 ; End of function task_creator

Unlock task loop (thanks Darkmen for the comments!)

RAM:00011630 ; =============== S U B R O U T I N E =======================================
RAM:00011630
RAM:00011630
RAM:00011630 task_loop_jmp
RAM:00011630                 STMFD   SP!, {R1-R12,LR}
RAM:00011634                 BLX     task_loop
RAM:00011634 ; ---------------------------------------------------------------------------
RAM:00011638                 LDMFD   SP!, {R1-R12,PC}
RAM:00011638 ; End of function task_loop_jmp
RAM:00011638
RAM:0001163C
RAM:0001163C ; =============== S U B R O U T I N E =======================================
RAM:0001163C
RAM:0001163C
RAM:0001163C task_loop
RAM:0001163C                 PUSH    {R4,R5,LR}
RAM:0001163E                 LDR     R5, =0x401E829C ; sec mailbox
RAM:00011640                 SUB     SP, SP, #0x14
RAM:00011642
RAM:00011642 loop                                    ; CODE XREF: task_loop+44�j
RAM:00011642                 LDR     R3, =0x2042FFD8 ; NU_Receive_From_Mailbox
RAM:00011644                 ADDS    R0, R5, #0      ; NU_MAILBOX *mailbox
RAM:00011646                 MOV     R1, SP          ; void *Message
RAM:00011648                 MOVS    R2, #0xFF       ; Timeout
RAM:0001164A                 BLX     R3              ; NU_Receive_From_Mailbox(sec_mailbox,SP,0xFF)
RAM:0001164C                 LDR     R3, [SP]        ; Message[0]
RAM:0001164E                 CMP     R3, #0xD        ; Message[0] = 0xD ?
RAM:00011650                 BNE     skip
RAM:00011652                 LDR     R1, [SP,#4]     ; Message[1]
RAM:00011654                 LDR     R3, =0x40301650
RAM:00011656                 LDR     R2, [R1]        ; Message[1].field0
RAM:00011658                 STR     R2, [R3]        ; sec_task_var1 = Message[1].field0
RAM:0001165A                 ADDS    R3, #4          ; 0x40301654
RAM:0001165C                 LDR     R2, [R1,#4]     ; Message[1].field1
RAM:0001165E                 STR     R2, [R3]        ; sec_task_var2 = Message[1].field1
RAM:00011660                 LDR     R2, [R1,#8]     ; Message[1].field2
RAM:00011662                 LDR     R3, =0x100FF00
RAM:00011664                 STR     R3, [R2]        ; Message[1].field2[0] = 0x100FF00
RAM:00011666                 LDR     R3, =0x4020401
RAM:00011668                 STR     R3, [R2,#4]     ; Message[1].field2[1] = 0x4020401
RAM:0001166A                 LDR     R3, =0x4040403
RAM:0001166C                 STR     R3, [R2,#8]     ; Message[1].field2[2] = 0x4040403
RAM:0001166E                 MOVS    R3, #1
RAM:00011670                 STR     R3, [R1,#0xC]   ; Message[1].field3 = 1
RAM:00011672                 MOVS    R3, #0x20 ; ' '
RAM:00011674                 STR     R3, [SP] ; Message[0] = 0x20
RAM:00011676
RAM:00011676 skip                                    ; CODE XREF: task_loop+14�j
RAM:00011676                 ADDS    R0, R5, #0      ; sec mailbox
RAM:00011678                 MOV     R1, SP          ; void *Message
RAM:0001167A                 MOVS    R2, #0xFF       ; timeout
RAM:0001167C                 LDR     R3, =0x20430040
RAM:0001167E                 BLX     R3              ; NU_Send_To_Mailbox()
RAM:00011680                 B       loop
RAM:00011680 ; End of function task_loop
RAM:00011680
RAM:00011680 ; ---------------------------------------------------------------------------

Old yellowsn0w payload w/ comments (by Darkmen)

The exploit consists from 4 parts:

Code loader

ROM:00000000 ; =============== S U B R O U T I N E =======================================
ROM:00000000
ROM:00000000
ROM:00000000 loader
ROM:00000000                 LDR     R2, =0x11700    ; unused ram to place code
ROM:00000002                 ADDS    R4, R2, #1      ; thumb switch
ROM:00000004                 LDR     R3, =0x40159FBF ; at-handler buffer where stage2 binary and following hexdata are
ROM:00000006
ROM:00000006 copy.loop                               ; CODE XREF: loader+12�j
ROM:00000006                 LDRB    R0, [R3]        ; copying code+data until double quotes
ROM:00000008                 CMP     R0, #0x22 ; '"'
ROM:0000000A                 BEQ     run             ; jump thumb code
ROM:0000000C                 STRB    R0, [R2]
ROM:0000000E                 ADDS    R2, #1
ROM:00000010                 ADDS    R3, #1
ROM:00000012                 B       copy.loop       ; 
ROM:00000014 run                                     ; CODE XREF: loader+A�j
ROM:00000014                 BX      R4              ; jump stage2 code
ROM:00000014 ; End of function loader
ROM:00000014
ROM:00000014 ; ---------------------------------------------------------------------------

Stage2(tm)

RAM:00000000 ; =============== S U B R O U T I N E =======================================
RAM:00000000 stage2
RAM:00000000                 ADDS    R2, #0x10       ; R2 = 0x11700 + stage2 size
RAM:00000002                 MOVS    R7, #0xF
RAM:00000004                 BICS    R2, R7          ; align offset by 0x10
RAM:00000006                 ADDS    R7, R2, #0      ; saving address to jump
RAM:00000008                 ADR     R4, 0x44        ; skipping Stage2 size and taking first char from at-string
RAM:0000000A                 ADR     R5, char2byte   ; loading routine addr
RAM:0000000C                 ADDS    R5, #1          ; thumb
RAM:0000000E
RAM:0000000E loop                                    ; CODE XREF: stage2+2C�j
RAM:0000000E                 LDRB    R1, [R4]        ; at-string[index]
RAM:00000010                 CMP     R1, #'x'        ; end of line?
RAM:00000012                 BEQ     jump_code
RAM:00000014                 BLX     R5              ; char2byte first hakfbyte
RAM:00000016                 LSLS    R3, R1, #4      ; <<4 0X becoming X0
RAM:00000018                 LDRB    R1, [R4,#1]     ; at-string[index+1]
RAM:0000001A                 BLX     R5              ; char2hex second halfbyte
RAM:0000001C                 NOP
RAM:0000001E                 NOP
RAM:00000020                 NOP
RAM:00000022                 NOP
RAM:00000024                 ADDS    R1, R1, R3      ; R1 = complete byte
RAM:00000026                 STRB    R1, [R2]        ; storing byte to dst
RAM:00000028                 ADDS    R4, #2          ; hexstr_index+=2
RAM:0000002A                 ADDS    R2, #1          ; dst++
RAM:0000002C                 B       loop            ; at-string[index]
RAM:0000002E jump_code
RAM:0000002E                 NOP
RAM:00000030                 NOP
RAM:00000032                 ADDS    R7, #1          ; thumbing
RAM:00000034                 BX      R7              ; run Task creator code
RAM:00000034 ; End of function stage2
RAM:00000038
RAM:00000038 ; =============== S U B R O U T I N E =======================================
RAM:00000038 char2byte                               ; DATA XREF: stage2+A�o
RAM:00000038                 CMP     R1, #0x41 ; 'A'
RAM:0000003A                 BGE     letter          ; letter to number
RAM:0000003C                 SUBS    R1, #0x30 ; '0' ; digit to number
RAM:0000003E                 BX      LR
RAM:00000040 letter                                  ; CODE XREF: char2byte+2�j
RAM:00000040                 SUBS    R1, #0x37 ; '7' ; letter to number
RAM:00000042                 BX      LR              ; ret
RAM:00000042 ; End of function char2byte

Task creator

RAM:000119A0 ; =============== S U B R O U T I N E =======================================
RAM:000119A0
RAM:000119A0
RAM:000119A0 handler_replace
RAM:000119A0                 LDR     R0, =0x4011714C ; soft reset handler addr
RAM:000119A2                 ADR     R1, new_handler
RAM:000119A4                 ADDS    R1, #1          ; thumbing
RAM:000119A6                 STR     R1, [R0]        ; setting new handler
RAM:000119A8                 POP     {R0-R4,PC}      ; safe exit fixing stack
RAM:000119A8 ; End of function handler_replace

RAM:000119B0 ; =============== S U B R O U T I N E =======================================
RAM:000119B0
RAM:000119B0
RAM:000119B0 new_handler                             ; DATA XREF: handler_replace+2�o
RAM:000119B0                 PUSH    {R4-R7,LR}
RAM:000119B2                 LDR     R3, =0x403BB344 ; jamptable var
RAM:000119B4                 MOVS    R6, #0x80
RAM:000119B6                 SUB     SP, SP, #0x2C
RAM:000119B8                 LSLS    R6, R6, #4      ; 0x200
RAM:000119BA                 STRH    R0, [R3]        ; saving R0 to mem var
RAM:000119BC                 STR     R1, [SP,#0x40+resp_string] ; saving responce prt to stack
RAM:000119BE                 LDR     R4, =0x201420AC ; malloc
RAM:000119C0                 ADDS    R0, R6, #0
RAM:000119C2                 BLX     R4              ; malloc(0x200)
RAM:000119C4                 MOVS    R5, #0
RAM:000119C6                 STR     R0, [SP,#0x40+ptr_200] ; saving pointer to stack
RAM:000119C8                 MOVS    R0, #0x98       ; sizeof(NU_TASK)
RAM:000119CA                 BLX     R4              ; malloc(0x98)
RAM:000119CC                 ADDS    R7, R0, #0      ; R7 = task
RAM:000119CE                 STR     R5, [R0,#0xC]   ; task.field=0
RAM:000119D0                 MOVS    R0, 0x100
RAM:000119D4                 BLX     R4              ; malloc(0x100)
RAM:000119D6                 MOVS    R2, #0x80
RAM:000119D8                 LDR     R1, =task_loop  ; src
RAM:000119DA                 LSLS    R2, R2, #1      ; size to copy
RAM:000119DC                 LDR     R3, =0x203C58A0 ; bytecpy
RAM:000119DE                 ADDS    R4, R0, #0      ; R4 = dyn_task_loop
RAM:000119E0                 BLX     R3              ; bytecpy(task_loop, dyn_task_loop, 0x100)
RAM:000119E2                 LDR     R3, [SP,#0x40+ptr_200]
RAM:000119E4                 STR     R3, [SP,#4]     ; void *stack_address = malloc(0x200)
RAM:000119E6                 MOVS    R3, #0x44
RAM:000119E8                 STR     R3, [SP,#0xC]   ; priority = 0x44
RAM:000119EA                 MOVS    R3, #0xA
RAM:000119EC                 ADDS    R4, #1          ; thumbing dyn_task_loop
RAM:000119EE                 STR     R3, [SP,#0x14]  ; preempt = NU_PREEMPT
RAM:000119F0                 MOVS    R3, #0xC
RAM:000119F2                 ADDS    R2, R4, #0      ; void(*task_entry)
RAM:000119F4                 STR     R3, [SP,#0x18]  ; auto_start = NU_START
RAM:000119F6                 LDR     R1, =devteam1   ; char *name
RAM:000119F8                 STR     R5, [SP]        ; void *argv = 0
RAM:000119FA                 STR     R6, [SP,#8]     ; stack_size = 0x200
RAM:000119FC                 STR     R5, [SP,#0x10]  ; time_slice = 0
RAM:000119FE                 ADDS    R0, R7, #0      ; NU_TASK *task
RAM:00011A00                 MOVS    R3, #0          ; int argc = 0
RAM:00011A02                 LDR     R4, =0x203FB540 ; NU_Create_Task
RAM:00011A04                 BLX     R4              ; status = NU_Create_Task()
RAM:00011A06                 ADDS    R2, R0, #0
RAM:00011A08                 CMP     R0, #0          ; success = zero
RAM:00011A0A                 BNE     status_error
RAM:00011A0C                 LDR     R1, =OK
RAM:00011A0E                 LDR     R0, [SP,#0x40+resp_string]
RAM:00011A10                 LDR     R3, =0x2046DD00 ; sprintf
RAM:00011A12                 BLX     R3              ; sprintf(resp_string,"OK")
RAM:00011A14                 B       exit            ; fixing stack
RAM:00011A16 ; ---------------------------------------------------------------------------
RAM:00011A16
RAM:00011A16 status_error                            ; CODE XREF: new_handler+5A�j
RAM:00011A16                 LDR     R1, =ERROR
RAM:00011A18                 LDR     R0, [SP,#0x40+resp_string]
RAM:00011A1A                 LDR     R3, =0x2046DD00 ; sprintf
RAM:00011A1C                 BLX     R3              ; sprintf(resp_string,"ERROR")
RAM:00011A1E
RAM:00011A1E exit                                    ; CODE XREF: new_handler+64�j
RAM:00011A1E                 ADD     SP, SP, #0x2C   ; fixing stack
RAM:00011A20                 POP     {R4-R7,PC}      ; bye
RAM:00011A20 ; End of function new_handler
RAM:00011A20
RAM:00011A20 ; ---------------------------------------------------------------------------

Unlock task loop

RAM:00011A64 ; =============== S U B R O U T I N E =======================================
RAM:00011A64
RAM:00011A64 task_loop                               ; DATA XREF: RAM:off_11A2C�o
RAM:00011A64                 PUSH    {R4,R5,LR}
RAM:00011A66                 LDR     R5, =0x40232754 ; sec mailbox
RAM:00011A68                 SUB     SP, SP, #0x14
RAM:00011A6A
RAM:00011A6A loop                                    ; CODE XREF: task_loop+44�j
RAM:00011A6A                 LDR     R3, =0x20165998 ; NU_Receive_From_Mailbox
RAM:00011A6C                 ADDS    R0, R5, #0      ; NU_MAILBOX *mailbox
RAM:00011A6E                 MOV     R1, SP          ; void *Message
RAM:00011A70                 MOVS    R2, #0xFF       ; Timeout
RAM:00011A72                 BLX     R3              ; NU_Receive_From_Mailbox(sec_mailbox,SP,0xFF)
RAM:00011A74                 LDR     R3, [SP]        ; Message[0]
RAM:00011A76                 CMP     R3, #0xD        ; Message[0] = 0xD ?
RAM:00011A78                 BNE     skip            ; 
RAM:00011A7A                 LDR     R1, [SP,#4]     ; Message[1]
RAM:00011A7C                 LDR     R3, =0x402F79BC
RAM:00011A7E                 LDR     R2, [R1]        ; Message[1].field0
RAM:00011A80                 STR     R2, [R3]        ; sec_task_var1 = Message[1].field0
RAM:00011A82                 ADDS    R3, #4          ; 0x402F79C0
RAM:00011A84                 LDR     R2, [R1,#4]     ; Message[1].field1
RAM:00011A86                 STR     R2, [R3]        ; sec_task_var2 = Message[1].field1
RAM:00011A88                 LDR     R2, [R1,#8]     ; Message[1].field2
RAM:00011A8A                 LDR     R3, =0x100FF00
RAM:00011A8C                 STR     R3, [R2]        ; Message[1].field2[0] = 0x100FF00
RAM:00011A8E                 LDR     R3, =0x4020401
RAM:00011A90                 STR     R3, [R2,#4]     ; Message[1].field2[1] = 0x4020401
RAM:00011A92                 LDR     R3, =0x4040403
RAM:00011A94                 STR     R3, [R2,#8]     ; Message[1].field2[2] = 0x4040403
RAM:00011A96                 MOVS    R3, #1
RAM:00011A98                 STR     R3, [R1,#0xC]   ; Message[1].field3 = 1
RAM:00011A9A                 MOVS    R3, #0x20       
RAM:00011A9C                 STR     R3, [SP]        ; Message[0] = 0x20
RAM:00011A9E
RAM:00011A9E skip                                    ; CODE XREF: task_loop+14�j
RAM:00011A9E                 ADDS    R0, R5, #0      ; sec mailbox
RAM:00011AA0                 MOV     R1, SP          ; void *Message
RAM:00011AA2                 MOVS    R2, #0xFF       ; timeout
RAM:00011AA4                 LDR     R3, =0x203ED568
RAM:00011AA6                 BLX     R3              ; NU_Send_To_Mailbox()
RAM:00011AA8                 B       loop            ; NU_Receive_From_Mailbox
RAM:00011AA8 ; End of function task_loop

Explanation from planetbeing

13:24:29  <crash-x_> especially how does ultra/yellow sn0w work
13:24:40  <crash-x_> are you overwriting instructions
13:24:48  <crash-x_> or some values in memory to make it accept the sim?
13:24:48  <planetbeing> Nah.
13:24:53  <planetbeing> It's a task.
13:25:06  <planetbeing> That just waits for securiy messages to go through the inbox.
13:25:13  <westbaer> planetbeing: btw, why isnt yellowsn0w/ultrasn0w not open-source anymore? like u posted an *oooold* version once

...

13:26:33  <planetbeing> The only thing I do for ys/us is the loader bit.
13:26:39  <westbaer> so whats actually the loader stuff you've been talking about?
13:26:46  <planetbeing> That uses the exploit to start MuscleNerd's payload.
13:27:21  <westbaer> ah
13:27:26  <planetbeing> Well, you have a vulnerability.
13:27:30  <planetbeing> And you want to load a large chunk of code.
13:27:39  <planetbeing> And you don't have much room to wriggle in for your overflow
13:28:21  <westbaer> aah, makes sense
13:28:50  <planetbeing> So the solution is a small loader that loads the rest of the code, and overcomes any restrictions there are on allowable characters.
13:28:55  <ashikase> francis: pm
13:28:59  <westbaer> yeah
13:29:10  <crash-x_> planetbeing: the baseband is it like one process that runs there
13:29:19  <crash-x_> or is it like a small os with process and stuff
13:29:19  <planetbeing> Basically a good loader should turn a vulnerability into a reliable platform for the execution of arbitrary code, unrestricted by vulnerability-specific stuff.
13:29:37  <planetbeing> Oh, it's a full-featured OS.
13:29:38  <planetbeing> Nucleus.
13:29:51  <planetbeing> http://www.mentor.com/products/embedded_software/nucleus_rtos/
13:29:54  <crash-x_> and when you execute an at command
13:30:06  <crash-x_> does that start another process that is crashed then
13:30:21  <planetbeing> Ideally, you don't crash anything.
13:30:21  <crash-x_> or does it crash like the main baseband program
13:30:23  <planetbeing> And we don't.
13:30:49  <crash-x_> so am i understand it right
13:30:50  <westbaer> wait. is nucleus on the baseband already installed or do you actually inject it with ultrasn0w?
13:30:51  <planetbeing> We load a bunch of code into certain memory locations, execute them, and then return safely back to the main command parser task.
13:31:00  <planetbeing> Nucleus is what the baseband runs.
13:31:04  <westbaer> ah ok
13:31:29  <planetbeing> I mean, even the bootrom is an OS.
13:31:36  <planetbeing> With one task, but it still has a scheduler. =P
13:31:39  <crash-x_> ah thats how you do it
13:31:42  <westbaer> heh
13:31:44  <crash-x_> and about your payload
13:31:57  <crash-x_> does it start a new process like using fork() 
13:32:03  <crash-x_> or does it all the work in the exploited process
13:32:11  <planetbeing> It uses Nucleus-specific calls that create the new task.
13:32:19  <planetbeing> Well, the payload has to create a new task
13:32:22  <westbaer> I think they are documented on the wiki
13:32:25  <planetbeing> To monitor for certain events.
13:32:47  <planetbeing> Yeah, just read Darkmen's decompile.
13:33:00  <planetbeing> us has the exact same payload as ys
13:33:08  <planetbeing> Just different addresses for function calls and stuff.
13:33:19  <planetbeing> And I had to rewrite the loader due to even tighter constraints.
13:33:28  <crash-x_> thats cool, thanks for explaining
13:33:34  <westbaer> yup, thanks


From irc.saurik.com #iphone on Sunday {{date|2009|07|05}}.

Source Code

The source code for yellowsn0w 0.9.1 (old version) was released along with yellowsn0w release.

See Also

External Links