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