[轉]ARM64 匯編


寄存器

匯編指令棧栗子

逆向工程繞不過的一部分就是匯編指令的分析。我們iPhone里面用到的是ARM匯編,但是不同的設備也有差異,因CPU的架構不同。

架構 設備
armv6 iPhone, iPhone2, iPhone3G, 第一代、第二代 iPod Touch
armv7 iPhone3GS, iPhone4, iPhone4S,iPad, iPad2, iPad3(The New iPad), iPad mini, iPod Touch 3G, iPod Touch4
armv7s iPhone5, iPhone5C, iPad4(iPad with Retina Display)
arm64 iPhone5S 及以后版本

從iPhone5s之后的蘋果手機都是ARM64位操作系統了,所以我們直接從ARM64匯編指令開始。

寄存器

我們都知道CPU的典型構成中有寄存器、控制器和運算器等組成,部件之間通過總線連接。運算器負責信息處理,控制器負責控制其他期間進行工作,寄存器用於信息存儲。對我們程序員來說寄存器是最主要部件,可以通過改變寄存器的內容來實現對CPU的控制。

不同的CPU,寄存器的個數和結構不相同。像8086CPU有14個寄存器。ARM64 有34個寄存器,包括31個通用寄存器、SP、PC、CPSR。

寄存器 位數 描述
X0-X30 64bit 通用寄存器,如果有需要可以當做32bit使用:WO-W30
FP(x29) 64bit 保存棧幀地址(棧底指針)
LR (X30) 64bit 通常稱X30為程序鏈接寄存器,保存跳轉返回信息地址
SP 64bit 保存棧指針
PC 64bit 程序計數器,俗稱PC指針,總是指向即將要執行的下一條指令

X0-X7: 用於子程序調用時的參數傳遞,X0還用於返回值傳遞

X8: 間接尋址結果

LR: 保存子程序結束后需要執行的下一條指令

Xcode在真機中運行項目,然后在viewWillAppear添加斷點,lldb中查看各寄存器狀態register read

匯編指令

下面介紹ARM64經常用到的匯編指令

MOV X1,X0 ; 將寄存器X0的值傳送到寄存器X1

ADD X0,X1,X2 ; 寄存器X1和X2的值相加后傳送到X0

SUB X0,X1,X2 ; 寄存器X1和X2的值相減后傳送到X0

AND X0,X0,#0xF ; X0的值與0xF相位與后的值傳送到X0

ORR X0,X0,#9 ; X0的值與9相或后的值傳送到X0

EOR X0,X0,#0xF ; X0的值與0xF相異或后的值傳送到X0

LDR X5,[X6,#0x08] ;X6寄存器加0x08的和的地址值內的數據傳送到X5

STR X0, [SP, #0x8] ;X0寄存器的數據傳送到SP+0x8地址值指向的存儲空間

STP x29, x30, [sp, #0x10] ; 入棧指令

LDP x29, x30, [sp, #0x10] ; 出棧指令

CBZ ; 比較(Compare),如果結果為零(Zero)就轉移(只能跳到后面的指令)

CBNZ ; 比較,如果結果非零(Non Zero)就轉移(只能跳到后面的指令)

CMP ; 比較指令,相當於SUBS,影響程序狀態寄存器

CPSR B/BL ; 絕對跳轉#imm, 返回地址保存到LR(X30)

RET ; 子程序返回指令,返回地址默認保存在LR(X30)

 

AND R0, R1, R2 ; R0 = R1 & R2
ORR R0, R1, R2 ; R0 = R1 | R2
EOR R0, R1, R2 ; R0 = R1 ^ R2
BIC R0, R1, R2 ; R0 = R1 &~ R2
MOV R0, R2 ; R0 = R2

 

NZCV是狀態寄存器中存的幾個狀態值,分別代表運算過程中產生的狀態,其中:

  • N, negative condition flag,一般代表運算結果是負數

  • Z, zero condition flag, 運算結果為0

  • C, carry condition flag, 無符號運算有溢出時,C=1。

  • V, oVerflow condition flag 有符號運算有溢出時,V=1。

棧就是指令執行時存放臨時變量的內存空間,具有特殊的訪問方式:后進先出, Last In Out Firt。

  • 棧是從高地址到低地址存儲數據的,棧底是高地址,棧頂是高地址。

  • FP指向棧底

  • SP指向棧頂

栗子

下面我們寫一個簡單求和的子函數調用,看看編譯成ARM64匯編指令是什么樣子的。

  • testarm.m的內容如下:

      #include<stdio.h>

      int mySum(inta , intb) 

  {

     intc=a+b;

     returnc; 

  } 

  int main (intargc, char*argv[])

   {

     int outA = 10;

     int outB = 20;

     int result = mySum(10, 20);

     printf("%d",result);

    return0; 

  }

  • 用clang編譯成arm64匯編代碼

    編譯命令如下:

    clang -O0-archarm64 -isysroot`xcrun --sdk iphoneos --show-sdk-path`-otestarm01 testarm.m

    testarm01: 輸出文件名

    testarm.m: 需要編譯的文件

    arm64:輸出匯編類型

  • 分析匯編

    使用IDA或者Hopper查看匯編代碼,下面我粘貼處主要匯編代碼分析。

    • mySum對應的匯編:

      從SUB SP, SP, #0x10開始分析

      SUB SP, SP, #0x10 ; 分配棧控件16個字節; 下面是先存儲參數,然后取出來用 

    • STR W0, [SP,#0x10+var_4] ; 把W0入棧,即a

    • STR W1, [SP,#0x10+var_8] ; 把W1入棧,即b

    • LDR W0, [SP,#0x10+var_4] ;出棧a,存儲到W0

    • LDR W1, [SP,#0x10+var_8] ;出棧b,存儲到W1;

    • 主代碼到了,求和ADD W0, W0, W1 ;求和,並把和存儲到W0,相當於int c = a + b;;

    • 返回值處理 STR W0, [SP,#0x10+var_C] ;把和W0入棧

    • LDR W0, [SP,#0x10+var_C] ; 把和W0出棧,現在W0存儲的就是結果了。

    • ADD SP, SP, #0x10 ;平棧,采用平棧方式是add

    • RET ;子程序結束

    • 下面是main函數的匯編代碼:

      想必通過上邊sum函數的講解,大家也能基本能看懂main函數的匯編

      主要代碼解釋

      MOV X0, X8 ;實參outA: #0xA = 10

    • MOV X1, X9 ;實參outB: #0x14 = 20

    • BL _mySum ;調用mySum子函數


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM