A ferramenta akheron
é escrita em python e projetada para ajudar a dar visibilidade às comunicações entre chips UART e auxiliar na compreensão, reversão e manipulação dessas comunicações para discernir a funcionalidade do dispositivo (intencional e não intencional). Isso é feito através do suporte a vários modos de operação:
A comunicação entre chips via UART ainda é uma escolha de design comum encontrada em muitos dispositivos e é mais ou menos assim:
+------------+ +------------+
| TXD +-------------------------->+ RXD |
| CHIP A | | CHIP B |
| RXD +<--------------------------+ TXD |
+------------+ +------------+
Neste exemplo, o chip A envia dados para o chip B enviando dados pelo pino de transmissão (TX) do chip A e o chip B recebe os dados recebidos em seu pino de recepção (RX). O chip B envia dados pelo seu pino de transmissão (TX) para serem recebidos pelo chip A no pino de recepção (RX) do chip A.
Mas o que exatamente eles estão enviando entre si?
Se nos tornarmos uma máquina física intermediária, poderemos descobrir!
A ferramenta akheron
foi projetada para ser executada em um sistema com duas portas seriais (adaptadores USB para serial são adequados, desde que o sistema operacional do sistema os suporte), atuando como um proxy para enviar tráfego entre essas duas portas. Algo assim:
^ + ^ +
| v | v
+---------------------------------+
| |TXD1 RXD1| |TXD2 RXD2| |
| +---------+ +---------+ |
| UART 1 UART 2 |
| |
| Machine-in-the-Middle |
| (running Akheron Proxy) |
| |
+---------------------------------+
Se cortarmos fisicamente os traços de comunicação entre o chip A e o chip B e depois os encaminharmos para as portas seriais da nossa máquina intermediária, poderemos ver o que esses chips estão enviando entre si por meio de suas comunicações UART com 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) |
| |
+---------------------------------+
Com essa configuração, akheron
está pronto para uso!
akheron
versão 0.1 é a primeira iteração desse esforço e nasce de um código de prova de conceito. É uma ferramenta de linha de comando, usando um REPL padrão para interação.
A ferramenta akheron
requer Python 3.6 ou posterior e usa a biblioteca pyserial
para fazer interface com as portas seriais do sistema. Ele foi testado no macOS 10.15 e no Ubuntu 18.04.
pip install -r requirements.txt
Você pode iniciar akheron
a partir de uma janela de terminal no diretório de nível superior do repositório:
./akheron.py
Em muitos sistemas, o acesso a dispositivos seriais é restrito. Para evitar executar akheron
com privilégios elevados, certifique-se de que sua conta de usuário pertence ao mesmo grupo do dispositivo que você deseja usar. No Linux, o dispositivo serial provavelmente é membro do grupo dialout
. Adicionar sua conta de usuário a esse grupo (por exemplo, sudo usermod -a -G dialout $USER
) deve permitir que você acesse o dispositivo. Para ver as alterações, pode ser necessário sair e fazer login novamente em sua conta ou possivelmente reiniciar o sistema.
Após a execução, você verá um banner e um prompt >
:
$ ./akheron.py
######################################################
Akheron Proxy, UART proxy tool for inter-chip analysis
version 0.1
######################################################
>
Vários comandos estão disponíveis neste prompt, que você pode acessar digitando 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
Você pode obter mais ajuda sobre um comando específico digitando help <command>
.
> list
/dev/ttyS0
/dev/ttyUSB0
/dev/ttyUSB1
/dev/ttyUSB2
/dev/ttyUSB3
Você também pode obter uma listagem detalhada:
> 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
As etapas a seguir encaminharão o tráfego entre portas, 'observarão' e interromperão o encaminhamento de tráfego:
> 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".
>
Este é o mesmo fluxo, mas com um delimitador de início de mensagem de 0x37
definido:
> 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".
>
As etapas a seguir encaminharão o tráfego entre portas, capturarão-no em um arquivo, observarão e, em seguida, interromperão e despejarão o conteúdo da captura e, em seguida, interromperão o encaminhamento de tráfego:
> 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".
>
As etapas a seguir mostram o encaminhamento do tráfego entre portas com reprodução de dados (neste exemplo, um arquivo de captura que contém uma única linha) nesta sequência:
0x64 0x61
por 0x99 0x91
e reproduzir (observe os dados substituídos na saída)Checksum8Modulo256Plus1
dos bytes anteriores e reproduza > 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".
>