我正在我的屋子裡尋找下一個逆向的潛在目標,很高興地發現了我的XBox One控制器手柄:
我並沒有真正玩過XBox,所以我認為拆掉該控制器手柄並查看可以從中提取什麼樣的信息可能很有趣。
0x01 分析目標
在評估嵌入式平臺時,你可以做或嘗試完成許多事情,在這篇文章中,我想測試以下內容:
1. 可以從目標中提取固件嗎?
2. 目標是否可以通過調試或檢測的方式使我們能夠了解其內部操作的更多信息?
3. 是否可以通過軟體開發或硬體修改來修改或更改固件?
回答其中一些問題的第一步將是硬體拆解。
0x02 硬體拆解
打開外殼可以看到以下PCB:
請注意,由於主晶片上塗有環氧樹脂,因此這裡實際上看不到太多東西。對我們來說幸運的是,許多測試板都被標記了,但是被標記的板似乎是各種按鈕按下的測試點,因此沒有什麼令人興奮的地方。
電路板底部有一個標記為AK4961的IC,但這是音頻編解碼器晶片。數據表可以在這裡找到。該晶片是有麥克風,耳機和揚聲器放大器的低功耗24位立體聲編解碼器。
https://www.digikey.com/product-detail/en/akm-semiconductor-inc/AK4951EN/974-1064-1-ND/5180415
但是,如果我們仔細看,可以看到上面帶有一些絲網印刷標籤:
於是我們看到3V3,A13,A14,RES標記在絲網印刷。如果你已經閱讀了我以前的有關路由器拆除和發現UART的文章,那麼你可能已經對如何進行此操作有了一些想法。我們首先用萬用表測量每個引腳的電壓:
RES,A14或A13上沒有波動或調製,因此肯定是其他原因,但那又是什麼呢?假設其中一個標籤是RES(可能表示系統重置),那麼很有可能存在JTAG或SWD標頭。
我們可以通過RES使用10k電阻將其拉低來測試該引腳是否真的將目標復位。如果你不熟悉這些類型的接頭連接器或系統復位引腳的典型工作方式,它們通常為低電平有效,這意味著它們以高電平空閒並且必須拉低才能激活。因此,如果我們監控輸出dmesg -w並使用10k電阻將該線切換為低電平,我們會看到什麼?
[ 2108.588884] usb 1-6.4: new full-speed USB device number 10 using xhci_hcd
[ 2108.691108] usb 1-6.4: New USB device found, idVendor=0e6f, idProduct=02a2, bcdDevice= 1.0f
[ 2108.691113] usb 1-6.4: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[ 2108.691116] usb 1-6.4: Product: PDP Wired Controller for Xbox One - Crimson Red
[ 2108.691119] usb 1-6.4: Manufacturer: Performance Designed Products
[ 2108.691122] usb 1-6.4: SerialNumber: 0000AE38D7650465
[ 2108.698675] input: Generic X-Box pad as /devices/pci0000:00/0000:00:14.0/usb1/1-6/1-6.4/1-6.4:1.0/input/input25
[ 2131.403862] usb 1-6.4: USB disconnect, device number 10
[ 2133.420350] usb 1-6.4: new full-speed USB device number 11 using xhci_hcd
[ 2133.522469] usb 1-6.4: New USB device found, idVendor=0e6f, idProduct=02a2, bcdDevice= 1.0f
[ 2133.522474] usb 1-6.4: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[ 2133.522478] usb 1-6.4: Product: PDP Wired Controller for Xbox One - Crimson Red
[ 2133.522480] usb 1-6.4: Manufacturer: Performance Designed Products
[ 2133.522483] usb 1-6.4: SerialNumber: 0000AE38D7650465
[ 2133.530103] input: Generic X-Box pad as /devices/pci0000:00/0000:00:14.0/usb1/1-6/1-6.4/1-6.4:1.0/input/input26
這樣做會使控制器復位,降低了1針,還剩下2針。
當查看這樣的調試頭時,通常的假設是它用於JTAG或某種其他形式的硬體級調試。然而,JTAG規格要求有至少4個引腳,TDO,TDI,TMS和TCK。我們的目標上只有兩個,因此很有可能這是一個單線調試(SWD)埠。
0x03 SWD協議
SWD是用於ARM Cortex目標的通用調試接口。顧名思義,SWD僅需要一條數據線和一條時鐘線,但是我們如何確定哪一條呢?在分析之前,我們應該多了解一些SWD的工作原理以及可以使用哪些工具與之交互。
首先,SWD與稱為「調試訪問埠」(DAP)的接口連接。DAP代理訪問各種「訪問埠」(AP),這些埠提供的功能包括典型的硬體調試,舊式JTAG內核以及其他高性能內存總線。從本文檔中提取的下圖是DAP和AP的結構的直觀表示。
https://stm32duinoforum.com/forum/files/pdf/Serial_Wire_Debug.pdf
這些AP均由64個32位寄存器組成,其中一個寄存器用於標識AP的類型。AP的功能和特性決定了如何訪問和利用這些寄存器。你可以在此處找到有關某些標準AP的有關這些交易的所有信息。ARM接口規範默認情況下定義了兩個AP,它們分別是JTAG-AP和MEM-AP,MEM-AP還包括用於與其連接的組件的發現機制。
https://static.docs.arm.com/ihi0031/c/IHI0031C_debug_interface_as.pdf
如前所述,SWD是JTAG的替代品。使用SWD時,引腳數從4個減少到2個,並且提供了許多與JTAG相同的功能。但是,SWD的一個缺點是無法將設備連結在一起,這正是JTAG所允許的。SWD中使用的兩個引腳如下:
SWD利用基於數據包的協議來讀取和寫入DAP / AP中的寄存器,它們包括以下階段:
1. 主機到目標數據包請求;
2. bus轉換;
3. 為目標主機確認響應;
4. 數據傳輸階段。
數據包的結構可以在下圖中看到,我也細分了表中的各個欄位。
從極高的層次來看,SWD埠使用這些數據包與DAP交互,從而允許訪問MEM-AP,後者提供對調試以及內存讀取/寫入功能的訪問。出於本文的目的,我們將使用一個名為OpenOCD的工具來執行這些事務。接下來,我們將回顧如何編譯和使用OpenOCD。
0x04 OpenOCD
安裝依賴項:
sudo apt-get install build-essential libusb-1.0-0-dev automake libtool gdb-multiarch
安裝存儲庫,配置和編譯!
wrongbaud@115201:~/blog$ git clone https://git.code.sf.net/p/openocd/code openocd-code
cd openocd-code
./bootstrap
./configure
make -j$(nproc)
使用OpenOCD編譯後,我們可以嘗試通過SWD調試此控制器。為了做到這一點,我們需要至少做兩件事:
·使用什麼調試器
·我們調試的目標是什麼
為了進行調試,我們將使用上一篇文章中使用的FT2232H 轉儲SPI快閃記憶體。通過此接口,我們可以使用OpenOCD通過SWD查詢有關目標的信息,這很重要,因為在逆向過程的此階段,我們甚至都不知道目標CPU是什麼!
https://wrongbaud.github.io/Holiday-Teardown/
下表是確定FT2232H上的哪些引腳需要連接到SWD目標的表格:
最後,為了將FT2232H用作SWD適配器,必須在FT2232H上的AD1/ AD2之間放置一個470 OHM電阻。
一旦我們將FT2232H上的引腳連接到目標,就可以使用以下腳本查詢DAP控制器上的DPIDR寄存器:
# We are using an FT2232H so specify this here
interface ftdi
# Provide the VID/PID of the FT2232H
ftdi_vid_pid 0x0403 0x6010
# There are two channels, this is the default
ftdi_channel 0
# To the best of my knowledge, this is used to properly set and confiture the state of the lines we are using
ftdi_layout_init 0x0018 0x05fb
# Enable SWD for the lines that we are using, and the port
ftdi_layout_signal SWD_EN -data 0
# This is used to specify the sRST pin, in our case we're using
ftdi_layout_signal nSRST -data 0x0010
# Here we are selecting SWD as opposed to another transport layer such as JTAG
transport select swd
# Set the speed of the adapter, this will vary based on what your hardware supports
adapter_khz 100
# Create a new dap, (TAP for JTAG terms) with name chip and role CPU, -enable let's OpenOCD to know to add it to the scan
swd newdap chip cpu -enable
# Create the DAP instance, this must be explicitly created according to the OpenOCD docs
dap create chip.dap -chain-position chip.cpu
我們可以使用openocd如圖所示運行此腳本,並顯示以下輸出(請注意,第一次運行該腳本時,沒有輸出,在交換SWD/ SCLK行之後,將輸出以下輸出)。參見下表,了解從FT2232到控制器的連接
我們已經找到了一個晶片ID0x2ba01477,如果我們通過谷歌搜索該ID,就會看到各種Cortex M / STM32組件的點擊率很高,這很有意義,因為該處理器系列支持SWD。現在我們可以與DAP進行通信,我們應該看看是否可以確定正在使用的處理器,如果該處理器已為其編寫了配置文件,則我們將能夠轉儲快閃記憶體組並從中獲取其他輔助信息。有了這些額外的信息,我們可以告訴OpenOCD使用具有Cortex M定義的晶片來創建目標,這將使我們能夠在弄清楚DAP的更多優點並獲得一些更通用的功能確切地定位的是哪個CPU:
# Set up the GDB target for the CPU, cortex_m is the CPU type, target create chip.cpu cortex_m -dap chip.dap
# init reads out all of the necessary information from the DAP, kicks off the debugging session, etc init
# Read out the information from the DAP, including the ROM table dap info
當使用此配置文件運行openocd時,將看到以下結果:
wrongbaud@wubuntu:~/blog/stm32-xbox$ sudo openocd -f openocd.cfg
Open On-Chip Debugger 0.10.0+dev-01040-ge7e681ac (2020-01-27-18:55)
Licensed under GNU GPL v2
For bug reports, read
http://openocd.org/doc/doxygen/bugs.html
Info : FTDI SWD mode enabled
Info : clock speed 100 kHz
Info : SWD DPIDR 0x2ba01477
Info : chip.cpu: hardware has 6 breakpoints, 4 watchpoints
Info : chip.cpu: external reset detected
Info : Listening on port 3333 for gdb connections
AP ID register 0x24770011
Type is MEM-AP AHB3
MEM-AP BASE 0xe00ff003
Valid ROM table present
Component base address 0xe00ff000
Peripheral ID 0x00000a0411
Designer is 0x0a0, STMicroelectronics
Part is 0x411, Unrecognized
Component class is 0x1, ROM table
MEMTYPE system memory present on bus
ROMTABLE[0x0] = 0xfff0f003
Component base address 0xe000e000
Peripheral ID 0x04000bb00c
Designer is 0x4bb, ARM Ltd.
Part is 0xc, Cortex-M4 SCS (System Control Space)
Component class is 0xe, Generic IP component
ROMTABLE[0x4] = 0xfff02003
Component base address 0xe0001000
Peripheral ID 0x04003bb002
Designer is 0x4bb, ARM Ltd.
Part is 0x2, Cortex-M3 DWT (Data Watchpoint and Trace)
Component class is 0xe, Generic IP component
ROMTABLE[0x8] = 0xfff03003
Component base address 0xe0002000
Peripheral ID 0x04002bb003
Designer is 0x4bb, ARM Ltd.
Part is 0x3, Cortex-M3 FPB (Flash Patch and Breakpoint)
Component class is 0xe, Generic IP component
ROMTABLE[0xc] = 0xfff01003
Component base address 0xe0000000
Peripheral ID 0x04003bb001
Designer is 0x4bb, ARM Ltd.
Part is 0x1, Cortex-M3 ITM (Instrumentation Trace Module)
Component class is 0xe, Generic IP component
ROMTABLE[0x10] = 0xfff41003
Component base address 0xe0040000
Peripheral ID 0x04000bb9a1
Designer is 0x4bb, ARM Ltd.
Part is 0x9a1, Cortex-M4 TPIU (Trace Port Interface Unit)
Component class is 0x9, CoreSight component
Type is 0x11, Trace Sink, Port
ROMTABLE[0x14] = 0xfff42003
Component base address 0xe0041000
Peripheral ID 0x04000bb925
Designer is 0x4bb, ARM Ltd.
Part is 0x925, Cortex-M4 ETM (Embedded Trace)
Component class is 0x9, CoreSight component
Type is 0x13, Trace Source, Processor
ROMTABLE[0x18] = 0x0
End of ROM table
Info : Listening on port 6666 for tcl connections
Info : Listening on port 4444 for telnet connections
有了這些新的更改,我們不僅可以與DAP和MEM-AP進行交互,還可以通過GDB調試目標。由於MEM-AP條目中的0x411部件號,我們還可以確定目標CPU是STM32F2X系列:
MEM-AP BASE 0xe00ff003
Valid ROM table present
Component base address 0xe00ff000
Peripheral ID 0x00000a0411
Designer is 0x0a0, STMicroelectronics
Part is 0x411, Unrecognized
Component class is 0x1, ROM table
如果我們無法訪問DAP並想通過內存讀寫確定我們的目標是什麼呢?為了弄清楚這一點,在STM32 CPU中有一些常見的存儲區域用於存儲ID和快閃記憶體信息。利用此信息,我們可以修改OpenOCD腳本以讀取這些區域並查找相關的ID信息!
https://github.com/antongus/stm32tpl/blob/master/stm32.h
下表具有ID信息的必要偏移量:
mdw 0x1FFFF7AC 3
mdw 0x1FFFF7E8 3
mdw 0x1FFF7A10 3
mdw 0x1FF0F420 3
mdw 0x1FF80050 3
mdw 0x1FF800D0 3
當我們運行更新的OpenOCd腳本和以上命令時,我們看到以下結果:
> mdw 0x1FFFF7AC 3
0x1ffff7ac: ffffffff ffffffff ffffffff
> mdw 0x1FFFF7E8 3
0x1ffff7e8: ffffffff ffffffff ffffffff
> mdw 0x1FFF7A10 3
0x1fff7a10: 006c0028 31385114 30373639
> mdw 0x1FF0F420 3
SWD DPIDR 0x2ba01477
Failed to read memory at 0x1ff0f424
> mdw 0x1FF80050 3
SWD DPIDR 0x2ba01477
Failed to read memory at 0x1ff80054
> mdw 0x1FF800D0 3
SWD DPIDR 0x2ba01477
Failed to read memory at 0x1ff800d4
>
我們可以使用以下命令,使用該晶片數據手冊中的快閃記憶體地址或上面連結的存儲庫,獲得快閃記憶體大小:
> mdh 0x1FFF7A22
0x1fff7a22: 0100
https://github.com/antongus/stm32tpl/blob/master/stm32.h
現在我們知道確切的目標,可以刪除swd和dap的目標,在命令行-f /usr/local/share/openocd/scripts/target/stm32f2x.cfg,將正確枚舉目標CPU,現在我們也知道了該STM32F2系列晶片具有0x100 1kb頁的快閃記憶體。
wrongbaud@wubuntu:~/blog/stm32-xbox$ sudo openocd -f openocd.cfg -f /usr/local/share/openocd/scripts/target/stm32f2x.cfg
[sudo] password for wrongbaud:
Open On-Chip Debugger 0.10.0+dev-01040-ge7e681ac (2020-01-27-18:55)
Licensed under GNU GPL v2
For bug reports, read
http://openocd.org/doc/doxygen/bugs.html
Info : FTDI SWD mode enabled
adapter speed: 100 kHz
Info : Listening on port 6666 for tcl connections
Info : Listening on port 4444 for telnet connections
Info : clock speed 1000 kHz
Info : SWD DPIDR 0x2ba01477
Info : stm32f2x.cpu: hardware has 6 breakpoints, 4 watchpoints
Info : Listening on port 3333 for gdb connections
現在可以正常工作了,我們可以使用以下命令轉儲內部快閃記憶體:
> flash list
{name stm32f2x base 0 size 0 bus_width 0 chip_width 0} {name stm32f2x base 536836096 size 0 bus_width 0 chip_width 0}
> flash read_bank 0 bank0.bin
device id = 0x00016423
flash size = 256 kbytes
wrote 262144 bytes to file bank0.bin from flash bank 0 at offset 0x00000000 in 3.690861s (69.361 KiB/s)
> flash read_bank 1 bank1.bin
flash size = 512 bytes
wrote 512 bytes to file bank1.bin from flash bank 1 at offset 0x00000000 in 0.007852s (63.678 KiB/s)
我們還可以使用以下命令使用gdb調試控制器:
wrongbaud@wubuntu:~/blog/stm32-xbox$ gdb-multiarch
GNU gdb (Ubuntu 8.1-0ubuntu3.2) 8.1.0.20180409-git
Copyright (C) 2018 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
.
Find the GDB manual and other documentation resources online at:
.
For help, type "help".
Type "apropos word" to search for commands related to "word".
(gdb) set architecture arm
The target architecture is assumed to be arm
(gdb) target remote localhost:3333
Remote debugging using localhost:3333
warning: No executable has been specified and target does not support
determining executable automatically. Try using the "file" command.
0x0800307e in ?? ()
(gdb) x/10x 0x1FFF7A10
0x1fff7a10: 0x006c0028 0x31385114 0x30373639 0xc000fcc0
0x1fff7a20: 0x0100c000 0x67ff47d2 0x05dcf000 0x04a803b3
0x1fff7a30: 0x451744b1 0xffffffff
(gdb)
因此,在這一點上,我們將快閃記憶體轉儲了,可以調試並單步執行固件,但是……可以重新刷新MCU嗎?
如果我們可以在固件映像中找到USB描述符字符串並進行修補,則可以將其用作確定是否可以修補固件的可見方法。讓我們在GHIDRA中加載固件,看看是否可以找到它們,固件映像可以加載到address 0x8000000。我們知道固件是0x8000000基於數據表加載的,但是如果我們沒有數據表,則可以通過發出reset halt命令並單步執行第一條指令從OpenOCD確定。幸運的是,此固件映像很小,Ghidra可以快速對其進行處理。在下面的截圖中可以看到在dmesg輸出中看到的字符串:
讓我們用字符串做一個簡單的patch,將其更改為「 Testing Firmware Patches」。可以在OpenOCD telnet控制臺中使用以下命令覆蓋快閃記憶體:
wrongbaud@wubuntu:~/blog/stm32-xbox$ telnet localhost 4444
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
Open On-Chip Debugger
> flash read 0 bank0-orig.bin
> flash read_bank 1 bank1-orig.bin
flash size = 512 bytes
wrote 512 bytes to file bank1-orig.bin from flash bank 1 at offset 0x00000000 in 0.007867s (63.557 KiB/s)
> stm32f2x unlock 0
Target not halted
stm32f2x failed to unlock device
> halt
target halted due to debug-request, current mode: Handler External Interrupt(67)
xPSR: 0x61000053 pc: 0x0800839c msp: 0x2000ff48
> stm32f2x unlock 0
stm32f2x unlocked.
INFO: a reset or power cycle is required for the new settings to take effect.
> reset halt
target halted due to debug-request, current mode: Thread
xPSR: 0x01000000 pc: 0x080002a4 msp: 0x20010000
> stm32f2x mass_erase 0
stm32x mass erase complete
> flash write_bank 0 bank0-patch.bin
wrote 262144 bytes from file bank0-patch.bin to flash bank 0 at offset 0x00000000 in 3.744948s (68.359 KiB/s)
> reset
>
這裡有一些步驟可能沒有意義,所以我想解釋一下:
1. 在嘗試重新刷新之前,請始終始終備份所有快閃記憶體映像。
2. STM32快閃記憶體控制器具有一個鎖定位,可以防止不必要的寫入。這在STM32的「選項字節」中設置
·對我們來說幸運的是,我們能夠解鎖鎖定位,有時候這不是一個很好的選擇!
·對於STM32上的內部快閃記憶體,我們需要先執行擦除操作,然後再對其進行寫入
·我要在這裡補充一點,如果你的目標昂貴或很重要,這絕不是你要做的事情,除非你百分百確定可以將其恢復為原始狀態
·我們編寫修補後的固件映像,然後重新啟動CPU,並提示以下 dmesg內容
[54691.886194] usb 1-6.4: new full-speed USB device number 14 using xhci_hcd
[54691.992411] usb 1-6.4: New USB device found, idVendor=0e6f, idProduct=02a2, bcdDevice= 1.0f
[54691.992417] usb 1-6.4: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[54691.992420] usb 1-6.4: Product: Testing Firmware Patches
[54691.992423] usb 1-6.4: Manufacturer: Performance Designed Products
[54691.992426] usb 1-6.4: SerialNumber: 0000AE38D7650465
[54691.998102] input: Generic X-Box pad as /devices/pci0000:00/0000:00:14.0/usb1/1-6/1-6.4/1-6.4:1.0/input/input28
現在我們已經完全提取了固件並將其加載到ghidra中,並且能夠按我們認為合適的方式對其進行修改,現在是時候編寫一些宏文件了。
0x05 分析總結
在分析嵌入式系統時,你通常希望枚舉和探索與目標交互的所有可能的接口和方法。無論你的最終目標是尋找漏洞,修改設備的正常操作還是只是了解其工作原理,硬體調試都是極其重要的有用。通過利用硬體調試,我們能夠從該目標中提取固件,設置實時調試器並修改固件。通過本練習,我們還介紹了單線調試的工作方式,以及如何使用硬體調試工具識別,枚舉和調試未知的CPU。OpenOCD還與基於FT2232H的界面一起使用,以提取固件映像並將新固件重新刷寫到目標上。
參考及來源:https://wrongbaud.github.io/stm-xbox-jtag/