iOS逆向之旅(基础篇) — 汇编(三) — 汇编下的 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,则跳转到 0x100c96694,如果不等于0,则继续执行代码
    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,则跳转到 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,则跳转到  0x100c966bc
    0x100c96690 <+76>:  b      0x100c966d0               ; 如果都不满足即default,则跳转到 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,则跳转到地址,如果不等于0,则继续执行代码
  • subs : subs其实就是sub指令,但是这个指令操作结束后,会影响到标志寄存器

用一段最简单的switch带码来介绍,这一段代码参照之前的IF语句,本质上一点区别都没有,就是判断跳转,判断跳转

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,则跳转到 0x102fae774【加上前面的减法实际的意思就是如果w8>4的话就跳转】
    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               ; 计算出要调转的位置
    0x100be670c <+68>:  br     x8                        ; 跳转

先科普一下adrp指令,之前在汇编(一) 中有大致介绍过
在本案例中
adrp x8, 0 :x8 = PC寄存器(0x100be66fc) 的 第十二位清零 + 0 << 12位 = 0x100be6000
接下来介绍当分支大于3的时候,编译器做了什么,首先编译器会生成一个分支跳转表,也就是我们0x100be66fc获取到的值
我们在lldb环境下进行调试:

(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  .........{......

能发现他里面几个值分别是 0xFFFFFF80、0xFFFFFF94、0xFFFFFFBC、0xFFFFFFD0

ldrsw  x10, [x8, x9, lsl #2]  这一句是取出列表的值
add    x8, x10, x8  ;计算出跳转的位置  0xffffffbc+0x0100be6790 = 0x0000000100be674c

0x0000000100be674c这就是我们要跳转的地址,这样就不需要我们冗长的一步一步去判断,大大提高了执行效率
所以,当我们实际开发的时候如果分支<=3,if与switch语句的执行效率是一致的,我们尽量在分支大于3的时候使用switch语句,当然有时候为了可读性,这一点点效率也不用计较太多

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;
    }
}

当case的值,不规律的时候,他的汇编代码又会回归到 if - else if -else ..的汇编指令【这里我就不再过多的分析汇编解释】
所以我们写case 必须是规律的且分支大于三的时候,最能保证我们代码的执行效率

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,711评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,932评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,770评论 0 330
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,799评论 1 271
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,697评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,069评论 1 276
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,535评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,200评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,353评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,290评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,331评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,020评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,610评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,694评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,927评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,330评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,904评论 2 341

推荐阅读更多精彩内容