亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 系統 > iOS > 正文

ARM匯編逆向iOS 實戰

2020-07-26 03:32:25
字體:
來源:轉載
供稿:網友

我們先講一些ARM匯編的基礎知識。(我們以ARMV7為例,最新iPhone5s上的64位暫不討論)

基礎知識部分:

首先你介紹一下寄存器:

R0-R3:用于函數參數及返回值的傳遞

R4-R6, R8,R10-R11:沒有特殊規定,就是普通的通用寄存器

R7:棧幀指針(Frame Pointer).指向前一個保存的棧幀(stack frame)和鏈接寄存器(link register, lr)在棧上的地址。

R9:操作系統保留

R12:又叫IP(intra-procedure scratch), 要說清楚要費點筆墨,后續再詳細介紹

R13:又叫SP(stack pointer),是棧頂指針

R14:又叫LR(link register),存放函數的返回地址。

R15:又叫PC(program counter),指向當前指令地址。

CPSR:當前程序狀態寄存器(Current Program State Register),在用戶狀態下存放像condition標志中斷禁用等標志的。

   在其它系統狀態中斷狀等狀態下與CPSR對應還有一個SPSR,在這里不詳述了。

另外還有VFP(向量浮點運算)相關的寄存器,在此我們略過,感興趣的可以從后面的參考鏈接去查看。

基本的指令:

add 加指令

sub 減指令

str 把寄存器內容存到棧上去

ldr 把棧上內容載入一寄存器中

.w是一個可選的指令寬度說明符。它不會影響為此指令的行為,它只是確保生成 32 位指令。Infocenter.arm.com的詳細信息

bl 執行函數調用,并把使lr指向調用者(caller)的下一條指令,即函數的返回地址

blx 同上,但是在ARM和thumb指令集間切換。

bx bx lr返回調用函數(caller)。

接下來是函數調用的一些規則。

一. 在iOS中你需要使用BLX,BX這些指令來調用函數,不能使用MOV指令(具體意義下面會說)

二. ARM使用一個棧來來維護函數的調用及返回。ARM中棧是向下生長(由高地址向低地址生長的)。

函數調用前后棧的布局如圖一(引用的蘋果iOS ABI Reference):

              圖(一)

SP(stack pointer)指向棧頂(棧低在高地址)。棧幀(stack frame)其實就是通過R7及存在棧上的舊R7來標識的棧上的一塊一塊的存儲空間。棧幀包括:

參數區域(parameter area),存放調用函數傳遞的參數。對于32位ARM,前4個參數通過r0-r3傳遞,多余的參數通過棧來傳遞,就是存放在這個區域的。

鏈接區域(linkage area),存放調用者(caller)的下一條指令。

棧幀指針存放區域(saved frame pointer),存放調用函數的棧幀的底部,標識著調用者(caller)棧幀的結束及被調用函數(callee)的棧幀開始。

局部變量存儲區(local storage area)。用于存被調函數(callee)的局部變量及在被調用函數(callee)結束后反回調用函數(call)之前需要恢復的寄存器內容。

寄存器存儲區(saved registers area)。Apple的文檔中是這樣說的。但我認為這個區域和local storage area相鄰且干的事也是存放需要恢復的寄存器內容,因此我覺得要不就把這個區域在概念上不區分出來,要不就把存放需要恢復的寄存器這項功能從local storage area中分出來。 當然這些都只是概念上的,其實實質上是沒有區別的。

接下來看看在調用子函數開始及結尾時所要做的事情。(官方叫序言和結語, prologs and epilogs)

調用開始:

LR入棧R7入棧R7 = SP地址。在經過前面兩條入棧指令后,SP指向的地址向下移動,再把SP賦值給R7, 標志著caller棧幀的結束及callee的棧幀的開始將callee會修改且在返回caller時需要恢復的寄存器入棧。分配棧空間給子程序使用。由于棧是從高地址向低地址生長,所以通常使用sub sp, #size來分配。

調用結尾:

釋放??臻g。add sp, #size指令。恢復所保存的寄存器。恢復R7將之前存放的LR從棧上彈出到PC,這樣函數就返回了。

-----------------------------------------------------------華麗的分割線-------------------------------------------------------------

實戰部分(一):

用XCode創建一個Test工程,新建一個.c文件,添加如下函數:

#include <stdio.h> int func(int a, int b, int c, int d, int e, int f){  int g = a + b + c + d + e + f;  return g;}

查看匯編語言:

在XCode左上角選中targe 在真機下編譯,這樣產生的才是ARM匯編,不然在模擬器下生成的是x86匯編。

點擊 XCode => Product => Perform Action => Assemble file.c 生成匯編代碼。

代碼很多,有很多"."開頭的".section", ".loc"等,這些是匯編器需要的,我們不用去管。把這些"."開頭的及注釋增掉后,代碼如下:

_func:  .cfi_startprocLfunc_begin0:  add r0, r1Ltmp0:  ldr.w  r12, [sp]  add r0, r2  ldr.w  r9, [sp, #4]  add r0, r3  add r0, r12  add r0, r9  bx lrLtmp2:Lfunc_end0:

_func:表示接下來是func函數的內容。Lfunc_begin0及Lfunc_end0標識函數定義的起止。函數起止一般是"xxx_beginx:"及"xxx_endx:"

下面來一行行代碼解釋:

add r0, r1 將參數a和參數b相加再把結果賦值給r0ldr.w r12, [sp] 把最的一個參數f從棧上裝載到r12寄存器add r0, r2 把參數c累加到r0上ldr.w r9, [sp, #4] 把參數e從棧上裝載到r9寄存器add r0, r3 累加d累加到r0add r0, r12 累加參數f到r0add r0, r9 累加參數e到r0

至此,全部的a到f 共6個值全部累加到r0寄存器上。前面說了r0是存放返回值的。

bx lr: 返回調用函數。

-----------------------------------------------------------華麗的分割線-------------------------------------------------------------

實戰部分(二):

為了讓大家看清楚函數調用時棧上的變化,下面以一個有三個函數,兩個調用的C代碼的匯編代碼為例講解一下。

上代碼:

#include <stdio.h> __attribute__((noinline))int addFunction(int a, int b, int c, int d, int e, int f) {  int r = a + b + c + d + e + f;  return r;} __attribute__((noinline))int fooFunction(int a, int b, int c, int d, int f) {  int r = addFunction(a, b, c, d, f, 66);  return r;} int initFunction(){  int r = fooFunction(11, 22, 33, 44, 55);    return r;}

由于我們是要看函數調用及棧的變化的,所以在這里我們加上__attribute__((noinline))防止編譯器把函數內聯(如果你不懂內聯,請google之)。

在XCode左上角選中targe 在真機下編譯,這樣產生的才是ARM匯編,不然在模擬器下生成的是x86匯編。

點擊 XCode => Product => Perform Action => Assemble file.c 生成匯編代碼, 如下:

為了能更符合我們人的思考方式,我們從調用函數講起。

initFunction:

_initFunction:  .cfi_startprocLfunc_begin2:@ BB#0:  push  {r7, lr}  mov r7, sp  sub sp, #4  movs  r0, #55  movs  r1, #22Ltmp6:  str r0, [sp]  movs  r0, #11  movs  r2, #33  movs  r3, #44  bl _fooFunction  add sp, #4  pop {r7, pc}Ltmp7:Lfunc_end2:

還是一行行的解釋:

1.push {r7, lr} 就是前面基礎知識部分說的函數調用的序言(prologs)部分的1, 2兩條,將lr, r7 存到棧上去

2.mov r7, sp 序言(prolog)之3。

3.sub sp, #4 在棧上分配一個4字節空間用來存放局部變量, 即參數。前面我們說過,r0-r3可以傳遞4個參數,但超過的只能通過棧來傳遞。

4.movs r0, #55 把立即數55存入r0

5.movs r1, #22 把22存入r1

6.str r0, [sp] 把r0的值存入棧指針sp指向的內存。即棧上存了參數55

7.接下來三條指令moves r0, #11 moves r2, #33 moves r3, #44 把相應的立即數存入指定的寄存器。 到目前為止,r0-r3分別存放了11, 22, 33,44共4個立即數參數,棧上存放了55這一個參數。

8.bl _fooFunction 調用fooFunction, 調用后跳轉到fooFunction中的情況下面再分析。

9.add sp, #4 棧指針向上移動4個字節,回收第3個指令sub sp, #4分配的空間。

10.pop {r7, pc} 恢復第一條指令push {r7, lr}到棧中的值, 把之前的lr值賦給pc。注意:在進入initFunction的時候lr是調用initFunction的函數的下一條指令,所以現在把當時的lr中的值賦給pc程序計數器,這樣執行lr指向的這一條指令,函數就反回了。

指令1,2, 3是函數序言(prologs),指令9, 10是結語(epilogs)。這基本上是一個套路,看多了自然就知道了,都不用停下來一條條分析。

為了方便和棧的變化聯系起來,我們畫出指令8, bl __fooFunction時的棧布局如圖二:

          圖(二)

在上面的initFunction調用第8條指令bl _fooFunction之后,進入fooFunction, 其它匯編如下:

fooFunction:

_fooFunction:  .cfi_startprocLfunc_begin1:  push  {r4, r5, r7, lr}  add r7, sp, #8  sub sp, #8  ldr r4, [r7, #8]  movs  r5, #66  strd  r4, r5, [sp]  bl _addFunction  add sp, #8  pop {r4, r5, r7, pc}Lfunc_end1:

一樣,我們一行行來看:

1.push {r4, r5, r7, lr}             你應該發現了,這次和initFunction不同,除了lr和r7也把r4, r5 push到棧上去了,這是因為我們下面會用到r4, r5,所以我們先把r4,r5存到棧上,這樣我們在退出fooFunction返回initFunction的時候好恢復r4, r5的值。push到棧上的順序是lr, r7, r4, r5。
2.add r7, sp, #8                     在initFunction中我們沒有push r4, r5所以sp指向的位置正好是新的r7的值,但是這里我們把r4, r5也push到棧上了,現在sp指向棧上的r4的位置,而棧是向下生長的,所以我們把sp + #8個字節就是存放舊r7的位置。
3.sub sp, #8                          在棧上分配8個字節。
4.ldr r4, [r7, #8]                    r7加8個字節,在棧上的位置正好是在initFunction中我們存放的參數55的位置。因此,這里是把55賦值給r4
5.movs  r5, #66                     立即數賦值,不解釋了
6.strd r4, r5, [sp]                   把r4, r5中的值存到棧上。我們在initFunction中已經把11,22,33,44這4個參數存放到了r0-r3,現在55,66我們存放在棧上
7.bl _addFunction                   參數已經準備好了,因此現在調用addFunction。
8.add sp, #8                          回收??臻g
9.pop {r4, r5, r7, pc}              這最后兩條指令和 initFunction類似,只是多了個恢復r4,r5。不過也是一個指令就完事。

在指令bl _addFunction 調用addFunction后,棧的布局如圖(三):

            圖(三)

上面的fooFunction第7條指令bl _addFunction之后,進入addFunction。匯編代碼如下:

addFunction:

_addFunction:  .cfi_startprocLfunc_begin0:  add r0, r1  ldr.w  r12, [sp]  add r0, r2  ldr.w  r9, [sp, #4]  add r0, r3  add r0, r12  add r0, r9  bx lrLfunc_end0:

逐行解釋之:

add r0, r1         r0 += r1ldr.w r12, [sp]      把sp指向的內容load到r12寄存器。從圖(三)我們知道sp指向66,因此r12存的66add r0, r2         r0 += r2ldr.w r9, [sp, #4]    從圖(三) sp加4個字節存的是55, r9存的55add r0, r3         r0 += r3add r0, r12        r0 += r12add r0, r9        r0 += r9。 至此r0-r4存的11,22,33,44,及棧上存的55,66想加存到了r0上。bx lr             返回。

大家應該有注意到因為addFunction沒有調用其它的函數,序言和結語與initFunction和fooFunction不一樣。因為我們不調用其它函數,就不會有bl, blx這樣的指令,所以不會個性lr, 所以我們沒有push lr。

在這里我們用了r9, r12為什么不需要保存與恢復,我還沒大搞明白,大俠們若能賜教,將不勝感激。

iOS ABI Reference上是這樣說的:

關于R9:

In iOS 2.x, register R9 is reserved for operating system use and must not be used by application code. Failure to do so can result in application crashes or aberrant behavior. However, in iOS 3.0 and later, register R9 can be used as a volatile scratch register. These guidelines differ from the general usage provided for by the AAPCS document.

關于R12

R12is the intra-procedure scratch register, also known as IP. It is used by the dynamic linker and is volatile across all function calls. However, it can be used as a scratch register between function calls.

這是C函數的匯編。下篇講obj-c函數的匯編,包括objc block。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
日韩av网址在线| 欧美日韩亚洲天堂| 亚洲第一福利视频| 亚洲高清一二三区| 亚洲人成亚洲人成在线观看| 亚洲精品xxx| 日韩欧美亚洲综合| y97精品国产97久久久久久| 51色欧美片视频在线观看| 国产欧美精品日韩| 久久91亚洲精品中文字幕奶水| 国产成人涩涩涩视频在线观看| 欧美黄色www| 欧美午夜性色大片在线观看| 久久夜精品va视频免费观看| 久久精品国产成人| 欧美亚洲激情在线| 国内精品一区二区三区四区| 国产亚洲人成网站在线观看| 国产综合久久久久| 久久久国产精品免费| 国产精品视频26uuu| 国产精品美乳一区二区免费| 在线视频亚洲欧美| 欧美xxxwww| 欧美性69xxxx肥| 自拍视频国产精品| 88国产精品欧美一区二区三区| 91在线|亚洲| 91九色蝌蚪国产| 亚洲第一中文字幕| 国产精品免费一区豆花| 欧美日在线观看| 国产成人精品一区二区在线| 国产午夜精品免费一区二区三区| 九九热精品视频国产| 日韩欧美国产成人| 日韩少妇与小伙激情| 国产主播在线一区| 欧美一区亚洲一区| 欧美插天视频在线播放| 国产91亚洲精品| 中文字幕综合在线| 欧美日韩午夜激情| 成人午夜两性视频| 亚洲欧美制服综合另类| 97精品一区二区视频在线观看| 国产91在线播放九色快色| 久久久久久久久中文字幕| 欧美高清视频在线观看| 中文字幕亚洲欧美日韩高清| 日韩欧美亚洲国产一区| 日韩精品丝袜在线| 日韩av综合中文字幕| 亚洲日本中文字幕| 久久久人成影片一区二区三区观看| 中文字幕在线亚洲| 91中文字幕一区| 中日韩午夜理伦电影免费| 欧美电影在线观看| 精品福利在线看| 欧美老肥婆性猛交视频| 成人写真福利网| 亚洲免费av网址| 成人黄色在线播放| 亚洲国产成人久久| 久久精品电影网| 久久色精品视频| 97超级碰碰人国产在线观看| 人九九综合九九宗合| 九九热最新视频//这里只有精品| 国产成人一区二区三区| 欧美中文在线字幕| 久久久久女教师免费一区| 欧美成人中文字幕| 亚洲美女又黄又爽在线观看| 欧美激情精品久久久久久免费印度| 日韩在线激情视频| 久久久国产视频91| 欧美日韩美女视频| 欧美成人精品在线| 欧美成aaa人片在线观看蜜臀| 亚洲最大的网站| 欧美老妇交乱视频| 国产97在线亚洲| 97在线免费观看视频| 亚洲人成电影网站色…| 日本在线精品视频| 国产精品视频在线观看| 日韩av在线导航| 精品久久香蕉国产线看观看gif| 91香蕉嫩草影院入口| 日韩欧美亚洲一二三区| 欧美性xxxxxxx| 亚洲精品小视频在线观看| 欧美成人三级视频网站| 亚洲第一精品福利| 久久午夜a级毛片| 国产精品va在线播放我和闺蜜| 国产精品96久久久久久又黄又硬| 久久精品国产2020观看福利| 精品久久久在线观看| 久久久亚洲网站| 丝袜一区二区三区| 欧美性猛交xxxxx免费看| 日韩av网址在线观看| 亚洲自拍av在线| 国产精品久久久久久婷婷天堂| 国产午夜精品免费一区二区三区| 日韩精品在线免费观看| 亚洲综合色激情五月| 国模视频一区二区三区| 国产丝袜视频一区| 黄色精品在线看| 日韩精品在线电影| 高潮白浆女日韩av免费看| www.国产一区| 国产精品成人在线| 久久中文字幕在线视频| 国产精品久久久久久久久久99| 欧美裸体xxxxx| 国产精品久久久久高潮| 欧美精品少妇videofree| 久久精品亚洲热| 欧美性生交大片免网| 日韩欧美999| 久久资源免费视频| 亚洲精品久久久久中文字幕欢迎你| 亚洲www在线观看| 亚洲欧美成人网| 亚洲片av在线| 欧美亚洲一区在线| 欧美另类在线观看| 日韩欧美亚洲范冰冰与中字| 91黄色8090| 国产v综合v亚洲欧美久久| 亚洲欧美激情在线视频| 国产欧美日韩中文字幕在线| 国产精品视频专区| 中文字幕精品在线视频| 精品久久久久人成| 中文字幕国内精品| 国产日韩欧美在线播放| 日韩中文字幕免费| 国产精品入口日韩视频大尺度| 78色国产精品| 欧美一乱一性一交一视频| 欧美成人四级hd版| 亚洲成av人影院在线观看| 国产一区二区三区在线看| 久久香蕉国产线看观看网| 欧美精品中文字幕一区| 国产精品劲爆视频| 97香蕉超级碰碰久久免费的优势| 久久精品国产亚洲| 国产成人鲁鲁免费视频a| x99av成人免费| 久久五月天综合| 91国产美女在线观看| 国产精品成久久久久三级| 亚洲第一区第一页| 中文字幕亚洲综合久久筱田步美| 亚洲欧洲中文天堂| 久久97精品久久久久久久不卡|