iOS逆向之旅(基础篇) — 汇编(四) — 汇编下的函数

首先我们先观察最干净的函数,做了什么

这个函数什么都没做

void _func_1_(){
}

我没来看看这个函数的调用,与函数的里面的汇编是咋样的
函数调用的汇编

0x1004228a0 <+24>:  bl     0x100422824               ; _func_1_ at main.m:13

函数执行的汇编

02-汇编-函数`_func_1_:
->  0x100422824 <+0>: ret 

函数调用的汇编就是这么简单,通过bl/ret指令实现代码块的跳转实现。
首先我们回顾一下bl/ret指令的功能

  • bl指令 跳转,将下一条执行的指令放入lr(X30)寄存器
  • ret 返回到lr寄存器所保存的地址 执行代码

我们可以直接查看寄存器看看是不是真的



当然因为这个是空的函数,所以才会看起来那么简单

接下来我们在函数里面调用别的函数试试

先看C代码

void _func_2_(){
    _func_1_();
}

函数的调用都是一样的,我们去看看函数里面发什么了什么变化

02-汇编-函数`_func_2_:
    0x1022e6810 <+0>:  stp    x29, x30, [sp, #-0x10]!
    0x1022e6814 <+4>:  mov    x29, sp
    0x1022e6818 <+8>:  bl     0x1022e680c               ; _func_1_ at main.m:13
    0x1022e681c <+12>: ldp    x29, x30, [sp], #0x10
    0x1022e6820 <+16>: ret 

接下来我们仔细观察函数发生的变化,多了以下,两句话

  stp    x29, x30, [sp, #-0x10]! // 1.把x29 和 x30存方到sp-8 sp-10的位置  2.sp -= 0x16
  ldp    x29, x30, [sp], #0x10   // 1.将sp-8 sp-10位置的值取出来,放入x29 和 x30,2.sp += 0x16

通过堆栈的操作在函数的开头保存了x30(lr),x29(fp),两个寄存器,在函数结尾的时候,又把这些值取出来,为什么要怎么做呢?
反过来想,如果不这么做,会导致什么问题?会出现一个很严重的问题!【下面纯文字解释,请耐心理解】

当我们在执行这句话的 bl 0x1022e680c 会把x30寄存器改成 0x1022e681c地址,那么 0x1022e6820这个位置的时候执行ret,代码会跳回到main函数吗?肯定是不会的,它只会跳到x30指向的位置。那么代码就会在 0x1022e681c 0x1022e6820 这两个位置不断执行,知道把堆栈弄炸,程序奔溃~~~~~~~

所以这两句汇编是为了保护代码回家的的路,以后我们在逆向别人的代码的时候,请不要不破坏~~~

接下来我们继续深入理解函数参数的传递,及返回值的返回

先上个简单的C代码

int _func_3_(int a,int b,int c,int d,int e,int f,int g,int h,int i,int j,int k,int l){
    return a+b;
}

接着上调用函数的汇编解释

02-汇编-函数`main:
    0x1028f2888 <+0>:   sub    sp, sp, #0x40             ; =0x40 
    0x1028f288c <+4>:   stp    x29, x30, [sp, #0x30]
    0x1028f2890 <+8>:   add    x29, sp, #0x30            ; =0x30 
    0x1028f2894 <+12>:  stur   wzr, [x29, #-0x4]
    0x1028f2898 <+16>:  stur   w0, [x29, #-0x8]
    0x1028f289c <+20>:  stur   x1, [x29, #-0x10]
    0x1028f28a0 <+24>:  bl     0x1028f2818               ; _func_1_ at main.m:13
    0x1028f28a4 <+28>:  bl     0x1028f281c               ; _func_2_ at main.m:15
    0x1028f28a8 <+32>:  orr    w0, wzr, #0x1             ;  ----华丽分割线-----
    0x1028f28ac <+36>:  orr    w1, wzr, #0x2
    0x1028f28b0 <+40>:  orr    w2, wzr, #0x3
    0x1028f28b4 <+44>:  orr    w3, wzr, #0x4
    0x1028f28b8 <+48>:  mov    w4, #0x5
    0x1028f28bc <+52>:  orr    w5, wzr, #0x6
    0x1028f28c0 <+56>:  orr    w6, wzr, #0x7
    0x1028f28c4 <+60>:  orr    w7, wzr, #0x8
    0x1028f28c8 <+64>:  mov    w8, #0x9
    0x1028f28cc <+68>:  mov    w9, #0xa
    0x1028f28d0 <+72>:  mov    w10, #0xb
    0x1028f28d4 <+76>:  orr    w11, wzr, #0xc
->  0x1028f28d8 <+80>:  str    w8, [sp]
    0x1028f28dc <+84>:  str    w9, [sp, #0x4]
    0x1028f28e0 <+88>:  str    w10, [sp, #0x8]
    0x1028f28e4 <+92>:  str    w11, [sp, #0xc]           ; ----华丽分割线-----
    0x1028f28e8 <+96>:  bl     0x1028f2830               ; 在这里调用_func_3_函数
    0x1028f28ec <+100>: stur   w0, [x29, #-0x14]
    0x1028f28f0 <+104>: ldur   w8, [x29, #-0x14]
    0x1028f28f4 <+108>: mov    x30, x8
    0x1028f28f8 <+112>: mov    x12, sp
    0x1028f28fc <+116>: str    x30, [x12]
    0x1028f2900 <+120>: adrp   x0, 1
    0x1028f2904 <+124>: add    x0, x0, #0xf14            ; =0xf14 
    0x1028f2908 <+128>: bl     0x1028f2bfc               ; symbol stub for: printf
    0x1028f290c <+132>: mov    w8, #0x0
    0x1028f2910 <+136>: str    w0, [sp, #0x18]
    0x1028f2914 <+140>: mov    x0, x8
    0x1028f2918 <+144>: ldp    x29, x30, [sp, #0x30]
    0x1028f291c <+148>: add    sp, sp, #0x40             ; =0x40 
    0x1028f2920 <+152>: ret  

两段华丽的分割线展示了函数的参数是如何传递的
细致不多看,直接看结果


4.png
->  0x1028f28d8 <+80>:  str    w8, [sp]
    0x1028f28dc <+84>:  str    w9, [sp, #0x4]
    0x1028f28e0 <+88>:  str    w10, [sp, #0x8]
    0x1028f28e4 <+92>:  str    w11, [sp, #0xc] 

他们把第1-第8个参数放到了x0-x7八个寄存器,第9-第12个参数,存到堆栈进行传输参数
接着我们看看返回值

02-汇编-函数`_func_3_:
    0x104d46830 <+0>:  sub    sp, sp, #0x30             ; =0x30 
    0x104d46834 <+4>:  ldr    w8, [sp, #0x3c]
    0x104d46838 <+8>:  ldr    w9, [sp, #0x38]
    0x104d4683c <+12>: ldr    w10, [sp, #0x34]
    0x104d46840 <+16>: ldr    w11, [sp, #0x30]
    0x104d46844 <+20>: str    w0, [sp, #0x2c]
    0x104d46848 <+24>: str    w1, [sp, #0x28]
    0x104d4684c <+28>: str    w2, [sp, #0x24]
    0x104d46850 <+32>: str    w3, [sp, #0x20]
    0x104d46854 <+36>: str    w4, [sp, #0x1c]
    0x104d46858 <+40>: str    w5, [sp, #0x18]
    0x104d4685c <+44>: str    w6, [sp, #0x14]
    0x104d46860 <+48>: str    w7, [sp, #0x10]
->  0x104d46864 <+52>: ldr    w0, [sp, #0x2c]
    0x104d46868 <+56>: ldr    w1, [sp, #0x28]
    0x104d4686c <+60>: add    w0, w0, w1                ; 把 w0+w1的值放到w0,也就是参数1+参数2
    0x104d46870 <+64>: str    w11, [sp, #0xc]
    0x104d46874 <+68>: str    w10, [sp, #0x8]
    0x104d46878 <+72>: str    w8, [sp, #0x4]
    0x104d4687c <+76>: str    w9, [sp]
    0x104d46880 <+80>: add    sp, sp, #0x30             ; =0x30 
    0x104d46884 <+84>: ret    

根据我上述的备注,他们吧结果放到w0,之后返回
所以我这边做个简单的总结:

  • 参数会存放到X0到X7(W0到W7)这8个寄存器里面,如果超过8个参数,就会入栈,返回值是通过x0进行返回获取
  • 由于操作堆栈会比操作寄存器更消耗性能,所以我们的参数尽可能不要超过8个

拓展:

好像了解了函数的原理之后,没啥用?不是的,这对之后的逆向很有帮助,下面简单说一下最大的用处在哪
对于了解过OC runtime的开发者来说 ,都知道OC调用函数,都是通过 objc_msgSend 来实现的


5.png

objc_msgSend的第一个参数就是对象本身,第二个参数就是SEL,后面就是传入这个SEL的具体参数
那么对于我们进行动态调试得是有多大的益处呀~~嘿嘿

资源代码:【https://github.com/qq631192328/CodeReverse

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

推荐阅读更多精彩内容

  • bl和ret指令 bl标号 将下一条指令的地址放入lr(x30)寄存器 转到标号处执行指令 注意:当我们遇到bl指...
    struggle3g阅读 7,742评论 0 1
  • 关于CPU 寄存器 CPU除了有控制器、运算器还有寄存器。其中寄存器的作用就是进行数据的临时存储。 CPU的运算速...
    CoderLWG阅读 1,384评论 0 0
  • 002--函数本质 关于CPU的补充 寄存器 CPU除了有控制器、运算器还有寄存器。其中寄存器的作用就是进行数据的...
    宵衣旰食阅读 251评论 0 0
  • 关于CPU的补充 寄存器 CPU除了有控制器、运算器还有寄存器。其中寄存器的作用就是进行数据的临时存储。 CPU的...
    lukyy阅读 487评论 0 0
  • 一、简介 CPU中央处理器,内部主要包括寄存器、运算器、控制器。 寄存器:存储数据 运算器:处理数据 控制器:控制...
    yahibo阅读 1,040评论 4 2