iOS逆向之旅(基礎(chǔ)篇) — 匯編(三) — 匯編下的 Switch語句

Switch樣式一

原C代碼如下:

void __switch_1__(){
    int value = 5;
    switch (value) {
        case 0:
            printf("1");
            break;
        case 1:
            printf("2");
            break;
        case 2:
            printf("3");
            break;
        default:
            printf("else");
            break;
    }
}

匯編代碼如下:

01-匯編-IF-SWITCH`__switch_1__:
    0x100c96644 <+0>:   sub    sp, sp, #0x30             ; =0x30 
    0x100c96648 <+4>:   stp    x29, x30, [sp, #0x20]
    0x100c9664c <+8>:   add    x29, sp, #0x20            ; =0x20 
->  0x100c96650 <+12>:  mov    w8, #0x5                  ; w8 = 5
    0x100c96654 <+16>:  stur   w8, [x29, #-0x4]
    0x100c96658 <+20>:  ldur   w8, [x29, #-0x4]          ; value = w8
    0x100c9665c <+24>:  mov    x9, x8
    0x100c96660 <+28>:  stur   w9, [x29, #-0x8]
    0x100c96664 <+32>:  cbz    w8, 0x100c96694           ; cbz 指令的意思是 如果w8==0鸽凶,則跳轉(zhuǎn)到 0x100c96694李剖,如果不等于0救崔,則繼續(xù)執(zhí)行代碼
    0x100c96668 <+36>:  b      0x100c9666c               ; <+40> at main.m:26
    0x100c9666c <+40>:  ldur   w8, [x29, #-0x8]
    0x100c96670 <+44>:  subs   w9, w8, #0x1              ; w9=w8-1
    0x100c96674 <+48>:  stur   w9, [x29, #-0xc]
    0x100c96678 <+52>:  b.eq   0x100c966a8               ; 如果w9==0,則跳轉(zhuǎn)到 0x100c966a8
    0x100c9667c <+56>:  b      0x100c96680               ; <+60> at main.m:26
    0x100c96680 <+60>:  ldur   w8, [x29, #-0x8]
    0x100c96684 <+64>:  subs   w9, w8, #0x2              ; w9=w8-2
    0x100c96688 <+68>:  str    w9, [sp, #0x10]
    0x100c9668c <+72>:  b.eq   0x100c966bc               ; 如果w9==0,則跳轉(zhuǎn)到  0x100c966bc
    0x100c96690 <+76>:  b      0x100c966d0               ; 如果都不滿足即default扶供,則跳轉(zhuǎn)到 0x100c966d0
    0x100c96694 <+80>:  adrp   x0, 1
    0x100c96698 <+84>:  add    x0, x0, #0xf29            ; =0xf29 
    0x100c9669c <+88>:  bl     0x100c96c04               ; printf("1");
    0x100c966a0 <+92>:  str    w0, [sp, #0xc]
    0x100c966a4 <+96>:  b      0x100c966e0               ; <+156> at main.m:40
    0x100c966a8 <+100>: adrp   x0, 1
    0x100c966ac <+104>: add    x0, x0, #0xf2b            ; =0xf2b 
    0x100c966b0 <+108>: bl     0x100c96c04               ; printf("2");
    0x100c966b4 <+112>: str    w0, [sp, #0x8]
    0x100c966b8 <+116>: b      0x100c966e0               ; <+156> at main.m:40
    0x100c966bc <+120>: adrp   x0, 1
    0x100c966c0 <+124>: add    x0, x0, #0xf2d            ; =0xf2d 
    0x100c966c4 <+128>: bl     0x100c96c04               ; printf("3");
    0x100c966c8 <+132>: str    w0, [sp, #0x4]
    0x100c966cc <+136>: b      0x100c966e0               ; <+156> at main.m:40
    0x100c966d0 <+140>: adrp   x0, 1
    0x100c966d4 <+144>: add    x0, x0, #0xf24            ; =0xf24 
    0x100c966d8 <+148>: bl     0x100c96c04               ; printf("else");
    0x100c966dc <+152>: str    w0, [sp]
    0x100c966e0 <+156>: ldp    x29, x30, [sp, #0x20]
    0x100c966e4 <+160>: add    sp, sp, #0x30             ; =0x30 
    0x100c966e8 <+164>: ret 

先科普一下兩個新指令:

  • cbz :【cbz 寄存器筛圆,地址 】指令的意思是 如果寄存器的值==0,則跳轉(zhuǎn)到地址椿浓,如果不等于0太援,則繼續(xù)執(zhí)行代碼
  • subs : subs其實就是sub指令,但是這個指令操作結(jié)束后扳碍,會影響到標(biāo)志寄存器

用一段最簡單的switch帶碼來介紹提岔,這一段代碼參照之前的IF語句,本質(zhì)上一點區(qū)別都沒有笋敞,就是判斷跳轉(zhuǎn)碱蒙,判斷跳轉(zhuǎn)

Switch樣式二

原C代碼如下:

void __switch_2__(){
    int value = 5;
    switch (value) {
        case 0:
            printf("1");
            break;
        case 1:
            printf("2");
            break;
        case 2:
            printf("3");
            break;
        case 3:
            printf("3");
            break;
        case 4:
            printf("4");
            break;
        default:
            printf("else");
            break;
    }
}

匯編代碼如下:

01-匯編-IF-SWITCH`__switch_2__:
    0x100be66c8 <+0>:   sub    sp, sp, #0x40             ; =0x40 
    0x100be66cc <+4>:   stp    x29, x30, [sp, #0x30]
    0x100be66d0 <+8>:   add    x29, sp, #0x30            ; =0x30 
    0x100be66d4 <+12>:  orr    w8, wzr, #0x3
    0x100be66d8 <+16>:  stur   w8, [x29, #-0x4]
    0x100be66dc <+20>:  ldur   w8, [x29, #-0x4]
    0x100be66e0 <+24>:  mov    x9, x8
    0x100be66e4 <+28>:  mov    x8, x9
    0x100be66e8 <+32>:  subs   w8, w8, #0x4              ; 如果 w8 > 0,則跳轉(zhuǎn)到 0x102fae774【加上前面的減法實際的意思就是如果w8>4的話就跳轉(zhuǎn)】
    0x100be66ec <+36>:  stur   x9, [x29, #-0x10]
    0x100be66f0 <+40>:  stur   w8, [x29, #-0x14]
    0x100be66f4 <+44>:  b.hi   0x100be6774               ; <+172> at main.m:62
    0x100be66f8 <+48>:  adrp   x8, 0
    0x100be66fc <+52>:  add    x8, x8, #0x790            ; x0 = 0x0000000100be6790
    0x100be6700 <+56>:  ldur   x9, [x29, #-0x10]
    0x100be6704 <+60>:  ldrsw  x10, [x8, x9, lsl #2]
->  0x100be6708 <+64>:  add    x8, x10, x8
    0x100be670c <+68>:  br     x8
    0x100be6710 <+72>:  adrp   x0, 1
    0x100be6714 <+76>:  add    x0, x0, #0xf29            ; =0xf29 
    0x100be6718 <+80>:  bl     0x100be6c04               ; symbol stub for: printf
    0x100be671c <+84>:  str    w0, [sp, #0x18]
    0x100be6720 <+88>:  b      0x100be6784               ; <+188> at main.m:65
    0x100be6724 <+92>:  adrp   x0, 1
    0x100be6728 <+96>:  add    x0, x0, #0xf2b            ; =0xf2b 
    0x100be672c <+100>: bl     0x100be6c04               ; symbol stub for: printf
    0x100be6730 <+104>: str    w0, [sp, #0x14]
    0x100be6734 <+108>: b      0x100be6784               ; <+188> at main.m:65
    0x100be6738 <+112>: adrp   x0, 1
    0x100be673c <+116>: add    x0, x0, #0xf2d            ; =0xf2d 
    0x100be6740 <+120>: bl     0x100be6c04               ; symbol stub for: printf
    0x100be6744 <+124>: str    w0, [sp, #0x10]
    0x100be6748 <+128>: b      0x100be6784               ; <+188> at main.m:65
    0x100be674c <+132>: adrp   x0, 1
    0x100be6750 <+136>: add    x0, x0, #0xf2d            ; =0xf2d 
    0x100be6754 <+140>: bl     0x100be6c04               ; symbol stub for: printf
    0x100be6758 <+144>: str    w0, [sp, #0xc]
    0x100be675c <+148>: b      0x100be6784               ; <+188> at main.m:65
    0x100be6760 <+152>: adrp   x0, 1
    0x100be6764 <+156>: add    x0, x0, #0xf2f            ; =0xf2f 
    0x100be6768 <+160>: bl     0x100be6c04               ; symbol stub for: printf
    0x100be676c <+164>: str    w0, [sp, #0x8]
    0x100be6770 <+168>: b      0x100be6784               ; <+188> at main.m:65
    0x100be6774 <+172>: adrp   x0, 1
    0x100be6778 <+176>: add    x0, x0, #0xf24            ; =0xf24 
    0x100be677c <+180>: bl     0x100be6c04               ; symbol stub for: printf
    0x100be6780 <+184>: str    w0, [sp, #0x4]
    0x100be6784 <+188>: ldp    x29, x30, [sp, #0x30]
    0x100be6788 <+192>: add    sp, sp, #0x40             ; =0x40 
    0x100be678c <+196>: ret    

其中的這一段匯編代碼是核心

    0x100be66f8 <+48>:  adrp   x8, 0
    0x100be66fc <+52>:  add    x8, x8, #0x790            ; x8 = 0x0000000100be6790 
    0x100be6700 <+56>:  ldur   x9, [x29, #-0x10]         ; x9 就是前面存進來的值 也就是3
    0x100be6704 <+60>:  ldrsw  x10, [x8, x9, lsl #2]     ; 取出[0x0000000100be6790 + 03 << 2],給x10
    0x100be6708 <+64>:  add    x8, x10, x8               ; 計算出要調(diào)轉(zhuǎn)的位置
    0x100be670c <+68>:  br     x8                        ; 跳轉(zhuǎn)

先科普一下adrp指令,之前在匯編(一) 中有大致介紹過
在本案例中
adrp x8, 0 :x8 = PC寄存器(0x100be66fc) 的 第十二位清零 + 0 << 12位 = 0x100be6000
接下來介紹當(dāng)分支大于3的時候赛惩,編譯器做了什么哀墓,首先編譯器會生成一個分支跳轉(zhuǎn)表,也就是我們0x100be66fc獲取到的值
我們在lldb環(huán)境下進行調(diào)試:

(lldb) memory read 0x0000000100be6790
0x100be6790: 80 ff ff ff 94 ff ff ff a8 ff ff ff bc ff ff ff  ................
0x100be67a0: d0 ff ff ff ff c3 00 d1 fd 7b 02 a9 fd 83 00 91  .........{......

能發(fā)現(xiàn)他里面幾個值分別是 0xFFFFFF80喷兼、0xFFFFFF94篮绰、0xFFFFFFBC、0xFFFFFFD0

ldrsw  x10, [x8, x9, lsl #2]  這一句是取出列表的值
add    x8, x10, x8  ;計算出跳轉(zhuǎn)的位置  0xffffffbc+0x0100be6790 = 0x0000000100be674c

0x0000000100be674c這就是我們要跳轉(zhuǎn)的地址褒搔,這樣就不需要我們?nèi)唛L的一步一步去判斷阶牍,大大提高了執(zhí)行效率
所以,當(dāng)我們實際開發(fā)的時候如果分支<=3星瘾,if與switch語句的執(zhí)行效率是一致的走孽,我們盡量在分支大于3的時候使用switch語句,當(dāng)然有時候為了可讀性琳状,這一點點效率也不用計較太多

Switch樣式三

void __switch_3__(){
    int value = 5;
    switch (value) {
        case 100:
            printf("1");
            break;
        case 4353:
            printf("2");
            break;
        case 199:
            printf("3");
            break;
        case 1:
            printf("3");
            break;
        default:
            printf("else");
            break;
    }
}

當(dāng)case的值磕瓷,不規(guī)律的時候,他的匯編代碼又會回歸到 if - else if -else ..的匯編指令【這里我就不再過多的分析匯編解釋】
所以我們寫case 必須是規(guī)律的且分支大于三的時候念逞,最能保證我們代碼的執(zhí)行效率

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末困食,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子翎承,更是在濱河造成了極大的恐慌硕盹,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,591評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件叨咖,死亡現(xiàn)場離奇詭異瘩例,居然都是意外死亡,警方通過查閱死者的電腦和手機甸各,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,448評論 3 392
  • 文/潘曉璐 我一進店門垛贤,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人趣倾,你說我怎么就攤上這事聘惦。” “怎么了儒恋?”我有些...
    開封第一講書人閱讀 162,823評論 0 353
  • 文/不壞的土叔 我叫張陵善绎,是天一觀的道長。 經(jīng)常有香客問我诫尽,道長涂邀,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,204評論 1 292
  • 正文 為了忘掉前任箱锐,我火速辦了婚禮比勉,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己浩聋,他們只是感情好观蜗,可當(dāng)我...
    茶點故事閱讀 67,228評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著衣洁,像睡著了一般墓捻。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上坊夫,一...
    開封第一講書人閱讀 51,190評論 1 299
  • 那天砖第,我揣著相機與錄音,去河邊找鬼环凿。 笑死梧兼,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的智听。 我是一名探鬼主播羽杰,決...
    沈念sama閱讀 40,078評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼到推!你這毒婦竟也來了考赛?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,923評論 0 274
  • 序言:老撾萬榮一對情侶失蹤莉测,失蹤者是張志新(化名)和其女友劉穎颜骤,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體捣卤,經(jīng)...
    沈念sama閱讀 45,334評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡忍抽,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,550評論 2 333
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了腌零。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片梯找。...
    茶點故事閱讀 39,727評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡唆阿,死狀恐怖益涧,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情驯鳖,我是刑警寧澤闲询,帶...
    沈念sama閱讀 35,428評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站浅辙,受9級特大地震影響扭弧,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜记舆,卻給世界環(huán)境...
    茶點故事閱讀 41,022評論 3 326
  • 文/蒙蒙 一鸽捻、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦御蒲、人聲如沸衣赶。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,672評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽府瞄。三九已至,卻和暖如春碘箍,著一層夾襖步出監(jiān)牢的瞬間遵馆,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,826評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人坠狡。 一個月前我還...
    沈念sama閱讀 47,734評論 2 368
  • 正文 我出身青樓馍管,卻偏偏與公主長得像,于是被迫代替她去往敵國和親遭居。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,619評論 2 354

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