iOS逆向?qū)W習(arm64匯編入門)

iOS匯編

iOS匯編語音有很多鐘霎肯。常見的有8086匯編柑土、arm匯編、x86匯編等等酌予。

arm匯編

iOS的架構(gòu)從最初的armv6發(fā)展到后來的armv7和armv7s磺箕,最后發(fā)展到現(xiàn)在的arm64,不管是armv6還是后來的armv7,以及arm64都是arm處理器的指令集霎终。armv7和armv7s是真機32位處理器使用的架構(gòu)滞磺,而arm64是真機64位處理器使用的架構(gòu)。 iPhone 5C是最后一款arm32位版本的iPhone莱褒,在iPhone5s之后击困,所有的iPhone設(shè)備都采用arm64架構(gòu)。arm64匯編在真機上使用广凸,如下:

TestFont`-[ViewController test]:
    0x10286e574 <+0>:  sub    sp, sp, #0x20             ; =0x20 
    0x10286e578 <+4>:  mov    w8, #0x14
    0x10286e57c <+8>:  mov    w9, #0xa
    0x10286e580 <+12>: str    x0, [sp, #0x18]
    0x10286e584 <+16>: str    x1, [sp, #0x10]
->  0x10286e588 <+20>: str    w9, [sp, #0xc]
    0x10286e58c <+24>: str    w8, [sp, #0x8]
    0x10286e590 <+28>: add    sp, sp, #0x20             ; =0x20 
    0x10286e594 <+32>: ret  

x86匯編

x86匯編是模擬器使用的匯編語言阅茶,它的指令和arm64匯編的語法不同,如下

TestFont`-[ViewController test]:
    0x10b089520 <+0>:  pushq  %rbp
    0x10b089521 <+1>:  movq   %rsp, %rbp
    0x10b089524 <+4>:  movq   %rdi, -0x8(%rbp)
    0x10b089528 <+8>:  movq   %rsi, -0x10(%rbp)
->  0x10b08952c <+12>: movl   $0xa, -0x14(%rbp)
    0x10b089533 <+19>: movl   $0x14, -0x18(%rbp)
    0x10b08953a <+26>: popq   %rbp
    0x10b08953b <+27>: retq   

為什么要學習arm64匯編?

代碼調(diào)試

在平常開發(fā)中谅海,在調(diào)試程序的時候脸哀,如果程序crash,通常會定位到具體的崩潰代碼扭吁。但是有時候也會遇到一些比較詭異的crash撞蜂,比如說崩潰在了系統(tǒng)庫中,這個時候定位到具體的crash原因會非常困難侥袜。如果利用匯編調(diào)試技巧來進行調(diào)試蝌诡,可能會讓我們事半功倍。

逆向調(diào)試

在逆向別人App過程中枫吧,我們可以通過LLDB對內(nèi)存地址進行斷點操作浦旱,但是當執(zhí)行到斷點時,LLDB展現(xiàn)給我們的是匯編代碼九杂,而不是OC代碼颁湖,所以想要逆向并且動態(tài)調(diào)試別人的App宣蠕,就需要學習匯編的知識。

作為一個開發(fā)者甥捺,有一個學習的氛圍跟一個交流圈子特別重要抢蚀,這有個iOS交流群:642363427,不管你是小白還是大牛歡迎入駐 涎永,分享BAT,阿里面試題思币、面試經(jīng)驗,討論技術(shù)羡微,iOS開發(fā)者一起交流學習成長!

arm64匯編入門

想要學習arm64匯編惶我,需要從以下三個方面入手妈倔,寄存器、指令和堆棧绸贡。

寄存器

arm64中有34個寄存器盯蝴,如下

通用寄存器

  • 64 bit的通用寄存器有29個,分別是x0 ~ x28
  • 32 bit的也有29個听怕,分別是w0 ~ w28(屬于x0 ~ x28的低32位)
  • 其中x0 ~ x7通常拿來存放函數(shù)的參數(shù)捧挺,如果參數(shù)更多,則采用堆棧來進行傳遞
  • x0中通常存放函數(shù)的返回值
也會有人將x0 ~ x30叫做通用寄存器尿瞭,但是在實際使用中x29和x30并沒有對應的低32位的寄存器w29闽烙、w30,而且x29和x30寄存器有著特殊的用途声搁,所以在此我只講x0 ~ x28記為通用寄存器

程序計數(shù)器

pc (Program Counter)寄存器黑竞,它記錄著當前CPU正在執(zhí)行的指令的地址,通過register read pc查看寄存器中存儲的值

(lldb) register read pc
      pc = 0x000000010286e588  TestFont`-[ViewController test] + 20 at ViewController.m:28
(lldb) 

堆棧指針

  • sp (Stack Pointer)
  • fp (Frame Pointer)疏旨,也就是之前所說的x29

鏈接寄存器

lr (Link Register)寄存器很魂,也就是之前所說的x30寄存器,它存儲著函數(shù)的返回地址

程序狀態(tài)寄存器

arm體系中包含一個當前程序狀態(tài)寄存器cpsr (Current Program Status Register)和五個備份的程序狀態(tài)寄存器spsr (Saved Program Status Registe)檐涝,備份的程序狀態(tài)寄存器用來進行異常處理遏匆。

  • 程序狀態(tài)寄存器的每一位都有特定的用途,此處只介紹幾種常用的標志位
  • 其中N谁榜、Z幅聘、C、V均為條件碼標志位惰爬,他們的內(nèi)容可被算數(shù)或者邏輯運算的結(jié)果所改變喊暖,并且可以決定某條指令是否被執(zhí)行。條件碼標志各位的具體含義如下

指令

mov指令

mov指令可以將另一個寄存器撕瞧、被移位的寄存器或者將一個立即數(shù)加載到目的寄存器

mov指令在arm64匯編中的實際使用

  • 在xcode中新建test.s文件陵叽,在test.s文件中添加以下代碼
; 此處.text表示此代碼放在text段中
.text
; .global表示將后面跟隨的方法給暴露出去狞尔,不然外部無法調(diào)用,方法名以_開頭
.global _test

; 此處為_test方法
_test:
; mov指令巩掺,將立即數(shù)4加載到x0寄存器中
mov x0, #0x4
mov x1, x0
; 匯編指令中偏序,ret表示函數(shù)的終止
ret

  • 在xcode中新建test.h頭文件,將test.s中的_test方法暴露出來
#ifndef test_h
#define test_h

void test(void);

#endif /* test_h */

  • 在viewDidLoad中調(diào)用test()函數(shù)胖替,然后在LLDB中使用register read x0 讀取寄存器中存放的值
(lldb) register read x0
      x0 = 0x000000010320c980
(lldb) si
(lldb) register read x0
      x0 = 0x0000000000000004
(lldb) register read x1
      x1 = 0x00000001e60f3bc7  "viewDidLoad"
(lldb) si
(lldb) register read x1
      x1 = 0x0000000000000004

通過對匯編指令增加斷點研儒,一步一步調(diào)試可以看出,在執(zhí)行完mov指令后独令,x0和x1寄存器的值都被修改了

ret

ret指令表示函數(shù)的返回端朵,而且它還有一個非常重要的作用,就是將lr(x30)寄存器的值賦值給pc寄存器

  • 在viewDidLoad中調(diào)用test()函數(shù),在test()函數(shù)上打上斷點燃箭,執(zhí)行程序如下
  • 使用register read 查看lr和pc寄存器的值
(lldb) register read lr
      lr = 0x00000001021965a4  TestFont`-[ViewController viewDidLoad] + 68 at ViewController.m:23
(lldb) register read pc
      pc = 0x00000001021965a4  TestFont`-[ViewController viewDidLoad] + 68 at ViewController.m:23
(lldb) 

此時冲呢,lr寄存器和pc寄存器的值都是test()函數(shù)起始地址

  • 使用si指令跳轉(zhuǎn)到test()函數(shù)中
  • 再次查看lr和pc寄存器的值,發(fā)現(xiàn)lr的值變成了test()函數(shù)的下一條指令的地址招狸,也就是test()函數(shù)執(zhí)行完成之后敬拓,主程序需要執(zhí)行的下一條指令。pc寄存器保存了當前即將執(zhí)行的指令的地址裙戏,如下
(lldb) register read lr
      lr = 0x00000001021965a8  TestFont`-[ViewController viewDidLoad] + 72 at ViewController.m:24
(lldb) register read pc
      pc = 0x0000000102196abc  TestFont`test

  • 執(zhí)行完test()函數(shù)乘凸,發(fā)現(xiàn)程序跳轉(zhuǎn)到了lr寄存器所保存的指令地址,也就是0x00000001021965a8累榜,此時再次查看lr和pc寄存器的值营勤,發(fā)現(xiàn)pc寄存器存放的地址已經(jīng)變成了lr寄存器存放的地址
(lldb) register read lr
      lr = 0x00000001021965a8  TestFont`-[ViewController viewDidLoad] + 72 at ViewController.m:24
(lldb) register read pc
      pc = 0x00000001021965a8  TestFont`-[ViewController viewDidLoad] + 72 at ViewController.m:24
(lldb) 

add指令

add指令是將兩個操作數(shù)相加,并將結(jié)果存放到目標寄存器中信柿。具體說明如下

在arm64匯編中冀偶,相應的就是操作x0~x28,執(zhí)行如下匯編代碼

.text
.global _test

_test:

mov x0, #0x4
mov x1, #0x3

add x0, x1, x0

ret

執(zhí)行完test()函數(shù)渔嚷,通過register read查詢x0的值进鸠,最后可以看到x0存放的值為7,如下

(lldb) register read x0
      x0 = 0x0000000000000004
(lldb) si
(lldb) register read x1
      x1 = 0x0000000000000003
(lldb) si
(lldb) register read x0
      x0 = 0x0000000000000007

sub指令

sub指令是將操作數(shù)1減去操作數(shù)2,再減去cpsr中的C條件標志位的反碼形病,并將結(jié)果存放到目標寄存器中

cmp指令

cmp指令是把一個寄存器的內(nèi)容和另一個寄存器的內(nèi)容或者立即數(shù)做比較客年,同時會更新CPSR寄存器中條件標志位的值

  • 執(zhí)行如下匯編代碼
.text
.global _test

_test:

mov x0, #0x4
mov x1, #0x3

cmp x0, x1

ret

  • 在執(zhí)行cmp代碼之前和之后各打印一次CPSR寄存器的值如下
(lldb) register read cpsr
    cpsr = 0x60000000
(lldb) si
(lldb) si
(lldb) si
(lldb) register read cpsr
    cpsr = 0x20000000
(lldb) 

可以發(fā)現(xiàn),在執(zhí)行cmp操作之后漠吻,cpsr寄存器的值變成了0x20000000,轉(zhuǎn)換成16進制后量瓜,得到32位標志位如下

可以發(fā)現(xiàn)第31位,也就是N位的值為0途乃,同時第30位绍傲,也就是Z位的值也為0,這就表示,x0和x1寄存器相比較之后的值為非零非負,而使用x0 - x1得到的結(jié)果是1烫饼,符合非零非負的條件猎塞。

  • 修改匯編代碼,調(diào)換x0和x1寄存器的位置杠纵,如下
_test:

mov x0, #0x4
mov x1, #0x3

cmp x1, x0

ret

  • 再次在cmp代碼執(zhí)行前后讀取CPSR寄存器的值
(lldb) register read cpsr
    cpsr = 0x60000000
(lldb) s
(lldb) register read cpsr
    cpsr = 0x80000000
(lldb) 

這個時候荠耽,cpsr寄存器的值變成了0x80000000,轉(zhuǎn)換成16進制后,如下

可以看出比藻,第31位N位的值變成了1铝量,第30位Z位的值為0,這表示银亲,x0和x1寄存器相比較之后的值為非零負數(shù)慢叨,使用x1-x0得到的結(jié)果是-1,符合非零負數(shù)的條件

B指令

B指令是最簡單的跳轉(zhuǎn)指令群凶,一旦遇到B指令插爹,程序會無條件跳轉(zhuǎn)到B之后所指定的目標地址處執(zhí)行。

BL指令

BL指令是另一個跳轉(zhuǎn)指令请梢,但是在跳轉(zhuǎn)之前,它會先將當前標記位的下一條指令存儲在寄存器lr(x30)中力穗,然后跳轉(zhuǎn)到標記處開始執(zhí)行代碼毅弧,當遇到ret時,會將lr(x30)中存儲的地址重新加載到PC寄存器中当窗,使得程序能返回標記位的下一條指令繼續(xù)執(zhí)行够坐。

  • 首先執(zhí)行以下匯編代碼
.text
.global _test

label:
mov x0, #0x1
mov x1, #0x8
ret

_test:
mov x0, #0x4
bl label
mov x1, #0x3
cmp x1, x0
ret

  • 斷點到bl label指令時,讀取lr寄存器和PC寄存器的值
  • 執(zhí)行bl label指令崖面,跳轉(zhuǎn)到label標記處元咙,再次讀取lr(x30)寄存器和PC寄存器的值,這個時候會發(fā)現(xiàn)lr(x30)寄存器存放的地址已經(jīng)變成mov x1, #0x3這條指令的內(nèi)存地址
  • 執(zhí)行完label標記中的所有代碼,發(fā)現(xiàn)程序再次回到lr寄存器所存儲的地址巫员,也就是mov x1, #0x3這句指令繼續(xù)執(zhí)行,并且此時pc寄存器所存儲的地址也變成了mov x1, #0x3這句指令的地址庶香。

想了解更多逆向相關(guān)知識不妨動動小手,添加一下咱們的交流群642363427來為你的技術(shù)多添一份光彩简识。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末赶掖,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子七扰,更是在濱河造成了極大的恐慌奢赂,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,907評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件颈走,死亡現(xiàn)場離奇詭異膳灶,居然都是意外死亡,警方通過查閱死者的電腦和手機立由,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,987評論 3 395
  • 文/潘曉璐 我一進店門轧钓,熙熙樓的掌柜王于貴愁眉苦臉地迎上來序厉,“玉大人,你說我怎么就攤上這事聋迎≈茫” “怎么了?”我有些...
    開封第一講書人閱讀 164,298評論 0 354
  • 文/不壞的土叔 我叫張陵霉晕,是天一觀的道長庭再。 經(jīng)常有香客問我,道長牺堰,這世上最難降的妖魔是什么拄轻? 我笑而不...
    開封第一講書人閱讀 58,586評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮伟葫,結(jié)果婚禮上恨搓,老公的妹妹穿的比我還像新娘。我一直安慰自己筏养,他們只是感情好斧抱,可當我...
    茶點故事閱讀 67,633評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著渐溶,像睡著了一般辉浦。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上茎辐,一...
    開封第一講書人閱讀 51,488評論 1 302
  • 那天宪郊,我揣著相機與錄音,去河邊找鬼拖陆。 笑死弛槐,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的依啰。 我是一名探鬼主播乎串,決...
    沈念sama閱讀 40,275評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼孔飒!你這毒婦竟也來了灌闺?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,176評論 0 276
  • 序言:老撾萬榮一對情侶失蹤坏瞄,失蹤者是張志新(化名)和其女友劉穎桂对,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體鸠匀,經(jīng)...
    沈念sama閱讀 45,619評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡蕉斜,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,819評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片宅此。...
    茶點故事閱讀 39,932評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡机错,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出父腕,到底是詐尸還是另有隱情弱匪,我是刑警寧澤,帶...
    沈念sama閱讀 35,655評論 5 346
  • 正文 年R本政府宣布璧亮,位于F島的核電站萧诫,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏枝嘶。R本人自食惡果不足惜帘饶,卻給世界環(huán)境...
    茶點故事閱讀 41,265評論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望群扶。 院中可真熱鬧及刻,春花似錦、人聲如沸竞阐。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,871評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽骆莹。三九已至茴扁,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間汪疮,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,994評論 1 269
  • 我被黑心中介騙來泰國打工毁习, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留智嚷,地道東北人。 一個月前我還...
    沈念sama閱讀 48,095評論 3 370
  • 正文 我出身青樓纺且,卻偏偏與公主長得像盏道,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子载碌,可洞房花燭夜當晚...
    茶點故事閱讀 44,884評論 2 354

推薦閱讀更多精彩內(nèi)容