Android逆向中常用的ARM彙編指令

轉載:

https://blog.csdn.net/weifengzhimo/article/details/70477899

本來想自己整理的,但是懶癌發作。找到一篇寫的很清楚的。就貼上來了。

1.彙編指令格式

<opcode>{<cond>}{S}<Rd>,<Rn>{,<OP2>}
格式中<>的內容必不可少,{}中的內容可省略
<opcode>:表示操作碼,如ADD表示算術加法
{<cond>}:表示指令執行的條件域,如EQ、NE等。
{S}:決定指令的執行結果是否影響CPSR的值,使用該後綴則指令執行的結果影響CPSR的值,否則不影響
<Rd>:表示目的寄存器
<Rn>:表示第一個操作數,爲寄存器
<op2>:表示第二個操作數,可以是立即數、寄存器或寄存器移位操作數

 

例子:ADDEQS R0,R1,#8;其中操作碼爲ADD,條件域cond爲EQ,S表示該指令的執行影響CPSR寄存器的值,目的寄存器Rd爲R0,第一個操作數寄存器Rd爲R1,第二個操作數OP2爲立即數#8

 

2.指令的可選後綴
S:指令執行後程序狀態寄存器的條件標誌位將被刷新
    ADDS R1,R0,#2
!:指令中的地址表達式中含有!後綴時,指令執行後,基址寄存器中的地址值將發生變化,變化的結果是:基址寄存器中的值(指令執行後)=指令執行前的值 + 地址偏移量

    LDR R3,[R0,#2]!    指令執行後,R0 = R0 + 2

 

3.指令的條件執行
指令的條件後綴只是影響指令是否執行,不影響指令的內容

條件碼

助記符後綴

標誌

含義

0000

EQ

Z置位

相等

0001

NE

Z清零

不相等

0010

CS

C指令

無符號數大於或等於

0011

CC

C清零

無符號數小於

0100

MI

N置位

負數

0101

PL

N清零

正數或零

0110

VS

V置位

溢出

0111

VC

V清零

未溢出

1000

HI

C置位Z清零

無符號數大於

1001

LS

C清零Z置位

無符號數小於或等於

1010

GE

N等於V

帶符號數大於或等於

1011

LT

N不等於V

帶符號數小於

1100

GT

Z清零且(N等於V)

帶符號數大於

1101

LE

Z置位或(N不等於V)

帶符號數小於或等於

1110

AL

忽略

無條件執行

 

例子:ADDEQ R4,R3,#1 相等則相加,即CPSR中Z置位時該指令執行,否則不執行。

 

4.ARM指令分類

 

助記符

指令功能描述

助記符

指令功能描述

ADC

帶進位加法指令

MRC

從協處理器寄存器到ARM寄存器的數據傳輸指令

ADD

加法指令

MRS

傳送CPSR或SPSR的內容到通用寄存器指令

AND

邏輯與指令

MSR

傳送通用寄存器到CPSR或SPSR的指令

B

分支指令

MUL

32位乘法指令

BIC

位清零指令

MLA

32位乘加指令

BL

帶返回的分支指令

MVN

數據取反傳送指令

BLX

帶返回和狀態切換的分支指令

ORR

邏輯或指令

BX

帶狀態切換的分支指令

RSB

逆向減法指令

CDP

協處理器數據操作指令

RSC

帶錯位的逆向減法指令

CMN

比較反值指令

SBC

帶錯位減法指令

CMP

比較指令

STC

協處理器寄存器寫入存儲器指令

EOR

異或指令

STM

批量內存字寫入指令

LDC

存儲器到協處理器的數據傳輸指令

STR

寄存器到存儲器的數據存儲指令

LDM

加載多個寄存器指令

SUB

減法指令

LDR

存儲器到寄存器的數據加載指令

SWI

軟件中斷指令

MCR

從ARM寄存器到協處理器寄存器的數據傳輸指令

TEQ

相等測試指令

MOV

數據傳送指令

TST

位測試指令

 

 

5.ARM尋址方式

尋址方式就是根據指令中操作數的信息來尋找操作數實際物理地址的方式

 

1)立即數尋址

MOV R0,#15       #15就是立即數

 

2)寄存器尋址

ADD R0, R1, R2    將R1和R2的內容相加,其結果存放在寄存器R0中

 

3)寄存器間接尋址

LDR R0, [R4]      以寄存器R4的值作爲操作數的地址,在存儲器中取得一個操作數存入寄存器R0中

 

4)寄存器移位尋址
ADD R0,R1,R2,LSL #1    將R2的值左移一位,所得值與R1相加,存放到R0中

MOV R0,R1,LSL R3    將R1的值左移R3位,然後將結果存放到R0中

 

5)基址變址尋址
LDR R0,[R1,#4]    將R1的值加4作爲操作數的地址,在存儲器中取得操作數放入R0中
LDR R0,[R1,#4]!   將R1的值加4作爲操作數的地址,在存儲器中取得操作數放入R0中,然後R1 = R1+4
LDR R0,[R1],#4    R0 = [R1],R1 = R1 +4

LDR R0,[R1,R2]   R0 = [R1+R2]

 

6).多寄存器尋址
一條指令可以完成多個寄存器值的傳送(最多可傳送16個通用寄存器),連續的寄存器用“-”,否則用“,”
LDMIA R0!,{R1 - R4}   R1 = [R0],R2=[R0+4],R3=[R0+8],R4=[R0+12]

後綴IA表示在每次執行玩加載/存儲操作後,R0按自長度增加。

 

7).相對尋址
以程序計數器PC的當前值爲基地址,指令中的地址標號作爲偏移量,將兩者相加之後得到操作數的有效地址,如下圖的BL分支跳轉
     BL proc        跳轉到子程序proc處執行
     ...
proc MOV R0,#1

     ...

 

8).堆棧尋址
按先進先出的方式工作,堆棧指針用R13表示,總是指向棧頂,LDMFD和STMFD分別表示POP出棧和PUSH進棧
STMFD R13!,{R0 - R4};

LDMFD R13!,{R0 - R4};

 

6.數據處理指令

 

1). MOV指令

MOV {<cond>}{S} Rd,op2          將op2傳給Rd
MOV R1, R0          將寄存器R0的值傳到寄存器R1
MOV PC,R14          將寄存器R14的值傳到PC,常用於子程序返回
MOV R1,R0,LSL #3    將寄存器R0的值左移3位後傳給R1

MOV R0,#5           將立即數5傳給R0

 

2). MVN指令
MVN {<cond>}{S}Rd, op2          將op2取反傳給Rd
MVN R0,#0           將0取反後傳給R0,R0 = -1

MVN R1,R2           將R2取反,結果保存到R1

 

3). 移位指令
LSL 邏輯左移
LSR 邏輯右移
ASR 算術右移
ROR 循環右移

RRX 帶擴展的循環右移

 

4). ADD加法指令
ADD{<cond>}{S}Rd, Rn, op2
ADD R0,R1,R2            R0 = R1 + R2
ADD R0,R1,#5            R0 = R1 + 5

ADD R0,R1,R2,LSL #2     R0 = R1 + (R2左移2位)

 

5). ADC帶進位加法指令
ADC{<cond>}{S} Rd,Rn,op2    將Rn的值和操作數op2相加,再加上CPSR中C條件標誌位的值,並將結果保存到Rd中
例:用ADC完成64位加法,設第一個64位操作數保存在R2,R3中,第二個64位操作數放在R4,R5中,結果保存在R0,R1中
ADDS R0,R2,R4       低32位相加,產生進位

ADC R1,R3,R5        高32位相加,加上進位

 

6). SUB減法指令
SUB{<cond>}{S} Rd,Rn,op2    Rd = Rn - op2
SUB R0,R1,R2            R0 = R1 - R2
SUB R0,R1,#6            R0 = R1 -6

SUB R0,R2,R3,LSL #1     R0 = R2 - (R3左移1位)

 

7). SBC帶借位減法指令
SBC{<cond>}{S} Rd,Rn,op2    把Rn的值減去操作數op2,再減去CPSR中的C標誌位的反碼,並將結果保存到Rd中,Rd = Rn - op2 - !C
例:用SBC完成64位減法,設第一個64位操作數保存在R2,R3中,第二個64位操作數放在R4,R5中,結果保存在R0,R1中
SUBS R0,R2,R4       低32位相減,S影響CPSR

SBC R1,R3,R5        高32位相減,去除C的反碼

 

8). RSC帶借位的逆向減法指令

RSC{<cond>}{S} Rd,Rn,op2    把操作數op2減去Rn,再減去CPSR中的C標誌位的反碼,並將結果保存到Rd中,Rd = op2 - Rn - !C

 

9). 邏輯運算指令
AND{<cond>}{S} Rd,Rn,op2    按位與,Rd = Rn AND op2
ORR{<cond>}{S} Rd,Rn,op2    按位或,Rd = Rn OR op2

EOR{<cond>}{S} Rd,Rn,op2    按位異或,Rd = Rn EOR op2

 

10). CMP比較指令
CMP{<cond>}{S} Rd,Rn,op2    將Rn的值和op2進行比較,同時更新CPSR中條件標誌位的值(實際上是執行一次減法,但不存儲結果),當操作數Rn大於op2時,則此後帶有GT後綴的指令將可以執行(根據相應的指令判斷是否執行,如GT,LT等)。
CMP R1,#10                  比較R1和10,並設置CPSR的標誌位

ADDGT R0,R0,#5              如果R1>10,則執行ADDGT指令,將R0加5

 

11). CMN反值比較指令
CMN{<cond>}{S} Rd,Rn,op2    將Rn的值和op2取反後進行比較,同時更新CPSR中條件標誌位的值(實際上將Rn和op2相加),後面的指令就可以根據條件標誌位決定是否執行。  

CMN R0,R1       將R0和R1相加,並設置CPSR的值

 

12). MUL/MLA/SMULL/SMLAL/UMULL/UMLAL乘法指令
MUL     32位乘法指令
MLA     32位乘加指令
SMULL   64位有符號數乘法指令
SMLAL   64位有符號數乘加指令
UMULL   64位無符號數乘法指令
UMLAL   64位無符號數乘加指令
MUL{<cond>}{S} Rd,Rm,Rs         Rd = Rm * Rs
MULS R0,R1,R2
MLA{<cond>}{S} Rd,Rm,Rs,Rn      Rd = (Rm * Rs) + Rn

MLAS R0,R1,R2,R3

 

7.數據加載與存儲指令

助記符

說明

操作

LDR{}Rd,addr

加載字數據

Rd = [addr]

LDRB{}Rd,addr

加載無符號字節數據

Rd = [addr]

LDRT{}Rd,addr

以用戶模式加載字數據

Rd = [addr]

LDRBT{}Rd,addr

以用戶模式加載無符號字節數據

Rd = [addr]

LDRH{}Rd,addr

加載無符號半字數據

Rd = [addr]

LDRSB{}Rd,addr

加載有符號字節數據

Rd = [addr]

LDRSH{}Rd,addr

加載有符號半字數據

Rd = [addr]

STR{}Rd,addr

存儲字數據

[addr] = Rd

STRB{}Rd,addr

存儲字節數據

[addr] = Rd

STRT{}Rd,addr

以用戶模式存儲字數據

[addr] = Rd

STRBT{}Rd,addr

以用戶模式存儲字節數據

[addr] = Rd

STRH{}Rd,addr

存儲半字數據

[addr] = Rd

LDM{}{type}Rn{!},regs

多寄存器加載

reglist = [Rn...]

STM{}{type}Rn{!},regs

多寄存器存儲

[Rn...] = reglist

SWP{}Rd,Rm,[Rn]

寄存器和存儲器字數據交換

Rd=[Rn],[Rn]=Rm(Rn!=Rd或Rm)

SWP{}B Rd,Rm,[Rn]

寄存器和存儲器字節數據交換

Rd = [Rn],[Rn] = Rm(Rn!=Rd或Rm)

 

 

1). LDR/STR字數據加載/存儲指令
LDR/STR{<cond>}{T}Rd,addr       LDR指令用於從存儲器中將一個32位的字數據加載到目的寄存器Rd中,當程序計數器PC作爲目的寄存器時,指令從存儲器中讀取的字數據被當做目的地址,從而可以實現程序流程的跳轉。
STR指令用於從源寄存器中將一個32位的字數據存儲到存儲器中,和LDR相反。後綴T可選。
LDR R4,START            將存儲地址爲START的字數據讀入R4
STR R5,DATA1            將R5存入存儲地址爲DATA1中
LDR R0,[R1]             將存儲器地址爲R1的字數據讀入存儲器R0
LDR R0,[R1,R2]          將存儲器地址爲R1+R2的字數據讀入存儲器R0
LDR R0,[R1,#8]          將存儲器地址爲R1+8的字數據讀入存儲器R0
LDR R0,[R1,R2,LSL #2]   將存儲器地址爲R1+R2*4的字數據讀入存儲區R0
STR R0,[R1,R2]!         將R0字數據存入存儲器地址R1+R2的存儲單元中,並將新地址R2+R2寫入R2
STR R0,[R1,#8]!         將R0字數據存入存儲器地址R1+8的存儲單元中,並將新地址R2+8寫入R2
STR R0,[R1,R2,LSL #2]   將R0字數據存入存儲器地址R1+R2*4的存儲單元中,並將新地址R2+R2*4寫入R1
LDR R0,[R1],#8          將存儲器地址爲R1的字數據讀入寄存器R0,並將新地址R1+8寫入R1  
LDR R0,[R1],R2          將存儲器地址爲R1的字數據讀入寄存器R0,並將新地址R1+R2寫入R1

LDR R0,[R1],R2,LSL #2   將存儲器地址爲R1的字數據讀入寄存器R0,並將新地址R1+R2*4寫入R1

 

2). LDRB/STRB字節數據加載/存儲指令

LDRB/STRB{<cond>}{T}Rd,addr         LDRB指令用於從存儲器中將一個8位的字節數據加載到目的寄存器中,同時將寄存器的高24位清零,當程序計數器PC作爲目的寄存器時,指令從存儲器中讀取的字數據被當做目的地址,從而可以實現程序流程的跳轉。

 

STRB指令用於從源寄存器中將一個8位的字節數據存儲到存儲器中,和LDRB相反。後綴T可選。

 

3). LDRH/STRH半字數據加載/存儲指令

LDRH/STRH{<cond>}{T}Rd,addr         LDRH指令用於從存儲器中將一個16位的半字數據加載到目的寄存器中,同時將寄存器的高16位清零,當程序計數器PC作爲目的寄存器時,指令從存儲器中讀取的字數據被當做目的地址,從而可以實現程序流程的跳轉。

 

STRH指令用於從源寄存器中將一個16位的半字數據存儲到存儲器中,和LDRH相反。後綴T可選。

 

4). LDM/STM批量數據加載/存儲指令

LDM/STM{<cond>}{<type>}Rn{!},<regs>{^}      LDM用於從基址寄存器所指示的一片連續存儲器中讀取數據到寄存器列表所指向的多個寄存器中,內存單元的起始地址爲基址寄存器Rn的值,各個寄存器由寄存器列表regs表示,該指令一般用於多個寄存器數據的出棧操作

 

STM用於將寄存器列表所指向的多個寄存器中的值存入由基址寄存器所指向的一片連續存儲器中,內存單元的起始地址爲基址寄存器Rn的值,各個寄存器又寄存器列表regs表示。該指令一般用於多個寄存器數據的進棧操作。

 

type表示類型,用於數據的存儲與讀取有以下幾種情況:
IA:每次傳送後地址值加。
IB:每次傳送前地址值加。
DA:每次傳送後地址值減。
DB:每次傳送前地址值減。
用於堆棧操作時有如下幾種情況:
FD:滿遞減堆棧
ED:空遞減堆棧
FA:滿遞增堆棧

EA:空遞增堆棧

 

5). SWP字數據交換指令
SWP{<cond>}<Rd>,<Rm>,[<Rn>]         Rd = [Rn],[Rn] = Rm,當寄存器Rm和目的寄存器Rd爲同一個寄存器時,指令交換該急促親和存儲器的內容
SWP R0,R1,[R2]          R0 = [R2],[R2] = R1
SWP R0,R0,[R1]          R0 = [R1],[R1] = R0

SWPB指令用於將寄存器Rn指向的存儲器中的字節數據加載到目的寄存器Rd中,目的寄存器的高24位清零,同時將Rm中的字數據存儲到Rn指向的存儲器中。

 

8.分支語句
助記符                        說明                                                                  操作
B{cond}label          分支指令                                           PC<-label  
BL{cond}label         帶返回的分支指令                 PC<-label,LR=BL後面的第一條指令地址
BX{cond}Rm           帶狀態切換的分支指令   PC = Rm & 0xffffffe,T=Rm[0] & 1

BLX{cond}label Rm                                                        帶返回和狀態切換的分支指令 | PC=label,T=1 PC; PC = Rm                                                                                 &0xffffffe,T=Rm[0] & 1;LR = BLX後面的第一條指令地址

 

1). 分支指令B
B{<cond>}label          跳轉到label處執行,PC=label


例子:
backword    SUB R1,R1,#1
            CMP R1,#0           比較R1和0
            BEQ forward         如果R1=0,跳轉到forware處執行
            SUB R1,R2,#3
            SUB R1,R1,#1
forward     ADD R1,R2,#4
            ADD R2,R3,#2

            B backword          無條件跳轉到backword處執行

 

2). 帶返回的分支指令BL
BL{<cond>}label         在跳轉之前,將PC的當前內容保存在R14(LR)中保存,因此,可以通過將R14的內容重新加載到PC中,返回到跳轉指令之後的指令處執行。該指令用於實現子程序的調用,程序的返回可通過把LR寄存器的值複製到PC寄存器中來實現。
例子:
BL func             跳轉到子程序
ADD R1,R2,#2        子程序調用完返回後執行的語句,返回地址
....
func                子程序
...

MOV R15,R14         複製返回地址到PC,實現子程序的返回

 

3). 帶狀態切換的分支指令BX
BX{<cond>} Rm       當執行BX指令時,如果條件cond滿足,則處理器會判斷Rm的位[0]是否爲1,如果爲1則跳轉時自動將CPSR寄存器的標誌T置位,並將目標地址的代碼解釋爲Thumb代碼來執行,則處理器會切換到Thumb狀態,反之,若Rm的位[0]爲0,則跳轉時自動將CPSR寄存器的標誌T復位,並將目標地址處的代碼解釋爲ARM代碼來執行,即處理器會切換到ARM狀態。
注意:bx lr的作用等同於mov pc,lr。即跳轉到lr中存放的地址處。 非零值存儲在R0中返回。
那麼lr存放的是什麼地址呢?lr就是連接寄存器(Link Register, LR),在ARM體系結構中LR的特殊用途有兩種:一是用來保存子程序返回地址;二是當異常發生時,LR中保存的值等於異常發生時PC的值減4(或者減2),因此在各種異常模式下可以根據LR的值返回到異常發生前的相應位置繼續執行。  

當通過BL或BLX指令調用子程序時,硬件自動將子程序返回地址保存在R14寄存器中。在子程序返回時,把LR的值複製到程序計數器PC即可實現子程序返回。

 

9.堆棧

 

1). 進棧出棧
出棧使用LDM指令,進棧使用STM指令。LDM和STM指令往往結合下面一些參數實現堆棧的操作。
FD:滿遞減堆棧。
ED:空遞減堆棧。
FA:滿遞增堆棧。
EA:空遞增堆棧。
滿堆棧是指SP(R13)指向堆棧的最後一個已使用地址或滿位置(也就是SP指向堆棧的最後一個數據項的位置);相反,空堆棧是指SP指向堆棧的第一個沒有使用的地址或空位置。

LDMFD和STMFD分別指POP出棧和PUSH入棧

 

2). PUSH指令
PUSH{cond} reglist      PUSH將寄存器推入滿遞減堆棧
PUSH {r0,r4-r7}         將R0,R4-R7寄存器內容壓入堆棧
2.9.3. POP指令
POP{cond} reglist       POP從滿遞減堆棧中彈出數據到寄存器
POP {r0,r4-r7}          將R0,R4-R7寄存器從堆棧中彈出

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章