fishhook源码分析

作者: 阿呆少爷 | 来源:发表于2017-03-01 19:03 被阅读1619次

    最早了解到fishhook是看了下面两篇文章之后,顿时让我觉得这是一个非常好的东西。总共210行代码,收获了1500+个star,神作啊。

    1. 使用fishhook拦截NSSetUncaughtExceptionHandler函数解决NSUncaughtExceptionHandler被修改的问题。
    2. 聊聊苹果的Bug - iOS 10 nano_free Crash,通过fishhook替换malloc相关的函数尝试解决crash。

    OC的runtime非常强大,可以玩很多黑魔法。而操作系统也会提供一些基础设施,比如Solaris/Mac DTrace和Linux systemtap,通过编写脚本分析各种系统调用的情况。相比之下,C语言没有runtime,也玩不出什么花来。不过fishhook提供了一种很好的方式,让我们得以做一些有意义的工作。花了点时间研究一下fishhook的源代码,也能增加一下对Mach-O执行格式的理解。

    _dyld_register_func_for_add_image

    fishhook利用了_dyld_register_func_for_add_image在动态库加载完成之后,做一次符号地址的替换,简化了遍历逻辑。当然fishhook也支持在App启动之后遍历所有的动态库做符号替换。

    /*
     * The following functions allow you to install callbacks which will be called   
     * by dyld whenever an image is loaded or unloaded.  During a call to _dyld_register_func_for_add_image()
     * the callback func is called for every existing image.  Later, it is called as each new image
     * is loaded and bound (but initializers not yet run).  The callback registered with
     * _dyld_register_func_for_remove_image() is called after any terminators in an image are run
     * and before the image is un-memory-mapped.
     */
    extern void _dyld_register_func_for_add_image(void (*func)(const struct mach_header* mh, intptr_t vmaddr_slide))    __OSX_AVAILABLE_STARTING(__MAC_10_1, __IPHONE_2_0);
    

    我们App目前在用_dyld_register_func_for_add_image将所有要加载的动态库都在控制台打印出来了。

    Added: 0x101afe000 (0x8000) /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk/usr/lib/libBacktraceRecording.dylib <0B27D656-0E24-3133-BAA2-3B3EC2409C04> time: 1488353483592
    
    Added: 0x101b0c000 (0x8000) /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator10.2.sdk/Developer/Library/PrivateFrameworks/DTDDISupport.framework/libViewDebuggerSupport.dylib <31AD1037-C99E-3141-AAD1-CF345BA42E72> time: 1488353483592
    

    Mach-O

    Mach-O的格式如下所示。每个segment里面包含了很多section。__DATA segment的section尤其多,__la_symbol_ptr是其中一个。

    screenshot.png

    fishhook的原理是遍历__DATA segment里面__nl_symbol_ptr__la_symbol_ptr两个section里面的符号,通过Indirect Symbol Table、Symbol Table、String Table的配合,找到自己要替换的函数,然后做替换。整个过程如下所示。

    screenshot.png

    MachOView

    MachOView看Mach-O格式比较直观。

    screenshot.png

    otools && nm

    通过otools和nm也可以对可执行程序做很多分析。

    $ otool -l /Users/henshao/Library/Developer/Xcode/DerivedData/FishHookTest-elsztizpkmqzuedzxtjbslvzndzj/Build/Products/Debug-iphonesimulator/FishHookTest.app/FishHookTest  
    /Users/henshao/Library/Developer/Xcode/DerivedData/FishHookTest-elsztizpkmqzuedzxtjbslvzndzj/Build/Products/Debug-iphonesimulator/FishHookTest.app/FishHookTest:
    Mach header
          magic cputype cpusubtype  caps    filetype ncmds sizeofcmds      flags
     0xfeedfacf 16777223          3  0x00           2    20       2760 0x00200085
    Load command 0
          cmd LC_SEGMENT_64
      cmdsize 72
      segname __PAGEZERO
       vmaddr 0x0000000000000000
       vmsize 0x0000000100000000
      fileoff 0
     filesize 0
      maxprot 0x00000000
     initprot 0x00000000
       nsects 0
        flags 0x0
    Load command 1
          cmd LC_SEGMENT_64
      cmdsize 792
      segname __TEXT
       vmaddr 0x0000000100000000
       vmsize 0x0000000000004000
      fileoff 0
     filesize 16384
      maxprot 0x00000007
     initprot 0x00000005
       nsects 9
        flags 0x0
    Section
      sectname __text
       segname __TEXT
          addr 0x00000001000018c0
          size 0x0000000000000f7a
        offset 6336
         align 2^4 (16)
        reloff 0
        nreloc 0
         flags 0x80000400
     reserved1 0
     reserved2 0
    Section
      sectname __stubs
       segname __TEXT
          addr 0x000000010000283a
          size 0x0000000000000096
        offset 10298
         align 2^1 (2)
        reloff 0
        nreloc 0
         flags 0x80000408
     reserved1 0 (index into indirect symbol table)
     reserved2 6 (size of stubs)
    Section
      sectname __stub_helper
       segname __TEXT
          addr 0x00000001000028d0
          size 0x000000000000010a
        offset 10448
         align 2^2 (4)
        reloff 0
        nreloc 0
         flags 0x80000400
     reserved1 0
     reserved2 0
    Section
      sectname __objc_methname
       segname __TEXT
          addr 0x00000001000029da
          size 0x0000000000000a13
        offset 10714
         align 2^0 (1)
        reloff 0
        nreloc 0
         flags 0x00000002
     reserved1 0
     reserved2 0
    Section
      sectname __objc_classname
       segname __TEXT
          addr 0x00000001000033ed
          size 0x000000000000003c
        offset 13293
         align 2^0 (1)
        reloff 0
        nreloc 0
         flags 0x00000002
     reserved1 0
     reserved2 0
    Section
      sectname __objc_methtype
       segname __TEXT
          addr 0x0000000100003429
          size 0x000000000000082a
        offset 13353
         align 2^0 (1)
        reloff 0
        nreloc 0
         flags 0x00000002
     reserved1 0
     reserved2 0
    Section
      sectname __cstring
       segname __TEXT
          addr 0x0000000100003c53
          size 0x00000000000001cb
        offset 15443
         align 2^0 (1)
        reloff 0
        nreloc 0
         flags 0x00000002
     reserved1 0
     reserved2 0
    Section
      sectname __entitlements
       segname __TEXT
          addr 0x0000000100003e1e
          size 0x0000000000000190
        offset 15902
         align 2^0 (1)
        reloff 0
        nreloc 0
         flags 0x00000000
     reserved1 0
     reserved2 0
    Section
      sectname __unwind_info
       segname __TEXT
          addr 0x0000000100003fb0
          size 0x0000000000000050
        offset 16304
         align 2^2 (4)
        reloff 0
        nreloc 0
         flags 0x00000000
     reserved1 0
     reserved2 0
    Load command 2
          cmd LC_SEGMENT_64
      cmdsize 1192
      segname __DATA
       vmaddr 0x0000000100004000
       vmsize 0x0000000000001000
      fileoff 16384
     filesize 4096
      maxprot 0x00000007
     initprot 0x00000003
       nsects 14
        flags 0x0
    Section
      sectname __nl_symbol_ptr
       segname __DATA
          addr 0x0000000100004000
          size 0x0000000000000010
        offset 16384
         align 2^3 (8)
        reloff 0
        nreloc 0
         flags 0x00000006
     reserved1 25 (index into indirect symbol table)
     reserved2 0
    Section
      sectname __got
       segname __DATA
          addr 0x0000000100004010
          size 0x0000000000000008
        offset 16400
         align 2^3 (8)
        reloff 0
        nreloc 0
         flags 0x00000006
     reserved1 27 (index into indirect symbol table)
     reserved2 0
    Section
      sectname __la_symbol_ptr
       segname __DATA
          addr 0x0000000100004018
          size 0x00000000000000c8 //0xc8 = 200,200/8=25。
        offset 16408
         align 2^3 (8)
        reloff 0
        nreloc 0
         flags 0x00000007
     reserved1 28 (index into indirect symbol table)
     reserved2 0
    Section
      sectname __objc_classlist
       segname __DATA
          addr 0x00000001000040e0
          size 0x0000000000000010
        offset 16608
         align 2^3 (8)
        reloff 0
        nreloc 0
         flags 0x10000000
     reserved1 0
     reserved2 0
    Section
      sectname __objc_protolist
       segname __DATA
          addr 0x00000001000040f0
          size 0x0000000000000010
        offset 16624
         align 2^3 (8)
        reloff 0
        nreloc 0
         flags 0x00000000
     reserved1 0
     reserved2 0
    Section
      sectname __objc_imageinfo
       segname __DATA
          addr 0x0000000100004100
          size 0x0000000000000008
        offset 16640
         align 2^2 (4)
        reloff 0
        nreloc 0
         flags 0x00000000
     reserved1 0
     reserved2 0
    Section
      sectname __objc_const
       segname __DATA
          addr 0x0000000100004108
          size 0x0000000000000be0
        offset 16648
         align 2^3 (8)
        reloff 0
        nreloc 0
         flags 0x00000000
     reserved1 0
     reserved2 0
    Section
      sectname __objc_selrefs
       segname __DATA
          addr 0x0000000100004ce8
          size 0x0000000000000018
        offset 19688
         align 2^3 (8)
        reloff 0
        nreloc 0
         flags 0x10000005
     reserved1 0
     reserved2 0
    Section
      sectname __objc_classrefs
       segname __DATA
          addr 0x0000000100004d00
          size 0x0000000000000008
        offset 19712
         align 2^3 (8)
        reloff 0
        nreloc 0
         flags 0x10000000
     reserved1 0
     reserved2 0
    Section
      sectname __objc_superrefs
       segname __DATA
          addr 0x0000000100004d08
          size 0x0000000000000008
        offset 19720
         align 2^3 (8)
        reloff 0
        nreloc 0
         flags 0x10000000
     reserved1 0
     reserved2 0
    Section
      sectname __objc_ivar
       segname __DATA
          addr 0x0000000100004d10
          size 0x0000000000000008
        offset 19728
         align 2^3 (8)
        reloff 0
        nreloc 0
         flags 0x00000000
     reserved1 0
     reserved2 0
    Section
      sectname __objc_data
       segname __DATA
          addr 0x0000000100004d18
          size 0x00000000000000a0
        offset 19736
         align 2^3 (8)
        reloff 0
        nreloc 0
         flags 0x00000000
     reserved1 0
     reserved2 0
    Section
      sectname __data
       segname __DATA
          addr 0x0000000100004db8
          size 0x00000000000000c0
        offset 19896
         align 2^3 (8)
        reloff 0
        nreloc 0
         flags 0x00000000
     reserved1 0
     reserved2 0
    Section
      sectname __bss
       segname __DATA
          addr 0x0000000100004e78
          size 0x0000000000000018
        offset 0
         align 2^3 (8)
        reloff 0
        nreloc 0
         flags 0x00000001
     reserved1 0
     reserved2 0
    Load command 3
          cmd LC_SEGMENT_64
      cmdsize 72
      segname __LINKEDIT
       vmaddr 0x0000000100005000
       vmsize 0x0000000000005000
      fileoff 20480
     filesize 17040
      maxprot 0x00000007
     initprot 0x00000001
       nsects 0
        flags 0x0
    Load command 4
                cmd LC_DYLD_INFO_ONLY
            cmdsize 48
         rebase_off 20480
        rebase_size 200
           bind_off 20680
          bind_size 296
      weak_bind_off 0
     weak_bind_size 0
      lazy_bind_off 20976
     lazy_bind_size 568
         export_off 21544
        export_size 200
    Load command 5
         cmd LC_SYMTAB
     cmdsize 24
      symoff 21776
       nsyms 162
      stroff 24580
     strsize 3152
    Load command 6
                cmd LC_DYSYMTAB
            cmdsize 80
          ilocalsym 0
          nlocalsym 121
         iextdefsym 121
         nextdefsym 8
          iundefsym 129
          nundefsym 33
             tocoff 0
               ntoc 0
          modtaboff 0
            nmodtab 0
       extrefsymoff 0
        nextrefsyms 0
     indirectsymoff 24368
      nindirectsyms 53
          extreloff 0
            nextrel 0
          locreloff 0
            nlocrel 0
    Load command 7
              cmd LC_LOAD_DYLINKER
          cmdsize 32
             name /usr/lib/dyld (offset 12)
    Load command 8
         cmd LC_UUID
     cmdsize 24
        uuid 0F497FE2-E79F-3376-BCFE-3E51F2AB6112
    Load command 9
          cmd LC_VERSION_MIN_IPHONEOS
      cmdsize 16
      version 10.2
          sdk 10.2
    Load command 10
          cmd LC_SOURCE_VERSION
      cmdsize 16
      version 0.0
    Load command 11
           cmd LC_MAIN
       cmdsize 24
      entryoff 9920
     stacksize 0
    Load command 12
              cmd LC_LOAD_DYLIB
          cmdsize 88
             name /System/Library/Frameworks/Foundation.framework/Foundation (offset 24)
       time stamp 2 Thu Jan  1 08:00:02 1970
          current version 1349.13.0
    compatibility version 300.0.0
    Load command 13
              cmd LC_LOAD_DYLIB
          cmdsize 56
             name /usr/lib/libobjc.A.dylib (offset 24)
       time stamp 2 Thu Jan  1 08:00:02 1970
          current version 228.0.0
    compatibility version 1.0.0
    Load command 14
              cmd LC_LOAD_DYLIB
          cmdsize 56
             name /usr/lib/libSystem.dylib (offset 24)
       time stamp 2 Thu Jan  1 08:00:02 1970
          current version 1238.0.0
    compatibility version 1.0.0
    Load command 15
              cmd LC_LOAD_DYLIB
          cmdsize 80
             name /System/Library/Frameworks/UIKit.framework/UIKit (offset 24)
       time stamp 2 Thu Jan  1 08:00:02 1970
          current version 3600.6.21
    compatibility version 1.0.0
    Load command 16
              cmd LC_RPATH
          cmdsize 40
             path @executable_path/Frameworks (offset 12)
    Load command 17
          cmd LC_FUNCTION_STARTS
      cmdsize 16
      dataoff 21744
     datasize 32
    Load command 18
          cmd LC_DATA_IN_CODE
      cmdsize 16
      dataoff 21776
     datasize 0
    Load command 19
          cmd LC_CODE_SIGNATURE
      cmdsize 16
      dataoff 27744
     datasize 9776
    
    #这里面_OBJC_CLASS_xxx都是外部符号。还有些依赖的函数不在__la_symbol_ptr里面,比如___stack_chk_guard和dyld_stub_binder。
    $ nm -um /Users/henshao/Library/Developer/Xcode/DerivedData/FishHookTest-elsztizpkmqzuedzxtjbslvzndzj/Build/Products/Debug-iphonesimulator/FishHookTest.app/FishHookTest 
                     (undefined) external _NSStringFromClass (from Foundation)
                     (undefined) external _OBJC_CLASS_$_UIResponder (from UIKit)
                     (undefined) external _OBJC_CLASS_$_UIViewController (from UIKit)
                     (undefined) external _OBJC_METACLASS_$_NSObject (from libobjc)
                     (undefined) external _OBJC_METACLASS_$_UIResponder (from UIKit)
                     (undefined) external _OBJC_METACLASS_$_UIViewController (from UIKit)
                     (undefined) external _UIApplicationMain (from UIKit)
                     (undefined) external ___memcpy_chk (from libSystem)
                     (undefined) external ___stack_chk_fail (from libSystem)
                     (undefined) external ___stack_chk_guard (from libSystem)
                     (undefined) external __dyld_get_image_header (from libSystem)
                     (undefined) external __dyld_get_image_vmaddr_slide (from libSystem)
                     (undefined) external __dyld_image_count (from libSystem)
                     (undefined) external __dyld_register_func_for_add_image (from libSystem)
                     (undefined) external __objc_empty_cache (from libobjc)
                     (undefined) external _close (from libSystem)
                     (undefined) external _dladdr (from libSystem)
                     (undefined) external _free (from libSystem)
                     (undefined) external _malloc (from libSystem)
                     (undefined) external _memset (from libSystem)
                     (undefined) external _objc_autoreleasePoolPop (from libobjc)
                     (undefined) external _objc_autoreleasePoolPush (from libobjc)
                     (undefined) external _objc_msgSend (from libobjc)
                     (undefined) external _objc_msgSendSuper2 (from libobjc)
                     (undefined) external _objc_release (from libobjc)
                     (undefined) external _objc_retainAutoreleasedReturnValue (from libobjc)
                     (undefined) external _objc_storeStrong (from libobjc)
                     (undefined) external _open (from libSystem)
                     (undefined) external _printf (from libSystem)
                     (undefined) external _read (from libSystem)
                     (undefined) external _strcmp (from libSystem)
                     (undefined) external _strnlen (from libSystem)
                     (undefined) external dyld_stub_binder (from libSystem)
    

    一点点注释

    #import "fishhook.h"
    #import <stdio.h>
    
    #import <dlfcn.h>
    #import <stdlib.h>
    #import <string.h>
    #import <sys/types.h>
    #import <mach-o/dyld.h>
    #import <mach-o/loader.h>
    #import <mach-o/nlist.h>
    
    #ifdef __LP64__
    typedef struct mach_header_64 mach_header_t;
    typedef struct segment_command_64 segment_command_t;
    typedef struct section_64 section_t;
    typedef struct nlist_64 nlist_t;
    #define LC_SEGMENT_ARCH_DEPENDENT LC_SEGMENT_64
    #else
    typedef struct mach_header mach_header_t;
    typedef struct segment_command segment_command_t;
    typedef struct section section_t;
    typedef struct nlist nlist_t;
    #define LC_SEGMENT_ARCH_DEPENDENT LC_SEGMENT
    #endif
    
    #ifndef SEG_DATA_CONST
    #define SEG_DATA_CONST  "__DATA_CONST"
    #endif
    
    struct rebindings_entry {
        struct rebinding *rebindings;
        size_t rebindings_nel;
        struct rebindings_entry *next;
    };
    
    static struct rebindings_entry *_rebindings_head;
    
    static int prepend_rebindings(struct rebindings_entry **rebindings_head,
                                  struct rebinding rebindings[],
                                  size_t nel) {
        struct rebindings_entry *new_entry = malloc(sizeof(struct rebindings_entry));
        if (!new_entry) {
            return -1;
        }
        new_entry->rebindings = malloc(sizeof(struct rebinding) * nel);
        if (!new_entry->rebindings) {
            free(new_entry);
            return -1;
        }
        memcpy(new_entry->rebindings, rebindings, sizeof(struct rebinding) * nel);
        new_entry->rebindings_nel = nel;
        new_entry->next = *rebindings_head;
        *rebindings_head = new_entry;
        return 0;
    }
    
    static void perform_rebinding_with_section(struct rebindings_entry *rebindings,
                                               section_t *section,
                                               intptr_t slide,
                                               nlist_t *symtab,
                                               char *strtab,
                                               uint32_t *indirect_symtab) {
        printf("size: %llu\n", section->size);
    
        uint32_t *indirect_symbol_indices = indirect_symtab + section->reserved1;
    
        //slide+section->addr 就是符号地址的数组
        void **indirect_symbol_bindings = (void **)((uintptr_t)slide + section->addr);
    
        //遍历section里面的每一个符号
        for (uint i = 0; i < section->size / sizeof(void *); i++) {
    
            //找到符号在Indrect Symbol Table表中的值
            uint32_t symtab_index = indirect_symbol_indices[i];
            if (symtab_index == INDIRECT_SYMBOL_ABS || symtab_index == INDIRECT_SYMBOL_LOCAL ||
                symtab_index == (INDIRECT_SYMBOL_LOCAL   | INDIRECT_SYMBOL_ABS)) {
                continue;
            }
    
            //接着去symbol table里面找到符号的值,进一步获取到符号在String Table的名字。
            uint32_t strtab_offset = symtab[symtab_index].n_un.n_strx;
            char *symbol_name = strtab + strtab_offset;
            if (strnlen(symbol_name, 2) < 2) {
                continue;
            }
    
            printf("symbol_name: %s\n", symbol_name);
    
            struct rebindings_entry *cur = rebindings;
            while (cur) {
                for (uint j = 0; j < cur->rebindings_nel; j++) {
                    if (strcmp(&symbol_name[1], cur->rebindings[j].name) == 0) {
                        if (cur->rebindings[j].replaced != NULL &&
                            indirect_symbol_bindings[i] != cur->rebindings[j].replacement) {
    
                            //把函数原来的地址保存起来
                            *(cur->rebindings[j].replaced) = indirect_symbol_bindings[i];
                        }
    
                        //将新函数的地址设置上
                        indirect_symbol_bindings[i] = cur->rebindings[j].replacement;
                        goto symbol_loop;
                    }
                }
                cur = cur->next;
            }
        symbol_loop:;
        }
    }
    
    static void rebind_symbols_for_image(struct rebindings_entry *rebindings,
                                         const struct mach_header *header,
                                         intptr_t slide) {
        Dl_info info;
        if (dladdr(header, &info) == 0) {
            return;
        }
    
        segment_command_t *cur_seg_cmd;
        segment_command_t *linkedit_segment = NULL;
        struct symtab_command* symtab_cmd = NULL;
        struct dysymtab_command* dysymtab_cmd = NULL;
    
        //遍历Mach-O的segment非常有意思,要通过Load Command来遍历。
    
        //从下面的代码来看,SEG_LINKEDIT这个segment非常重要,Indirect Symbol Table、Symbol Table、String Table的地址都要基于它获取。
        uintptr_t cur = (uintptr_t)header + sizeof(mach_header_t);
        for (uint i = 0; i < header->ncmds; i++, cur += cur_seg_cmd->cmdsize) {
            cur_seg_cmd = (segment_command_t *)cur;
            if (cur_seg_cmd->cmd == LC_SEGMENT_ARCH_DEPENDENT) {
                if (strcmp(cur_seg_cmd->segname, SEG_LINKEDIT) == 0) {
                    linkedit_segment = cur_seg_cmd;
                }
            } else if (cur_seg_cmd->cmd == LC_SYMTAB) {
                symtab_cmd = (struct symtab_command*)cur_seg_cmd;
            } else if (cur_seg_cmd->cmd == LC_DYSYMTAB) {
                dysymtab_cmd = (struct dysymtab_command*)cur_seg_cmd;
            }
        }
    
        if (!symtab_cmd || !dysymtab_cmd || !linkedit_segment ||
            !dysymtab_cmd->nindirectsyms) {
            return;
        }
    
        // Find base symbol/string table addresses
        uintptr_t linkedit_base = (uintptr_t)slide + linkedit_segment->vmaddr - linkedit_segment->fileoff;
    
        //linkedit_base+symtab_cmd->symoff是Symbol Table的位置
        nlist_t *symtab = (nlist_t *)(linkedit_base + symtab_cmd->symoff);
    
        //linkedit_base+symtab_cmd->stroff是String Table的位置
        char *strtab = (char *)(linkedit_base + symtab_cmd->stroff);
    
        // Get indirect symbol table (array of uint32_t indices into symbol table)
        uint32_t *indirect_symtab = (uint32_t *)(linkedit_base + dysymtab_cmd->indirectsymoff);
    
        cur = (uintptr_t)header + sizeof(mach_header_t);
        for (uint i = 0; i < header->ncmds; i++, cur += cur_seg_cmd->cmdsize) {
            cur_seg_cmd = (segment_command_t *)cur;
            if (cur_seg_cmd->cmd == LC_SEGMENT_ARCH_DEPENDENT) {
    
                //找到DATA和DATA_CONST segment
                if (strcmp(cur_seg_cmd->segname, SEG_DATA) != 0 &&
                    strcmp(cur_seg_cmd->segname, SEG_DATA_CONST) != 0) {
                    continue;
                }
    
                for (uint j = 0; j < cur_seg_cmd->nsects; j++) {
    
                    //找到__nl_symbol_ptr和__la_symbol_ptr这两个section
                    section_t *sect =
                    (section_t *)(cur + sizeof(segment_command_t)) + j;
                    if ((sect->flags & SECTION_TYPE) == S_LAZY_SYMBOL_POINTERS) {
                        perform_rebinding_with_section(rebindings, sect, slide, symtab, strtab, indirect_symtab);
                    }
                    if ((sect->flags & SECTION_TYPE) == S_NON_LAZY_SYMBOL_POINTERS) {
                        perform_rebinding_with_section(rebindings, sect, slide, symtab, strtab, indirect_symtab);
                    }
                }
            }
        }
    }
    
    //完成动态库的binding之后,会回调这个函数。其中slide跟ALSR(Address space layout randomization)有关系,是一个随机的加载地址。
    static void _rebind_symbols_for_image(const struct mach_header *header,
                                          intptr_t slide) {
    
        Dl_info image_info;
        int result = dladdr(header, &image_info);
        if (result == 0) {
            printf("Could not print info for mach_header: %p\n\n", header);
            return;
        }
        printf("added dylib: %s\n", image_info.dli_fname);
    
        rebind_symbols_for_image(_rebindings_head, header, slide);
    }
    
    int rebind_symbols_image(void *header,
                             intptr_t slide,
                             struct rebinding rebindings[],
                             size_t rebindings_nel) {
        struct rebindings_entry *rebindings_head = NULL;
        int retval = prepend_rebindings(&rebindings_head, rebindings, rebindings_nel);
        rebind_symbols_for_image(rebindings_head, header, slide);
        free(rebindings_head);
        return retval;
    }
    
    int rebind_symbols(struct rebinding rebindings[], size_t rebindings_nel) {
        int retval = prepend_rebindings(&_rebindings_head, rebindings, rebindings_nel);
        if (retval < 0) {
            return retval;
        }
        // If this was the first call, register callback for image additions (which is also invoked for
        // existing images, otherwise, just run on existing images
        if (!_rebindings_head->next) {
    
            //启动的时候做函数替换
            _dyld_register_func_for_add_image(_rebind_symbols_for_image);
        } else {
            uint32_t c = _dyld_image_count();
            for (uint32_t i = 0; i < c; i++) {
    
                //启动之后也可以做函数替换,非常强大。
                _rebind_symbols_for_image(_dyld_get_image_header(i), _dyld_get_image_vmaddr_slide(i));
            }
        }
        return retval;
    }
    

    通过日志可以看出,主程序和所有动态库的open和close都被替换掉了。

    dylib: /Users/henshao/Library/Developer/CoreSimulator/Devices/BFC573F8-E181-4C9F-92CC-87F5E06F5B3C/data/Containers/Bundle/Application/C1226A56-043D-4029-B034-2B8D85C1D3CE/FishHookTest.app/FishHookTest
    
    sectname: __nl_symbol_ptr, segname: __DATA
    size: 16
    symbol_name: dyld_stub_binder
    
    sectname: __got, segname: __DATA
    size: 8
    symbol_name: ___stack_chk_guard
    
    sectname: __la_symbol_ptr, segname: __DATA
    size: 200
    symbol_name: _NSStringFromClass
    symbol_name: _objc_autoreleasePoolPop
    symbol_name: _objc_autoreleasePoolPush
    symbol_name: _objc_msgSend
    symbol_name: _objc_msgSendSuper2
    symbol_name: _objc_release
    symbol_name: _objc_retainAutoreleasedReturnValue
    symbol_name: _objc_storeStrong
    symbol_name: ___memcpy_chk
    symbol_name: ___stack_chk_fail
    symbol_name: __dyld_get_image_header
    symbol_name: __dyld_get_image_vmaddr_slide
    symbol_name: __dyld_image_count
    symbol_name: __dyld_register_func_for_add_image
    symbol_name: _close
    symbol_name: _dladdr
    symbol_name: _free
    symbol_name: _malloc
    symbol_name: _memset
    symbol_name: _open
    symbol_name: _printf
    symbol_name: _read
    symbol_name: _strcmp
    symbol_name: _strnlen
    symbol_name: _UIApplicationMain
    

    参考文章

    1. fishhook 源码分析
    2. Mach-O的动态链接相关知识
    3. 趣探 Mach-O:文件格式分析
    4. 趣探 Mach-O:加载过程
    5. 通过 GDB 调试理解 GOT/PLT
    6. DTrace

    相关文章

      网友评论

        本文标题:fishhook源码分析

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