1. 程式人生 > >Android安全/安全技術--19--ARM組合語言

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