
Tengo un amigo que se dedica a la reparación de hierro para automóviles. De alguna manera me trajo un microcontrolador soldado de una unidad de control de calentador autónomo. Dijo que su programador no lo toma, y que le gustaría poder transferir firmware de un lado a otro, porque Hay muchos bloques, en hierro a menudo son los mismos, pero las unidades que controlan son diferentes. Y parece que hay un bloque en lugar de uno defectuoso, pero el software es diferente y es simplemente imposible reemplazarlo así. Como la tarea era interesante, decidí hurgar. Si el tema es interesante para usted, debajo del gato ...
El sujeto era M306N5FCTFP. Este es un microcontrolador del grupo M16C / 6N5. El núcleo M16C / 60 fue desarrollado por Mitsubishi, y como Desde 2003, el sucesor de esta compañía en términos de MK ha sido Renesas, ahora estos microcontroladores son conocidos bajo esta marca.
Un poco sobre el microcontrolador en sí
El guijarro es un microcontrolador de 16 bits en un paquete QFP de 100 pines. El núcleo tiene 1 MB de espacio de direcciones, una frecuencia de reloj de 20 MHz para rendimiento automotriz. El conjunto de periféricos también es muy extenso: dos temporizadores de 16 bits y la posibilidad de generar un PWM trifásico para controlar motores, todo tipo de UART, SPI, I2C naturalmente, 2 canales DMA, hay un controlador CAN2.0B incorporado, así como un PLL. En mi opinión, es muy bueno para el viejo. Aquí hay un cuadro general de la documentación:

Como mi tarea es arrancar el software, también está muy interesado en la memoria. Este MK se produjo en dos versiones: enmascarado y Flash. Obtuve, como se mencionó anteriormente, el M306N5FCTFP. Sobre él, la descripción dice lo siguiente:
- Versión de memoria flash
- 128 KBytes + 4K (4K adicional: el llamado bloque A como un regalo para el usuario por almacenar datos, pero también puede almacenar el programa)
- V-ver. (versión automotriz con un rango de + 125 ° C)
Cómo extraer del dispositivo lo que los desarrolladores arrastraron
Es natural que comience a intentar obtener algo del microcontrolador estudiando los mecanismos integrados por el desarrollador del chip para las tareas de programación de memoria. El manual establece que el fabricante colocó amablemente un gestor de arranque en la memoria para las necesidades de programación en circuito del dispositivo.

Como puede ver en la imagen de arriba, la memoria se divide en 2 partes: el área de usuario y el área del gestor de arranque. En el segundo, se carga un cargador de arranque predeterminado de fábrica, que puede escribir, leer, borrar la memoria del usuario y comunicarse a través de una interfaz asíncrona, síncrona o CAN. Se indica que puede reescribirse a su cuenta, o no puede reescribirse. Al final, esto se verifica fácilmente al intentar tocar el cargador de arranque estándar al menos a través de UART ... Mirando hacia el futuro: el fabricante del calentador no se molestó con su cargador de arranque, por lo que puede profundizar más en esta dirección. Inmediatamente haga una reserva de que todavía hay un método de programación paralela, pero desde No tenía un programador para esto, no consideré esta opción.
El acceso al modo de operación del gestor de arranque lo proporciona una combinación determinada en las entradas CNVSS, P5_0, P5_5 durante un reinicio de hardware. A continuación, escriba su propia utilidad para copiar el contenido de la memoria o use la que haya terminado. Renesas ofrece su propia utilidad, llamada "M16C Flash Starter", pero tiene una función de lectura reducida. No guarda lo que lee en el disco, pero lo compara con un archivo del disco. Es decir de hecho, esto no es lectura, sino verificación. Sin embargo, hay una utilidad gratuita alemana llamada M16C-Flasher, que puede leer el firmware. En general, se recogió el conjunto de herramientas inicial.
Sobre la protección de lectura

Todo sería bastante simple si el gestor de arranque no proporcionara protección contra el acceso no autorizado. Solo daré una traducción muy gratuita del manual.
Función de verificación de ID
Usado en modos de intercambio serial y CAN. El identificador transmitido por el programador se compara con el identificador registrado en la memoria flash. Si los identificadores no coinciden, no se aceptan los comandos enviados por el programador. Sin embargo, si 4 bytes del vector de reinicio son FFFFFFFFh, los identificadores no se comparan, lo que permite ejecutar todos los comandos. El identificador tiene 7 bytes almacenados secuencialmente, comenzando desde el primer byte, en las direcciones 0FFFDFh, 0FFFE3h, 0FFFEBh, 0FFFEFh, 0FFFF3h, 0FFFF7h y 0FFFFBh.Por lo tanto, para acceder al programa, debe conocer los 7 bytes apreciados. De nuevo, mirando hacia el futuro, me conecté a MK usando el mismo "M16C Flash Starter" y me aseguré de que las combinaciones de ceros y FF no funcionaran y este problema tendría que resolverse de alguna manera. Aquí surgió una idea con un ataque a través de canales de terceros. Ya comencé a fingir ser un pañuelo en la cabeza, lo que me permite medir la corriente en el circuito de alimentación, pero decidí que Internet es grande y que la mayoría de las bicicletas ya se han inventado. Después de realizar algunas búsquedas, rápidamente encontré en hackaday.io el proyecto Serge 'q3k' Bazanski, titulado “Ingeniería inversa del BIOS Toshiba R100”. Y en el marco de este proyecto, el autor resolvió esencialmente el mismo problema: extraer el firmware de MK M306K9FCLR. Además, en ese momento la tarea ya había sido resuelta con éxito por él. Por un lado, estaba un poco molesto: un acertijo interesante no fue resuelto por mí. Por otro lado, la tarea pasó de una búsqueda de vulnerabilidad a su explotación, que prometía una solución mucho más rápida.
En pocas palabras, q3k, exactamente por la misma lógica, comenzó el estudio con un análisis del consumo actual, en este sentido estaba en condiciones mucho más favorables, porque él tenía ChipWhisperer, todavía no tengo esta cosa. Pero desde su primera sonda para eliminar la corriente de consumo resultó ser inapropiada y no pudo aislar algo útil del ruido, decidió intentar un ataque simple en el tiempo de respuesta. El hecho es que el gestor de arranque extrae la salida BUSY durante la ejecución del comando para informar al host que está ocupado o que está listo para ejecutar el siguiente comando. Según la suposición de q3k, medir el tiempo desde la transmisión del último bit del identificador hasta la eliminación de la bandera ocupada podría servir como fuente de información durante la enumeración. Al verificar esta suposición enumerando el primer byte de la clave, realmente se encontró una desviación de tiempo en un solo caso, cuando el primer byte era igual a FFh. Para la conveniencia de medir el tiempo, el autor incluso desaceleró el MK apagando el resonador de cuarzo y aplicando una onda cuadrada de 666 kHz a la entrada del reloj para simplificar el procedimiento de medición. Después de eso, el identificador se seleccionó con éxito y se recuperó el software.
El primer panqueque: un rastrillo
Ja! Pensé ... Ahora rápidamente remacho el programa a mi STM32VLDiscovery c STM32F100 a bordo, que enviará el código y medirá el tiempo de respuesta, y escupirá los resultados de la medición en el terminal. Porque La placa de pruebas con el controlador de destino se conectó previamente a la PC a través del adaptador USB-UART, para no cambiar nada en la placa de pruebas, trabajaremos en modo asíncrono.

Cuando se inicia el gestor de arranque, la entrada CLK1 se tira al suelo, se da cuenta de que desean una comunicación asincrónica de él. Por eso lo usé: el tirante ya estaba soldado y solo conecté las dos placas con cables: Discovery y la placa de pruebas con el objetivo M306.
Nota sobre la armonización de niveles:
Porque Dado que M16 tiene niveles TTL en los terminales y STM32 tiene LVTTL (simplificado, consulte la hoja de datos para más detalles), entonces es necesario un ajuste de nivel. Porque este no es un dispositivo que, como una batería conocida, debería funcionar, funcionar y funcionar, pero de hecho se conecta una vez sobre la mesa, no me molesté con los traductores de nivel: los niveles de salida digeridos por MK de cinco voltios de STM32, en el sentido de 3 voltios que percibe como "1" , las salidas de M16 se alimentan a las entradas STM32 tolerantes a 5V para que no se sienta mal, y no nos olvidemos de poner la pata que pone RESET M16 en modo de drenaje abierto. Lo he olvidado, y esto es + 2 horas para la alcancía del tiempo perdido.
Este mínimo es suficiente para entender las glándulas del otro.La lógica del software de ataque es la siguiente:
- Establecemos una conexión con el controlador. Para hacer esto, debe esperar hasta que se complete el restablecimiento, luego transmitir 16 caracteres cero con un intervalo de más de 20 ms. Esto es para resolver el algoritmo para determinar automáticamente el tipo de cambio, porque la interfaz es asíncrona y MK no sabe nada sobre su frecuencia. La velocidad de arranque del transmisor debe ser de 9600 baudios, es a esta velocidad que calcula el cargador. Después de eso, si lo desea, puede solicitar un tipo de cambio diferente de cinco disponibles en el rango 9600-115200 (aunque en mi caso el cargador se negó a trabajar en 115200). No necesito cambiar la velocidad, así que solo solicité la versión del gestor de arranque para controlar la sincronización. Pasamos FBh, el cargador responde con una línea como "VER.1.01".
- Enviamos el comando "desbloquear", que contiene la iteración actual de la clave, y medimos el tiempo hasta que se borra la bandera de ocupado.

El comando consta de código F5h, tres bytes de la dirección donde comienza el área del identificador (en mi caso, para el núcleo M16C, es 0FFFDFh), longitud (07h) y el identificador mismo.
- Medimos el tiempo entre la transmisión del último bit del identificador y la eliminación de la bandera ocupada.
- Aumentamos el byte clave que se está ordenando (KEY1 en la etapa inicial), volvemos al paso 2 hasta que clasifiquemos los 255 valores del byte actual.
- Restablecemos las estadísticas al terminal (bueno, o realizamos el análisis "a bordo").
Para comunicarme con el objetivo MK, usé USART en STM32, para medir el tiempo, un temporizador en modo de captura de entrada. Lo único, por simplicidad, no medí el tiempo entre el último bit de la llave y la eliminación de la bandera, sino entre el inicio de la transmisión y la bandera. La razón era que el último bit podía cambiar, y en modo asíncrono no había nada que adjuntar a la entrada de captura. Al mismo tiempo, UART es hardware y el tiempo de transmisión es básicamente idéntico y no debe haber ningún error tangible.
Como resultado, para todos los valores, los resultados fueron idénticos. Completamente idéntico La frecuencia de reloj del temporizador fue de 24 MHz, respectivamente, la resolución de tiempo es de 41,6 ns. Bueno, bueno, intenté ralentizar el objetivo MK. Nada ha cambiado. Aquí surgió la pregunta en mi cabeza: ¿qué estoy haciendo mal, como hizo q3k? Después de la comparación, se encontró la diferencia: utiliza una interfaz de intercambio sincrónico (SPI), y yo soy asíncrono (UART). Y en algún lugar aquí, llamé la atención sobre el momento que perdí al principio. Incluso en los diagramas de cableado para modos de gestor de arranque síncrono y asíncrono, la salida preparada se denomina de manera diferente:

En síncrono es "OCUPADO", en asíncrono es "Monitor". Vemos la tabla "Funciones de salida en modo de E / S serie estándar":
"Semyon Semenych ..."La bagatela, que se perdió al principio, trajo el lugar equivocado. En realidad, si en modo síncrono este es exactamente el indicador de ocupado del cargador de arranque, entonces en modo asíncrono (el que tiene el modo de E / S en serie 2) es solo un "parpadeo" para indicar la operación. Quizás, en general, la señal de hardware de la disponibilidad del transceptor y, por lo tanto, la sorprendente precisión de su elevación.
En general, soldamos la resistencia en el pin SCLK desde el suelo a VCC, soldamos el cable allí, lo conectamos a SPI y comenzamos de nuevo ...
Éxito!

En el modo sincrónico, todo es casi igual, solo que no se requiere ningún procedimiento preliminar para establecer una conexión, la sincronización se simplifica y la captura de tiempo se puede realizar con mayor precisión. Si elijo este modo de inmediato, ahorraría tiempo ... De nuevo, no complicar y medir el tiempo desde el último bit, pero inicié el temporizador antes de comenzar la transferencia del último byte de la clave, es decir. activamos el temporizador y lo enviamos al transmisor KEY7 (en la captura de pantalla anterior, desde el analizador lógico, puede ver la distancia entre los cursores. Este es el intervalo de tiempo medido).
Esto fue más que suficiente para una identificación exitosa. Aquí está la enumeración de un byte:

En el eje x, tenemos el número de recuentos discretos, en el eje y, respectivamente, el valor clave transmitido. La relación señal / ruido es tal que incluso no se requieren filtros, al igual que en la escuela en una lección de informática: encontramos el máximo en la matriz y vamos a la selección del siguiente byte. Los primeros 6 bytes se seleccionan de manera fácil y rápida, un poco más difícil con el último: allí es solo una revelación descarada que no funciona, debe restablecer la "víctima" antes de cada intento. Como resultado, se requieren alrededor de 400 ms para cada intento, y la búsqueda se encuentra en el peor de los casos, en la región de un minuto y medio. Pero esto es lo peor. Después de cada intento, solicitamos un estado y, tan pronto como lo adivinamos, nos detenemos. Al principio, generalmente revisé rápidamente el identificador con bolígrafos, insertando la salida de la consola en Excel y trazando el gráfico, más aún porque era una tarea única, pero por el artículo decidí agregar iteración automática, por el bien de una hermosa consola ...

Por supuesto, si el desarrollador borra el gestor de arranque (reemplazado por el suyo), no sería tan fácil salir, pero en electrónica automotriz, los MK a menudo no están cerrados en absoluto. En particular, en la unidad de control de otro calentador, en el que se instaló el V850 del mismo Renesas, todo se decidió soldando un par de cables y copiando el firmware con una utilidad estándar. Este es todo el motor de criptomonedas en el mundo de la ECU. Aparentemente, a los fabricantes no les gusta el fenómeno de ajuste de chips y otros tipos de interferencia ... Aunque esto es como una carrera de armaduras y proyectiles: las glándulas son más empinadas, más caras, pero no hay ganador ...
Referencias
- https://www.dataman.com/media/datasheet/Renesas/M16C6N5Group.pdf
- https://hackaday.io/project/723-reverse-engineering-toshiba-r100-bios/log/51302-ec-firmware-dumped
- https://q3k.org/slides-recon-2018.pdf