MachO动态库绑定过程详解

作者: 狼性刀锋 | 来源:发表于2020-06-22 15:45 被阅读0次

    动态库绑定过程详解

    首先动态库绑定分为lazy bind 和no_lazy_bind,
    lazy bind 主要用于模块外部的函数调用,由于调用者并不是每个函数都调用,延迟绑定有利于提高动态库的加载速度
    no_lazy_bind: 主要用于模块外部调用一些全局的变量,由于通常暴露的外部变量较少,所以在启动时绑定,但少数函数除外,例如dyld_stub_binder。

    no_lazy_bind 会在程序启动之后又dynamic_link_edit完成,想要了解可以看看动态链接库的原理。

    这里主要分析一下 lazy bind过程。

    先写一段demo

    @implementation ViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        // Do any additional setup after loading the view, typically from a nib.
        [[DemoFramework new] codingLife];
        [[GoodBoy new] xuanGao];
        
        helloWorld();
        
    }
    
    
    @end
    
    

    其中helloWorld是动态库一个函数,反编译一下

                                           ; 
                                           ; Section __text
                                           ; 
                                           ; Range 0x100001680 - 0x100001a33 (947 bytes)
                                           ; File offset 5760 (947 bytes)
                                           ; Flags : 0x80000400
                                           ; 
                         -[ViewController viewDidLoad]:
    0000000100001680         push       rbp                                         ; Objective C Implementation defined at 0x1000030d8 (instance), XREF=0x1000000d0
    0000000100001681         mov        rbp, rsp
    0000000100001684         sub        rsp, 0x30
    0000000100001688         lea        rax, qword [ss:rbp+var_20]
    000000010000168c         mov        qword [ss:rbp+var_8], rdi
    0000000100001690         mov        qword [ss:rbp+var_10], rsi
    0000000100001694         mov        rsi, qword [ss:rbp+var_8]
    0000000100001698         mov        qword [ss:rbp+var_20], rsi
    000000010000169c         mov        rsi, qword [ds:0x100003cb0]                 ; 0x100003cb0
    00000001000016a3         mov        qword [ss:rbp+var_18], rsi
    00000001000016a7         mov        rsi, qword [ds:0x100003c70]                 ; @selector(viewDidLoad), argument "selector" for method imp___stubs__objc_msgSendSuper2
    00000001000016ae         mov        rdi, rax                                    ; argument "super" for method imp___stubs__objc_msgSendSuper2
    00000001000016b1         call       imp___stubs__objc_msgSendSuper2
    00000001000016b6         mov        rax, qword [ds:objc_cls_ref_DemoFramework]  ; objc_cls_ref_DemoFramework
    00000001000016bd         mov        rsi, qword [ds:0x100003c78]                 ; @selector(new), argument "selector" for method imp___got__objc_msgSend
    00000001000016c4         mov        rdi, rax
    00000001000016c7         call       qword [ds:imp___got__objc_msgSend]
    00000001000016cd         mov        rsi, qword [ds:0x100003c80]                 ; @selector(codingLife), argument "selector" for method imp___got__objc_msgSend
    00000001000016d4         mov        rdi, rax                                    ; argument "instance" for method imp___got__objc_msgSend
    00000001000016d7         mov        qword [ss:rbp+var_28], rax
    00000001000016db         call       qword [ds:imp___got__objc_msgSend]
    00000001000016e1         mov        rax, qword [ss:rbp+var_28]
    00000001000016e5         mov        rdi, rax
    00000001000016e8         call       qword [ds:imp___got__objc_release]
    00000001000016ee         mov        rax, qword [ds:objc_cls_ref_GoodBoy]        ; objc_cls_ref_GoodBoy
    00000001000016f5         mov        rsi, qword [ds:0x100003c78]                 ; @selector(new), argument "selector" for method imp___got__objc_msgSend
    00000001000016fc         mov        rdi, rax
    00000001000016ff         call       qword [ds:imp___got__objc_msgSend]
    0000000100001705         mov        rsi, qword [ds:0x100003c88]                 ; @selector(xuanGao), argument "selector" for method imp___got__objc_msgSend
    000000010000170c         mov        rdi, rax                                    ; argument "instance" for method imp___got__objc_msgSend
    000000010000170f         mov        qword [ss:rbp+var_30], rax
    0000000100001713         call       qword [ds:imp___got__objc_msgSend]
    0000000100001719         mov        rax, qword [ss:rbp+var_30]
    000000010000171d         mov        rdi, rax
    0000000100001720         call       qword [ds:imp___got__objc_release]
    0000000100001726         mov        al, 0x0
    0000000100001728         call       imp___stubs__helloWorld
    000000010000172d         add        rsp, 0x30
    0000000100001731         pop        rbp
    0000000100001732         ret        
                            ; endp
    
    

    跟踪一下 call imp___stubs__helloWorld

    
                                           ; 
                                           ; Section __stubs
                                           ; 
                                           ; Range 0x100001a34 - 0x100001a64 (48 bytes)
                                           ; File offset 6708 (48 bytes)
                                           ; Flags : 0x80000408
                                           ; 
                         imp___stubs__NSStringFromClass:
    0000000100001a34         jmp        qword [ds:imp___la_symbol_ptr__NSStringFromClass] ; XREF=0x100000120, _main+74
                            ; endp
    
    
    ================ B E G I N N I N G   O F   P R O C E D U R E ================
    
    
    
                         imp___stubs__UIApplicationMain:
    0000000100001a3a         jmp        qword [ds:imp___la_symbol_ptr__UIApplicationMain] ; XREF=_main+107
                            ; endp
    
    
    ================ B E G I N N I N G   O F   P R O C E D U R E ================
    
    
    
                         imp___stubs__helloWorld:
    0000000100001a40         jmp        qword [ds:imp___la_symbol_ptr__helloWorld]  ; XREF=-[ViewController viewDidLoad]+168
                            ; endp
    
    

    这是一个__stubs段,需要lazy_bind的函数都可以在这个段找到。

                                           ; 
                                           ; Section __la_symbol_ptr
                                           ; 
                                           ; Range 0x100003020 - 0x100003060 (64 bytes)
                                           ; File offset 12320 (64 bytes)
                                           ; Flags : 0x00000007
                                           ; 
                         imp___la_symbol_ptr__NSStringFromClass:
    0000000100003020         dq         0x0000000100001a7e                          ; XREF=0x100000488, imp___stubs__NSStringFromClass
                         imp___la_symbol_ptr__UIApplicationMain:
    0000000100003028         dq         0x0000000100001aba                          ; XREF=imp___stubs__UIApplicationMain
                         imp___la_symbol_ptr__helloWorld:
    0000000100003030         dq         0x0000000100001a74                          ; XREF=imp___stubs__helloWorld
                         imp___la_symbol_ptr__objc_autoreleasePoolPop:
    0000000100003038         dq         0x0000000100001a88                          ; XREF=imp___stubs__objc_autoreleasePoolPop
                         imp___la_symbol_ptr__objc_autoreleasePoolPush:
    0000000100003040         dq         0x0000000100001a92                          ; XREF=imp___stubs__objc_autoreleasePoolPush
                         imp___la_symbol_ptr__objc_msgSendSuper2:
    0000000100003048         dq         0x0000000100001a9c                          ; XREF=imp___stubs__objc_msgSendSuper2
                         imp___la_symbol_ptr__objc_retainAutoreleasedReturnValue:
    0000000100003050         dq         0x0000000100001aa6                          ; XREF=imp___stubs__objc_retainAutoreleasedReturnValue
                         imp___la_symbol_ptr__objc_storeStrong:
    0000000100003058         dq         0x0000000100001ab0                          ; XREF=imp___stubs__objc_storeStrong
                                           ; 
           
    
    

    __la_symbol_ptr 段,这里可以看到 imp___stubs__helloWorld = 0x0000000100001a74

    所以这段代码最终会跳转到 0x0000000100001a74

                                           ; 
                                           ; Section __stub_helper
                                           ; 
                                           ; Range 0x100001a64 - 0x100001ac4 (96 bytes)
                                           ; File offset 6756 (96 bytes)
                                           ; Flags : 0x80000400
                                           ; 
    0000000100001a64         lea        r11, qword [ds:0x100003008]                 ; 0x100003008 (imp___nl_symbol_ptr_dyld_stub_binder + 0x8), XREF=0x100000170, 0x100001a79, 0x100001a83, 0x100001a8d, 0x100001a97, 0x100001aa1, 0x100001aab, 0x100001ab5, 0x100001abf
    0000000100001a6b         push       r11
    0000000100001a6d         jmp        qword [ds:imp___nl_symbol_ptr_dyld_stub_binder]
    0000000100001a73         nop        
    0000000100001a74         push       0x32                                        ; XREF=imp___la_symbol_ptr__helloWorld
    0000000100001a79         jmp        0x100001a64
    0000000100001a7e         push       0x0                                         ; XREF=imp___la_symbol_ptr__NSStringFromClass
    0000000100001a83         jmp        0x100001a64
    0000000100001a88         push       0x44                                        ; XREF=imp___la_symbol_ptr__objc_autoreleasePoolPop
    0000000100001a8d         jmp        0x100001a64
    0000000100001a92         push       0x63                                        ; XREF=imp___la_symbol_ptr__objc_autoreleasePoolPush
    0000000100001a97         jmp        0x100001a64
    0000000100001a9c         push       0x83                                        ; XREF=imp___la_symbol_ptr__objc_msgSendSuper2
    0000000100001aa1         jmp        0x100001a64
    0000000100001aa6         push       0x9d                                        ; XREF=imp___la_symbol_ptr__objc_retainAutoreleasedReturnValue
    0000000100001aab         jmp        0x100001a64
    0000000100001ab0         push       0xc7                                        ; XREF=imp___la_symbol_ptr__objc_storeStrong
    0000000100001ab5         jmp        0x100001a64
    0000000100001aba         push       0x19                                        ; XREF=imp___la_symbol_ptr__UIApplicationMain
    0000000100001abf         jmp        0x100001a64
    

    这一段是核心代码

    0000000100001a64         lea        r11, qword [ds:0x100003008]                 ; 0x100003008 (imp___nl_symbol_ptr_dyld_stub_binder + 0x8), XREF=0x100000170, 0x100001a79, 0x100001a83, 0x100001a8d, 0x100001a97, 0x100001aa1, 0x100001aab, 0x100001ab5, 0x100001abf
    0000000100001a6b         push       r11
    0000000100001a6d         jmp        qword [ds:imp___nl_symbol_ptr_dyld_stub_binder]
    0000000100001a73         nop        
    0000000100001a74         push       0x32                                        ; XREF=imp___la_symbol_ptr__helloWorld
    0000000100001a79         jmp        0x100001a64
    
    

    仔细分析一下其实执行顺序是这样的

    0000000100001a74         push       0x32  
    0000000100001a64         lea        r11, qword [ds:0x100003008]                 ; 0x100003008 (imp___nl_symbol_ptr_dyld_stub_binder + 0x8), XREF=0x100000170, 0x100001a79, 0x100001a83, 0x100001a8d, 0x100001a97, 0x100001aa1, 0x100001aab, 0x100001ab5, 0x100001abf
    0000000100001a6b         push       r11
    0000000100001a6d         jmp        qword [ds:imp___nl_symbol_ptr_dyld_stub_binder]
    
    

    可以确定的是imp___nl_symbol_ptr_dyld_stub_binder 需要两个参数一个0x32, 一个是 qword [ds:0x100003008] 内存指针,看一下这块内存

                                       ; Section __nl_symbol_ptr
                                           ; 
                                           ; Range 0x100003000 - 0x100003010 (16 bytes)
                                           ; File offset 12288 (16 bytes)
                                           ; Flags : 0x00000006
                                           ; 
                         imp___nl_symbol_ptr_dyld_stub_binder:
    0000000100003000         dq         dyld_stub_binder                            ; XREF=0x100000398, 0x1000003e8, 0x100001a6d
    0000000100003008         dq         0x0000000000000000                          ; XREF=0x100001a64
    

    大胆推测一下其中一个可能是偏移地址一个是基地址,之后可能需要花些时间研究一下。

    整个逻辑应该是 偏移地址 + 基地址, 如果该快内存有值的话,那么就不需要查找真正的函数地址,否则则需要根据符号表去查找函数表的地址,然后写入该内存。
    在回过头追踪下这行指令:

    
    [ds:imp___nl_symbol_ptr_dyld_stub_binder]
    
    ;  imp___nl_symbol_ptr_dyld_stub_binder =  0000000100003000
    
    
    屏幕快照 2019-10-30 下午5.36.18.png

    dyld_stub_binder 没有被初始化,因为它也是动态库函数,只有在加载的时候才会初始化。

    静态分析 可执行文件结构

    加载命令 加载动态执行库、加载动态链接库
    关键函数 dyld_stub_binder

    自举: 动态链接库也是一个动态库,在加载动态库时第一件事情就是加载动态链接库,所以可怜的动态链接库只能自己加载自己,别的动态库可以通过链接器实行动态加载,这种行为称为自举。 所以它是一个有点特殊的动态链接库

    follow 动态绑定source code 梳理流程

    .got global offset table
    ._no_lazy_symbol
    ._lazy_symbol
    .dynamic_symbol_table
    got 段 global offset table
    _no_lazy_symbol
    _lazy_symbol

    dynamic_symbol_table

    相关文章

      网友评论

        本文标题:MachO动态库绑定过程详解

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