The iPhone Wiki is no longer updated. Visit this article on The Apple Wiki for current information. |
Difference between revisions of "Ultrasn0w"
m (→Compatibility) |
m |
||
(64 intermediate revisions by 23 users not shown) | |||
Line 1: | Line 1: | ||
+ | {{lowercase}} |
||
− | The first [[iPhone 3G]] [[Unlock 2.0|unlock]] payload. 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== |
+ | == Credit == |
− | MuscleNerd |
+ | [[User:MuscleNerd|MuscleNerd]] and [[iPhone Dev Team]] |
− | ==Exploit== |
+ | == Exploit == |
Relies on an unsigned code injection vulnerability. |
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. |
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 == |
+ | * [[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 == |
||
− | yellowsn0w 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. |
||
+ | === iPhone 3G/3GS === |
||
− | |||
+ | * 02.28.00 (yellowsn0w only) |
||
− | The injection vector is discussed [[AT+stkprof Exploit|here]] |
||
+ | * 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) |
||
− | The source code for yellowsn0w is now live [http://xs1.iphwn.org/releases/yellowsn0w.tar.bz2] |
||
+ | == ultrasn0w payload with comments (by [[User:Oranav|Oranav]]) == |
||
− | ==Compatibility== |
||
+ | === 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=== |
||
− | {| class="wikitable sortable" style="text-align: center; width: auto; table-layout: fixed; border-collapse: collapse;" border="1" |
||
+ | <pre> |
||
− | |- |
||
+ | RAM:00011600 ; =============== S U B R O U T I N E ======================================= |
||
− | ! Country |
||
+ | RAM:00011600 |
||
− | ! Provider |
||
+ | RAM:00011600 |
||
− | ! yellowsn0w Version |
||
+ | RAM:00011600 handler_replace |
||
− | ! SIM/USIM |
||
+ | RAM:00011600 PUSH {LR} |
||
− | ! Ingoing Calls? |
||
+ | RAM:00011602 LDR R0, =0x40492FC0 ; where to save task_loop_jmp + task_loop |
||
− | ! Outgoing Calls? |
||
+ | RAM:00011604 ADR R1, task_loop_jmp |
||
− | ! SMS? |
||
+ | RAM:00011606 ADR R2, task_loop_end |
||
− | ! GPRS/EDGE? |
||
+ | RAM:00011608 SUBS R2, R2, R1 ; size of task_loop + task_loop_jmp = 0x70 |
||
− | ! UMTS/HSDPA? |
||
+ | RAM:0001160A LDR R3, =0x2040882C ; memcpy() |
||
− | ! Comments |
||
+ | RAM:0001160C BLX R3 |
||
− | |- |
||
+ | RAM:0001160E LDR R0, =0x40492C20 ; where to save task_creator_jmp + task_creator |
||
− | | Bermuda |
||
+ | RAM:00011610 ADR R1, task_creator_jmp |
||
− | | Mobility |
||
+ | RAM:00011612 ADR R2, task_creator_end |
||
− | | 0.9.5 |
||
+ | RAM:00011614 SUBS R2, R2, R1 ; size of task_creator + task_creator_jmp = 0xA0 |
||
− | | SIM |
||
+ | RAM:00011616 LDR R3, =0x2040882C ; memcpy() |
||
− | | {{no}} |
||
+ | RAM:00011618 BLX R3 |
||
− | | {{no}} |
||
+ | RAM:0001161A LDR R0, =0x40492C20 |
||
− | | {{no}} |
||
+ | RAM:0001161C BLX R0 ; task_creator_jmp() |
||
− | | {{no}} |
||
+ | RAM:0001161E POP {PC} |
||
− | | Not Available |
||
+ | RAM:0001161E ; End of function handler_replace |
||
− | | Still stops working after a while of regular use :( |
||
+ | </pre> |
||
− | |- |
||
− | | Germany |
||
− | | O2 |
||
− | | <=0.9.4 |
||
− | | SIM |
||
− | | {{yes}} |
||
− | | {{yes}} |
||
− | | {{yes}} |
||
− | | Icon shown but not tested |
||
− | | Icon shown but not tested |
||
− | | |
||
− | |- |
||
− | | Israel |
||
− | | IL Orange |
||
− | | 0.9.5 |
||
− | | USIM |
||
− | | {{yes}} |
||
− | | {{yes}} |
||
− | | {{yes}} |
||
− | | {{yes}} |
||
− | | {{yes}} |
||
− | | Requires turning airplane mode on and off to get signal. After that, works perfectly. |
||
− | |} |
||
+ | ===Task creator (thanks Darkmen for the comments!)=== |
||
− | Additional information: |
||
+ | <pre> |
||
− | http://report.yellowsn0w.com/ |
||
+ | 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!)=== |
||
− | ==See Also== |
||
+ | <pre> |
||
− | * [[Unlock 2.0]] |
||
+ | 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 |
||
+ | |||
+ | |||
+ | From irc.saurik.com #iphone on Sunday {{date|2009|07|05}}. |
||
+ | </pre> |
||
+ | |||
+ | == Source Code == |
||
+ | The [http://xs1.iphwn.org/releases/yellowsn0w.tar.bz2 source code] for yellowsn0w 0.9.1 (old version) was released along with yellowsn0w release. |
||
+ | |||
+ | == See Also == |
||
+ | * [[X-Gold 608 Unlock]] |
||
* [[X-Gold 608]] |
* [[X-Gold 608]] |
||
− | * [[Baseband]] |
+ | * [[Baseband Device]] |
− | ==External |
+ | == 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://qik.com/video/729275 MuscleNerd's Demo] |
+ | * [http://qik.com/video/729275 MuscleNerd's yellowsn0w Demo] |
− | * [http:// |
+ | * [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.
Contents
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
- 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)
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.