akheron
工具是用 python 编写的,旨在帮助提高 UART 芯片间通信的可见性,并帮助理解、逆转和操纵这些通信以识别设备功能(有意的和无意的)。它通过支持多种操作模式来实现这一点:
通过 UART 进行芯片间通信仍然是许多设备中常见的设计选择,它看起来像这样:
+------------+ +------------+
| TXD +-------------------------->+ RXD |
| CHIP A | | CHIP B |
| RXD +<--------------------------+ TXD |
+------------+ +------------+
在此示例中,芯片 A 通过从芯片 A 的发送 (TX) 引脚发送数据来向芯片 B 发送数据,而芯片 B 在其接收 (RX) 引脚上接收传入数据。芯片 B 从其发送 (TX) 引脚发送数据,由芯片 A 在芯片 A 的接收 (RX) 引脚上接收。
但他们之间到底在相互发送什么?
如果我们让自己成为一台物理中间机器,我们就能找到答案!
akheron
工具设计为在具有两个串行端口的系统上运行(USB 转串行适配器就可以,只要系统的操作系统支持它们),充当这两个端口之间发送流量的代理。像这样的东西:
^ + ^ +
| v | v
+---------------------------------+
| |TXD1 RXD1| |TXD2 RXD2| |
| +---------+ +---------+ |
| UART 1 UART 2 |
| |
| Machine-in-the-Middle |
| (running Akheron Proxy) |
| |
+---------------------------------+
如果我们物理上切断芯片 A 和芯片 B 之间的通信轨迹,然后将它们路由到中间机的串行端口,我们将能够看到这些芯片通过akheron
的 UART 通信相互发送的内容:
+------------+ +------------+
| 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) |
| |
+---------------------------------+
通过这样的设置, akheron
就可以使用了!
akheron
版本 0.1 是这项工作的第一次迭代,诞生于概念验证代码。它是一个命令行工具,使用标准 REPL 进行交互。
akheron
工具需要 Python 3.6 或更高版本,并使用pyserial
库与系统的串行端口连接。它在 macOS 10.15 和 Ubuntu 18.04 上进行了测试。
pip install -r requirements.txt
您可以从存储库顶级目录中的终端窗口启动akheron
:
./akheron.py
在许多系统上,对串行设备的访问受到限制。为了避免以提升的权限运行akheron
,请确保您的用户帐户与您要使用的设备属于同一组。在 Linux 上,串行设备可能是dialout
组的成员。将您的用户帐户添加到该组(例如sudo usermod -a -G dialout $USER
)应该允许您访问该设备。为了让您看到更改,您可能需要注销并重新登录您的帐户,或者可能需要重新启动系统。
运行后,您将看到一个横幅和一个>
提示:
$ ./akheron.py
######################################################
Akheron Proxy, UART proxy tool for inter-chip analysis
version 0.1
######################################################
>
此提示符下提供了许多命令,您可以通过键入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
您可以通过输入help <command>
来获取有关特定命令的更多帮助。
> list
/dev/ttyS0
/dev/ttyUSB0
/dev/ttyUSB1
/dev/ttyUSB2
/dev/ttyUSB3
您还可以获得详细列表:
> 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
以下步骤将在端口之间转发流量,“监视”它,然后停止流量转发:
> 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".
>
这是相同的流程,但设置了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".
>
以下步骤将在端口之间转发流量,将其捕获到文件中,监视它,然后停止并转储捕获内容,然后停止流量转发:
> 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".
>
以下步骤显示了按以下顺序重播数据(在本示例中为包含单行的捕获文件)的端口之间转发流量:
0x64 0x61
序列与0x99 0x91
交换并重放(注意输出中的替换数据)Checksum8Modulo256Plus1
更新消息的最后一个字节并重放 > 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".
>