前言
對固件的一些逆向思路,通過幾個具體的案例。
單片機
相對於嵌入式設備的逆向,單片機的逆向純屬於體力活,需要根據芯片定義的每個 IO 口,配合電路和外部模塊進行分析、調試。逐步確定每一個分支的功能,邏輯等,是非常繁瑣和復雜的工作。 這里使用 MSP430 系列芯片作為逆向分析的案例,其他的單片機也類似。
基礎知識
MSP430 開發基礎
Know it then hack it ,在對一個單片機芯片做逆向分析以及漏洞挖掘時,需要熟悉單片機開發和底層的工作原理,以 MSP430G2553 為例,簡單介紹下有關單片機開發的基礎知識。
芯片特性
德州儀器 (TI) MSP430G2x13 和 MSP430G2x53 系列是超低功耗混合信號微控制器,具有內置的 16 位定時器、多達 24 個支持觸摸感測的 I/O 引腳、一個通用型模擬比較器以及采用通用串行通信接口的內置通信能力。 此外,MSP430G2x53 系列成員還具有一個 10 位模數 (A/D) 轉換器。 典型應用包括低成本傳感器系統,此類系統負責捕獲模擬信號、將之轉換為數字值、隨后對數據進行處理以進行顯示或傳送至主機系統。
程序基礎
MSP430 單片機的程序設計可以使用匯編語言,也可以使用 c 語言 ,無論匯編還是 c 語言,都需要掌握 MSP430 微處理器的結構、原理、接口等才可以進行軟件與硬件的設計。 MSP430 系列采用的是“馮-諾依曼”結構,ROM、RAM 在同一地址空間,使用一組地址數據總線。中央處理單元采用了精簡的、高透明的、高效率的正交設計,它包括一個 16 位 ALU(算術邏輯運算單元),16 個寄存器,一個指令控制單元,16 個寄存器中有 4 個為特殊用途,扮演重要角色,分別是:程序計數器、堆棧指針、狀態寄存器、常數發生器。程序流程通過程序計數器控制,而程序執行的現場狀態體現在程序狀態字中。
開發環境
德州儀器 (TI) 官方提供免費版本的開發軟件 CCS,采用 eclipse+plugs+compiler 的組合開發平台, CCS 平台自由度較高,可以更了解芯片的細節部分,比如啟動過程 cstart ,中斷的跳轉方式,如何把中斷向量表放置到 RAM 中,如何把函數拷貝到 RAM 中執行等等,IAR Embedded Workbench 是另一款收費的專業的 IDE 工具,集成度比較高,使用很方便,提供給用戶的很多的友好的功能,對程序下載調試支持更友好,目前 IAR 已經更新至 7.X 版本,但建議使用 5.3 或 5.6 版本,功能更為穩定,這里使用 IAR 作為開發調試的環境。
工作原理
目前市場上使用的單片機種類繁雜,包括 C51、AVR、MSP430、STM32、PIC 等等,其硬件架構雖不盡相同,但基本原理一致,最小單元都是 CMOS 管,通過邏輯運算,操作 IO 口輸出不同數字電平信號,實現對外部模塊的控制和通信。
內部大多會有 CPU、RAM、ROM、時鍾晶振、總線接口、串行接口、寄存器、 ADC 等功能模塊。
單片機程序執行原理基本一致,單片機自動完成賦予它的任務的過程,也就是單片機執行程序的過程,即一條條執行指令的過程,所謂指令就是把要求單片機執行的各種操作用的命令的形式寫下來,這一系列指令的集合就成為程序,程序需要預先存放在具有存儲功能的部件——存儲器中,燒寫程序的過程就是把程序代碼轉為為二進制,然后根據二進制數值不同,轉為高低電平信號,改變存儲器中晶體管的狀態,程序就被固化在了存儲器中。存儲器由許多存儲單元(基本結構為浮柵晶體管)組成,指令就存放在這些單元里,單元里的指令取出並執行就像大樓房的每個房間的被分配到了唯一一個房間號一樣,每一個存儲單元也必須被分配到唯一的地址號,該地址號稱為存儲單元的地址,這樣只要知道了存儲單元的地址,就可以找到這個存儲單元,其中存儲的指令就可以被取出,然后再被執行。
單片機程序通常是順序執行的,所以程序中的指令也是一條條順序存放的,單片機在執行程序時要能把這些指令一條條取出並加以執行,必須有一個部件能追蹤指令所在的地址,這一部件就是程序計數器 PC(包含在 CPU 中),在開始執行程序時,給 PC 賦以程序中第一條指令所在的地址,然后取得每一條要執行的命令,PC 在中的內容就會自動增加,增加量由本條指令長度決定,可能是 1 、2 或 3 ,以指向下一條指令的起始地址,保證指令順序執行。
通過 IAR 的仿真調試,可知CPU初始會進行復位操作,然后把復位向量數據作為 PC 寄存器的值 ,在執行 IAR 編譯器定義的程序入口點 __program_start 函數,其又被編譯器定義為 cstart_begin 函數,后面緊跟着的是 cstart_call_main 函數,此函數才會去調用 main 函數 ,因此在一般的逆向過程中, 只需要從 main 入口函數開始分析。
編程大多基於 c 或匯編語言,對於不同的單片機,首先需要通過芯片型號查找官方數據手冊,里面官方會有詳細的介紹,包括功能模塊、引腳定義、寄存器、ROM、RAM、時序圖等信息,參考官方說明,對單片機開發入門具有幫助。
實例分析
下面是一個簡單控制 LED 閃爍的程序 :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
#include <msp430g2553.h>
//IO口初始化
void
Port_Init()
{
P1DIR|= 0x40;
// P1^6配置為輸出
P1OUT|= 0x40;
// P1輸出0100 0000
}
//看門狗初始化
void
WDT_Init()
{
WDTCTL = WDTPW + WDTHOLD;
//關閉看門狗
}
int
main(
void
)
{
WDT_Init();
Port_Init();
while
(1)
{
__delay_cycles(500000);
// 系統延時 500 000 機器周期
P1OUT ^= 0x40;
// 循環異或實現LED閃爍
}
}
|
硬件連線圖如下 :
程序首先定義 P1 口寄存器,初始化為輸出狀態,寄存器為8位數據,然后在 while 循環改變 IO 輸出狀態,通過高低電片的循環延時變化,使 LED 閃爍,詳細說明如下:
- WDTCTL = WDTPW + WDTHOLD; //MSP430 的看門狗默認是打開的,如果在程序開始不關閉,程序執行到一定時間就會自動復位,那樣程序就無法正常執行
- P1DIR |= 0x40; //PxDIR,Px 口方向寄存器,為 0 端口配置為輸入(默認),為 1 端口配置為輸入,P1.6 口配置為輸出
- P1OUT |= 0x40; // 配置IO口寄存器,PxOUT,Px 口輸出寄存器(輸入、輸出兩種模式),當 IO 口配置為輸出模式時:0 輸出低電平、1 輸出高電平,當 IO 口配置為輸入模式並且置高/置低使能時:0置低、1置高,P1輸出 0100 0000,此時 P1.6 口為高電平,點亮 LED 燈。
-
__delay_cycles(500000); // IAR編譯器內聯的精准延時函數,此芯片默認設置時鍾主頻為1M,即每個機器周期為 1us,500000即為執行500000個機器周期的時間,延時500毫秒,實際開發中,可以根據如下代碼,設置主頻然后換算成毫秒來計時
#define CPU_F ((double)1000000) 設置主頻晶振1MHZ #define delay_ms(x) __delay_cycles((long)(CPU_F*(double)x/1000.0))
P1OUT ^=0x40; //P1 異或輸出 0000 0000 ,熄滅 LED 燈,再次循環,異或輸出 0100 0000 點亮 LED,循環實現閃爍功能。
MSP430 逆向基礎
使用上面 LED 閃爍程序來做案例,通過調試查看源代碼和二進制還有匯編指令一一對應的關系。
走邊為源代碼,右邊紅色圈為hex文件的地址,藍色圈為二進制字節碼,綠色圈為對應的匯編代碼,通過一一對比可以正向看出 MSP430 編碼怎么編譯成固件,需要注意幾個點:
- 關閉看門狗,芯片工作時必須的操作,這是一個宏定義值,因此可以用於定位入口函數。
- __delay_cycles的參數為需要執行的機器周期個數,IAR根據該參數編譯為需要執行對應機器周期數量的匯編指令 。
初步分析
現在假設我們不知道源碼,只有 hex 文件和電路圖,參考芯片的手冊《MSP430G2553 用戶指南》和《MSP430 匯編指令集》 。我們使用 ida 來一一逆向分析固件 , 載入ida,處理器選擇 MSP430 。
可以看到有四個函數,這里有些函數地址會和之前調試的不一樣,根據看門狗 mov.w #5A80h, &120h 指令可以確定 sub_C038 為關閉看門狗函數, 按 n 重命名此函數 ,按 x 查看交叉引用可以回溯到 main 函數里面,可以確定 sub_C00C 為程序的入口。
整個固件程序結構
自動化分析
對比之前和 IAR 調試界面,發現 ida 里面一些寄存器地址例如 P1OUT ,WDTCTL 不能自動顯示出來,而是具體的偏移 21h , 120h ,為了方便分析,可以寫一個的idaPython 腳本來自動化注釋,讀取 msp430g2553.h 宏定義替換。
...... #define P1IN_ (0x0020u) /* Port 1 Input */ READ_ONLY DEFC( P1IN , P1IN_) #define P1OUT_ (0x0021u) /* Port 1 Output */ DEFC( P1OUT , P1OUT_) #define P1DIR_ (0x0022u) /* Port 1 Direction */ DEFC( P1DIR , P1DIR_) ...... #define WDTCTL_ (0x0120u) /* Watchdog Timer Control */ DEFW( WDTCTL , WDTCTL_) ......
Python腳本,也可以從附件文件夾 /scripts/2.3.2/msp430_auto_comment.py 獲取。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
from
idaapi
import
*
file
=
open
(
"msp430g2553.h"
,
'r'
)
lines
=
file
.readlines()
funcs
=
Functions()
for
f
in
funcs:
for
i
in
FuncItems(f):
try
:
if
idc.GetOpnd(i,
0
)[
0
]
=
=
'&'
:
for
line
in
lines:
if
line.find(idc.GetOpnd(i,
0
)[
1
:].replace(
'h'
,'',
1
)) !
=
-
1
:
line.expandtabs()
words
=
line.split(
' '
)
MakeComm(i,words[
1
][:
-
1
])
break
if
idc.GetOpnd(i,
1
)[
0
]
=
=
'&'
:
for
line
in
lines:
if
line.find(idc.GetOpnd(i,
1
)[
1
:].replace(
'h'
,'',
1
)) !
=
-
1
:
line.expandtabs()
words
=
line.split(
' '
)
MakeComm(i,words[
1
][:
-
1
])
break
except
:
continue
|
在某固件中執行腳本,可以自動把地址對應的寄存器自動注釋出來,大大方便之后的逆向。
逆向結果
回到 main 函數,繼續根據流程逐步分析 ,調用 sub_C02A ,這個函數有兩個指令。
1
2
|
bis.b #40h, &22h ; P1DIR 配置P1.6口配置為輸出口
bis.b #40h, &21h ; P1OUT P1 ,配合電路圖分析即為高電平,LED 燈亮 。
|
猜測此函數功能為一些 io 口的初始化,添加備注和修改函數名稱。繼續后面為一個循環結構。
根據 ida 結構顯示為兩個循環嵌套,外面一個死循環,嵌套一個 loc_C01C 條件循環,根據指令操作和上下關聯推斷其為延時功能:
mov.w #E846 , R15 // 0xE846 移入R15寄存器,耗時2個機器周期 nop // 空指令占位,耗時1個機器周期 mov.w #0x1 , R14 // 0x1 移入R14寄存器,設置為R15寄存器的最高位,耗時1個機器周期 add.w #0xFFFF , R15 // 0xFFFF 移入R15寄存器,因數值超過16位,需要進位,同時SR寄存器N狀態位置1,C狀態位置為1,耗時1個機器周期 addc.w #0xFFFF , R14 // 0xFFFF 加上 C 狀態位的值,移入R14寄存器,因數值超過16位,需要進位,C狀態位置保持為1,耗時1個機器周期 jc 0xC0IC //根據進位位的值也就是C狀態位的值判斷是否跳轉至 0xC0IC ,當循環完所有周期,C狀態位復位為0,結束循環,耗時2個機器周期。
loc_C01C 執行需要4個機器周期,初始置位賦值需要8個機器周期,即可推算出整個循環需要 0x1e846*4 + 8 = 500000 個機器周期,配合上之前定義的時鍾主頻 1M hz,推算出總延時長為 0.5 s ,然后執行下面的語句。
1
|
xor.b #40h, &21h ; P1OUT寄存器的值與0x40異或, P1.6口輸出寄存器第7位的值, 循環異或,輸出高低電平,實現閃爍功能。
|
根據上述分析,結合電路和硬件,本程序通過對IO口寄存器值的循環異或,輸出高低電平,再通過每次延時500毫秒,實現控制 LED 閃爍功能。
完整逆向結果:
某智能鎖
再來看一個實際的例子,對一個基於 MSP430 芯片的電子鎖逆向分析,該款電子密碼鎖板載 MSP430F149 單片機,基本功能是當輸入正確密碼時,單片機會輸出一個信號,使電機轉動 實現開鎖動作。
提取固件
通過之后的 2.5.2 章節 SBW 協議提取 hex 格式的固件。
電路分析
查看電路結構,發現在 P2.0 到 P2.3 口布線連接至 TC1508S 型號的芯片上,查芯片手冊得知 TC1508S 是雙通道內置功率 MOS 全橋驅動芯片。該芯片主要實現驅動直流電機進行正反轉、前進后退等功能。
ULN2003 輸出管腳連至一個雙極性的直流電機上,用於控制電機正反轉等動作,由此可知在代碼中會初始化P2.0-P2.3 IO口,並在密碼正確的情況下,輸出控制信號,參考 TC1508S 的邏輯真值表:
逆向分析
載入 ida ,運行 msp430_auto_comment.py 自動加上注釋 ,確定 main 函數,從 main 開始分析整個固件流程。 根據之前的電路分析,可以初步得出P2.0-P2.3 IO 口來控制電機芯片的,也就是要開關鎖的關鍵 。 初步逆向分析結果:
由於篇幅有限,對智能鎖的詳細逆向分析及其攻防可以看后續的章節 。
嵌入式
嵌入式設備的逆向和傳統二進制一樣差不多,注意架構就行,這里使用路由器的 web 服務器漏洞逆向來做案例。
某路由器漏洞分析
某路由器存在溢出漏洞,測試 poc 如下,來靜態逆向分析漏洞。
從poc中可以得知,路由器上的 web 服務器在處理 /goform/set_manpwd 請求時出現了問題,導致在未進行用戶校驗的情況下,通過 routepwd 字段可以更改管理員密碼,且能崩潰 web 服務器。
提取路由器中的固件,使用 binwalk 解壓固件,在 /bin 目錄下可以得到路由器的 web服務器的二進制文件 goahead。使用 file 命令查看 goahead 的信息如下:
可以看到目標平台是 mips32 位,LSB 字段表明是小端序,指令集為 mips32 rel2。 使用 ida 對 goahead 進行靜態分析,在 strings 窗口中直接搜索 set_manpwd ,得到兩處字符串。
分別查看交叉引用得到 0x46c558 處的字符串在 sub_457ebc 中被引用兩次,
0x46b6b4 處的字符串在 formDefineCGIjson 中被引用了一次。
查看 formDefineCGIjson 中的引用位置發現 websFormDefine 的第二個參數被置為 sub_457ebc 的指針。
推斷 sub_457ebc 為主要處理 set_manpwd 的函數,進入sub_457ebc 函數發現主要有以下函數調用: 獲取 routepwd 的值,該字段正是可以更改密碼和命令執行的字段.
將傳入的參數格式化成 json 對象並傳入 bs_setmanpwd 函數,同時傳入的還有當前棧幀的字符串地址,對 bs_setmanpwd 函數分析之后發現是一個來自 libshare.so 的庫函數,且對我們的漏洞並無重大影響.
對 http 請求進行回復並刪除 json 對象。
獲取 password 並使用 password 格式化字符串 “chpasswd.sh admin %s”,可以看出此條命令應該和修改管理員密碼有關,繼續向下發現 bl_do_system 函數的參數為剛才格式化好的字符串,推測此處應該是修改密碼並進行命令執行的地方。
轉載:https://www.cnblogs.com/xiaoyehack/p/9453727.html