Android 圖解逆向工程中ARM常用匯編指令(一)
我們走得太快,靈魂都跟不上了。
微小的幸福就在身邊,容易滿足就是天堂。
在逆向和爆破中我們經常會在IDA中接觸到彙編,一般做安卓的不會太瞭解VB回編等,不太瞭解的同學可以先檢視上篇文章《Android ARM常用的彙編指令合集》 再來繼續我們的學習,我們先來看張圖。
這個view裡面有 PUSH/LDR/SUB/MOVS/BLX/SUBS/BEQ/CMP ,這些差不多都是常見的,不過也不需要看得懂,理解這個指令即可,接下來我們就來分析下這些指令分別有什麼作用吧。
先引入 概念性 東西,免得大家後面被搞混,那就是為什麼會有S和!。
- S:指令執行後程序狀態暫存器的條件標誌位將被重新整理 , 如ADDS R1,R0,#2
- ! :指令中的地址表示式中含有!字尾時,指令執行後,基址暫存器中的地址值將發生變化,變化的結果是:基址暫存器中的值(指令執行後)=指令執行前的值 + 地址偏移量,如 LDR R3,[R0,#2]! 指令執行後,R0 = R0 + 2
接下來分別講解這個View裡面的指令分別有什麼作用。
PUSH,顧名思義,直接PUSH進棧了。相反的,POP則為出棧了。
指令示例:
- PUSH{cond} reglist PUSH將暫存器推入滿遞減堆疊
- PUSH {r0,r4-r7} 將R0,R4-R7暫存器內容壓入堆疊
- POP{cond} reglist POP從滿遞減堆疊中彈出資料到暫存器
- POP {r0,r4-r7} 將R0,R4-R7暫存器從堆疊中彈出
LDR,指令語法:LDR{條件} 目的暫存器,<儲存器地址>,LDR指令用於從儲存器中將一個32位的字資料傳送到目的暫存器中。該指令通常用於從儲存器中讀取32位的字資料到通用暫存器,然後對資料進行處理,當程式計數器PC作為 目的暫存器時,指令從儲存器中讀取的字資料被當作目的地址,從而可以實現程式流程的跳轉。該指令在程式設計 中比較常用,且定址方式靈活多樣。
詳情可見上篇文章中 Ctrl + F 搜尋《Android ARM常用的彙編指令合集》:載入/儲存指令
指令示例:
- LDR R0,[R1] ;將儲存器地址為R1的字資料讀入暫存器R0。
- LDR R0,[R1,R2] ;將儲存器地址為R1+R2的字資料讀入暫存器R0。
MOVS 、LDR 這些是跳轉指令,直接向程式計數器PC寫入跳轉地址值,通過向程式計數器PC寫入跳轉地址值,可以實現在4GB的地址空間中的任意跳轉,那有人會問,如果說從當前指令向前或向後的32MB的地址空間的跳轉是怎麼個實現原理?其實在 上篇文章中提及到了,它們是B\BL\BLX\BX 四大指令,這個我們最後才來講解,其實它們有點像我們常說的分支結構,我們從圖片裡面選第四條指令作為檢視資料。
則可以看到,R5是原地址,其實為0xFF8->0x104A,複製返回地址到PC,實現子的返回,做安卓的同學可能會有個疑問,為什麼有個S,因為語法就是 MOV{條件}{S} 目的暫存器+源運算元。
看到這裡大家可能會頭暈,怎麼感覺都是看不懂的數字,那其它那些,如ADD、等就給大家整理了一份表格。
助記符 | 指令功能描述 | 助記符 | 指令功能描述 |
---|---|---|---|
ADD | 加法指令 | MRS | 傳送CPSR或SPSR的內容到通用暫存器指令 |
ADC | 帶進位加法指令 | MRC | 從協處理器暫存器到ARM暫存器的資料傳輸指令 |
AND | 邏輯與指令 | MSR | 傳送通用暫存器到CPSR或SPSR的指令 |
B | 分支指令 | MUL | 32位乘法指令 |
BL | 帶返回的分支指令 | BIC | 位清零指令 |
BLX | 帶返回和狀態切換的分支指令 | MLA | 32位乘加指令 |
BX | 帶狀態切換的分支指令 | MVN | 資料取反傳送指令 |
TST | 位測試指令 | ORR | 邏輯或指令 |
CDP | 協處理器資料操作指令 | RSC | 帶錯位的逆向減法指令 |
RSB | 逆向減法指令 | SBC | 帶錯位減法指令 |
CMN | 比較反值指令 | CMP | 比較指令 |
STC | 協處理器暫存器寫入儲存器指令 | EOR | 異或指令 |
STM | 批量記憶體字寫入指令 | LDC | 儲存器到協處理器的資料傳輸指令 |
STR | 暫存器到儲存器的資料儲存指令 | LDM | 載入多個暫存器指令 |
SUB | 減法指令 | LDR | 儲存器到暫存器的資料載入指令 |
SWI | 軟體中斷指令 | MCR | 從ARM暫存器到協處理器暫存器的資料傳輸指令 |
TEQ | 相等測試指令 | MOV | 資料傳送指令 |
SUBS 從表中可以看到,SUB是減法指令,如SUB R0,R1,R2則對應了R0 = R1 - R2,SUB R0,R1,#1 則是R0 = R1 -1,要注意的是 SUBS 是低32位相減。
那 BEQ 呢?!不要著急,來看下圖
BEQ 指令是跳轉指令,但是跳轉要滿足一定的條件,滿足則跳轉執行,看下圖紅框部分。
那就只剩下 CMP 了,CMP是比較指令,指令格式:CMP{條件} 運算元1,運算元2。
指令示例:
- 如 CMP R1,#10,則等於比較R1和10,並設定CPSR的標誌位。
- CMP R1,R0 ;將暫存器R1的值與暫存器R0的值相減,並根據 結果設定CPSR的標誌位
- CMP R1,#100 ;將暫存器R1的值與立即數100相減,並根 據結果設定CPSR的標誌位
- 如果和BEQ一起使用話則是:CMP R1,#0 換行 BEQ Label ;當CPSR暫存器中的Z條件碼置位時,程式跳轉到標號Label處執行
OK , 從第一張圖中我們看到後面跟的是兩位,那如果是複雜一點的兩位以上怎麼看?
指令示例:
- 先來看MOV的,如MOV R0,R1 , LSL R3 ,這個又是何解?其實它是將R1的值左移R3位,然後將結果存放到R0中 。
- 再來看LDR的,LDR R0,[R1],R2 ,這個何解? 它是將儲存器地址為R1的字資料讀入暫存器R0,並將新地址R1+R2寫入R1 , 要記住,R1是最終落地的地址 。
上篇文章中提及了其它更復雜的指令示例,不太明白這些可以看上篇文章的《Android ARM常用的彙編指令合集》,然後Ctrl + F 搜:資料載入/儲存指令 或者搜尋 資料處理指令,又或者搜尋 自己需要的指令。