
使用Raspi配置 raspi-config是一個用戶空間工具,它允許我們配置樹莓派的各個方面,其中之一是啟用各種外部接口。我們將使用raspi-config來啟用UART接口,首先啟動工具,如下所示: sudo raspi-config 這將導致出現以下結果: 接下來,我們將選擇Interface Options,然後是Serial Port,如下圖所示: 選擇這個選項後,我們會遇到兩個問題: 1.你希望通過串行方式訪問登錄shell嗎? 2.你想啟用串行端口硬件嗎? 我們現在已經在樹莓派上啟用了UART,接下來,我們需要將它連接到我們的機櫃。我們將機櫃的Tx連接到Pi的Rx,將機櫃的 Rx 連接到 Pi 的 Tx: 使用樹莓派上的UART接口,我們可以嘗試連接到目標設備上的這個Serial Port。為了與這個Serial Port交互,我們將使用屏幕實用程序。當與UART接口時,屏幕要求我們傳遞一個設備和波特率,由於我們知道上一段的波特率,我們將按如下方式運行: sudo screen -L -Logfile cabinet-bootup.log /dev/ttyS0 115200 -L -Logfile cabinet-bootup.log——將會話記錄到cabinet-bootup.log文件; /dev/ttyS0——要使用的串行設備; 115200——波特率; 我們現在可以在配置我們的 UART 和啟動屏幕後打開機櫃。當我們打開機櫃電源時,我們看到以下內容: 最終,我們發現自己在一個控制台: 我們現在有一個根控制台,可以探索文件系統,查看目標上正在運行的內容,並了解有關它是如何構建的更多信息。如果可能,我們的下一步將是對分區進行映像;讓我們先看看掛載了哪些分區: 我們的根文件系統是以只讀的形式掛載的,並且使用的是squashfs格式。此外,還掛載了標記為userdata的另一個分區。如果我們檢查可用的block設備,我們會看到以下內容: 我們可以看到,SPI flash設備大概位於/dev/rkflash0。要獲得這個block設備的圖像,我們可以將USB插到機櫃的USB端口並使用dd實用程序。當我們插入一個USB閃存驅動器時,它在 /dev/sda 中被枚舉,我們可以用以下命令將SPI閃存的內容映射到USB驅動器: Sudo dd if=/dev/rkflash0 of=/dev/sda status=progress 如果我們將 USB 驅動器插入 Pi 並檢查分區表,我們會看到相應的分區已映射到驅動器。 現在我們有了閃存的備份,這是我們嘗試修改嵌入式系統時應該採取的第一步;在我們嘗試修改任何內容或重新刷新任何分區之前,我們應該確保我們有辦法恢復它們;為此,我們將調查引導加載程序。作為起點,讓我們注意啟動日誌開頭的以下行: 如果我們在為機櫃供電時在屏幕提示中按住 Ctrl-c,我們會看到以下內容: 我們現在有一個 UBoot 提示符,在深入探討之前,讓我們先談談 UBoot 及其工作原理。 UBoot是嵌入式系統中常用的開源引導加載程序。它支持各種架構和CPU類型。但是,UBoot 的職責通常是為嵌入式系統加載操作系統內核或主應用程序。 UBoot 還包括在你的逆向工程工作中有用的調試實用程序;最值得注意的是 UBoot 命令提示符。 UBoot 控制台可以包含大量的內置實用程序,這些實用程序可以在標準引導過程中(通常通過環境變量)或在 UBoot 命令行中使用。可用的命令將根據UBoot映像的構建方式而有所不同。 現在我們已經發現了一個 UBoot 控制台,讓我們首先通過運行 help 命令查看哪些命令是公開可用的。 在查看每個命令之前,讓我們重新審視一下我們的主要目標,即能夠從引導加載程序讀取和寫入根文件系統分區,以防我們以後需要恢復這個機櫃。下面的命令非常醒目,因為它們涉及內存讀取和寫入: 接下來,我們可以使用 printenv 命令查看此引導加載程序配置的環境變量。這將為我們提供更多關於該平台如何啟動、正在使用的內存地址以及其他可用接口的背景信息。 在為設備構建或配置UBoot映像時,可以配置各種環境變量。這些環境變量控制啟動時執行的操作。存儲這些變量的方法有很多種。有時它們被硬編碼到二進制中,它們也可以駐留在閃存分區上,允許用戶從UBoot提示符修改它們。 我們可以使用 printenv 命令檢查環境變量: 我想在下表中指出一些有趣的變量: 此時,如果我們交叉引用我們在硬件檢查期間收集的信息,我們會看到一致的結果。在我們的硬件檢查之後,我們假設SPI flash是主要的存儲方法,這個假設在UBoot環境變量和可用的命令中得到驗證。 讓我們從檢查rksfc命令開始,通過搜索,這是RockChip的SPI SFC(串行flash控制器)接口工具。該命令包含以下子命令: 可以通過以下命令獲取SPI flash的信息: 使用這些命令,我們可以了解更多關於SPI flash的信息。我們可以看到塊大小為512,該芯片總共包含220672 (0x35E00)塊,被分成5個分區: uboot ——可能包含我們的 UBoot 映像/第一階段引導加載程序; trust ——可信執行環境映像; boot ——內核映像/ ramdisk; rootfs ——我們最大的分區,內核的根文件系統; user data——用戶特定數據,可能用於高分、用戶設置等; 注意,該數據與我們之前在根控制台提示符中看到的內容相匹配。我們現在了解了閃存是如何分區的以及可能有哪些數據可用,但是我們如何在不向板上焊接額外線路的情況下讀取/寫入這些數據呢?如果我們檢查 usb 命令,我們會看到以下內容: 使用機櫃側面的 USB 端口,如果我們插入設備並運行 USB start 後跟 USB info,則會生成以下輸出: 這樣,我們就可以看到USB堆棧成功枚舉並檢測到我們的大容量存儲設備。 在繼續之前,讓我們回顧一下我們對 UBoot 環境的了解: 通過檢查環境變量,我們可以在RAM中找到可用的地址; 使用rksfc讀取實用程序,我們可以讀取SPI閃存扇區到RAM; 使用USB命令,我們可以枚舉一個USB設備並寫入它; 我們可以將SPI flash讀入RAM,連接USB設備,然後使用USB寫入命令將SPI flash數據寫入USB設備。如果這種方法有效,我們還應該能夠通過反向步驟恢復閃存圖像,從USB驅動器讀取數據,並使用rksfc write寫入閃存。讓我們從測試讀取開始。 首先,我們將嘗試使用以下命令將整個 SPI 閃存讀入 RAM 以獲取目標地址,我們將嘗試存儲在 $ramdisk_addr_r 中的地址,即 0x6a200000: 這不起作用,我們以某種方式觸發了未定義的指令異常。我們可能破壞了 UBoot 正在使用的一些東西,讓我們看看當我們嘗試另一個內存較低的地址時會發生什麼: 移動到 RAM 中的較低地址允許讀取完成而不會破壞任何內容,讓我們看看我們現在是否可以將這些數據寫回 USB 驅動器: 現在我們來看看這個驅動器的內容,把它插入樹莓派,看看我們有什麼: 此時,我們可以看到USB驅動器上的分區表與rksfc part 0命令的輸出相匹配。接下來,我們將使用dd實用程序提取用於分析的各個分區。 到目前為止,該數據與我們在查看正在運行的系統上的掛載輸出和 UBoot 菜單中的分區表時看到的數據相匹配。因此,我們可以通過 unsquashfs 提取 squashfs 分區並嘗試掛載 ext2 分區以確認它們是有效的: 看起來我們有一個有效的根文件系統,現在我們可以開始逆向工程軟件了,並了解更多關於我們如何修改這個系統來玩更多遊戲或運行自定義固件的信息。 現在我們已經確認可以讀取flash,讓我們測試一下,看看我們是否可以使用上面描述的方法將這張圖片寫回flash: 現在我們重新啟動,希望我們重新刷新的圖像仍然有效。 成功!我們現在可以使用我們的 USB 驅動器從 UBoot 讀取/寫入 SPI 閃存;這對於測試補丁和固件修改很有用! 現在我們可以用 UBoot 讀/寫這個機櫃的 flash,如果我們可以自動擦除 flash 的各個分區和段,而不需要每次手動輸入範圍,那就太好了。為此,我們將使用 Depthcharge 實用程序來自動化我們的 UBoot 交互! 在使用UBoot環境時,我們經常需要自動化交互。例如,在我們的示例中,我們可能希望自動重寫特定的閃存分區,而不必每次都手動輸入地址偏移量。對我們來說幸運的是,NCC集團的人已經組裝了一個工具來幫助我們,這個工具叫做深度充電。我們可以使用這個自動化的過程,從我們的閃存芯片和外部USB驅動器讀取數據。我們的腳本將需要執行以下操作: 連接到UART並識別UBoot提示符; 通過rksfc讀寫命令對SPI flash進行讀寫操作; 通過USB讀寫命令對USB驅動器進行讀寫; 首先,我們需要安裝模塊,可以通過執行命令sudo pip install depthcharge.o在Pi上安裝depthcharge。 連接到UART並識別UBoot提示符 我們可以使用以下python代碼連接到UBoot提示符: 在上面的函數中,我們創建了一個Console對象,它要求我們提供一個到Serial Port和波特率的路徑。然後這個控制台對象被用來製作Depthcharge上下文,我們將使用它來訪問Depthcharge所提供的功能。depthcharge文檔中有一個很好的例子,詳細描述了安裝過程。 現在我們已經連接到接口,我們需要實現rksfc讀寫命令。我們可以使用depthcharge的send_command() API來做到這一點。這個API調用允許我們生成UBoot命令並將其發送到命令提示符並返迴響應。在下面的例子中,我們在cmd_str變量中構造了read命令,並確保參數被正確格式化,然後使用send_command() API發出命令。 現在我們已經實現了對閃存的讀寫,接下來我們需要枚舉USB堆棧,然後從閃存驅動器中讀寫。 與我們實現 rksfc 命令的方式類似,接下來我們將實現 usb 命令。該過程將類似於用於 rksfc 命令的過程: 現在我們已經定義了適當的函數,我們可以嘗試以下操作: 如果我們運行這個腳本,就會看到如下輸出: 當我們將u盤插入Pi時,就會會看到以下分區: 成功!我們已經使用 Depthcharge 將 SPI 閃存提取到 USB 設備! 現在我們有了一種可靠的讀取和寫入flash的方法,讓我們簡要地檢查一下內容。有趣的文件位於/moo文件夾中。此文件夾包含仿真器及其相關資源。Moo是一個使用自定義ROM格式的自定義模擬器,2020年,一些研究人員在模擬器的另一個版本上進行了測試。然而,如果我們查看目錄內容,會發現一些有趣的現象: 在這個系統上肯定不可能有 PE32 Windows 可執行文件,如果我們將此文件複製到 Windows 機器上並嘗試執行它: 它運行了!顯然,這是一個構建工件,開發者沒有意識到它存在於系統中。 使用本文介紹的方法,我們現在可以使用 UBoot 將 SPI 閃存讀寫到 USB 驅動器。我們已經提取了根文件系統並確定了核心模擬組件。我們的下一個目標將是對該目標上的一些二進制文件進行逆向工程,以確定運行自定義固件的困難程度。 我們在本文中介紹了如何使用我們的萬用表/邏輯分析儀執行嵌入式設備的初始拆卸和識別潛在的調試頭。然後進一步詳細介紹了如何分析未知的 UART 流量並使用帶有 Raspberry Pi 的屏幕連接到Serial Port。連接到Serial Port後,我們發現可以通過按Ctrl-C來訪問UBoot控制台。在查看了 UBoot 控制台之後,我們編寫了一個 depthcharge 腳本來將每個 SPI 閃存分區提取到一個外部閃存驅動器中。所有使用的腳本和工具都可以在github上找到。 參考及來源:https://voidstarsec.com/blog//2022/01/27/uart-uboot-and-usbUART工具
UBOOT
UBoot命令
UBoot環境變量
使用 DEPTHCHARGE 編寫 UBOOT
Flash 通過 depthcharge 讀寫
USB 通過 depthcharge 讀寫
使用Depthcharge 轉儲閃存
文件系統內容
總結