L'outil akheron
est écrit en python et conçu pour aider à donner de la visibilité aux communications inter-puces UART et aider à comprendre, inverser et manipuler ces communications pour discerner les fonctionnalités de l'appareil (à la fois intentionnelles et non intentionnelles). Pour ce faire, il prend en charge plusieurs modes de fonctionnement :
La communication entre puces via UART reste un choix de conception courant dans de nombreux appareils, et elle ressemble à ceci :
+------------+ +------------+
| TXD +-------------------------->+ RXD |
| CHIP A | | CHIP B |
| RXD +<--------------------------+ TXD |
+------------+ +------------+
Dans cet exemple, la puce A envoie des données à la puce B en envoyant des données via la broche de transmission (TX) de la puce A et la puce B reçoit les données entrantes sur sa broche de réception (RX). La puce B envoie des données sur sa broche de transmission (TX) pour être reçues par la puce A sur la broche de réception (RX) de la puce A.
Mais qu’est-ce qu’ils s’échangent exactement ?
Si nous nous transformons en une machine physique au milieu, nous pouvons le découvrir !
L'outil akheron
est conçu pour être exécuté sur un système doté de deux ports série (les adaptateurs USB-série conviennent, à condition que le système d'exploitation du système les prenne en charge), agissant comme un proxy pour envoyer du trafic entre ces deux ports. Quelque chose comme ça :
^ + ^ +
| v | v
+---------------------------------+
| |TXD1 RXD1| |TXD2 RXD2| |
| +---------+ +---------+ |
| UART 1 UART 2 |
| |
| Machine-in-the-Middle |
| (running Akheron Proxy) |
| |
+---------------------------------+
Si nous coupons physiquement les traces de communication entre la puce A et la puce B, puis les acheminons vers les ports série de notre machine du milieu, nous pourrons voir ce que ces puces s'envoient via leurs communications UART avec akheron
:
+------------+ +------------+
| TXD +--------+ +------->+ RXD |
| CHIP A | | | | CHIP B |
| RXD +<-+ | | +--+ TXD |
+------------+ | | | | +------------+
| | | |
| v | v
+---------------------------------+
| |TXD1 RXD1| |TXD2 RXD2| |
| +---------+ +---------+ |
| UART 1 UART 2 |
| |
| Machine-in-the-Middle |
| (running Akheron Proxy) |
| |
+---------------------------------+
Avec une telle configuration, akheron
est prêt à l’emploi !
La version 0.1 akheron
est la première itération de cet effort et est née d'un code de preuve de concept. Il s'agit d'un outil en ligne de commande, utilisant un REPL standard pour l'interaction.
L'outil akheron
nécessite Python 3.6 ou version ultérieure et utilise la bibliothèque pyserial
pour l'interface avec les ports série du système. Il a été testé sur macOS 10.15 et Ubuntu 18.04.
pip install -r requirements.txt
Vous pouvez démarrer akheron
à partir d'une fenêtre de terminal dans le répertoire de niveau supérieur du dépôt :
./akheron.py
Sur de nombreux systèmes, l'accès aux périphériques série est restreint. Pour éviter d'exécuter akheron
avec des privilèges élevés, assurez-vous que votre compte utilisateur appartient au même groupe que l'appareil que vous souhaitez utiliser. Sous Linux, le périphérique série est probablement membre du groupe dialout
. L'ajout de votre compte utilisateur à ce groupe (par exemple sudo usermod -a -G dialout $USER
) devrait vous permettre d'accéder à l'appareil. Pour que vous puissiez voir les modifications, vous devrez peut-être vous déconnecter et vous reconnecter à votre compte, ou éventuellement redémarrer le système.
Une fois exécuté, vous verrez une bannière et une invite >
:
$ ./akheron.py
######################################################
Akheron Proxy, UART proxy tool for inter-chip analysis
version 0.1
######################################################
>
Un certain nombre de commandes sont disponibles à cette invite, auxquelles vous pouvez accéder en tapant help
:
> help
Documented commands (type help <topic>):
========================================
capturedump checksumget delimset portget replaceset stop
capturestart checksumset help portset replay watch
capturestop delimget list replaceget start
Undocumented commands:
======================
exit quit version
Vous pouvez obtenir plus d'aide sur une commande spécifique en tapant help <command>
.
> list
/dev/ttyS0
/dev/ttyUSB0
/dev/ttyUSB1
/dev/ttyUSB2
/dev/ttyUSB3
Vous pouvez également obtenir une liste détaillée :
> list -v
/dev/ttyS0
desc: ttyS0
hwid: PNP0501
/dev/ttyUSB0
desc: Quad RS232-HS
hwid: USB VID:PID=0403:6011 LOCATION=1-1:1.0
/dev/ttyUSB1
desc: Quad RS232-HS
hwid: USB VID:PID=0403:6011 LOCATION=1-1:1.1
/dev/ttyUSB2
desc: Quad RS232-HS
hwid: USB VID:PID=0403:6011 LOCATION=1-1:1.2
/dev/ttyUSB3
desc: Quad RS232-HS
hwid: USB VID:PID=0403:6011 LOCATION=1-1:1.3
Les étapes suivantes permettront de transférer le trafic entre les ports, de le « surveiller », puis d'arrêter le transfert de trafic :
> portset A /dev/ttyUSB1 115200
> portset B /dev/ttyUSB2 115200
> start
Data now PASSING between ports "/dev/ttyUSB1" <-> "/dev/ttyUSB2"...
> watch
Watching data passed between ports. Press CTRL-C to stop...
A -> B: 0x61 0x61 0x73 0x73 0x64 0x64
B -> A: 0x31 0x32 0x33 ^C
Watch mode exited.
> stop
Data now BLOCKED between ports "/dev/ttyUSB1" <-> "/dev/ttyUSB2".
>
Il s'agit du même flux, mais avec un délimiteur de début de message défini sur 0x37
:
> portset A /dev/ttyUSB1 115200
> portset B /dev/ttyUSB2 115200
> delimset start 0x37
> start
Data now PASSING between ports "/dev/ttyUSB1" <-> "/dev/ttyUSB2"...
> watch
Watching data passed between ports. Press CTRL-C to stop...
A -> B: 0x37 0x71 0x77 0x65 0x65 0x72
0x37 0x64 0x66 0x61 0x64
0x37 0x73
0x37 0x68 0x68
B -> A: 0x37 0x6e 0x6d 0x62
0x37 0x69 0x69
A -> B: 0x37 0x61 0x73 0x64 ^C
Watch mode exited.
> stop
Data now BLOCKED between ports "/dev/ttyUSB1" <-> "/dev/ttyUSB2".
>
Les étapes suivantes transféreront le trafic entre les ports, le captureront dans un fichier, le surveilleront, puis arrêteront et videront le contenu de la capture, puis arrêteront le transfert du trafic :
> portset A /dev/ttyUSB1 115200
> portset B /dev/ttyUSB2 115200
> start
Data now PASSING between ports "/dev/ttyUSB1" <-> "/dev/ttyUSB2"...
> capturestart mycap.out
Saving captured traffic to "mycap.out"...
> watch
Watching data passed between ports. Press CTRL-C to stop...
A -> B: 0x31 0x32 0x33
B -> A: 0x33 0x32 0x31
A -> B: 0x20 0x20 0x20
B -> A: 0x36 0x36 0x37 0x38 0x39 ^C
Watch mode exited.
> capturestop
Capture stopped
> capturedump mycap.out
1: A -> B: 0x31 0x32 0x33
2: B -> A: 0x33 0x32 0x31
3: A -> B: 0x20 0x20 0x20
4: B -> A: 0x36 0x36 0x37 0x38 0x39
> stop
Data now BLOCKED between ports "/dev/ttyUSB1" <-> "/dev/ttyUSB2".
>
Les étapes suivantes montrent le transfert du trafic entre les ports avec relecture des données (dans cet exemple, un fichier de capture contenant une seule ligne) dans cette séquence :
0x64 0x61
avec 0x99 0x91
et rejouer (notez les données substituées dans la sortie)Checksum8Modulo256Plus1
des octets précédents et relire > portset A /dev/ttyUSB1 115200
> portset B /dev/ttyUSB2 115200
> start
Data now PASSING between ports "/dev/ttyUSB1" <-> "/dev/ttyUSB2"...
> replay /tmp/aaa
Replaying data from A -> B, press CTRL-C to exit watch mode...
A -> B: 0x61 0x73 0x64 0x61 0x73 0x64 ^C
Watch mode exited.
> replaceset A 0x64 0x61 -> 0x99 0x91
> replaceget
Replace port A pattern X -> pattern Y:
0x64 0x61 -> 0x99 0x91
Replace port B pattern X -> pattern Y:
> replay /tmp/aaa
Replaying data from A -> B, press CTRL-C to exit watch mode...
A -> B: 0x61 0x73 0x99 0x91 0x73 0x64 ^C
Watch mode exited.
> checksumset A 3
> checksumget
Replace on port A using checksum 'Checksum8Modulo256Plus1'
No replace checksum specified on port B
> replay /tmp/aaa
Replaying data from A -> B, press CTRL-C to exit watch mode...
A -> B: 0x61 0x73 0x99 0x91 0x73 0x72 ^C
Watch mode exited.
> stop
Data now BLOCKED between ports "/dev/ttyUSB1" <-> "/dev/ttyUSB2".
>