Comment casser un appareil photo cher pour que votre femme ne vous tue pas

Avertissement: l'étude a commencé en 2013, donc si vous pensez que certaines méthodes sont stupides et dangereuses - vous avez raison, c'est tout. Cependant, j'ai beaucoup appris au cours du processus.

Entrée
Tout a commencé quelques mois avant la naissance de mon premier enfant. Ma femme et moi avons toujours voulu acheter un appareil photo Leica cool et nous avons soudain réalisé que si nous ne l’achetions pas maintenant, nous ne pourrions pas le faire pendant longtemps. Par conséquent, nous avons commandé la caméra M240 et ... boom, nous avons été mis en ligne pendant six mois. Bientôt, j'étais fatigué d'attendre et j'ai commencé à étudier leur site. Mon attention a été immédiatement attirée sur la section des fichiers. Eh bien, vous pouvez deviner pourquoi ... Firmware!

J'ai vu un fichier non chiffré et non compressé ( m8-2_005.upd ) qui commence par la magie PWAD . Reconnaissez-vous? Oui, c'est vrai, c'est le format Doom Patch WAD. Les gars semblent aimer les classiques. Le format est très bien documenté , il n'a donc pas été difficile de l'analyser.

Fichiers du firmware Leica


Micrologiciel Leica M8


C'est en fait très drôle, car lorsque j'ai étudié plus tard le fichier de firmware compressé de Leica T, j'ai d'abord décidé de tester les méthodes de compression utilisées par id Software dans le passé.

Wikipédia dit qu'ils ont utilisé le format LHA , qui est essentiellement LZW. Mais les décompresseurs LZW courants ne convenaient pas, alors j'ai commencé à chercher une implémentation spécifique du logiciel d'identification - et le tour est joué, j'ai trouvé Catacomb Armageddon dans la source . Je dois admettre, chanceux.

Dans tous les cas, revenons au M8. Voici la structure du firmware:

  RÈGLES: 0x0000008C (3036: 0x00000BDC) - Description XML
 LUTS: 0x00000C68 (183274: 0x0002CBEA)
  GAMMA: 0x0000007C (31760: 0x00007C10)
  GAIN: 0x00007C8C (50344: 0x0000C4A8)
  LEICA: 0x00014134 (7000: 0x00001B58)
  BLEMISH: 0x00015C8C (250: 0x000000FA)
  WREF: 0x00015D88 (82480: 0x00014230)
  OBJ: 0x00029FB8 (11268: 0x00002C04)
  VERSION: 0x0002CBBC (46: 0x0000002E)
 PXA: 0x0002D854 (858384: 0x000D1910)
 BF: 0x000FF164 (134522: 0x00020D7A) - famille de processeurs Blackfin Analog Devices
 GUI: 0x0011FEE0 (3574180: 0x003689A4)
  TRANS: 0x0000005C (59988: 0x0000EA54) - localisation
  IMAGES: 0x0000EAB0 (267433: 0x000414A9)
   21_1PRT: 0x000000CC (18411: 0x000047EB) - photo de JFIF
   21_2GRP: 0x000048B8 (23172: 0x00005A84) - image de JFIF
   21_3PAN: 0x0000A33C (23034: 0x000059FA) - Photo de JFIF
   24_1PRT: 0x0000FD38 (18489: 0x00004839) - image de JFIF
   24_2GRP: 0x00014574 (23230: 0x00005ABE) - image de JFIF
   24_3PAN: 0x0001A034 (22998: 0x000059D6) - image de JFIF
   28_1PRT: 0x0001FA0C (22605: 0x0000584D) - photo de JFIF
   28_2GRP: 0x0002525C (23081: 0x00005A29) - image de JFIF
   28_3PAN: 0x0002AC88 (23282: 0x00005AF2) - image de JFIF
   35_1PRT: 0x0003077C (22496: 0x000057E0) - image de JFIF
   35_2GRP: 0x00035F5C (23532: 0x00005BEC) - photo de JFIF
   35_3PAN: 0x0003BB48 (22881: 0x00005961) - image de JFIF
  FONT1: 0x0004FF5C (1522988: 0x00173D2C)
  FONT2: 0x001C3C88 (1723676: 0x001A4D1C)
  VERSION: 0x003689A4 (0: 0x00000000)
 M16C: 0x00488884 (130406: 0x0001FD66) - Famille Renesas M16C (Motorola S-record)
 FPGA: 0x004A85EC (131604: 0x00020214) - Xilinx Spartan 3
 FSL: 0x004C8800 (814: 0x0000032E) - le chargeur de démarrage de premier étage 

L'IDA prêt à l'emploi ne prend pas en charge les processeurs Blackfin, mais il existe un plugin tiers .

Micrologiciel Leica M9


Le fichier du firmware du Leica M9 ( m9-1_196.upd ) semble crypté: l'histogramme montre une distribution d'environ 0,45%.



La fin de l'histoire? Peut-être pas. Le fait est que Leica a utilisé des processeurs plutôt faibles dans les caméras, et à cette époque, le cryptage XOR était souvent utilisé dans l'électronique grand public, j'ai donc décidé d'écrire un outil simple pour l'opération XOR pour comparer le firmware avec moi-même et calculer des statistiques.

La longueur de clé a été déterminée en recherchant le motif de répétition le plus long. Cela est logique, car tout micrologiciel comprend généralement de gros blocs de données répétitives, comme un pavé 0x00 / 0xFF ou des graphiques avec des pixels LUT. La clé elle-même est calculée par la fréquence d'octets dans la longueur de la clé, où l'octet le plus courant va au tampon de clé. Le résultat du programme indiquait clairement le cryptage XOR. Ensuite, j'ai dû modifier un peu l'outil pour obtenir la clé potentielle et décrypter le code. Cela s'est avéré à nouveau être un fichier PWAD.

Le contenu de PWAD a révélé la structure suivante:

  RÈGLES: 0x0000007C (2788: 0x00000AE4) - Description XML
 LUTS: 0x00000B60 (4060616: 0x003DF5C8)
  PROCESSUS: 0x0000004C (3900572: 0x003B849C)
   CRÉER: 0x0000004C (20: 0x00000014) - horodatage
   LUTS: 0x00000060 (427744: 0x000686E0)
   GAINMAP: 0x00068740 (20008: 0x00004E28)
   LENTILLE: 0x0006D568 (3452724: 0x0034AF34)
  CCD: 0x003B84E8 (148662: 0x000244B6)
   CRÉER: 0x0000004C (20: 0x00000014) - horodatage
   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-RVB: 0x00000EA0 (560: 0x00000230)
  WBPARAM: 0x003DDA70 (7000: 0x00001B58)
 BF561: 0x003E0128 (289128: 0x00046968) - Famille de processeurs Blackfin Analog Devices
  bf0: 0x0000004C (117846: 0x0001CC56) - processeur principal
  bf1: 0x0001CCA4 (117826: 0x0001CC42) - firmware du sous-processeur
  bf0.map: 0x000398E8 (27072: 0x000069C0) - carte de microprogramme du processeur principal avec caractères: D
  bf1.map: 0x000402A8 (26304: 0x000066C0) - carte de microprogramme de sous-processeur avec caractères: D
 CORPS: 0x00426A90 (143280: 0x00022FB0) - Famille Renesas M16C (Motorola S-record)
 GUI: 0x00449A40 (3647624: 0x0037A888)
  TRANS: 0x0000005C (131656: 0x00020248) - localisation
  IMAGES: 0x000202A4 (267433: 0x000414A9)
   21_1PRT: 0x000000CC (18411: 0x000047EB) - photo de JFIF
   21_2GRP: 0x000048B8 (23172: 0x00005A84) - image de JFIF
   21_3PAN: 0x0000A33C (23034: 0x000059FA) - Photo de JFIF
   24_1PRT: 0x0000FD38 (18489: 0x00004839) - image de JFIF
   24_2GRP: 0x00014574 (23230: 0x00005ABE) - image de JFIF
   24_3PAN: 0x0001A034 (22998: 0x000059D6) - image de JFIF
   28_1PRT: 0x0001FA0C (22605: 0x0000584D) - photo de JFIF
   28_2GRP: 0x0002525C (23081: 0x00005A29) - image de JFIF
   28_3PAN: 0x0002AC88 (23282: 0x00005AF2) - image de JFIF
   35_1PRT: 0x0003077C (22496: 0x000057E0) - image de JFIF
   35_2GRP: 0x00035F5C (23532: 0x00005BEC) - photo de JFIF
   35_3PAN: 0x0003BB48 (22881: 0x00005961) - image de JFIF
  FONT1: 0x00061750 (1522988: 0x00173D2C)
  USBLOGO: 0x001D547C (1775: 0x000006EF) - photo de JFIF
  FONT2: 0x001D5B6C (1723676: 0x001A4D1C)
 FPGA: 0x007C42C8 (150176: 0x00024AA0) - Xilinx Spartan 3A
 BF547: 0x007E8D68 (937576: 0x000E4E68) - Famille de processeurs Blackfin Analog Devices (FSL?) 


Micrologiciel Leica M240


J'ai pris l'habitude de vérifier la page de téléchargement avec le firmware Leica chaque matin. Bientôt, un nouveau fichier est apparu: FW_M240_1_1_0_2.FW .

Il n'avait pas l'air crypté, mais était compressé ...

La compression


L'histogramme montre une énorme rafale à 0x9D.



C'est peut-être une sorte de magie de compression. Une recherche sur Internet [compression 9D +] n'a rien donné, sauf que 0x1F9D est utilisé comme signature pour la compression LZW . Si quoi que ce soit, je comprends les types de compression LZ et j'ai décidé de regarder les octets après 0x9D. Et j'ai vu quatre options:

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

Qu'avez-vous réussi à remarquer d'autre:

  • la première option n'apparaît qu'une seule fois à l'adresse 0x30: elle est probablement utilisée comme indicateur de données compressées;
  • XX ne dépasse jamais 0x7F;
  • le dernier octet de YY dans les troisième et quatrième cas ne dépasse jamais 0x7F

D'après ce que je sais de LZ, c'est très similaire à LZ77 ou LZSS, où YY est l'étape de retrait et XX est le nombre d'octets à copier. Et la deuxième option est un cas spécial d'émission de 0x9D. J'ai écrit une simple fonction C qui implémente cette logique. Elle a confirmé que nous allons dans la bonne direction, mais la quatrième option ne rentre toujours pas dans le schéma.

J'ai essayé de toutes les manières de l'interpréter, mais rien n'en est sorti. Par conséquent, je me suis tourné vers mes camarades pour obtenir des conseils. Un gars a remarqué que, selon mes propres observations, le quatrième octet de YY n'apparaît que lorsque le bit le plus élevé 0x8Y est défini: ce n'est qu'une distance supplémentaire pour l'étape de retrait. J'avais honte, tout s'est avéré si évident ...

Enfin, le décompresseur a commencé à émettre un flux valide ... jusqu'à ce qu'il se coince au milieu du fichier. Cela est dû à la longueur inconnue de la fenêtre coulissante. Des débogages et des tests supplémentaires ont corrigé la situation.

Il y avait donc un outil pour analyser le firmware M240 .

Structure du firmware


Pour travailler avec un format inconnu, je n'ai rien trouvé de mieux que de mesurer certains décalages et tailles de sections de code - et d'essayer de trouver les valeurs les plus proches dans l'en-tête du fichier. Par exemple, ce bloc:

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


finalement transformé en:

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


En comprenant la structure du firmware, j'ai amélioré mon outil, et au final, il a produit ceci:

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!


Le firmware M240 comprend un conteneur avec neuf éléments:

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 -


Comme vous pouvez le voir, dans un micrologiciel, il existe deux ensembles de fichiers. Plus tard, j'ai appris que le 212 est une version du microcircuit de traitement d'image et deux versions du Leica M240 sont entrées en production. Cette étude est basée sur la version 212.

Gestion du système: CTRL_SYS-11.bin


La seule partie commune est le firmware de la puce de contrôle du système. Il s'agit d'un très gros binaire, et le code peut facilement deviner à quoi il est destiné.

$ 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


Ainsi, nous avons le processeur Renesas SH7216 (SH-2A), qui est responsable de la première étape du chargement, des tests d'E / S et des mises à jour du firmware. IDA prêt à l'emploi prend en charge ce type de processeur. Il ne restait plus qu'à trouver l'adresse de chargement de base correcte, connue d'après la description des sections du firmware: c'est 0x0 .

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


Je l'ai chargé dans l'IDA et reconnu toutes les fonctions, mais je ne l'ai pas creusé spécialement, car le firmware du processeur principal est beaucoup plus intéressant.

Ici, on peut également noter que l'UART de cette puce s'ouvre sur le port de service, où il affiche le journal de téléchargement. Nous y reviendrons plus tard.

Puce principale: IMG_LOKI-212.bin


Pour démarrer la rétro-ingénierie de ce firmware, vous devez d'abord répondre à quelques questions:

  1. quel type de processeur
  2. quelle est l'adresse de chargement de base
  3. sur quel système d'exploitation est-il basé, le cas échéant

Grâce à notre outil, nous connaissons déjà l'adresse de la charge de base: c'est 0x100000 .

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


Le micrologiciel stocke les réponses restantes sous une forme lisible. Par exemple, cette ligne:

$ 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
...


Ainsi, nous avons affaire à un processeur personnalisé Fujitsu FR (Leica l'appelle Maestro ) et au système d' exploitation Softune REALOS . En fait, c'est beaucoup mieux que Blackfin, car l'IDA prêt à l'emploi prend en charge FR.

Module processeur FR


La réalité n'était pas si brillante, car après avoir téléchargé le fichier du firmware, le programme IDA n'a pas montré d'instructions, de liens externes, etc.

J'ai décidé de le réparer, mais à la fin j'ai dû réécrire complètement certaines parties du firmware . Voici le résultat:





En plus des corrections en ana , ins et out , un tout nouveau code emu peut:

  • reconnaître divers types de code et des liens externes vers des données;
  • Reconnaître les instructions de commutateur
  • effectuer le traçage de la pile;
  • Arguments de pile séparés et variables locales
  • reconnaître correctement les fonctions.

Mais le plus grand changement, comme vous l'avez remarqué, ce sont les majuscules pour les instructions :)

Vous voulez voir l'ensemble complet des instructions? Le voici:

  AJOUTER OU BTSTH LSR MOV BN LDRES EXTSH   
 ADD2 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   
 ET BEORL DIV4S ST BNE DMOV ADDSP CONGÉ   
 ANDH BEORH LSL STH BC DMOVH EXTSB XCHB    
 ANDB BTSTL LSL2 STB BNC DMOVB EXTUB 

Donc, simple et beau.

À propos, vous avez peut-être remarqué que certaines instructions ne sont pas alignées:

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

Ce n'est pas une erreur dans le module processeur, mais en fait une caractéristique de la famille Fujitsu FR. Il est appelé un slot de retard et est assez typique pour les processeurs RISC.

Dans le manuel du processeur FR80 (remarque: le lien ne fonctionne plus):

L'instruction qui se trouve immédiatement après l'instruction de branchement (son emplacement est appelé «intervalle de retard») est exécutée avant la branchement, et l'instruction à l'adresse de destination est exécutée après la branchement. Étant donné que l'instruction dans la tranche de retard est exécutée avant l'opération de branchement, la vitesse d'exécution apparente est de 1 cycle.

Ainsi, il s'agit essentiellement d'une optimisation du pipeline, et il vaut mieux s'en souvenir, car il est utilisé partout dans le firmware Leica.

Softune REALOS


Depuis le wiki :

Softune est l'environnement de développement intégré de Fujitsu pour les familles de processeurs Fujitsu FR, FR-V et F2MC. Propulsé par le noyau temps réel REALOS µITRON. Par exemple, il est utilisé dans les appareils photo reflex numériques Nikon (voir Nikon EXPEED) et certains appareils photo Pentax avec K.

C'est donc un RTOS décent assez populaire avec des tâches, des sémaphores et d'autres goodies. Je me demandais s'il était possible de reconnaître certaines fonctions de bibliothèque standard dans le firmware Leica.

Je dois appeler la première partie de l'étude une grosse perte de temps, et voici pourquoi.

L'IDE Softune s'est avéré très difficile à trouver, mais j'ai finalement réussi à obtenir quelque chose. Comme prévu, l'EDI comprenait des bibliothèques. Il y avait quatre binaires:

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

Je ne sais pas pourquoi, peut-être par inertie, comme j'ai piraté tout ce qui était lié à Leica, j'ai recommencé la rétro-ingénierie du format. Oui, un format de module objet très bien documenté. Et oui, bien sûr, j'ai écrit un outil spécial pour cela :

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


En l'utilisant, vous pouvez créer des fichiers *.pat et les utiliser comme entrée dans l' IDA FLAIR pour générer des fichiers de signature .

$ 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


Après avoir apposé cette signature, j'ai finalement vu avec plaisir la correspondance dans IMG_LOKI-212.idb .



Disposition


Le nombre de lignes du firmware attire immédiatement l'attention. De nombreuses fonctions sont nommées pour leur fonctionnalité. Ceci est très utile dans le processus d'ingénierie inverse pour comprendre le modèle général.

Il est également important de noter que certaines parties du fichier du firmware sont copiées à une adresse différente dans le gestionnaire de réinitialisation. Par exemple, le chargeur intégré à l'exécution se déplace plus haut dans la RAM.

J'ai dû créer manuellement des sections supplémentaires, par conséquent, j'ai obtenu la mise en page suivante:



Interruptions


La table des vecteurs d'interruption peut être trouvée en accédant à TBR (Table Base Register):

LDI:32 #int_table, R0
MOV R0, TBR


Cela se produit généralement dans le gestionnaire de réinitialisation vectorielle au tout début du micrologiciel.

Les adresses des gestionnaires de la table sont stockées dans l'ordre inverse selon la formule TBR + (0x3FC - 4 × inum) , de sorte que le vecteur de réinitialisation à la fin de la table est décalé 0x3FC .

J'ai trouvé la plupart des interruptions du manuel FR et suggéré que Leica Maestro a une disposition similaire. Puis il a pris chaque gestionnaire et a essayé de trouver une chaîne ou tout autre indice qui révèle le but de l'interruption.

En conséquence, j'ai fait cette liste:



De nombreuses interruptions sont tout à fait attendues, comme AUDIO / SDIO / VIDEO / JPEG / RAW, mais essayez-vous d'identifier les plus mystérieuses d'entre elles? Je parle d'interrompre int_uart_in . Il semble que la caméra prenne en charge une sorte de CLI UART en mode console.

Appels système


Comme presque tous les systèmes d'exploitation, Softline REALOS utilise des appels système. En assembleur, ils ressemblent à ceci:



L'adresse réelle du gestionnaire d'appels système est calculée comme suit. Commençons par rechercher le gestionnaire d'interruption INT #0x40 . Comme décrit ci-dessus, cette

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

Dans le gestionnaire, il est facile de trouver un lien vers le bas de la table d'appels système avec des mots de 16 bits. L'enregistrement spécifique dans ce tableau est calculé par la formule syscall_table_bottom + (num * 2) :

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

Cela ne ressemble pas à une adresse, car l'adresse réelle du gestionnaire d'appels système est calculée comme syscall_table_bottom + offset . L'ensemble du processus est illustré dans le diagramme.



Tous les appels système et leurs fonctionnalités sont indiqués dans le manuel du noyau Softline REALOS / FR , j'ai donc réussi à restaurer tous les gestionnaires implémentés dans la table et à améliorer un peu plus IDB.



Bien sûr, vous pouvez rendre le code encore plus beau en définissant les types d'appels système dans l'IDA.



J'ai écrit un script Python pour rechercher automatiquement ces appels système et plus encore.

Les tâches


Dans l' sta_tsk système sta_tsk j'ai remarqué que non la fonction principale n'est pas passée en paramètre, mais pid. Cela signifie qu'il est temps de rechercher un large éventail de descripteurs de tâches. Et il est logique de commencer par sta_tsk lui-même.

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

Au tout début, nous voyons quelques liens. J'ai dû bricoler un peu avec les types de données, mais à la fin, les éléments se sont réunis:

  ROM: 100B80 word_100B80: .word 0xF;  nombre de tâches
 ROM: 100B82 .word 0x1C;  taille du descripteur de tâche

 ROM: 100B84 .long 0x82A09F5C;  descripteur de tâche 1
 ROM: 100B88 .long 0x1000D
 ROM: 100B8C .long 0
 ROM: 100B90 .long 0x40000000
 ROM: 100B94 .long sub_1A7DB2;  tâche principale
 ROM: 100B98 .long 0x8286EEC0
 ROM: 100B9C .long 0

 ROM: 100BA0 .long 0x82A09F88;  descripteur de tâche 2
 ROM: 100BA4 .long 0x20010
 ROM: 100BA8 .long 0
 ROM: 100BAC .long 0x40000000
 ROM: 100BB0 .long sub_1A6BD2;  tâche principale
 ROM: 100BB4 .long 0x8287EEC0
 ROM: 100BB8 .long 0
 ... 

et ainsi de suite. Seulement 15 tâches. C'était une question de temps pour examiner chaque fonction principale, déterminer le nom et le but de la tâche (sauf la dernière). Voici la liste complète:

  1. SubCPU
    Cette tâche est apparemment responsable des opérations de capture telles que l'exposition, l'observation à l'écran, etc.
  2. Keymanager
    Très probablement, cette tâche est associée à des boutons matériels.
  3. Guimanager
    Une tâche assez importante, dans laquelle la machine d'état de l'interface utilisateur et le rendu de l'interface sont implémentés.
  4. Debugmanager
    Oui, il y a quelque chose à déboguer. Miam miam.
  5. Gestionnaire de fichiers
    Cette tâche concerne les opérations sur les fichiers.
  6. Fammanager
    Je dirais que la tâche est responsable des fichiers et de la mémoire, car cela dépend des tâches du gestionnaire de fichiers et du gestionnaire de mémoire.
  7. Memorymanager
    Pas de surprise: opérations de mémoire, gestion de pool, etc.
  8. Imagemanager
    Cette tâche gère les processus de codage / décodage et autres processus de traitement d'image.
  9. Usbmanager
    Le défi actuel est le traitement des communications USB, qui comprend MassStorage, PTP et le propre protocole de Leica.
  10. IOManager
    Cette tâche semble gérer des périphériques de stockage tels que les cartes SD et CF (quoi? Quels autres CF? Peut-être du modèle 213).
  11. Systemmanager
    Diverses tâches comme les opérations générales du système, la gestion de l'alimentation, etc.
  12. SettingsManager
    Gère l'état et les paramètres de la caméra.
  13. Monitormanager
    Suit les changements d'état de la caméra et informe les autres tâches.
  14. Peripheralmanager
    Cette tâche contrôle le GPS, la luminosité et certains autres capteurs.
  15. Inconnu
    Malheureusement, je n'ai rien trouvé d'important pour elle.

Il est intéressant de noter qu'après le tableau principal, il existe un autre descripteur exceptionnel.

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


Et la fonction de la tâche est simplement de se ramifier.

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


Ce descripteur est référencé à la fin de la fonction de start , qui est chargée de créer d'autres tâches et de configurer le firmware. C'est donc probablement la tâche de l'inaction du système.

Modules et messages


En plus des tâches, vous pouvez définir certains objets logiques, tels que les modules d'E / S et périphériques. Les modules sont présentés comme un groupe de gestionnaires de messages dans le cadre de l'une des tâches.

Le groupe IO semble inclure:

  • IO Manager
  • Sous-processeur
  • Gestionnaire USB
  • USB PTP
  • Protocole USB Leica
  • Stockage de masse USB
  • Gestionnaire de boutons
  • Gestionnaire de débogage
  • Gestionnaire d'objectifs

Et dans le groupe périphérique:

  • Gestionnaire de périphériques
  • Capteur de lumière
  • LEDs
  • Conférencier
  • Capteur d'inclinaison
  • Reconnaissance de la fermeture de la casquette
  • Module GPS
  • Module 3DAxis

Le système de messagerie lui-même utilise les structures SOFTUNE standard:

 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 } 

Comme prévu, IPC dispose également de plusieurs groupes de messages. Étant donné que de nombreux messages sont traités dans des tâches et des modules, je n'ai pu récupérer que certains de ces groupes:

  0x1101xxxx - messages système globaux:
              0x11010002 = SYS_UPDATE_BOOTLOADER ou
              0x11010005 = SYS_ERASE_SETTINGS
 0x1102xxxx - messages liés à la capture d'image:
              0x11020001 = CMD_CAP_CAPTURE ou
              0x11020008 = IMAGE_STATUS_CHANGED  
 0x1104xxxx - messages sur les événements liés à la lecture:  
             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 - quelques autres messages liés à la mémoire:
             0x66600006 = HISTOGRAMME  
             0x66600011 = RAWCOMP  
0x771100xx et 0x77AA00xx - messages liés au changement de mode de caméra 

Malheureusement, de nombreux autres postes restent inconnus.

GUI


Dans le fichier du firmware, nous examinerons également les sections suivantes: CTRL_SYS-11 , IMG-LOKI-212 , IMG-DSP-212 , IMG-FPGA-212 et IMG-LENSDATA-212 .

Ce qui m'a surpris, c'est le manque total de ressources GUI. Mais ils devraient être quelque part et, très probablement, intégrés à IMG-LOKI-212 .

L'une de mes approches habituelles pour inverser le développement du firmware est de restaurer toutes les références croisées possibles. Non seulement dans le code, mais aussi dans la section des données. Ensuite, je les regarde, essayant de trouver des modèles ou des liens vers des parties connues du code.

Le firmware Leica ne fait pas exception. Il existe de nombreuses séquences de données similaires avec des adresses à d'autres séquences de données qui vont plus loin, etc. En gravissant la hiérarchie des liens, j'ai finalement vu une fonction familière.

Par exemple, j'ai trouvé une structure de données sans aucun lien:

 g_data = { ... } 

Une autre structure l'a abordé:

 g_data_struct1 = { ... , &g_data } 

Qui à son tour est désigné par une autre structure:

 g_data_struct2 = { &g_data, ... } 

Cette structure de données a un lien depuis le code, et elle est passée en paramètre à une autre fonction:

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

Cependant, func1()il n'est pas appelé directement à partir d'une autre fonction, mais est stocké dans un tableau:

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

En regardant ci-dessus, j'ai trouvé un appel dans le code g_func_list1:

 func3() { g_func_list1[x] } 

Et encore une fois, cette fonction est stockée dans un tableau:

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

Un autre code accède au tableau lui-même:

 func4() { g_func_list2[x] } 

Heureusement, cette fois -ci la fonction est appelée d' une autre fonction, et ainsi de suite gui_MADE_ApplicationRun.

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

Certaines lignes indiquent que le sous-système GUI est appelé «MADE» et les transitions de page sont gérées en utilisant MADE_GetSysTrice que cela signifie. La machine d'état GUI est essentiellement implémentée dans une fonction gui_Statemachine_DoStateChange. Après avoir collecté des informations sur l'interface graphique, l'image générale s'est dégagée:



comme vous pouvez le voir, la fonction principale des ressources de l'interface graphique est gui_CopyImageDesc(bien que ce ne soit pas un vrai nom). Elle a les arguments suivants:

 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 ) 

Il existe quatre types de descriptions de ressources:

 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; } 

Le premier type a un en-tête avec une référence à un tableau d'enregistrements. Chaque enregistrement a des coordonnées et une adresse pour les données de pixels. Le type actuel semble décrire des éléments dépendants de l'état, tels que des icônes, qui peuvent être grisés ou disparaître de l'interface utilisateur.

Le deuxième type commence également par un en-tête et est utilisé pour localiser, décrire des lignes ou des blocs de texte.

Le troisième type décrit les cartes de caractères pour différentes langues.

Ce dernier type est responsable de toutes les autres ressources statiques, telles que les images, les arrière-plans, etc.

Examinons maintenant les données des images elles-mêmes. Les six premiers octets ressemblent à un petit en-tête, suivi d'une sorte de motif répétitif, où chaque deuxième octet est soit , soit . Il est logique de supposer que et

+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- largeur et hauteur dans une vue avec un ordre d'octets direct (big endian). À la fin de ce vidage, nous voyons le début d'une autre séquence 00 06 00 14 00 01. Il s'agit très probablement de la prochaine ressource (comme le confirme un lien vers celle-ci). Ainsi, la taille des données d'image réelles est de 146 octets. Mais la taille de l'image doit être 0x8 * 0x14 = 0xA0 = 160. Il est clair que les données ne sont pas des pixels purs et même pas une LUT 8 bits, car elles sont 14 octets plus petites. Alors quoi?Probablement une sorte de compression.

En regardant ce vidage hexadécimal, il est difficile de croire qu'une sorte de schéma complexe est utilisé. L'interface graphique de Leica n'est pas très colorée, donc d'après mon expérience, il est préférable d'utiliser la table LUT ici. Dans ce cas, les ressources de l'interface utilisateur répéteront complètement les indices LUT comme 03 03 03ou 1 1 1. En règle générale, le compresseur essaie de se débarrasser de la duplication des données, en les remplaçant par un lien. Ces tableaux d'index sont idéaux pour la compression, même avec une méthode simple comme RLE [data][number]. Une simple commande pour écrire data(valeur) numberfois.

Avec tout cela à l'esprit, j'ai suggéré que nous regardions très probablement une image simple avec deux couleurs LUT ( 0xFFet 0x04), et l'octet devant la couleur est le nombre de pixels à dessiner.

«Et puis vous avez écrit un autre instrument», pensez-vous. Mais non, j'ai pris un stylo et du papier et j'ai commencé à remplir les cellules. C'est drôle que j'ai encore cette photo.



Quelque part en cours de route, j'ai réalisé que 160 pixels ne suffisaient pas pour cette image, donc 0x8 et 0x14 doivent être multipliés par deux. Le troisième mot 0x0001 indique si l'image est un caractère ASCII, la structure finale d'ImageAsset est donc la suivante:

 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[]; } 

Mais il manque encore une partie: LUT.

Ce n'était pas si difficile à trouver, car de nombreux liens et structures ont déjà été restaurés manuellement, j'ai donc lentement parcouru les sections de données, à la recherche d'un tableau de 256 éléments à partir de valeurs 16 bits ou 32 bits, jusqu'à ce que je tombe sur ceci: Encore une fois, merci Dans mon travail avec Blackmagic Design, j'ai immédiatement reconnu les pixels YUV (par exemple, toutes les valeurs avec les nombres 8080). Je ne suis pas dupe de dessiner à nouveau l'intégralité de l'interface utilisateur manuellement sur papier, alors oui, j'ai écrit un autre outil - M240UITool . En plus de réinitialiser toutes les ressources d'image du fichier du micrologiciel vers BMP / PNG, cet outil peut créer des scripts IDC dans IDA pour déterminer toutes les ressources d'interface utilisateur.

.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




Nous savons déjà qu'à partir de la fonction créée par une page d'interface utilisateur, elle est appelée plusieurs fois gui_CopyImageDesc. J'ai pensé qu'il serait formidable de créer un navigateur de ressources d'interface utilisateur et de définir toutes les fonctionnalités de rendu de page. L'option -cest destinée à cela - elle crée un conteneur spécial pour l'affichage des ressources.

Et qui a dit qu'un navigateur de ressources d'interface utilisateur pourrait ne pas sembler inhabituel?



Étant interactif (boutons translucides sur la capture d'écran), cet outil vous permet non seulement de faire défiler les pages du menu EVF / LCD, mais également de visualiser les étapes de rendu sur une seule page.

Malheureusement, le code source de ce chef-d'œuvre a été perdu quelque part, mais les fichiers d'en-tête sont toujours dans le code M240UITool, donc techniquement, vous pouvez le recréer à partir de zéro.

Menu de débogage


Quelle ligne recherchons-nous principalement lors du reverse engineering? À mon avis, ce mot debuget ses dérivés.

Il y avait beaucoup de lignes intéressantes dans le firmware, mais elles sont spéciales: il semble que vous pouvez entrer en mode débogage en utilisant une combinaison de touches. Toutes ces lignes sont appelées à partir d'une fonction géante , qui implémente une machine d'état de balayage des boutons. Voici à quoi cela ressemble dans l'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



Je ne vais pas mentir, il a fallu un certain temps pour comprendre comment les boutons matériels sont traités dans le firmware, puis restaurer les types énumérés pour les boutons et le joystick. Mais quand j'ai obtenu la combinaison, j'ai découvert avec chagrin qu'elle ne faisait rien. Cela ne fonctionne probablement qu'à partir d'une page GUI spécifique. Encore quelques nuits de traçage manuel de la machine d'état GUI - et le problème est résolu, et nous avons également réussi à trouver la page du menu de réinitialisation.

Enfin, bienvenue en mode débogage.



J'ai beaucoup pensé s'il fallait annoncer cette combinaison, mais j'ai décidé de m'abstenir. Je respecte le travail acharné que fait Leica, en libérant ses appareils uniques, et je ne veux pas être responsable du fait que leurs centres de service remplissent les carcasses cassées des caméras à la suite d'une curiosité irréfléchie.

Mais quand même, je fournirai quelques types énumérés afin de simplifier l'ingénierie inverse pour ceux qui sont prêts à suivre cette voie.

 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


En pensant à la tâche USB, j'ai défini trois modes (ce qui est également confirmé dans le menu de débogage):

  • Ptp
  • MSC (classe de stockage de masse)
  • Leica custom

Le PTP est le plus intéressant car il est bien documenté et vous permet de contrôler la caméra.

Il est assez facile de trouver des gestionnaires PTP dans le firmware, car il y a beaucoup d'appels à partir de ce code. Tous les appels PTP sont divisés en trois groupes: Legacy , Leica Extended (LE) et Production .

Les messages de débogage ont aidé à établir des noms pour presque tout le code.

 Héritage: Leica Étendu: Production:                           
0x1001 - GetDeviceInfo 0x9001 - Définir les paramètres de la caméra 0x9100 - Ouvrir la session de production      
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 

L'implémentation de l'interface PTP elle-même semble standard, mais certaines commandes ont des limitations que j'omet intentionnellement ici.

Dans tous les cas, tout ce qui précède est assez excitant. Vous pourriez penser: «Branchez simplement l'appareil photo via USB et commencez à sonder avec libptp.» C'est vrai.

Bon sang ...

Leica M240 n'a pas de port USB.

Port de poignée


Leica propose peu d'accessoires pour cet appareil photo, mais il y en a un particulièrement intéressant. Nous parlons de la poignée multifonctionnelle Leica M (14495) . Il remplace la partie métallique inférieure du boîtier, fournit un GPS intégré et plusieurs connecteurs comme USB, un terminal flash SCA, DIN / ISO-X et une prise de courant.



Et vous dites à nouveau: "Génial, maintenant achetez-le, fixez-le à l'appareil photo, connectez l'appareil photo via USB et commencez à sonder à l'aide de libptp." C'est vrai.

Mais bon sang ...

Ça coûte près de 900 dollars.

C'est près de neuf cents raisons de créer votre propre adaptateur. Cependant, juste au cas où, j'ai configuré des notifications eBay pour cet accessoire.

Connecteur


Le connecteur de l'appareil photo est le suivant:



j'ai essayé de le trouver sur Internet, mais sérieusement, comment le décririez-vous sur Google?

Désespéré un peu, j'ai commencé à penser à des choses folles, comme coller du papier d'aluminium ou des aiguilles sur une gomme en caoutchouc. Mais une fois au travail chez Blackmagic Design, en regardant le circuit imprimé de la caméra, j'ai remarqué que l'un des connecteurs avait une forme très familière. Le lendemain, j'ai amené mon Leica M240 au travail - et oui, il avait l'air similaire, juste beaucoup plus longtemps avec beaucoup de pads.

Reste à demander le numéro de pièce de notre gestionnaire de composants, puis à le retrouver dans le catalogue Samtec : ERM8-013-05.0-L-DV-TR .



Nous avons également demandé à Samtec s'il était possible d'obtenir un échantillon, et ils ont aimablement accepté.



Un peu de travail avec un fer à souder, du carton et du ruban électrique - et ma propre prise est prête (échantillon de 2013).



Cinq ans plus tard, en 2018, j'ai décidé de demander personnellement à Samtec d'envoyer un autre échantillon. Je voulais faire quelque chose de mieux.

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


Encore une fois, beaucoup de travail avec un fer à souder, jurer, couper le fil, jurer, travailler à nouveau avec un fer à souder pour faire une nouvelle option plus attrayante:



Brochage


Il y a 26 contacts dans le connecteur: 13 de chaque côté. Avant même de souder ma pièce, j'ai sondé le connecteur de la caméra avec un multimètre et un analyseur logique. Soit dit en passant, vous devez placer un aimant sur le capteur du couvercle inférieur afin que la caméra considère que le couvercle est en place.

Terre (appareil photo éteint, pas de batterie)

Je pars toujours du sol car c'est sûr et très facile à trouver.



Ainsi, nous avons huit lignes au sol (gris foncé).

Potentiel (caméra allumée)

Lorsque la caméra est allumée, vous pouvez mesurer le potentiel à chaque broche et avoir une idée de la logique et des niveaux de puissance.

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

Les performances sur les broches 8–9 et 11–13 sont trop élevées pour les broches logiques, je les ai donc définies comme alimentation (rouge).

Résistance (appareil photo éteint, pas de batterie)

Il est utile de mesurer la résistance. Dans certains cas, cela permet d'identifier les entrées et de regrouper certaines lignes.



Sorties connectées (appareil photo éteint, pas de batterie)

J'ai ensuite décidé de vérifier tous les pads externes sur le corps de l'appareil photo pour vérifier s'ils sont connectés au port de service.



Le contact de synchronisation du flash était directement connecté à la ligne 10.

Analyseur logique (appareil photo allumé)

Les données de chaque ligne ont été enregistrées dans l'ordre suivant: allumez, l'appareil photo doit être en mode LV, prendre une photo, démarrer l'enregistrement vidéo.



Deux lignes montrent la transmission de certaines données: 01 et 21.

01 - 115200, transmission de 8 bits, 1 bit d'arrêt, bit de parité, LSB en premier.



Toutes les 500 ms, il envoie un compteur 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, transmission de 8 bits, 1 bit d'arrêt, pas de bit de contrôle de parité, LSB en premier.



Il envoie le journal du chargeur de démarrage à SH7216 («Leica Camera AG» dans la capture d'écran ci-dessus).

Marquons-les en bleu foncé. Il est assez triste que le journal Maestro ne s'éteigne pas, même avec les paramètres de débogage maximum dans le menu Debug.



Sur ces contacts, la résistance est d'environ 310kOhm.

Je ne sais pas pourquoi, mais j'ai suggéré que d'autres lignes de données pourraient avoir une résistance similaire ou seraient fermées. Par conséquent, j'ai défini les lignes ~ 300kOhm, ~ 200kOhm et ~ 100kOhm comme des lignes de données (nuances de bleu sur l'image).

En général, l'image suivante a été dessinée.



12 candidats sur la ligne de données. Mais comment les vérifier? Après une courte conversation avec les experts du fer sur la protection électrique des circuits intégrés, j'ai commencé à piquer des contacts à travers une résistance de 4 kOhm, ce qui réduit le courant à un niveau que les entrées ne devraient pas brûler.

UART


J'ai fait une autre hypothèse que la ligne RX devrait être proche du TX. Les lignes 02, 03 et 20 ressemblent à de bons candidats car les deux ont une tension de 3,3 V comme TX.

Au départ, j'ai essayé d'explorer ces lignes en utilisant Bus Pirate. Malheureusement, le résultat était plutôt sale. Ensuite, j'ai pris les câbles basés sur SiLabs comme plus fiables et non conflictuels sur macOS.

Tout d'abord, j'ai connecté le câble TX à la broche 20 et j'ai commencé à taper helpaprès le chargeur de démarrage. Comme prévu, après un court délai, la caméra a répété les caractères.



Les contacts 02 et 03 ont été les prochains candidats à l'UART. Malheureusement, il n'y avait aucun signe que ces lignes étaient exploitées.

Dans le diagramme, les UART bien connus sont indiqués par une nuance de vert plus sombre.



USB


Tout a commencé par couper un câble USB en deux avec un en-tête au milieu et des résistances de 4 kOhm pour la détection. Intégrité du signal d'une paire différentielle? Non, alors je m'en fichais vraiment. :)



Ensuite, j'ai sondé plusieurs appareils domestiques USB à la maison pour avoir une idée de ce à quoi ressemblent les communications sur ce port. Appareil photo

Canon


Blackmagic Pocket


Camcorder Caméscope Canon


Caméscope JVC


Porte-clés


Appareil photo KidiZoom


Ils sont tous un peu différents, mais l'état D-D + initial est faible. Eh bien, nous le saurons, et maintenant nous allons vérifier que nous avons:

  • 22 - peu probable, car D-D + sont une paire différentielle et devraient être assez proches;
  • 04/05 - c'est peu probable car ils ont des résistances différentes;
  • 14/15 — , ;
  • 15/16 — , .

J'ai donc connecté l'USB D-D + aux broches 15/16 et je l'ai connecté à l'iMac ...



Sur l'écran USB PTP, mais la caméra n'apparaissait pas sur l'hôte. J'ai essayé de configurer différentes options sur la disposition du circuit électronique, mais rien n'a fonctionné. Beagle a montré beaucoup de paquets endommagés et d'autres erreurs. À la fin, j'ai abandonné et suis revenu à la rétro-ingénierie du firmware.

Il s'agit du brochage final, USB est marqué en vert foncé.



Qui aurait pensé que quelques années plus tard, la même notification eBay me parviendrait et j'achèterai à bon marché l'accessoire souhaité.

Enfin, je peux tester mes hypothèses sur PTP. Mais au début, il était très curieux de voir à quoi ressemblait l'USB PHY à l'intérieur du gadget.



À l'intérieur se trouvait le hub SMSC 2512bsur la route, de la prise de la poignée au connecteur Mini USB. La puce fonctionne en mode par défaut car il n'y a pas de broches EEPROM ou SCL / SDA. Le premier port en aval est acheminé vers une prise sur le corps de la caméra, mais le second n'est connecté à rien.

J'ai probablement raté quelque chose, mais pour moi une telle solution n'a pas beaucoup de sens. Le passeport technique indique que la puce a "des broches USB entièrement intégrées, ainsi que des résistances pour augmenter et diminuer la tension". Peut-être que les ingénieurs de Leica ont décidé de ne pas implémenter leur propre PHY USB, mais ont utilisé celui du concentrateur, qui est bien testé et fonctionne dès le départ. En fait, je ne peux pas leur en vouloir, parce qu'avant j'ai essayé de faire ça, et ça s'est avéré être une tâche difficile. C'est peut-être une fonctionnalité de protection contre les faux, qui sait.

En tout cas, si vous comprenez USB PHY et êtes prêt à aider, n'hésitez pas à m'écrire: il devrait être possible de travailler via un port USB sans cet accessoire de marque :)

PTP à nouveau


Comme je l'ai dit, il est temps de jouer avec l'extension Leica PTP.

Heureusement, j'ai trouvé une bibliothèque C ++ plutôt cool au lieu de libptp - c'est libEasyPTP . Il n'a pas non plus fallu beaucoup de temps pour écrire un outil basé sur cette bibliothèque: je connaissais déjà certaines limites de l'interface Leica PTP.

Et bien que M240PTPTool soit assez bogué, il convient tout à fait au rôle de preuve de concept ( code de programme ).

Seules deux demandes passent par PTP: GetDebugBuffer (0x900C) et DebugCommandString (0x900D) . Soit dit en passant, pour que les modules remplissent le journal de débogage, vous devez définir le niveau de débogage sur «Debug» ou «Debug RAW» dans le menu.

Il existe plusieurs options dans l'interface M240PTPTool:

  • quitter - fermer l'outil;
  • flush - fusionner le tampon de débogage de la caméra:

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
...


Tout autre texte est envoyé à la caméra en tant que commande de débogage. Par exemple, il helpaffiche toutes les commandes possibles avec des arguments: La liste complète est assez grande, mais regardez, vous pouvez envoyer des messages directs à Softune pour n'importe quelle tâche! Ce qui serait si intéressant à envoyer là-bas ... Une autre ligne populaire qui est souvent recherchée dans le firmware est . Voyons voir si nous en avons un. Apparemment, vous pouvez vider le firmware sur la carte SD. En utilisant le lien vers la ligne «Dumping files to card», il est facile de trouver le code responsable de cela. Il est situé dans le bloc de tâches système géant (pid 11, comme nous le savons déjà) et est appelé par le message sans arguments. Dial dans M240PTPTool , appuyez sur Entrée et regarder l'écran.

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



Retirez ensuite la carte SD et vérifiez ce qu'elle contient.



Le voici, un vidage complet, y compris le firmware.

Cela ouvre des possibilités infinies. Par exemple, vous pouvez faire un petit appareil avec un MCU, la prise en charge d'un hôte USB et des boutons pour lancer des séquences complexes de messages ...

Et puis nous avons eu un deuxième enfant. :)

Épilogue


Si vous ne voulez pas casser l'appareil, il existe généralement un moyen de l'examiner sans ouvrir le boîtier ni souder les fils à la carte de circuit imprimé. Voici mes conseils si vous êtes intéressé:

  • Retrouvez toutes les informations publiques sur l'appareil: spécifications techniques, données sur les composants, photos de l'intérieur, vidéo de l'usine ;)
  • si vous avez un firmware, explorez-le et recherchez des conseils sur les sorties externes;
  • , ;
  • GND// , ;
  • ;
  • , ;
  • , (, );
  • , Google (USB/UART/SPI/I2C/1Wire);
  • , ;
  • , ;
  • , .



github.com/alexhude

!

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


All Articles