Cómo romper una cámara cara para que tu esposa no te mate

Descargo de responsabilidad: el estudio comenzó en 2013, por lo que si cree que algunos métodos son estúpidos y peligrosos, tiene razón, eso fue todo. Sin embargo, aprendí mucho en el proceso.

Entrada
Todo comenzó unos meses antes del nacimiento de mi primer hijo. Mi esposa y yo siempre quisimos comprar una cámara Leica genial y de repente nos dimos cuenta de que si no la compramos ahora, no podríamos hacerlo por mucho tiempo. Por lo tanto, pedimos la cámara M240 y ... boom, nos pusieron en línea durante seis meses. Pronto me cansé de esperar y comencé a estudiar su sitio. Mi atención se dirigió inmediatamente a la sección del archivo. Bueno, puedes adivinar por qué ... ¡Firmware!

Vi un archivo sin cifrar y sin comprimir ( m8-2_005.upd ) que comienza con la magia PWAD . ¿Lo reconoces? Sí, así es, este es el formato Doom Patch WAD. Los chicos parecen amar los clásicos. El formato está muy bien documentado , por lo que no fue difícil analizarlo.

Archivos de firmware de Leica


Firmware Leica M8


Esto es realmente muy divertido, porque cuando más tarde estudié el archivo comprimido de firmware Leica T, primero decidí probar los métodos de compresión que el software id usó en el pasado.

Wikipedia dice que usaron el formato LHA , que esencialmente es LZW. Pero los descompresores comunes LZW no encajaban, así que comencé a buscar una implementación específica del software de identificación, y voila, encontré Catacomb Armageddon en el código fuente . Debo admitir, por suerte.

En cualquier caso, de vuelta al M8. Aquí está la estructura del firmware:

  REGLAS: 0x0000008C (3036: 0x00000BDC) - Descripción XML
 LUTS: 0x00000C68 (183274: 0x0002CBEA)
  GAMMA: 0x0000007C (31760: 0x00007C10)
  GANANCIA: 0x00007C8C (50344: 0x0000C4A8)
  LEICA: 0x00014134 (7000: 0x00001B58)
  BLEMISH: 0x00015C8C (250: 0x000000FA)
  WREF: 0x00015D88 (82480: 0x00014230)
  OBJ: 0x00029FB8 (11268: 0x00002C04)
  VERSIÓN: 0x0002CBBC (46: 0x0000002E)
 PXA: 0x0002D854 (858384: 0x000D1910)
 BF: 0x000FF164 (134522: 0x00020D7A) - Familia de procesadores Blackfin de Analog Devices
 GUI: 0x0011FEE0 (3574180: 0x003689A4)
  TRANS: 0x0000005C (59988: 0x0000EA54) - localización
  IMÁGENES: 0x0000EAB0 (267433: 0x000414A9)
   21_1PRT: 0x000000CC (18411: 0x000047EB): fotografía de JFIF
   21_2GRP: 0x000048B8 (23172: 0x00005A84) - imagen de JFIF
   21_3PAN: 0x0000A33C (23034: 0x000059FA): fotografía de JFIF
   24_1PRT: 0x0000FD38 (18489: 0x00004839) - imagen de JFIF
   24_2GRP: 0x00014574 (23230: 0x00005ABE) - imagen de JFIF
   24_3PAN: 0x0001A034 (22998: 0x000059D6) - imagen de JFIF
   28_1PRT: 0x0001FA0C (22605: 0x0000584D): fotografía de JFIF
   28_2GRP: 0x0002525C (23081: 0x00005A29) - imagen de JFIF
   28_3PAN: 0x0002AC88 (23282: 0x00005AF2) - imagen de JFIF
   35_1PRT: 0x0003077C (22496: 0x000057E0) - imagen de JFIF
   35_2GRP: 0x00035F5C (23532: 0x00005BEC): fotografía de JFIF
   35_3PAN: 0x0003BB48 (22881: 0x00005961) - imagen de JFIF
  FUENTE1: 0x0004FF5C (1522988: 0x00173D2C)
  FUENTE2: 0x001C3C88 (1723676: 0x001A4D1C)
  VERSIÓN: 0x003689A4 (0: 0x00000000)
 M16C: 0x00488884 (130406: 0x0001FD66) - Familia Renesas M16C (Motorola S-record)
 FPGA: 0x004A85EC (131604: 0x00020214) - Xilinx Spartan 3
 FSL: 0x004C8800 (814: 0x0000032E): el gestor de arranque de la primera etapa 

Fuera de la caja IDA no es compatible con los procesadores Blackfin, pero hay un complemento de terceros .

Firmware Leica M9


El archivo de firmware Leica M9 ( m9-1_196.upd ) parece cifrado: el histograma muestra una distribución de aproximadamente 0,45%.



El final de la historia? Quizás no. El hecho es que Leica usaba procesadores bastante débiles en las cámaras, y en ese momento el cifrado XOR a menudo se usaba en la electrónica de consumo, por lo que decidí escribir una herramienta simple para la operación XOR para comparar el firmware conmigo mismo y calcular algunas estadísticas.

La longitud de la clave se determinó buscando el patrón repetitivo más largo. Esto tiene sentido, ya que cualquier firmware generalmente incluye grandes bloques de datos repetidos, como un pad 0x00 / 0xFF o gráficos con píxeles LUT. La clave misma se calcula por la frecuencia de bytes dentro de la longitud de la clave, donde el byte más común va al búfer de clave. El resultado del programa indica claramente el cifrado XOR. Luego tuve que modificar un poco la herramienta para obtener la clave potencial y descifrar el código. Esto nuevamente resultó ser un archivo PWAD.

El contenido de PWAD reveló la siguiente estructura:

  REGLAS: 0x0000007C (2788: 0x00000AE4) - Descripción XML
 LUTS: 0x00000B60 (4060616: 0x003DF5C8)
  PROCESO: 0x0000004C (3900572: 0x003B849C)
   CREATE: 0x0000004C (20: 0x00000014) - marca de tiempo
   LUTS: 0x00000060 (427744: 0x000686E0)
   GAINMAP: 0x00068740 (20008: 0x00004E28)
   LENTE: 0x0006D568 (3452724: 0x0034AF34)
  CCD: 0x003B84E8 (148662: 0x000244B6)
   CREATE: 0x0000004C (20: 0x00000014) - marca de tiempo
   BLEMISH: 0x00000060 (1092: 0x00000444)
   WREF: 0x000004A4 (147452: 0x00023FFC)
   LIN: 0x000244A0 (22: 0x00000016)
  ICCPROF: 0x003DC9A0 (4304: 0x000010D0)
   ECI-RGB: 0x0000003C (540: 0x0000021C)
   sRGB: 0x00000258 (3144: 0x00000C48)
   A-RGB: 0x00000EA0 (560: 0x00000230)
  WBPARAM: 0x003DDA70 (7000: 0x00001B58)
 BF561: 0x003E0128 (289128: 0x00046968) - Familia de procesadores Blackfin de Analog Devices
  bf0: 0x0000004C (117846: 0x0001CC56) - procesador principal
  bf1: 0x0001CCA4 (117826: 0x0001CC42) - firmware del subprocesador
  bf0.map: 0x000398E8 (27072: 0x000069C0) - tarjeta de firmware del procesador principal con caracteres: D
  bf1.map: 0x000402A8 (26304: 0x000066C0) - tarjeta de firmware de subprocesador con caracteres: D
 CUERPO: 0x00426A90 (143280: 0x00022FB0) - Familia Renesas M16C (Motorola S-record)
 GUI: 0x00449A40 (3647624: 0x0037A888)
  TRANS: 0x0000005C (131656: 0x00020248) - localización
  IMÁGENES: 0x000202A4 (267433: 0x000414A9)
   21_1PRT: 0x000000CC (18411: 0x000047EB): fotografía de JFIF
   21_2GRP: 0x000048B8 (23172: 0x00005A84) - imagen de JFIF
   21_3PAN: 0x0000A33C (23034: 0x000059FA): fotografía de JFIF
   24_1PRT: 0x0000FD38 (18489: 0x00004839) - imagen de JFIF
   24_2GRP: 0x00014574 (23230: 0x00005ABE) - imagen de JFIF
   24_3PAN: 0x0001A034 (22998: 0x000059D6) - imagen de JFIF
   28_1PRT: 0x0001FA0C (22605: 0x0000584D): fotografía de JFIF
   28_2GRP: 0x0002525C (23081: 0x00005A29) - imagen de JFIF
   28_3PAN: 0x0002AC88 (23282: 0x00005AF2) - imagen de JFIF
   35_1PRT: 0x0003077C (22496: 0x000057E0) - imagen de JFIF
   35_2GRP: 0x00035F5C (23532: 0x00005BEC): fotografía de JFIF
   35_3PAN: 0x0003BB48 (22881: 0x00005961) - imagen de JFIF
  FUENTE1: 0x00061750 (1522988: 0x00173D2C)
  USBLOGO: 0x001D547C (1775: 0x000006EF): fotografía de JFIF
  FUENTE2: 0x001D5B6C (1723676: 0x001A4D1C)
 FPGA: 0x007C42C8 (150176: 0x00024AA0) - Xilinx Spartan 3A
 BF547: 0x007E8D68 (937576: 0x000E4E68) - Familia de procesadores de aleta negra de dispositivos analógicos (FSL?) 


Firmware Leica M240


Tengo la costumbre de revisar la página de descarga con el firmware de Leica todas las mañanas. Pronto apareció un nuevo archivo: FW_M240_1_1_0_2.FW .

No parecía cifrado, pero estaba comprimido ...

Compresión


El histograma muestra una gran explosión a 0x9D.



Quizás esto es algún tipo de magia de compresión. Una búsqueda en Internet [compresión 9D +] no arrojó nada, excepto que 0x1F9D se utiliza como firma para la compresión LZW . En todo caso, entiendo los tipos de compresión LZ y decidí mirar los bytes después de 0x9D. Y vi cuatro opciones:

  1. 9D 70 C4
  2. 9D 00
  3. 9D XX YY
  4. 9D XX 8Y YY

¿Qué más lograste notar?

  • la primera opción aparece solo una vez en la dirección 0x30: probablemente se usa como un indicador de datos comprimidos;
  • XX nunca excede 0x7F;
  • el último byte de YY en el tercer y cuarto casos nunca excede 0x7F

Por lo que sé sobre LZ, esto es muy similar a LZ77 o LZSS, donde YY es el paso de sangría y XX es el número de bytes para copiar. Y la segunda opción es un caso especial de emisión de 0x9D. Escribí una función C simple que implementa esta lógica. Ella confirmó que nos estamos moviendo en la dirección correcta, pero la cuarta opción aún no encaja en el esquema.

Traté de interpretarlo en todos los sentidos, pero no salió nada. Por lo tanto, recurrí a mis camaradas para pedirles consejo. Un tipo notó que, según mis propias observaciones, el cuarto byte de YY aparece solo cuando se establece el bit más alto 0x8Y: esta es solo la distancia extra para el paso de sangría. Estaba avergonzado, todo resultó tan obvio ...

Finalmente, el descompresor comenzó a emitir una secuencia válida ... hasta que se atascó en el medio del archivo. Esto sucedió debido a la longitud desconocida de la ventana deslizante. Depuración y pruebas adicionales arreglaron la situación.

Así que había una herramienta para analizar el firmware M240 .

Estructura de firmware


Para trabajar con un formato desconocido, no se me ocurrió nada mejor que medir algunos desplazamientos y tamaños de secciones de código, y tratar de encontrar los valores más cercanos en el encabezado del archivo. Por ejemplo, este bloque:

0x00: 1E 1C AF 2E 01 01 00 02 07 E1 EA 5E 00 5C 1A B1
0x10: 01 29 1A 7E AE 38 73 65 9C 3D 75 B4 34 2F 44 6E
0x20: 13 17 8E 6B 00 00 00 01 00 00 00 30 E1 E3 50 D1


finalmente se convirtió en:

1E1CAF2E — "LEICA FILE"
01010002 - 1.1.0.2
005C1AB1 — (big endian)
01291A7E — (big endian)
AE3873659C3D75B4342F446E13178E6B — MD5
00000001 —
00000030 —


Cuando entendí la estructura del firmware, mejoré mi herramienta, y al final, produjo esto:

Running with options:
+ firmware folder: M240_FIRMWARE
+ verbose enabled

Open firmware file: FW_M240_1_1_0_2.FW
File size: 6036193 | 0x005C1AE1

Parse container header:
version: 1.1.0.2
packed size: 6036145 | 0x005C1AB1
unpacked size: 19470974 | 0x01291A7E
body blocks: 1 | 0x00000001
body offset: 48 | 0x00000030
MD5: AE387365 9C3D75B4 342F446E 13178E6B
MD5 check: PASSED

Uncompress container body:
6036145 -> 19470974
Uncompression: DONE

Split container:
Number of sections: 9 | 0x00000009
Section table size: 612 | 0x00000264
Section table offset: 36 | 0x00000024
Section 1
Section Name: "[A]IMG_LOKI-212"
Section offset: 0 | 0x00000000
Section size: 7340032 | 0x00700000
Section base: 1048576 | 0x00100000
MD5: A8D55AA2 B0ACDB14 0673AD79 707674F3
MD5 check: PASSED
Create file: M240_FIRMWARE/IMG_LOKI-212.bin

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Section 9
Section Name: "[A]IMG-LENSDATA-213"
Section offset: 19214844 | 0x012531FC
Section size: 255478 | 0x0003E5F6
Section base: 16252928 | 0x00F80000
MD5: 39C2BEC0 27ED23F6 2C1C8513 EEE697B9
MD5 check: PASSED
Create file: M240_FIRMWARE/IMG-LENSDATA-213.bin
Splitting container: DONE
Extraction COMPLETE!


El firmware M240 incluye un contenedor con nueve elementos:

IMG_LOKI-212.bin -
IMG_LOKI-213.bin -
CTRL_SYS-11.bin - -
IMG-FPGA-212.bin - ()
IMG-FPGA-213.bin - ()
IMG-DSP-212.bin - DSP
IMG-DSP-213.bin - DSP
IMG-LENSDATA-212.bin -
IMG-LENSDATA-213.bin -


Como puede ver, en un firmware hay dos conjuntos de archivos. Más tarde supe que 212 es una versión del microcircuito de procesamiento de imágenes, y dos versiones del Leica M240 entraron en producción. Este estudio se basa en la versión 212.

Gestión del sistema: CTRL_SYS-11.bin


La única parte común es el firmware para el chip de control del sistema. Este es un binario realmente grande, y el código puede adivinar fácilmente para qué está destinado.

$ strings CTRL_SYS-11.bin | rg SH
-> Test SH7216 data flash driver
-> Test SH7216 SCI driver
-> Test SH7216 I2C driver
-> Test SH7216 MTU2 driver
-> Test SH7216 ADC functions
-> Test SH7216 CMT driver


Por lo tanto, tenemos el procesador Renesas SH7216 (SH-2A), que es responsable de la etapa inicial de carga, pruebas de E / S y actualizaciones de firmware. Fuera de la caja IDA admite este tipo de procesador. Solo quedaba encontrar la dirección de carga base correcta, conocida por la descripción de las secciones de firmware: esto es 0x0 .

Section Name: "[A]CTRL_SYS-11"
Section offset: 14680064 | 0x00E00000
Section size: 917277 | 0x000DFF1D
Section base: 0 | 0x00000000


Lo cargué en la IDA y reconocí todas las funciones, pero no lo investigé especialmente, porque el firmware del procesador principal es mucho más interesante.

Aquí también se puede observar que el UART de este chip se abre en el puerto de servicio, donde muestra el registro de descarga. Volveremos a esto más tarde.

Chip principal: IMG_LOKI-212.bin


Para iniciar la ingeniería inversa de este firmware, primero debe responder algunas preguntas:

  1. que tipo de procesador
  2. ¿Cuál es la dirección de carga base?
  3. en qué sistema operativo se basa, si corresponde

Gracias a nuestra herramienta, ya conocemos la dirección de la carga base: esto es 0x100000 .

Section Name: "[A]IMG_LOKI-212"
Section offset: 0 | 0x00000000
Section size: 7340032 | 0x00700000
Section base: 1048576 | 0x00100000


El firmware almacena las respuestas restantes en una forma legible. Por ejemplo, esta línea:

$ strings ./IMG_LOKI-212.bin | rg Softune
6Softune REALOS/FR is Realtime OS for FR Family, based on micro-ITRON COPYRIGHT(C) FUJITSU LIMITED 1994-1999
...


Por lo tanto, estamos tratando con un procesador personalizado Fujitsu FR (Leica lo llama Maestro ) y el sistema operativo Softune REALOS . De hecho, esto es mucho mejor que Blackfin, porque la IDA lista para usar admite FR.

Módulo de procesador FR


La realidad no era tan brillante, porque después de descargar el archivo de firmware, el programa IDA no mostró ninguna instrucción, enlaces externos, etc.

Decidí arreglarlo, pero al final tuve que reescribir completamente algunas partes del firmware . Aquí está el resultado:





Además de las correcciones en ana , ins y out , un código emu completamente nuevo puede:

  • reconocer varios tipos de código y enlaces externos a datos;
  • Reconocer declaraciones de cambio
  • realizar el seguimiento de la pila;
  • Separar los argumentos de la pila y las variables locales.
  • reconocer funciones correctamente

Pero el cambio más grande, como notaron, es letras mayúsculas para instrucciones :)

¿Quieres ver el conjunto completo de instrucciones? Aquí esta:

  AGREGAR O BTSTH LSR MOV BN LDRES EXTSH   
 AGREGAR ORH MUL LSR2 JMP BP STRES EXTUH   
 ADDC ORB MULU ASR CALL BV COPOP SRCH0   
 ADDN EOR MULH ASR2 RET BNV COPLD SRCH1   
 ADDN2 EORH MULUH LDI INT BLT COPST SRCHC   
 SUB EORB DIV0S LDI INTE BGE COPSV LDM0    
 SUBC BANDL DIV0U LDI RETI BLE NOP LDM1    
 SUBN BANDH DIV1 LD BRA BGT ANDCCR STM0    
 CMP BORL DIV2 LDUH BNO BLS ORCCR STM1    
 CMP2 BORH DIV3 LDUB BEQ BHI STILM ENTER   
 Y BEORL DIV4S ST BNE DMOV ADDSP SALIR   
 ANDH BEORH LSL STH BC DMOVH EXTSB XCHB    
 ANDB BTSTL LSL2 STB BNC DMOVB EXTUB 

Entonces, simple y hermoso.

Por cierto, es posible que hayas notado que algunas instrucciones no están alineadas:

  BRA: D loc_xxx
     LDI: 8 # 0x64, R5 

Esto no es un error en el módulo del procesador, sino una característica de la familia Fujitsu FR. Se llama un intervalo de retraso y es bastante típico para los procesadores RISC.

Del manual del procesador FR80 (nota: el enlace ya no funciona):

La instrucción que se encuentra inmediatamente después de la instrucción de bifurcación (su ubicación se denomina "intervalo de retardo") se ejecuta antes de la bifurcación, y la instrucción en la dirección de destino se ejecuta después de la bifurcación. Dado que la instrucción en el intervalo de retraso se ejecuta antes de la operación de bifurcación, la velocidad de ejecución aparente es de 1 ciclo.

Por lo tanto, esto es, en esencia, la optimización de la tubería, y es mejor recordarlo, porque se usa en todas partes en el firmware de Leica.

Softune REALOS


De la wiki :

Softune es el entorno de desarrollo integrado de Fujitsu para las familias de procesadores Fujitsu FR, FR-V y F2MC. Desarrollado por REALOS µITRON kernel en tiempo real. Por ejemplo, se usa en cámaras Nikon DSLR (ver Nikon EXPEED) y algunas cámaras Pentax con K.

Así que este es un RTOS decente bastante popular con tareas, semáforos y otras cosas. Me preguntaba si es posible reconocer algunas funciones de biblioteca estándar en el firmware de Leica.

Tengo que llamar a la primera parte del estudio una gran pérdida de tiempo, y he aquí por qué.

El IDE de Softune resultó ser muy difícil de encontrar, pero al final logré obtener algo. Como se esperaba, el IDE incluía bibliotecas. Había cuatro binarios:

  • lib911.lib
  • lib911e.lib
  • lib911if.lib
  • lib911p.lib

No sé por qué, tal vez por inercia, cuando pirateé todo lo relacionado con Leica, comencé de nuevo la ingeniería inversa del formato. Sí, un formato de módulo de objeto muy bien documentado. Y sí, por supuesto, escribí una herramienta especial para esto :

Fujitsu RISC Library Tool v1.0
Usage: FRLibTool [-s start] [-i imagebase] [-o output] [-f index] [-dv] FIRMWARE.BIN LIBRARY.LIB

This tool will help you to find Softune REALOS library functions in FR (Fujitsu RISC) firmware.
Use following arguments:
-f Specify firmware image file
-s Specify firmware image scan offset
-b Specify firmware imagebase
-o Specify output type (exclusively)
list - list of functions
idc - IDC script
py - IDA python script
pat - FLAIR pattern file
-i xxx Specify index of particular function
-d Dump library
-v Be verbose


Utilizándolo, puede crear archivos *.pat y usarlos como entrada en IDA FLAIR para generar archivos de firma .

$ FRLibTool -o pat lib911.lib
$ FRLibTool -o pat lib911e.lib
$ FRLibTool -o pat lib911if.lib
$ FRLibTool -o pat lib911p.lib
...
$ sigmake -n "SOFTUNE C/C++ Library" lib911.pat lib911e.pat lib911if.pat lib911p.pat softune.sig


Después de aplicar esta firma, finalmente felizmente vi la correspondencia en IMG_LOKI-212.idb .



Diseño


El número de líneas en el firmware llama inmediatamente la atención. Muchas funciones se nombran por su funcionalidad. Esto es muy útil en el proceso de ingeniería inversa para comprender el patrón general.

También es importante tener en cuenta que algunas partes del archivo de firmware se copian a una dirección diferente en el controlador de reinicio. Por ejemplo, el cargador incorporado en tiempo de ejecución se mueve más alto en RAM.

Tuve que crear manualmente secciones adicionales, como resultado, obtuve el siguiente diseño:



Interrupciones


La tabla de vectores de interrupción se puede encontrar accediendo a TBR (Table Base Register):

LDI:32 #int_table, R0
MOV R0, TBR


Por lo general, ocurre en el controlador de reinicio de vector al comienzo del firmware.

Las direcciones de los manejadores en la tabla se almacenan en orden inverso de acuerdo con la fórmula TBR + (0x3FC - 4 × inum) , por lo que el vector de reinicio al final de la tabla se desplaza 0x3FC .

Encontré la mayoría de las interrupciones del manual de FR y sugerí que Leica Maestro tiene un diseño similar. Luego tomó cada controlador e intentó encontrar una cuerda o cualquier otra pista que revelara el propósito de la interrupción.

Como resultado, hice esta lista:



Se esperan muchas interrupciones, como AUDIO / SDIO / VIDEO / JPEG / RAW, pero ¿trata de identificar la más misteriosa? Estoy hablando de interrumpir int_uart_in . Parece que la cámara admite algún tipo de modo de consola UART CLI.

Sistema de llamadas


Como casi cualquier sistema operativo, Softline REALOS utiliza llamadas del sistema. En ensamblador, se ven así:



La dirección real del manejador de llamadas del sistema se calcula de la siguiente manera. Comencemos buscando el controlador de interrupción INT #0x40 . Como se describió anteriormente, esto

(0x3FC - 4 × inum) = (0x3FC - 4 × 0x40) = 0x2FC = int_realos_syscall

En el controlador, es fácil encontrar un enlace a la parte inferior de la tabla de llamadas del sistema con palabras de 16 bits. El registro específico en esta tabla se calcula mediante la fórmula syscall_table_bottom + (num * 2) :

[syscall_table_bottom + (-23 * 2)] = [syscall_table_bottom - 0x2E] = [0x1012EA] = 0xE68

Esto no parece una dirección, porque la dirección real del manejador de llamadas del sistema se calcula como syscall_table_bottom + offset . Todo el proceso se muestra en el diagrama.



Todas las llamadas al sistema y su funcionalidad se indican en el manual del núcleo Softline REALOS / FR , por lo que logré restaurar todos los controladores implementados en la tabla y mejorar un poco más el BID.



Por supuesto, puede hacer que el código sea aún más hermoso definiendo los tipos de llamadas al sistema en la IDA.



Escribí un script de Python para buscar automáticamente estas llamadas al sistema y más.

Las tareas


En la sta_tsk sistema sta_tsk noté que no se pasa la función principal como parámetro, sino pid. Esto significa que es hora de buscar una gran variedad de descriptores de tareas. Y tiene sentido comenzar con el propio sta_tsk .

  ROM: 102180 sys_sta_tsk:
 ROM: 102180 ST RP, @ -R15
 ROM: 102182 LDUB @ (R14, 0x4F), R3
 ROM: 102184 LDI: 32 # word_100B80, R14 

Al principio vemos algunos enlaces. Tuve que jugar un poco con los tipos de datos, pero al final las piezas se unieron:

  ROM: 100B80 word_100B80: .word 0xF;  cantidad de tareas
 ROM: 100B82 .word 0x1C;  tamaño del descriptor de tarea

 ROM: 100B84 .long 0x82A09F5C;  descriptor de tarea 1
 ROM: 100B88 .long 0x1000D
 ROM: 100B8C .long 0
 ROM: 100B90 .long 0x40000000
 ROM: 100B94 .long sub_1A7DB2;  tarea principal
 ROM: 100B98 .long 0x8286EEC0
 ROM: 100B9C .long 0

 ROM: 100BA0 .long 0x82A09F88;  descriptor de tarea 2
 ROM: 100BA4 .long 0x20010
 ROM: 100BA8 .long 0
 ROM: 100BAC .long 0x40000000
 ROM: 100BB0 .long sub_1A6BD2;  tarea principal
 ROM: 100BB4 .long 0x8287EEC0
 ROM: 100BB8 .long 0
 ... 

Y así sucesivamente. Solo 15 tareas. Era cuestión de tiempo examinar cada función principal, determinar el nombre y el propósito de la tarea (excepto la última). Aquí está la lista completa:

  1. SubCPU
    Aparentemente, esta tarea es responsable de las operaciones de captura, como la exposición, el avistamiento en pantalla, etc.
  2. Keymanager
    Lo más probable es que esta tarea esté asociada con botones de hardware.
  3. Guimanager
    Una tarea bastante grande, en la que se implementan la máquina de estado de la interfaz de usuario y la representación de la interfaz.
  4. Debugmanager
    Sí, hay algo que depurar. Ñam ñam.
  5. Administrador de archivos
    Esta tarea se trata de operaciones de archivos.
  6. Fammanager
    Yo diría que la tarea es responsable de los archivos y la memoria, porque depende de las tareas del administrador de archivos y el administrador de memoria.
  7. Administrador de memoria
    Sin sorpresas: operaciones de memoria, gestión de agrupaciones, etc.
  8. Imagemanager
    Esta tarea gestiona los procesos de codificación / decodificación y otros procesos de procesamiento de imágenes.
  9. Usbmanager
    El desafío actual es el procesamiento de comunicaciones USB, que incluye MassStorage, PTP y el propio protocolo de Leica.
  10. IOManager
    Esta tarea parece estar administrando dispositivos de almacenamiento como tarjetas SD y CF (¿qué? ¿Qué otros CF? Quizás sea del modelo 213).
  11. Administrador del sistema
    Diversas tareas como operaciones generales del sistema, administración de energía, etc.
  12. Administrador de configuraciones
    Maneja el estado y la configuración de la cámara.
  13. Monitormanager
    Rastrea los cambios de estado de la cámara e informa otras tareas.
  14. Gerente Periférico
    Esta tarea controla el GPS, el brillo y algunos otros sensores.
  15. Desconocido
    Desafortunadamente, no encontré nada significativo para ella.

Es interesante notar que después de la matriz principal hay otro descriptor destacado.

ROM:100D28 dword_100D28: .long 0x82A0A1F0
ROM:100D2C .long 0x21
ROM:100D30 .long 0
ROM:100D34 .long 0x80000000
ROM:100D38 .long tid16_task
ROM:100D3C .long 0x8285EEC0
ROM:100D40 .long 0


Y la función de la tarea es simplemente ramificarse.

ROM:101494 sub_101494:
ROM:101494 BRA sub_101494 ; CODE XREF: sub_101494


Se hace referencia a este descriptor al final de la función de start , que es responsable de crear otras tareas y configurar el firmware. Entonces, esta es probablemente la tarea de la inacción del sistema.

Módulos y Mensajes


Además de las tareas, puede definir algunos objetos lógicos, como IO y módulos periféricos. Los módulos se presentan como un grupo de manejadores de mensajes como parte de una de las tareas.

El grupo IO parece incluir:

  • Gerente de IO
  • Subprocesador
  • Administrador de USB
  • USB PTP
  • Protocolo USB Leica
  • Almacenamiento masivo USB
  • Administrador de botones
  • Administrador de depuración
  • Gerente de lentes

Y en el grupo periférico:

  • Gerente Periférico
  • Sensor de luz
  • LEDs
  • Orador
  • Sensor de inclinación
  • Reconocimiento de cierre de tapa
  • Módulo GPS
  • Módulo 3DAxis

El sistema de mensajería en sí utiliza las estructuras estándar de SOFTUNE:

 struct RealOS_MsgPayload { uint32_t msgID; // +0x0 uint32_t data[]; // +0x4 } struct RealOS_Message { uint32_t os_reserved1; // +0x0 uint32_t os_reserved2; // +0x4 uint32_t to; // +0x8 uint32_t from; // +0xC RealOS_MsgPayload* payload; // +0x10 } 

Como se esperaba, IPC también tiene varios grupos de mensajes. Como muchos mensajes se procesan en tareas y módulos, pude recuperar solo algunos de estos grupos:

  0x1101xxxx - mensajes globales del sistema:
              0x11010002 = SYS_UPDATE_BOOTLOADER o
              0x11010005 = SYS_ERASE_SETTINGS
 0x1102xxxx - mensajes relacionados con la captura de imágenes:
              0x11020001 = CMD_CAP_CAPTURE o
              0x11020008 = IMAGE_STATUS_CHANGED  
 0x1104xxxx: mensajes sobre eventos relacionados con la reproducción:  
             0x11040002 = PLY_DISABLE_PLAY_MODE 
             0x11040004 = PLY_IMAGE_READY  
0x1108xxxx -     PTP  .:
             0x11080002 = DBG_CHANGE_LEVEL 
             0x11080012 = DBG_WRITE_ROM_DUMP_SD  
0x2201xxxx -  USB PTP
             0x22010108 =    
             0x22010118 =  DebugObject  
0x2202xxxx -     SUBCPU:
             0x22020002 = E_SUBCPU_REQUEST_M_EXPOSURE_REQUEST  
             0x22020015 = E_IO_SUBCPU_COMMAND_CLEANING_SENSOR  
0x2203xxxx -    :
             0x22030001 =   
0x2204xxxx -   IO:
             0x2204000C = / Mass Storage 
             0x22040012 =    
0x330000xx -     UI:
             0x33000001 =  
             0x33000007 =  
0x440000xx -   ,     
             0x44000013 = E_IMG_CMD_CHANGE_PINFO  
0x55xxxxxx —   FAM:  
             0x558800xx = - FAM 
             0x558888xx =     FAM
0x6602xxxx —     LED, :
             0x66020001 -  LED  X 
             0x66020002 =   LED  
0x6604xxxx -  :
             0x66040001 =  
             0x66040007 =    
0x6611xxxx -  ,   
0x6622xxxx -   ,   
0x6660xxxx - algunos otros mensajes relacionados con la memoria:
             0x66600006 = HISTOGRAMA  
             0x66600011 = RAWCOMP  
0x771100xx y 0x77AA00xx: mensajes relacionados con el cambio de modo de cámara 

Desafortunadamente, muchas otras publicaciones siguen siendo desconocidas.

GUI


En el archivo de firmware, también veremos las siguientes secciones: CTRL_SYS-11 , IMG-LOKI-212 , IMG-DSP-212 , IMG-FPGA-212 e IMG-LENSDATA-212 .

Lo que me sorprendió fue la falta total de recursos de la GUI. Pero deberían estar en algún lugar y, muy probablemente, están integrados en IMG-LOKI-212 .

Uno de mis enfoques habituales para invertir el desarrollo del firmware es restaurar todas las referencias cruzadas posibles. No solo en el código, sino también en la sección de datos. Luego miro a través de ellos, tratando de encontrar algunos patrones o enlaces a partes conocidas del código.

El firmware de Leica no fue la excepción. Hay muchas secuencias de datos similares con direcciones a otras secuencias de datos que van más allá, etc. A medida que ascendía en la jerarquía de enlaces, finalmente vi una función familiar.

Por ejemplo, encontré una estructura de datos sin ningún enlace:

 g_data = { ... } 

Otra estructura lo abordó:

 g_data_struct1 = { ... , &g_data } 

Lo que a su vez se refiere a otra estructura:

 g_data_struct2 = { &g_data, ... } 

Esta estructura de datos tiene un enlace desde el código, y se pasa como parámetro a otra función:

 func1() ╰ func2(..., &g_data_struct2, ...) 

Sin embargo, func1()no se llama directamente desde otra función, sino que se almacena en una matriz:

 g_func_list1[] = { ..., func1(), ... } 

Mirando arriba, encontré una llamada en el código g_func_list1:

 func3() { g_func_list1[x] } 

Y nuevamente, esta función se almacena en una matriz:

 g_func_list2[] = { ..., func3(), ... } 

Algún otro código accede a la matriz en sí:

 func4() { g_func_list2[x] } 

Afortunadamente, esta vez la función se llama desde otra función, y así sucesivamente gui_MADE_ApplicationRun.

 gui_Statemachine_DoStateChange() ╰ gui_MADE_ApplicationRun() ╰ func5() ╰ func4() 

Algunas líneas indican que el subsistema GUI se llama "MADE", y las transiciones de página se manejan usando MADE_GetSysTrilo que eso signifique. La máquina de estado GUI se implementa básicamente en una función gui_Statemachine_DoStateChange. Después de recopilar información sobre la GUI, surgió la imagen general:



Como puede ver, la función principal de los recursos de la GUI es gui_CopyImageDesc(aunque este no es un nombre real). Ella tiene los siguientes argumentos:

 gui_CopyImageDesc( uint32_t dstAddress; // R4 - destination address UIDescType type; // R5 - description type UITarget target; // R6 - rendering target uint32_t descAddress; // R7 - description address uint8_t always0; // (SP + 0x0) - always 0 uint8_t index1; // (SP + 0x4) - index 1 uint8_t index2; // (SP + 0x8) - index 2 uint16_t x_offset; // (SP + 0xC) - x offset uint16_t y_offset; // (SP + 0x10) - y offset uint16_t unknown2; // (SP + 0x14) - uint32_t language1; // (SP + 0x18) - language id 1 uint32_t language2; // (SP + 0x1C) - language id 2 uint32_t funcAddress; // (SP + 0x20) - function address ) 

Hay cuatro tipos de descripciones de recursos:

 struct UIDescType0Header struct UIDescType1Header struct UIDescType2 struct UIDescType3 { { { { uint32_t address; uint32_t address; uint32_t reg; uint16_t x_offset; uint16_t entries; uint16_t entries; uint32_t address; uint16_t y_offset; uint16_t unknown; uint16_t unknown; uint16_t unknown1; uint32_t address; } } uint16_t unknown2; } uint16_t unknown3; struct UIDescType0Entry struct UIDescType1Entry uint16_t tableoff; { { } uint16_t x_offset; uint16_t x_offset; uint16_t y_offset; uint16_t y_offset; uint32_t address; uint32_t address; } uint16_t objects; uint16_t total_w; uint16_t total_h; uint16_t unknown; } 

El primer tipo tiene un encabezado con una referencia a una matriz de registros. Cada registro tiene coordenadas y una dirección para datos de píxeles. El tipo actual parece describir elementos dependientes del estado, como iconos, que pueden estar atenuados o desaparecer de la interfaz de usuario.

El segundo tipo también comienza con un encabezado y se utiliza para localizar, describir líneas o bloques de texto.

El tercer tipo describe mapas de caracteres para diferentes idiomas.

El último tipo es responsable de todos los demás recursos estáticos, como imágenes, fondos, etc.

Ahora echemos un vistazo a los datos de las imágenes mismas. Los primeros seis bytes se ven como un encabezado pequeño, seguido de algún tipo de patrón repetitivo, donde cada segundo byte es , o . Es lógico suponer que y

+0x00: 00 08 00 14 00 01 A2 FF 0A 04 05 FF 0C 04 03 FF
+0x10: 0D 04 03 FF 0E 04 02 FF 0E 04 02 FF 04 04 06 FF
+0x20: 04 04 02 FF 04 04 06 FF 04 04 02 FF 04 04 06 FF
+0x30: 04 04 02 FF 04 04 06 FF 04 04 02 FF 04 04 06 FF
+0x40: 04 04 02 FF 04 04 06 FF 04 04 02 FF 04 04 06 FF
+0x50: 04 04 02 FF 04 04 06 FF 04 04 02 FF 0E 04 02 FF
+0x60: 0E 04 02 FF 0D 04 03 FF 0D 04 03 FF 0C 04 04 FF
+0x70: 04 04 0C FF 04 04 0C FF 04 04 0C FF 04 04 0C FF
+0x80: 04 04 0C FF 04 04 0C FF 04 04 0C FF 04 04 0C FF
+0x90: 04 04 0D FF 02 04 2D FF 00 06 00 14 00 01 79 FF


0xFF0x040x00080x0014- ancho y alto en una vista con orden de bytes directo (big endian). Al final de este volcado, vemos el comienzo de otra secuencia 00 06 00 14 00 01. Lo más probable es que este sea el próximo recurso (como lo confirma un enlace). Por lo tanto, el tamaño de los datos reales de la imagen es de 146 bytes. Pero el tamaño de la imagen debe ser 0x8 * 0x14 = 0xA0 = 160. Está claro que los datos no son píxeles puros y ni siquiera un LUT de 8 bits, porque es 14 bytes más pequeño. Entonces que?Probablemente algún tipo de compresión.

Al observar este volcado hexadecimal, es difícil creer que se utilice algún tipo de esquema complejo. La GUI de Leica no es muy colorida, por lo que, en mi experiencia, es mejor usar la tabla LUT aquí. En este caso, los recursos de la interfaz de usuario repetirán completamente los índices LUT como 03 03 03o 1 1 1. Por lo general, el compresor intenta deshacerse de la duplicación de datos, reemplazándolos con un enlace. Estas matrices de índice son ideales para la compresión incluso con un método simple como RLE [data][number]. Un comando simple para escribir data(valor) numberveces.

Con todo esto en mente, sugerí que probablemente veamos una imagen simple con dos colores LUT ( 0xFFy 0x04), y el byte delante del color es el número de píxeles que se dibujarán.

"Y luego escribiste otro instrumento", piensas. Pero no, tomé un bolígrafo y papel y comencé a llenar las celdas. Es curioso que todavía tenga esa foto.



En algún momento, me di cuenta de que 160 píxeles no son suficientes para esta imagen, por lo que 0x8 y 0x14 deben multiplicarse por dos. La tercera palabra 0x0001 indica si la imagen es un carácter ASCII, por lo que la estructura final de ImageAsset es la siguiente:

 struct ImageAsset { uint16_t width; // /2 (big endian) uint16_t height; // /2 (big endian) uint16_t ascii; // 1,   ASCII struct image_data { uint8_t number; //     uint8_t color; //     LUT } data[]; } 

Pero todavía falta una parte: LUT.

No fue tan difícil de encontrar, ya que muchos enlaces y estructuras ya se restauraron manualmente, por lo que lentamente me desplacé por las secciones de datos, buscando una matriz de 256 elementos de valores de 16 bits o 32 bits, hasta que me encontré con esto: de nuevo, gracias En mi trabajo con Blackmagic Design, inmediatamente reconocí los píxeles YUV (por ejemplo, todos los valores con los números 8080). No soy un tonto para volver a dibujar toda la interfaz de usuario manualmente en papel, así que sí, escribí otra herramienta: M240UITool . Además de restablecer todos los recursos de imagen del archivo de firmware a BMP / PNG, esta herramienta puede crear scripts IDC en IDA para determinar todos los recursos de la interfaz de usuario.

.long 0x7008080, 0x72D8080, 0x73C8080, 0x75A8080, 0x79B8080, 0x71DFF6B, 0x7BE8080, 0x7FF8080
.long 0x77BBD27, 0x75B60E7, 0x7835F4A, 0x7D3089F, 0x7018080, 0x7028080, 0x7038080, 0x7048080
.long 0x7058080, 0x7068080, 0x7078080, 0x7088080, 0x7098080, 0x70A8080, 0x70B8080, 0x70C8080
.long 0x70D8080, 0x70E8080, 0x70F8080, 0x7108080, 0x7118080, 0x7128080, 0x7952B15, 0x7138080
.long 0x7148080, 0x7158080, 0x7168080, 0x7178080, 0x7188080, 0x7198080, 0x71A8080, 0x71C8080
.long 0x71D8080, 0x71E8080, 0x71F8080, 0x7338080, 0x7208080, 0x7218080, 0x7228080, 0x7238080
.long 0x7248080, 0x7248080, 0x7268080, 0x7278080, 0x7288080, 0x7298080, 0x72A8080, 0x72B8080
.long 0x72C8080, 0x75E8080, 0x7608080, 0x7628080, 0x7648080, 0x7678080, 0x7688080, 0x7698080
.long 0x76B8080, 0x76E8080, 0x7708080, 0x7728080, 0x7758080, 0x7778080, 0x7798080, 0x77C8080
.long 0x77E8080, 0x7818080, 0x7838080, 0x7868080, 0x7888080, 0x78B8080, 0x78D8080, 0x7908080
.long 0x7928080, 0x7958080, 0x7978080, 0x7998080, 0x79C8080, 0x79D8080, 0x7668080, 0x79E8080
.long 0x7A18080, 0x7A28080, 0x7A38080, 0x7A68080, 0x7A78080, 0x7A88080, 0x7AB8080, 0x7AC8080
.long 0x7AD8080, 0x7B08080, 0x7B28080, 0x7B58080, 0x7B88080, 0x7B98080, 0x7BC8080, 0x7CC8080
.long 0x7AB3BBB, 0x7E10094, 0x7E4556E, 0x4008080, 0x2922D17, 0x7B2AB00, 0x7C2A262, 0x71DFF6B
.long 0x768D4A2, 0x769D4EA, 0x7BD88AE, 0x705997B, 0x70BB377, 0x711CC73, 0x717E66F, 0x7238866
.long 0x729A262, 0x72FBB5E, 0x735D55A, 0x7417751, 0x747914D, 0x74DAA48, 0x753C444, 0x75F663B
.long 0x76B9933, 0x7998080, 0x771B32F, 0x77D5526, 0x7836F22, 0x789881E, 0x78FA21A, 0x7159095
.long 0x71AAA91, 0x720C38D, 0x726DD88, 0x7506F6A, 0x7568866, 0x75CA262, 0x762BB5E, 0x76E5E55
.long 0x7747751, 0x77A914D, 0x780AA48, 0x78C4D3F, 0x792663B, 0x7988037, 0x79E9933, 0x7AA3C2A
.long 0x7B05526, 0x7B66F22, 0x7BC881E, 0x72488AE, 0x72AA1AA, 0x72FBBA6, 0x735D4A2, 0x7427799
.long 0x7489095, 0x74DAA91, 0x753C38D, 0x77E556E, 0x7836F6A, 0x7898866, 0x78FA262, 0x79C4459
.long 0x7A15E55, 0x7A77751, 0x7AD914D, 0x7BF4D3F, 0x7CC8080, 0x7C5663B, 0x7CB8037, 0x7337FC8
.long 0x73999C4, 0x73FB2C0, 0x745CCBB, 0x7757799, 0x74C54FF, 0x77B9095, 0x780AA91, 0x7AB3C72
.long 0x7B1556E, 0x7B66F6A, 0x7BC8866, 0x74277E1, 0x74890DD, 0x74EAAD9, 0x754C3D5, 0x76066CC
.long 0x7667FC8, 0x76C99C4, 0x772B2C0, 0x77E55B7, 0x7846EB3, 0x78A88AE, 0x790A1AA, 0x7526EFB
.long 0x75787F7, 0x75DA1F3, 0x763BAEE, 0x76F5DE6, 0x77577E1, 0x77B90DD, 0x781AAD9, 0x78D4CD0
.long 0x79366CC, 0x79F99C4, 0x7E10094, 0x7CF44A1, 0x7DB7799, 0x7E71A90, 0x7ED338C, 0x7FF8080
.long 0x7328080, 0x7DC8080, 0x7C88080, 0x7508080, 0x775CD2C, 0x76944EA, 0x7808080, 0x71A61FF
.long 0x7244D40, 0x7242C15, 0xFFF8080, 0xF338080, 0xF668080, 0xF998080, 0xFCC8080, 0xF008080
.long 0xF4C54FF, 0xFAB3BBB, 0xFE10094, 0xFE4556E, 0xF952B15, 0xFDA7751, 0xFB2AB00, 0xFC2A262
.long 0xF1DFF6B, 0xF68D4A2, 0xF69D4EA, 0xFBD88AE, 0xA922D17, 0xC6E4130, 0xE286963, 0x74C55FF
.long 0x768D536, 0x7FF8080, 0x7FF8080, 0x7FF8080, 0x2922D17, 0x46E4130, 0x6286963, 0x8080






Leica M (typ 240) UI Tool v1.0
Usage: ./M240UITool [-a address] [-i imagebase] [-s script] [-d dump] [-f folder] [-l LUT] [-rbv] FIRMWARE.BIN

This tool will help you to find UI resources in firmware.
Use following arguments:
-a Specify address of the gui_CopyImageDesc function (ex. 0x2F95E0)
-i Specify firmware imagebase
-s Specify IDC file name
-c Specify container file name
-d Specify dump image format
png - PNG format
bmp - BMP (ARGB) format
-f Specify folder for dumped images
-l Specify LUT for images (filename of address)
-b Specify number of bytes to display in verbose mode
-r Try to recover string characters
-v Be verbose




Ya sabemos que por la función que crea una página de IU, se llama varias veces gui_CopyImageDesc. Pensé que sería genial hacer un navegador de recursos de interfaz de usuario y definir todas las características de representación de la página. La opción -cestá destinada a esto : crea un contenedor especial para ver recursos.

¿Y quién dijo que un navegador de recursos de la interfaz de usuario podría no parecer inusual?



Al ser interactiva (botones translúcidos en la captura de pantalla), esta herramienta le permite no solo desplazarse por las páginas del menú EVF / LCD, sino también ver los pasos de representación dentro de una página.

Desafortunadamente, el código fuente de esta obra maestra se perdió en alguna parte, pero los archivos de encabezado todavía están en el código M240UITool, por lo que técnicamente puede recrearlo desde cero.

Menú de depuración


¿Qué línea estamos buscando principalmente cuando la ingeniería inversa? En mi opinión, esta palabra debugy sus derivados.

Había muchas líneas interesantes en el firmware, pero estas son especiales: parece que puede ingresar al modo de depuración usando alguna combinación de teclas. Todas estas líneas se llaman desde una función gigante , que implementa una máquina de estado de exploración de botones. Así es como se ve en la IDA:

$ strings ./IMG_LOKI-212_1.1.0.2.bin | grep "Debug Mode"
GUI: State: %d! Scanning for Debug Mode successful
GUI: Scanning for Debug Mode: State: %d, Ignore long DEL
GUI: Scanning for Debug Mode: State: %d
GUI: Scanning for Debug Mode: State: %d, Ignore long DEL
GUI: Scanning for Debug Mode: State: %d
GUI: Scanning for Debug Mode: State: %d, Ignore long DEL
GUI: Scanning for Debug Mode: State: %d
GUI: Scanning for Debug Mode: State: %d, Ignore long DEL
GUI: Scanning for Debug Mode: State: %d
GUI: Scanning for Debug Mode: State: %d, Ignore long DEL
GUI: Scanning for Debug Mode: State: %d
...
GUI: ScanningForDebugWithKeyAndJoyStick(): g_GUI_CheckForDebugWithKeyAndJoyStick = %d


ScanningForDebugWithKeyAndJoyStick



No mentiré, me tomó un tiempo entender cómo se procesan los botones de hardware en el firmware y luego restaurar los tipos enumerados para los botones y el joystick. Pero cuando obtuve la combinación, descubrí con disgusto que ella no estaba haciendo nada. Probablemente solo funciona desde una página GUI específica. Un par de noches más de rastreo manual de la máquina de estado GUI, y el problema está resuelto, y también logramos encontrar la página del menú Restablecer.

Finalmente, bienvenido al modo de depuración.



Pensé mucho en anunciar esta combinación, pero decidí abstenerme. Respeto el arduo trabajo que realiza Leica, lanzando sus dispositivos únicos, y no quiero ser responsable del hecho de que sus centros de servicio llenen los cadáveres rotos de las cámaras como resultado de una curiosidad irreflexiva.

Pero aún así, proporcionaré algunos tipos enumerados para simplificar la ingeniería inversa para aquellos que están listos para seguir este camino.

 enum ControlActionType { kControlAction_Idle, // 0 kControlAction_Push, // 1 kControlAction_Release, // 2 kControlAction_LongPush // 3 }; enum ControlBtnType { kControlBtn_LV, // 0 kControlBtn_PLAY, // 1 kControlBtn_DEL, // 2 kControlBtn_ISO, // 3 kControlBtn_MENU, // 4 kControlBtn_SET // 5 }; enum ControlJoystickType { kControlJoy_INFO, // 0 kControlJoy_Up, // 1 kControlJoy_Down, // 2 kControlJoy_Left, // 3 kControlJoy_Right // 4 }; 

Ptp


Pensando en la tarea USB, definí tres modos (que también se confirma en el menú de depuración):

  • Ptp
  • MSC (clase de almacenamiento masivo)
  • Leica personalizada

PTP es muy interesante porque está bien documentado y le permite controlar la cámara.

Es bastante fácil encontrar controladores PTP en el firmware, porque hay muchas llamadas de este código. Todas las llamadas PTP se dividen en tres grupos: Legacy , Leica Extended (LE) y Production .

Los mensajes de depuración ayudaron a establecer nombres para casi todo el código.

 Legado: Leica Extendido: Producción:                           
0x1001 - GetDeviceInfo 0x9001 - Establecer la configuración de la cámara 0x9100 - Abrir sesión de producción      
0x1002 - OpenSession 0x9002 - Get Camera Settings 0x9101 - Close Production Session     
0x1003 - CloseSession 0x9003 - Get Lens Parameter 0x9102 - UpdateFirmware               
0x1004 - Get Storage ID 0x9004 - Release Stage 0x9103 - Open OSD Session             
0x1005 - Get Storage Info 0x9005 - Open LE Session 0x9104 - Close OSD Session            
0x1006 - GetNumObjects 0x9006 - Close LE Session 0x9105 - Get OSD Data                 
0x1007 - GetObjectHandles 0x9007 - RequestObjectTransferReady 0x9106 - GetFirmwareStruct            
0x1008 - GetObjectInfo 0x9008 - GetGeoTackingData 0x910B - GetDebugMenu                 
0x1009 - GetObject 0x900A - Open Debug Session 0x910C - SetDebugMenu                 
0x100A - Get Thumb 0x900B - Close Debug Session 0x910D - ODIN Message                 
0x100B - Delete Object 0x900C - Get Debug Buffer 0x910E - GetDebugObjectHandles        
0x100E - Initiate Capture 0x900D - Debug Command String 0x910F - GetDebugObject               
0x1014 - GetDevicePropDesc 0x900E - Get Debug Route 0x9110 - DeleteDebugObject            
0x1015 - GetDevicePropV 0x900F - SetIPTCData 0x9111 - GetDebugObjectInfo           
0x101C - Initiate Open Capture 0x9010 - GetIPTCData 0x9112 - WriteDebugObject             
                                   0x9020 - Get3DAxisData 0x9113 - CreateDebugObject            
                                   0x9030 - OpenLiveViewSession 0x9114 - Calibrate 3Daxis             
                                   0x9031 - CloseLiveViewSession 0x9115 - Magnetic calibration         
                                   0x9033 - Unknown 0x9116 - Get Viewfinder Data 

La implementación de la interfaz PTP en sí misma parece estándar, pero algunos comandos tienen limitaciones que omito intencionalmente aquí.

En cualquier caso, todo lo anterior es bastante emocionante. Puede pensar: "Solo conectemos la cámara a través de USB y comencemos a sondear con libptp". Eso es correcto

Maldita sea ...

Leica M240 no tiene un puerto USB.

Puerto de la manija


Leica ofrece algunos accesorios para esta cámara, pero hay uno especialmente interesante. Estamos hablando del mango multifunción Leica M (14495) . Reemplaza la parte metálica inferior de la carcasa, proporciona GPS incorporado y varios conectores como USB, un terminal de flash SCA, DIN / ISO-X y una toma de corriente.



Y usted dice de nuevo: "Genial, ahora solo cómprelo, conéctelo a la cámara, conecte la cámara a través de USB y comience a probar usando libptp". Eso es correcto

Maldita sea ...

Cuesta casi 900 dólares.

Estas son casi novecientas razones para crear su propio adaptador. Sin embargo, por si acaso, configuré notificaciones de eBay para este accesorio.

Conector


El conector de la cámara es el siguiente:



intenté encontrarlo en Internet, pero en serio, ¿cómo lo describirías en Google?

Desesperado un poco, comencé a pensar en algunas cosas locas, como pegar papel de aluminio o agujas a una goma de borrar. Pero una vez en el trabajo en Blackmagic Design, mirando la placa de circuito de la cámara, noté que uno de los conectores tenía una forma muy familiar. Al día siguiente traje mi Leica M240 al trabajo, y sí, se veía similar, mucho más tiempo con muchas almohadillas.

Queda por solicitar el número de pieza de nuestro administrador de componentes y luego encontrarlo en el catálogo de Samtec: ERM8-013-05.0-L-DV-TR .



También le preguntamos a Samtec si era posible obtener una muestra, y ellos aceptaron amablemente.



Un poco de trabajo con un soldador, cartón y cinta aislante, y mi propio enchufe está listo (muestra de 2013).



Cinco años después, en 2018, decidí pedirle personalmente a Samtec que enviara otra muestra. Quería hacer algo mejor.

ERCD-013-05.00-TTR-TTR-1-D


Nuevamente, mucho trabajo con un soldador, jurar, cortar alambre, jurar, nuevamente trabajar con un soldador para hacer una opción nueva y más atractiva:



Pinout


Hay 26 contactos en el conector: 13 en cada lado. Incluso antes de soldar mi parte, probé el conector de la cámara con un multímetro y un analizador lógico. Por cierto, debe colocar un imán en el sensor de la cubierta inferior para que la cámara considere que la cubierta está en su lugar.

Tierra (cámara apagada, sin batería)

Siempre comienzo desde el suelo porque es seguro y muy fácil de encontrar.



Por lo tanto, tenemos ocho líneas de tierra (gris oscuro).

Potencial (cámara encendida)

Cuando la cámara está encendida, puede medir el potencial en cada pin y tener una idea de la lógica y los niveles de potencia.

alexhude.imtqy.com/assets/2019/2019-01-24-hacking-leica-m240/probe2_potential.png

El rendimiento en los pines 8–9 y 11–13 es demasiado alto para los pines lógicos, por lo que los definí como potencia (rojo).

Resistencia (cámara apagada, sin batería)

Es útil para medir la resistencia. En algunos casos, esto ayuda a identificar las entradas y agrupar algunas líneas.



Salidas conectadas (cámara apagada, sin batería)

Luego decidí verificar todas las almohadillas externas en el cuerpo de la cámara para verificar si están conectadas al puerto de servicio.



El contacto de sincronización del flash se conectó directamente a la línea 10.

Analizador lógico (cámara encendida) Los

datos de cada línea se registraron en la siguiente secuencia: encienda, la cámara debe estar en modo LV, tomar una foto, iniciar la grabación de video.



Dos líneas muestran la transmisión de algunos datos: 01 y 21.

01 - 115200, transmisión de 8 bits, 1 bit de parada, bit de paridad, LSB primero.



Cada 500 ms, envía un contador C3 3C 02 81 00 01 00 82, C3 3C 02 81 01 01 00 83, C3 3C 02 81 02 01 00 80...

21 - 115200, transmisión de 8 bits, 1 bit de parada, sin bit de verificación de paridad, LSB primero.



Envía el registro del cargador de arranque a SH7216 ("Leica Camera AG" en la captura de pantalla anterior).

Vamos a marcarlos de azul oscuro. Es bastante triste que el registro de Maestro no salga incluso con la configuración máxima de depuración en el menú Depurar.



En estos contactos, la resistencia es de aproximadamente 310kOhm.

No sé por qué, pero sugerí que otras líneas de datos pueden tener una resistencia similar o se cerrarán. Por lo tanto, definí las líneas ~ 300kOhm, ~ 200kOhm y ~ 100kOhm como líneas de datos (sombras de azul en la imagen).

En general, se dibujó la siguiente imagen.



12 candidatos en la línea de datos. ¿Pero cómo verificarlos? Después de una breve conversación con los expertos en hierro sobre la protección eléctrica de los circuitos integrados, comencé a introducir contactos a través de una resistencia de 4kOhm, lo que reduce la corriente a un nivel que las entradas no deberían quemar.

UART


Hice otra suposición de que la línea RX debería estar cerca del TX. Las líneas 02, 03 y 20 parecen buenas candidatas porque ambas tienen un voltaje de 3.3 V como TX.

Inicialmente, intenté explorar estas líneas usando Bus Pirate. Lamentablemente, el resultado fue bastante sucio. Luego tomé los cables basados ​​en SiLabs como más confiables y no conflictivos en macOS.

Primero, conecté el cable TX al pin 20 y comencé a escribir helpdespués del gestor de arranque. Como era de esperar, después de un breve retraso, la cámara repitió los personajes.



Los contactos 02 y 03 fueron los próximos candidatos para UART. Desafortunadamente, no había señales de que estas líneas estuvieran siendo tocadas.

En el diagrama, los UART conocidos están indicados por un tono más oscuro de verde.



USB


Todo comenzó con cortar un cable USB por la mitad con un encabezado en el medio y resistencias de 4kOhm para la detección. Integridad de la señal de un par diferencial? No, entonces no me importaba. :)



Luego probé varios dispositivos domésticos USB en casa para tener una idea de cómo son las comunicaciones en este puerto. Cámara

Canon


Blackmagic


Videocámara de bolsillo Canon


Videocámara JVC Videocámara


Llavero


Cámara KidiZoom


Todos son un poco diferentes, pero el estado inicial D-D + es bajo. Bueno, lo sabremos, y ahora comprobaremos que tenemos:

  • 22 - poco probable, porque D-D + es un par diferencial y debería estar bastante cerca;
  • 04/05 - es poco probable porque tienen resistencia diferente;
  • 14/15 — , ;
  • 15/16 — , .

Así que conecté el USB D-D + a los pines 15/16 y lo conecté al iMac ...



En la pantalla USB PTP, pero la cámara no apareció en el host. Traté de configurar diferentes opciones en el diseño del circuito electrónico, pero nada funcionó. Beagle mostró muchos paquetes dañados y otros errores. Al final, me di por vencido y volví a la ingeniería inversa del firmware.

Este es el pinout final, el USB está marcado en verde oscuro.



¿Quién hubiera pensado que unos años más tarde esa misma notificación de eBay vendrá a mí y compraré el accesorio deseado de forma bastante económica?

Finalmente, puedo probar mis suposiciones sobre PTP. Pero al principio era muy curioso cómo se ve el USB PHY dentro del dispositivo.



Dentro estaba el hub SMSC 2512bjusto en el camino desde el conector de la manija al conector Mini USB. El chip funciona en modo predeterminado porque no hay pines EEPROM o SCL / SDA. El primer puerto descendente se enruta a un zócalo en el cuerpo de la cámara, pero el segundo no está conectado a nada.

Probablemente me perdí algo, pero para mí esa solución no tiene mucho sentido. El pasaporte técnico dice que el chip tiene "pines USB completamente integrados, así como resistencias para subir y bajar el voltaje". Quizás los ingenieros de Leica decidieron no implementar su propio PHY USB, pero usaron el que está en el concentrador, que está bien probado y funciona de inmediato. De hecho, no puedo culparlos, porque antes intenté hacer esto, y resultó ser una tarea difícil. Tal vez esta es una característica de protección contra la falsificación, quién sabe.

En cualquier caso, si comprende USB PHY y está listo para ayudar, no dude en escribirme: debería ser posible trabajar a través de un puerto USB sin este accesorio de marca :)

PTP nuevamente


Como dije, es hora de jugar con la extensión Leica PTP.

Afortunadamente, encontré una biblioteca C ++ bastante buena en lugar de libptp: es libEasyPTP . Tampoco me llevó mucho tiempo escribir una herramienta basada en esta biblioteca: ya conocía algunas limitaciones en la interfaz Leica PTP.

Y aunque M240PTPTool es bastante defectuoso, es bastante adecuado para el papel de prueba de concepto ( código de programa ).

Solo dos solicitudes pasan por PTP: GetDebugBuffer (0x900C) y DebugCommandString (0x900D) . Por cierto, para que los módulos completen el registro de depuración, debe establecer el Nivel de depuración como "Debug" o "Debug RAW" en el menú.

Hay varias opciones en la interfaz M240PTPTool:

  • salir : cierra la herramienta;
  • flush - fusionar el búfer de depuración de la cámara:

M240> flush
I:[00:11:468]|01| DATE/TIME CORRECTED by 5921 sec
D:[00:12:079]|00| Send message from TID 0 to TID 1 over MBX 3 - length: 4 - MesgID: 0x22020103
D:[00:12:179]|00| Send message from TID 0 to TID 1 over MBX 3 - length: 4 - MesgID: 0x22020103
D:[00:12:282]|11| Message received from TID 0 for TID 1 over MBX 3
D:[00:12:283]|11| Message received from TID 0 for TID 1 over MBX 3
D:[00:12:301]|00| Send message from TID 0 to TID 1 over MBX 3 - length: 4 - MesgID: 0x22020103
D:[00:12:402]|00| Send message from TID 0 to TID 1 over MBX 3 - length: 4 - MesgID: 0x22020103
D:[00:12:502]|00| Send message from TID 0 to TID 1 over MBX 3 - length: 4 - MesgID: 0x22020103
...


Cualquier otro texto se envía a la cámara como un comando de depuración. Por ejemplo, helpmuestra todos los comandos posibles con argumentos: la lista completa es bastante grande, pero mira, ¡puedes enviar mensajes directos a Softune para cualquier tarea! Qué sería tan interesante enviar allí ... Otra línea popular que a menudo se busca en el firmware es . A ver si tenemos uno. Aparentemente, puede volcar el firmware en la tarjeta SD. Usando el enlace a la línea "Volcar archivos a la tarjeta", es fácil encontrar el código responsable de esto. Se encuentra en el bloque gigante de tareas del sistema (pid 11, como ya sabemos) y el mensaje lo invoca sin argumentos. Dial en M240PTPTool , pulse Intro y vistazo a la pantalla.

M240> help
********* debug command description ********

exposure request
Description: requests a release from Sub CPU
Parameter 1: Exposure Time TV

still request
Description: simulates the -still request- command flow of Sub CPU
Parameter: no

...

send Message;[Parameter1];[Parameter2];[Parameter2];...;...
Description: Sending Message to Task
Parameter 1: Receiver Task ID
Parameter 2: Command ID
Parameter 3: Command Data[0] (32 Bit)
Parameter 4: Command Data[1] (32 Bit)
Parameter 5: .
Parameter 6: .
use maximum 10 Parameter

...




dump

$ strings IMG_LOKI-212_1.1.0.2.bin | rg -i dump
GUI: HEX DUMP: Address: %x, Length: %d
HSK: DBG_WRITE_ROM_DUMP_SD: File was properly opened, but it seems to be empty.
ROM_DUMP
HSK: DBG_WRITE_ROM_DUMP_SD: Flushing Dump to ROM. Size %d
SD:\ROM_DUMP.bin
HSK: DBG_WRITE_ROM_DUMP_SD Command received!
ROM_DUMP.bin
HSK: DUMP failed, no cards inserted!
HSK: DUMP FlashROM to SD card.
HSK: DUMP FlashROM to CF card.
Dumping files to card


0x11080006

send Message;11;0x11080006



Luego, retire la tarjeta SD y verifique qué contiene.



Aquí está, un volcado completo, incluido el firmware.

Esto abre infinitas posibilidades. Por ejemplo, puede hacer un dispositivo pequeño con un MCU, soporte para un host USB y botones para lanzar secuencias complejas de mensajes ...

Y luego tuvimos un segundo hijo. :)

Epílogo


Si no desea romper el dispositivo, generalmente hay una manera de examinarlo sin abrir la carcasa o soldar los cables a la placa de circuito. A continuación están mis consejos si está interesado:

  • encuentre toda la información pública sobre el dispositivo: especificaciones técnicas, datos sobre componentes, fotos del interior, video de fábrica ;)
  • si tiene firmware, profundice en él y busque consejos sobre salidas externas;
  • , ;
  • GND// , ;
  • ;
  • , ;
  • , (, );
  • , Google (USB/UART/SPI/I2C/1Wire);
  • , ;
  • , ;
  • , .



github.com/alexhude

!

Source: https://habr.com/ru/post/438168/


All Articles