The iPhone Wiki is no longer updated. Visit this article on The Apple Wiki for current information. |
Ultrasn0w
ultrasn0w (previously: yellowsn0w) is the only iPhone 3G unlock payload. yellowsn0w was released on 01/01/09 [1]. ultrasn0w was released on June 23th 2009 [2].
Contents
Credit
MuscleNerd, and The 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.
Current Injection Vector
ultrasn0w refers to the reuseable payload, but it requires an injection vector in order to be inserted into the baseband. yellowsn0w was originally to be released with an injection vector that works on pre-2.28.00 baseband versions. However, geohot had an injection vector for 2.28.00 and the decision was made to release yellowsn0w with this injection vector to benefit the most people. This injection vector is discussed here. ultrasn0w uses a different injection vector - AT+XLOG Exploit.
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 ; run payload 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
Unlock task loop (thanks Darkmen for the comments!)
RAM:0001163C ; =============== S U B R O U T I N E ======================================= RAM:0001163C RAM:0001163C ; Attributes: noreturn RAM:0001163C RAM:0001163C task_loop RAM:0001163C RAM:0001163C var_20 = -0x20 RAM:0001163C var_1C = -0x1C RAM:0001163C 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,#0x20+var_20] ; 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
Source Code
The source code for yellowsn0w 0.9.1 (old version) was released along with yellowsn0w release. [3]