Android安全/安全技術--19--ARM組合語言
==========================================================================
==========================================================================
2-1、處理器執行模式
使用者模式(usr):
ARM處理器正常的程式執行狀態。
快速中斷模式(fiq):
用於高速資料傳輸或通道處理。
外部中斷模式(irq):
用於通用的中斷處理。
管理模式(svc):
作業系統使用的保護模式。
資料訪問中止模式(abt):
當資料或指令預取終止時進入該模式,可用於虛擬儲存及儲存保護。
未定義指令中止模式(und):
系統模式(sys):
執行具有特權的作業系統任務。
ARM 處理器模式的執行模式可以通過軟體改變。此外,當特定的異常出現時,進入相應的異常模式。除使用者模式外,其他6種模式統稱"特權模式"。在這些模式下程式可以自由地方問系統資源和改變處理器模式。
異常模式:
在特權模式中,除系統模式之外的其餘 5 種稱為異常模式。除了可以通過程式切換進入外,也可以由特定的異常進入,當特定的異常出現時,處理器進入相應的模式,每種異常模式都有一些獨立的暫存器,以避免異常退出時使用者模式的狀態不可靠。
使用者和系統模式:
這兩種模式都不能由異常進入,而且他們使用完全相同的暫存器組。系統模式是特權模式,不受使用者模式的限制。作業系統在該模式下訪問使用者模式的暫存器就比較方便。
處理器的各種工作模式由當前程式狀態暫存器 CPSR 的低 5 位 M[4:0]決定。
處理器模式 | 說明 | 備註 | M[4:0] |
---|---|---|---|
使用者 (usr) | 正常程式執行 | 不能直接切換到其他模式 | 10000 |
快速中斷 (fiq) | 高速資料傳輸或通道處理 | fiq異常響應時進入此模式 | 10001 |
外部中斷 (irq) | 通用的中斷處理 | irq異常響應時進入此模式 | 10010 |
管理 (svc) | 作業系統保護模式 | 系統復位和軟體中斷響應時進入此模式 | 10011 |
中止 (abt) | 支援虛擬記憶體或儲存器保護 | 在ARM7TDMI沒有大用處 | 10111 |
未定義 (und) | 支援硬體協處理器的軟體模擬 | 未定義指令異常響應時進入此模式 | 11011 |
系統 (sys) | 執行作業系統的特權任務 | 與使用者模式類似,但具有可以直接切換到其他模式的特效 | 11111 |
字(Word):
在 ARM 體系結構中,字的長度為 32 位。
半字(Half-Word):
在 ARM 體系結構中,半字的長度為 16 位。
位元組(Byte):
在 ARM 體系結構中,位元組的長度為 8 位。
2-2、使用者模式下的暫存器分佈
注:不同的應用場景下(或不同的文獻中,暫存器表述不完全相同)
通用暫存器
暫存器 | 別稱 | 作用 |
---|---|---|
R0 | - | 引數/結果/暫時暫存器1 |
R1 | - | 引數/結果/暫時暫存器2 |
R2 | - | 引數/結果/暫時暫存器3 |
R3 | - | 引數/結果/暫時暫存器4 |
R4 | - | 區域性變數暫存器1 |
R5 | - | 區域性變數暫存器2 |
R6 | - | 區域性變數暫存器3 |
R7 | - | 區域性變數暫存器4 |
R8 | - | ARM狀態區域性變數暫存器5 |
R9 | SB | ARM狀態區域性變數暫存器6。RWPI變體中的靜態基址 |
R10 | SL | ARM狀態區域性變數暫存器7。棧檢查變體中的棧限制指標 |
R11 | - | ARM狀態區域性變數暫存器8 |
專用暫存器
暫存器 | 別稱 | 作用 |
---|---|---|
R12 | IP | 內部過程呼叫暫時暫存器 |
R13 | SP | 棧頂指標。指向堆疊的頂部 |
R14 | LR | 連結暫存器,用於儲存函式返回地址 |
R15 | PC | 用於儲存下一條指令的地址 |
狀態暫存器
暫存器 | 別稱 | 作用 |
---|---|---|
CPSR | - | 當前程式狀態暫存器,任何模式可訪問 |
SPSR | - | 程式狀態儲存暫存器,異常模式可訪問。各異常模式有自己的SPSR。發生異常時, SPSR儲存CPSR的值 |
條件標誌碼:該值的內容可被算術或邏輯運算的結果所改變,並且可以決定某條指令是否被執行
標記 | 含義 |
---|---|
N(Negative) | 指令執行結果為負時置1。為正數或零時置零 |
Z(Zero) | 指令執行結果為0時置1。不為零時置零 |
C(Carry) | 加法有進位則置1否則置0,減法有借位則置0否則置1 |
V(oVerflow) | 指令執行結果超出32位補碼儲存範圍時置1 |
Q | 指示增強的DSP運算指令是否發生了溢位。溢位為1否則置0 |
E(Endian-bit) | 置0時使用小端序,置1時使用大端序 |
T(Thumb-bit) | 置1時使用Thumb模式,置0時使用ARM模式 |
M(Mode-bit) | 共5位表示處理器執行模式 |
J(Jazelle) | 對於有的處理器,置位表示允許以硬體執行java位元組碼 |
F(fast) | 置1表示禁止FIQ中斷,置0表示允許FIQ中斷 |
2-3、ARM和Thumb
ARM(32位指令):
處理器執行32位的字對齊的ARM指令。
Thumb(16位指令):
處理器執行16位的字對齊的Thumb指令。用於ARMv6和更早的版本。
Thumb-2(16位和32位指令):
對Thumb的擴充套件,添加了更多指令並允許它們為16位或32位寬(ARMv6T2,ARMv7)。
ThumbEE:
在Thumb-2基礎上包含了針對動態程式碼生成(程式碼在執行前或執行期間編譯程式碼)的一些變更和補充。
32位ARM和Thumb指令:
32位Thumb指令具有.w字尾。
可以在ARM和Thumb兩種狀態之間切換。
2-4、ARM指令
<opcode> {condition} {S} {Rd}, Operand1, Operand2
-----------------------------------------------------------------------
<opcode> //操作碼,如ADD表示算術加操作指令
{condition} //條件與,決定指令執行的條件
{S} //決定指令執行是否影響CPRS暫存器的值
{Rd} //目的暫存器,儲存指令計算結果
Operand1 //第一個運算元,可以是一個暫存器或一個立即數
Operand2 //第二個(可變)運算元
一個簡單的ARM組合語言結構。Android軟體安全與逆向分析P166
標號 指令或偽指令 ;註釋
------------------------------------------------------------------------
.arch armv4t ;處理器架構為ARMv4
.file "hello.c" ;程式原始檔名稱
.section.rodata ;以"."開頭的是偽指令,與編譯器相關,與平臺無關
.align 2 ;2^2,即4位元組對齊
.LC0: ;程式標號0
.ascii "hello world!\000" ;定義hello world字串
.global main ;宣告main
.type main, %function ;宣告main為一個函式
main:
@args = 0, pretend = 1 ;@標誌註釋,由編譯器新增
stmfd sp!, {fp, lr} ;main函式中的具體邏輯
add fp, sp, #4
.L4: ;程式標號4
.word .LC0
.size main, .-main
.ident "GCC: (ctng-1.6.1) 4.4.3" ;編譯器標識
2-5、ARM指令的定址方式
1、立即定址:運算元本身包含在指令中
MOV R0, #1314 //後面是立即數(常數)以#號作為字首
2、暫存器定址:暫存器中的數值作為運算元
MOV R0, R1 //都為暫存器
3、暫存器間接定址:暫存器中的值作為地址,再通過這個地址去取得運算元
LDR R0, [R1] //後面是地址指標,在中括號中
4、基址變址定址:將暫存器中的值與指令中給出的地址偏移量相加,從而得到一個新的地址,再通過這個地址去取得運算元
LDR R0, [R1, #-4] //後面是地址指標,中括號中為立即定址
5、多暫存器定址:可以一次完成多個暫存器值的傳送
LDMIA R0, {R1,R2,R3 } //R1 <- [R0]; R2 <- [R0+4]; R3 <- [R0+8];
6、相對定址:在暫存器定址得到運算元後再進行移位操作,得到最終的運算元
MOV R0,R2,LSL #3 //R2左移3位,結果賦給R0
7、堆疊定址:先進後出方式,使用堆疊指標指示當前操作位置,堆疊指標總是指向棧頂
STMFD SP!, {R1-R7, LR} //將R1-R7,LR壓入堆疊。滿遞減堆疊
2-6、識別ARM彙編中的C/C++邏輯
1、識別if-else判斷邏輯
CMP R0, R1 ;比較R0與R1兩個暫存器的值,類似:if (R0>=R1)
BGE loc_C66 ;如果不等於,條件不成立邏輯,則跳轉到loc_C66指令塊
ADDS R0,#1 ;條件成立邏輯
B loc_C68 ;跳出判斷操作,繼續執行loc_C68指令塊
2、識別while-do迴圈邏輯
loc_C76 ;loc_C76程式碼塊
ADDS R0, #1 ;自增長邏輯,即R0++
loc_C78 ;loc_C78程式碼塊
CMP R0, #9 ;比較R0與9,即if (R0<10)
BLE loc_C76 ;如果條件成立,跳轉到loc_C76指令塊處
2-7、C語言和ARM語言的相互呼叫
1、彙編程式訪問 C 語言全域性變數
全域性變數只能通過地址間接呼叫,為了訪問C語言中全域性變數,首先要通過extern偽指令引入全域性變數,然後將其地址裝入暫存器中。
對於 unsigned char 型別,使用 LDRB/STRB 訪問; 對於 unsigned short 型別,使用 LDRH/STRH 訪問; 對於 unsigned int 型別,使用 LDR/STR 訪問; 對於 char 型別,使用 LDRSB/STRSB 訪問; 對於 short 型別,使用 LDRSH/STRSH 訪問;
舉例:
.text
.global asmsubroutine
.extern globvar
asmsubroutine:
LDR R1,=globvarLDR R0,[R1]
ADD R0,R0,#2
STR R0,[R1]
MOV PC,LR
.end
2、C 程式調用匯程式設計序
C程式調用匯程式設計序首先通過extern宣告要呼叫的彙編程式模組,宣告中形參個數要與彙編程式模組中需要的變數個數一致,且引數傳遞要滿足ATPCS規則,然後在C程式中呼叫。
例子:
#include<stdio.h>
extern void *strcopy(char*d,char*s); //模組宣告
int main()
{
char*srcstr="first";
char*dststr="second";
strcopy(dststr,srcstr); //彙編模組呼叫;
}
.text
.global strcopy
Strcopy:
LDRB R2,[R1],#1
STRB R2,[R0],#1
CMP R2,#0
BNE Sstcopy
MOV PC,LR
.end