本文默認讀者已經完成程式流分析,如果還不熟悉,建議先參考以下文章: Ghidra 逆向實戰|STM32(ARM) MCU 韌體逆向工程 | 無符號表(Symbol-less)分析技巧
本實作範例以 STM32H7A3 系列微控制器為目標平台,使用 Ghidra 進行韌體的逆向工程分析,並結合相關插件輔助進行解析。 實作目標為將一段自訂程式碼插入原始韌體,並於執行時顯示訊息視窗,內容為 "Evil Hello World"。 本流程將示範如何在 Ghidra 中進行靜態分析、定義記憶體區段、進行函式 Hook,以及插入自訂程式碼,並以此展示韌體修改的基本方法。
注意事項:
尋找合適的插入點,以便後續加入我們自訂的行為。 這通常是從 main 函數或其他有意義的函數切入,透過 Ghidra 的反組譯功能觀察程式流程, 展示是有RTOS時分析找到 start_Task(原始程式新增Thread的位置),設定並啟動新的 Thread 的。
為了插入自訂程式碼,我們需要在程式中建立新的記憶體區塊。這可以透過 Ghidra Script 完成,範例如下:
// 建立新的記憶體區段用於插入Shellcode
// 在 Ghidra 中,可以使用 Memory Map 功能
// 1. 選擇 Window -> Memory Map
// 2. 點擊 "Add Memory Block" 按鈕
// 3. 設定在空白區設定新起始地址
// 4. 設定大小為合適大小
// 5. 設定權限為 "rwx" (可讀、可寫、可執行)
// 6. 點擊 "OK" 完成建立
範例代碼將在 0x0805c78 建立一個大小為 0x100 的記憶體區塊,標記為可讀、可寫、可執行。
接著,我們可以 HOOK 某個原有函數,並建立一個新 thread 來執行我們的自訂邏輯:
// 將程式流程由原始位置跳轉至我們的Shellcode位置
// 在原始程式碼中插入跳轉指令
B 0x0805c78 // 無條件跳轉到我們的新記憶體區塊
// 在新記憶體區塊中,我們可以建立一個新的執行緒
// 假設 osThreadNew 函數位於 0x08001234
BL 0x08001234 // 呼叫 osThreadNew 函數建立新執行緒
插入跳躍指令,將控制流導向新記憶體區塊;建立一個執行該區塊的Thread。
這段自訂程式碼可簡單顯示出訊息以驗證我們的插入是否成功:
// 呼叫 printf函數以顯示訊息視窗
// 假設 printf 函數位於 0x08002468
LDR R0, =message // 載入訊息字串的地址到 R0 暫存器
BL 0x08002468 // 呼叫 printf 函數
// 訊息字串定義
message:
.ascii "Evil Hello World\0" // 以 null 結尾的字串
這會在執行時跳出一個訊息框,內容為 "Evil Hello World"。
成功將自訂程式碼插入並執行,證明我們能夠在分析程式中導入新邏輯。 此過程除了驗證反組譯與插入的可行性外,也展示了如何在 ARM 架構的微控制器上進行程式碼注入。 這種技術可應用於多種場景,包括韌體分析、安全測試、功能擴展等領域。