@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @ Code originally from delebile and mid-kid .section .large_patch.reboot, "aw", %progbits .arm .align 4 #define copy_launch_stub_stack_top 0x01FFB800 #define copy_launch_stub_stack_bottom 0x01FFA800 #define copy_launch_stub_addr 0x01FF9000 #define argv_addr (copy_launch_stub_stack_bottom - 0x100) #define fname_addr (copy_launch_stub_stack_bottom - 0x200) #define low_tid_addr (copy_launch_stub_stack_bottom - 0x300) #define firm_addr 0x20001000 #define firm_maxsize 0x07FFF000 .global rebootPatch rebootPatch: @ Interesting registers and locations to keep in mind, set just before this code is ran: @ - r1: FIRM path in exefs. @ - r7 (or r8): pointer to file object @ - *r7: vtable @ - *(vtable + 0x28): fread function @ - *(r7 + 8): file handle sub r7, r0, #8 mov r8, r1 pxi_wait_recv: ldr r2, =0x44846 ldr r0, =0x10008000 readPxiLoop1: ldrh r1, [r0, #4] lsls r1, #0x17 bmi readPxiLoop1 ldr r0, [r0, #0xC] cmp r0, r2 bne pxi_wait_recv @ Open file add r0, r7, #8 adr r1, rebootPatchFileName mov r2, #1 adr r6, rebootPatchFopenPtr ldr r6, [r6] orr r6, #1 blx r6 cmp r0, #0 bne panic @ Read file mov r0, r7 adr r1, bytes_read ldr r2, =firm_addr ldr r3, =firm_maxsize ldr r6, [r7] ldr r6, [r6, #0x28] blx r6 @ Copy the low TID (in UTF-16) of the wanted firm ldr r0, =low_tid_addr add r1, r8, #0x1A mov r2, #0x10 bl memcpy16 @ Copy argv[0] ldr r0, =fname_addr adr r1, rebootPatchFileName mov r2, #82 bl memcpy16 ldr r0, =argv_addr ldr r1, =fname_addr ldr r2, =low_tid_addr stmia r0, {r1, r2} @ Set kernel state mov r0, #0 mov r1, #0 mov r2, #0 mov r3, #0 svc 0x7C goto_reboot: @ Jump to reboot code ldr r0, kernel_func_displ add r0, pc @ pc is two instructions ahead of the instruction being executed (12 = 2*4 + 4) svc 0x7B die: b die memcpy16: cmp r2, #0 bxeq lr add r2, r0, r2 copy_loop16: ldrh r3, [r1], #2 strh r3, [r0], #2 cmp r0, r2 blo copy_loop16 bx lr panic: mov r1, r0 @ unused register mov r0, #0 svc 0x3C @ svcBreak(USERBREAK_PANIC) b die kernel_func_displ: .word kernelcode_start - goto_reboot - 12 bytes_read: .word 0 .global rebootPatchFopenPtr rebootPatchFopenPtr: .word 0 .pool .global rebootPatchFileName rebootPatchFileName: .skip 2*(80+1) .balign 4 kernelcode_start: msr cpsr_cxsf, #0xD3 @ disable interrupts and clear flags ldr sp, =copy_launch_stub_stack_top ldr r0, =copy_launch_stub_addr adr r1, copy_launch_stub mov r2, #(copy_launch_stub_end - copy_launch_stub) bl memcpy32 @ Disable MPU ldr r0, =0x42078 @ alt vector select, enable itcm mcr p15, 0, r0, c1, c0, 0 bl flushCaches ldr r0, =copy_launch_stub_addr bx r0 copy_launch_stub: ldr r4, =firm_addr mov r5, #0 load_section_loop: @ Such checks. Very ghetto. Wow. add r3, r4, #0x40 add r3, r5,lsl #5 add r3, r5,lsl #4 ldmia r3, {r6-r8} cmp r8, #0 movne r0, r7 addne r1, r4, r6 movne r2, r8 blne memcpy32 add r5, #1 cmp r5, #4 blo load_section_loop mov r0, #2 @ argc ldr r1, =argv_addr @ argv ldr r2, =0xBABE @ magic word mov r5, #0x20000000 ldr r6, [r4, #0x08] str r6, [r5, #-4] @ store arm11 entrypoint ldr lr, [r4, #0x0c] bx lr memcpy32: add r2, r0, r2 copy_loop32: ldr r3, [r1], #4 str r3, [r0], #4 cmp r0, r2 blo copy_loop32 bx lr .pool copy_launch_stub_end: flushCaches: @ Clean and flush data cache mov r1, #0 @ segment counter outer_loop: mov r0, #0 @ line counter inner_loop: orr r2, r1, r0 @ generate segment and line address mcr p15, 0, r2, c7, c14, 2 @ clean and flush the line add r0, #0x20 @ increment to next line cmp r0, #0x400 bne inner_loop add r1, #0x40000000 cmp r1, #0 bne outer_loop @ Drain write buffer mcr p15, 0, r1, c7, c10, 4 @ Flush instruction cache mcr p15, 0, r1, c7, c5, 0 bx lr .pool .balign 4 _rebootPatchEnd: .global rebootPatchSize rebootPatchSize: .word _rebootPatchEnd - rebootPatch