美文网首页
MachO的动态链接

MachO的动态链接

作者: coder_feng | 来源:发表于2020-04-23 14:00 被阅读0次

    对于存在别的动态库的函数,程序在运行的时候需要通过动态链接来获取函数的调用地址,在iOS上是通过dyld来实现的,下面来通过离子来做一下梳理

    - (void)viewDidLoad {
        [super viewDidLoad];
        // Do any additional setup after loading the view.
        NSLog(@"first call");
        NSLog(@"second call");
    }
    
    

    然后在两个NSLog都打上断点,运行。
    程序断住之后,调节成汇编模式Debug --> Debug Workflow --> Always Show Disassembly,

    留意到symbol stub for: NSLog 这句,这句就是跳转到NSLog的stub实现imp___stubs__NSLog
    我们先用image list命令来获取模块的基地址

    [ 0] 612400A7-6AEC-3714-842C-F83B079272BE 0x0000000100060000 /Users/apple/Library/Developer/Xcode/DerivedData/MachO的动态链接-dyjjhckpseuoonetiqiafxmmlsak/Build/Products/Debug-iphoneos/MachO的动态链接.app/MachO的动态链接

    0x0000000100060000 是这次运行时模块的基地址,因为iOS有ASLR,每次都会随机装到内存,随机只是偏移,并不是打乱,所以程序运行时候的及地址为:静态的基地址 + ASLR偏移,静态的基地址可以使用machOview来查看

    静态基地址 = 0000000100000000; Snip20200423_41.png

    所以这次运行的偏移地址ASLR偏移 = 0x0000000100060000 - 0000000100000000 = 0x60000

    回到刚刚的bl 0x1000e2560 ; symbol stub for: NSLog,我们可以去看看这个地址里面究竟是什么代码,先求出它对应的 静态地址=运行时地址-ASLR偏移 = 0x100066554 - 0x60000 = 0x100006554。然后用hopper打开,记住不勾选Resolve Lazy Bindings,跳转到该地址,如下

                         imp___stubs__NSLog:
    0000000100006554         nop                                                    ; CODE XREF=-[ViewController viewDidLoad]+72, -[ViewController viewDidLoad]+84
    0000000100006558         ldr        x16, #0x100008008
    000000010000655c         br         x16
    

    这几句代码是取值之后跳转,先看看#0x100008008的值,单击点进去。这里有个坑,如果你用hopper导入的时候选择了Resolve Lazy Binding,那么这个地址会解析成了符号。所以导入的时候不要选,那么可以看到这个地址的值如下:

    0000000100008008         dq         0x00000001000065fc                          ; DATA XREF=imp___stubs__NSLog+4
    
    Snip20200422_32.png

    所以上面的几句汇编的意思是跳转0x00000001000065fc这个地址,然后我们再切到这个地址看看。
    00000001000065fc ldr w16, #0x100006604 ; DATA XREF=_NSLog_ptr
    0000000100006600 b 0x1000065e4

    在这里压入一个参数之后,继续跳转到 0x1000065e4执行,继续跟入到这里,终于找到了stub_helper的调用。 Snip20200423_42.png ,然后就会进入动态绑定 Snip20200423_43.png 这个时候在终端si进入单步调试,发现第一次调用时候 Snip20200422_28.png
    NSLog方法跳转的是0x00000001000ce5fc,当第二次执行的时候,发现已经是拿到了真正的函数地址 Snip20200422_33.png

    但是这里其仍然是取的静态地址0x100008008处的值,只不过这个值已经变成了0x000000018248e598

    我们可以打印一下静态地址0x1000e2560对应的动态地址0x1000e2560+ 0x60000 = 0x100068008,确实已经变成了0x000000018248e598

    (lldb) x 0x100068008
    0x100068008: 98 e5 48 82 01 00 00 00 98 e5 47 82 01 00 00 00  ..H.......G.....
    0x100068018: 60 70 c2 87 01 00 00 00 14 66 06 00 01 00 00 00  `p.......f......
    

    然后进入0x18248e598这个地址,你会发现这里就是NSLog的函数入口

    Foundation`NSLog:
    ->  0x18248e598 <+0>:  sub    sp, sp, #0x20             ; =0x20 
        0x18248e59c <+4>:  stp    x29, x30, [sp, #0x10]
        0x18248e5a0 <+8>:  add    x29, sp, #0x10            ; =0x10 
        0x18248e5a4 <+12>: add    x8, x29, #0x10            ; =0x10 
        0x18248e5a8 <+16>: str    x8, [sp, #0x8]
        0x18248e5ac <+20>: add    x1, x29, #0x10            ; =0x10 
        0x18248e5b0 <+24>: mov    x2, x30
        0x18248e5b4 <+28>: bl     0x1825673c0               ; _NSLogv
        0x18248e5b8 <+32>: ldp    x29, x30, [sp, #0x10]
        0x18248e5bc <+36>: add    sp, sp, #0x20             ; =0x20 
        0x18248e5c0 <+40>: ret    
    

    附上刚刚image list的另外一个模块,你会发现0x000000018248e598这个地址已经是另外模块的了。

    [  2] 73FF2B76-D90F-3C90-B010-8F6E36E3B71F 0x000000018247c000 /Users/apple/Library/Developer/Xcode/iOS DeviceSupport/10.3.1 (14E304)/Symbols/System/Library/Frameworks/Foundation.framework/Foundation 
    

    这个就是MachO的懒加载符号表的加载过程。第一次调用的时候是指向stub_helper,调用完一次之后,就会修改懒加载符号指针,让其指向真正的函数地址,以后就可以直接跳转。这个可以从第一次调用和第二次调用的MachO二进制文件看到


    Snip20200422_36.png 从上面的图可以知道0x100008008 这个位置就是Lazy Symbol Pointers,并且从MachOView看到最后边的value值,0x100008008对应的就是NSLog,那这个对应关系是怎么来的呢?先看一下Dynamic Symbol Table 下的Indirect Symbols,点击右上角,搜索NSLog Snip20200423_44.png
    发现这里有两条记录,且两条记录的值是一样的,而且看MachOview解析出来的value,你会发现一个和TEXT段的_stubs 有关系,一个和DATA段的_la_symbol_ptr 有关系,这个关系是从哪里来的呢?先从_la_symbol_ptr的来说明,先找到下面的地方,section header 的_la_symbol_ptr Snip20200422_40.png
    首先Address指的是这个section的真实地址,这里你会发现Lazy Symbol Pointers的表的起始文件偏移就是这个地址减去基地址,然后是Indirect Sym Index这个字段,在代码里面是Reserved1这个属性,在MachOView里面显示的是十进制13,起始这是一个索引偏移,指的是Lazy Symbol Pointers表中对应元素的第几个,这里是13,然后Indirect Symbols么个元素是4个字节,所以这里距离Indirect Symbols表头是偏移13 * 4 = 52字节 = 0x34,然后Indirect Symbols表头的文件偏移是0xD358,两个之和0xD358 + 0x34 = 0xD38C; Snip20200423_46.png
    到这里,已经找到了Lazy Symbol Pointers表和Indirect Symbols表的对应关系,至于stubs表和Indirect Symbos表,同理可得。 跟住下来就是Indirect Symbols表是怎么找到"_NSLog" 这个字符的,留意上面的Data值000000D3,转为十进制是211,这个数值对应的就是Symbol Table的元素索引,找到Symbol Table 的第211个元素,如下图: Snip20200423_47.png
    留意Data值000000CE,这个就是string Table的偏移,继续去到String Table,它的起始文件偏移是0000D3BC Snip20200423_48.png
    然后找到文件偏移的位置,0000D3BC + 000000CE = 0xD48A
    Snip20200423_49.png

    相关文章

      网友评论

          本文标题:MachO的动态链接

          本文链接:https://www.haomeiwen.com/subject/zutoihtx.html