零时

//
//  _OVWork.cpp
//  asm
//
//  Created by 罗何 on 16/12/20.
//  Copyright © 2016年 罗何. All rights reserved.
//

#import <UIKit/UIKit.h>


#include <string>
#include <vector>
#include <set>
#include <map>

#include <mach-o/arch.h>
#include <mach-o/loader.h>
#include <mach-o/fat.h>
#include <mach-o/nlist.h>
#include <mach-o/reloc.h>

#if !__x86_64__ || !__i386__
#include "x86_64_reloc.h"
#endif

#include <mach-o/arm/reloc.h>
#include <mach-o/arm64/reloc.h>
#include <mach-o/ranlib.h>
#include <mach-o/compact_unwind_encoding.h>
#include <mach-o/swap.h>

#import <objc/runtime.h>

#include <pthread.h>
#include <dlfcn.h>
#include <err.h>
#include <sys/mman.h>
#include <mach/mach_init.h>
#include <mach/mach_host.h>
#include <algorithm>

static int _get_main_cup_type(int *sub_type){
    *sub_type = -1;
    host_basic_info_data_t hostInfo;
    mach_msg_type_number_t infoCount = HOST_BASIC_INFO_COUNT;
    kern_return_t ret = host_info(mach_host_self(),HOST_BASIC_INFO,(host_info_t)&hostInfo,&infoCount);
    return ret == KERN_SUCCESS ?(*sub_type = hostInfo.cpu_subtype,hostInfo.cpu_type ): -1;
}

#define MY_MMAP         ((void * (*)(void *,size_t, int, int, int, off_t))dlsym(RTLD_DEFAULT, "mmap"))
#define MY_MPROTECT     ((int (*)(void *,size_t,int))dlsym(RTLD_DEFAULT, "mprotect"))
#define MY_MUNMAP       ((int (*)(void *,size_t))dlsym(RTLD_DEFAULT, "munmap"))

#define MATCH_STRUCT(obj,location) \
    struct obj const * obj = (struct obj *)(bytes + location);

static uint8_t read_uint8(NSRange &range,uint8_t *bytes){
    uint8_t buffer = *(uint8_t *)(bytes + NSMaxRange(range));
    range = NSMakeRange(NSMaxRange(range),sizeof(uint8_t));
    return buffer;
}

static uint16_t read_uint16(NSRange &range,uint8_t *bytes){
    uint16_t buffer = *(uint16_t *)(bytes + NSMaxRange(range));
    range = NSMakeRange(NSMaxRange(range),sizeof(uint16_t));
    return buffer;
}

static uint32_t read_uint32(NSRange &range,uint8_t *bytes){
    uint32_t buffer = *(uint32_t *)(bytes + NSMaxRange(range));
    range = NSMakeRange(NSMaxRange(range),sizeof(uint32_t));
    return buffer;
}

static uint64_t read_uint64(NSRange &range,uint8_t *bytes){
    uint64_t buffer = *(uint64_t *)(bytes + NSMaxRange(range));
    range = NSMakeRange(NSMaxRange(range),sizeof(uint64_t));
    return buffer;
}

static int8_t read_int8(NSRange &range,uint8_t *bytes){
    int8_t buffer = *(int8_t *)(bytes + NSMaxRange(range));
    range = NSMakeRange(NSMaxRange(range),sizeof(int8_t));
    return buffer;
}

static int16_t read_int16(NSRange &range,uint8_t *bytes){
    int16_t buffer = *(int16_t *)(bytes + NSMaxRange(range));
    range = NSMakeRange(NSMaxRange(range),sizeof(int16_t));
    return buffer;
}

static int32_t read_int32(NSRange &range,uint8_t *bytes){
    int32_t buffer = *(int32_t *)(bytes + NSMaxRange(range));
    range = NSMakeRange(NSMaxRange(range),sizeof(int32_t));
    return buffer;
}

static int64_t read_int64(NSRange &range,uint8_t *bytes){
    int64_t buffer = *(int64_t *)(bytes + NSMaxRange(range));
    range = NSMakeRange(NSMaxRange(range),sizeof(int64_t));
    return buffer;
}

static uint64_t read_sleb128(NSRange &range,uint8_t *bytes){
    range.location = NSMaxRange(range);
    uint8_t * p = bytes + range.location, *start = p;
    
    int64_t result = 0;
    int bit = 0;
    uint8_t byte;
    
    do {
        byte = *p++;
        result |= ((byte & 0x7f) << bit);
        bit += 7;
    } while (byte & 0x80);
    
    // sign extend negative numbers
    if ( (byte & 0x40) != 0 )
    {
        result |= (-1LL) << bit;
    }
    
    range.length = (p - start);
    return result;
}

static uint64_t read_uleb128(NSRange &range,uint8_t *bytes){
    range.location = NSMaxRange(range);
    uint8_t * p = bytes + range.location, *start = p;
    
    uint64_t result = 0;
    int bit = 0;
    
    do {
        uint64_t slice = *p & 0x7f;
        
        if (bit >= 64 || slice << bit >> bit != slice)
            [NSException raise:@"uleb128 error" format:@"uleb128 too big"];
        else {
            result |= (slice << bit);
            bit += 7;
        }
    }
    while (*p++ & 0x80);
    
    range.length = (p - start);
    return result;
}

const char *read_string(NSRange &range,uint8_t *bytes){
    range.location = NSMaxRange(range);
    const char *string = (const char *)(bytes + range.location);
    range.length = strlen(string) + 1;
    return string;
}

static uint64_t alignMem(uint64_t p, uint64_t a) {
    a--;
    return (p + a) & ~a;
}

static void undefinedFunction() {
    fprintf(stderr, "Undefined function called\n");
    abort();
}

//------------------------------------------------//

static void doRebase(uint64_t address,uint64_t slider,std::vector<uint64_t> &sel_ref){
    uint8_t **ptr = (uint8_t **)(slider + address);
    std::vector<uint64_t>::iterator iter = std::find(sel_ref.begin(), sel_ref.end(), (uint64_t)*ptr);
    if(iter != sel_ref.end()){
        const char *real_name = (const char *)(slider + *ptr);
        char * exisit_sel = (char *)sel_getUid(real_name);
        if(!exisit_sel){ exisit_sel = (char *)sel_registerName(real_name); }
        *ptr = (uint8_t *)exisit_sel;
    }else{
        *ptr += slider;
    }
}

static void doBind(uint64_t address,uint64_t addend,uint64_t slide,const char *symbolName){
    if(symbolName && symbolName[0]=='_'){
        const char *sym_string = symbolName + 1;
        
        int8_t **ptr = (int8_t **)(slide + address);
        int8_t*  sym = (int8_t*)dlsym(RTLD_DEFAULT, sym_string);
        if(!sym){
            sym = (int8_t*)&undefinedFunction;
        }
        sym += addend;
        *ptr = sym;
    }
}

enum BindNodeType {NodeTypeBind, NodeTypeWeakBind, NodeTypeLazyBind};

void createBinding(uint64_t slide,uint32_t location,uint32_t length,uint64_t baseAddress,bool is_64,uint8_t *bytes,uint32_t ncmds,uint64_t segmentOffset,BindNodeType nodeType,
                   std::map<uint64_t,std::pair<uint32_t,const char *> > &bind_64,
                   std::map<uint64_t,std::pair<uint32_t,const char *> > &bind){
    NSRange range = NSMakeRange(location,0);
    BOOL isDone = NO;
    int32_t libOrdinal = 0;
    uint32_t type = 0;
    int64_t addend = 0;
    const char * symbolName = nil;
    uint32_t symbolFlags = 0;
    uint32_t doBindLocation = location;
    uint64_t ptrSize = (!is_64 ? sizeof(uint32_t) : sizeof(uint64_t));
    uint64_t address = baseAddress;
    
    while (NSMaxRange(range) < location + length && isDone == NO) {
        uint8_t byte = *(bytes + NSMaxRange(range));
        range  = NSMakeRange(NSMaxRange(range), sizeof(uint8_t));
        uint8_t opcode = byte & BIND_OPCODE_MASK;
        uint8_t immediate = byte & BIND_IMMEDIATE_MASK;
        
        switch (opcode) {
            case BIND_OPCODE_DONE:
                if(nodeType != NodeTypeLazyBind){
                    isDone = YES;
                }
                doBindLocation = NSMaxRange(range);
                break;
            case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM:
                libOrdinal = immediate;
                break;
                
            case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB:
                libOrdinal = read_uleb128(range,bytes);
                break;
                
            case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM: {
                if (immediate == 0) { libOrdinal = 0; }
                else {
                    int8_t signExtended = immediate | BIND_OPCODE_MASK; // This sign extends the value
                    libOrdinal = signExtended;
                }
            } break;
                
            case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM:
                symbolFlags = immediate;
                symbolName = read_string(range, bytes);
                break;
                
            case BIND_OPCODE_SET_TYPE_IMM:
                type = immediate;
                break;
                
            case BIND_OPCODE_SET_ADDEND_SLEB:
                addend = read_sleb128(range,bytes);
                break;
                
            case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB: {
                uint32_t segmentIndex = immediate;
                uint64_t val = read_uleb128(range,bytes);
                if (segmentIndex >= ncmds){
                    [NSException raise:@"Segment" format:@"index is out of range %u", segmentIndex];
                }

                for(uint32_t i = 0;i < ncmds;i++){
                    MATCH_STRUCT(load_command,segmentOffset)
                    if(i == segmentIndex){
                        switch (load_command->cmd) {
                            case LC_SEGMENT:{
                                MATCH_STRUCT(segment_command, segmentOffset)
                                address = segment_command->vmaddr + val;
                            }break;
                            case LC_SEGMENT_64:{
                                MATCH_STRUCT(segment_command_64,segmentOffset)
                                address = segment_command_64->vmaddr + val;
                            }break;
                            default:break;
                        }
                    }
                    segmentOffset += load_command->cmdsize;
                }
            } break;
                
            case BIND_OPCODE_ADD_ADDR_ULEB: {
                uint64_t val = read_uleb128(range,bytes);
                address += val;
            } break;
                
            case BIND_OPCODE_DO_BIND: {
//                is_64 ? bind_64.insert(std::make_pair(address, std::make_pair(addend, symbolName))) : bind.insert(std::make_pair(address, std::make_pair(addend, symbolName)));
                doBind(address, addend, slide, symbolName);
                
                doBindLocation = NSMaxRange(range);
                address += ptrSize;
            } break;
                
            case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB: {
                uint32_t startNextBind = NSMaxRange(range);
                uint64_t val = read_uleb128(range,bytes);
//                is_64 ? bind_64.insert(std::make_pair(address, std::make_pair(addend, symbolName))) : bind.insert(std::make_pair(address, std::make_pair(addend, symbolName)));
                doBind(address, addend, slide, symbolName);
                doBindLocation = startNextBind;
                address += ptrSize + val;
            } break;
                
            case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED: {
                uint32_t scale = immediate;
//                is_64 ? bind_64.insert(std::make_pair(address, std::make_pair(addend, symbolName))) : bind.insert(std::make_pair(address, std::make_pair(addend, symbolName)));
                doBind(address, addend, slide, symbolName);
                doBindLocation = NSMaxRange(range);
                address += ptrSize + scale * ptrSize;
            } break;
                
            case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB:  {
                uint32_t startNextBind = NSMaxRange(range);
                uint64_t count = read_uleb128(range,bytes);
                uint64_t skip = read_uleb128(range,bytes);
                
                for (uint64_t index = 0; index < count; index++) {
//                    is_64 ? bind_64.insert(std::make_pair(address, std::make_pair(addend, symbolName))) : bind.insert(std::make_pair(address, std::make_pair(addend, symbolName)));
                    doBind(address, addend, slide, symbolName);
                    doBindLocation = startNextBind;
                    address += ptrSize + skip;
                }
            } break;
            default:
                [NSException raise:@"Bind info" format:@"Unknown opcode (%u %u)",
                 ((uint32_t)-1 & opcode), ((uint32_t)-1 & immediate)];
        }
        
    }
}


void printSymbols(const char *symbolName, uint32_t location,uint32_t skip,uint64_t baseAddress,uint8_t *bytes){
    NSRange range = NSMakeRange(location + skip,0);
    uint8_t terminalSize =  *(bytes + NSMaxRange(range));
    range  = NSMakeRange(NSMaxRange(range), sizeof(uint8_t));
    if (terminalSize != 0) {
        uint32_t terminalLocation = NSMaxRange(range);
        uint64_t flags = read_uleb128(range,bytes);
        uint64_t offset = read_uleb128(range,bytes);
        printf("address:%lld symbolName:%s\n",baseAddress + offset,symbolName);
        range = NSMakeRange(terminalLocation, terminalSize);
    }
    uint8_t childCount = read_uint8(range,bytes);
    while (childCount-- > 0) {
        const char *label = read_string(range, bytes);
        uint64_t skip = read_uleb128(range, bytes);
        printSymbols(label, location, skip, baseAddress, bytes);
    }
}

void parserSymbol_total(NSURL *absoluteURL,NSString *typeName, NSError **outError){
    if(!absoluteURL) return;
    
    int cpu_type = -1,cpu_sub_type = -1;
    cpu_type = _get_main_cup_type(&cpu_sub_type);
    
    if(cpu_type == -1){ return; }
    
    bool is_64 = sizeof(void *) == 8 ? true : false;
    if(is_64){cpu_type |= CPU_ARCH_ABI64;}
    
    NSMutableData *map_data = [NSMutableData dataWithContentsOfURL:absoluteURL options:NSDataReadingMappedAlways error:outError];
    uint8_t *bytes = (uint8_t *)[map_data bytes];
    
    uint32_t imageOffset = 0;
    uint32_t      ncmds = 0;
    
    uint32_t magic = *(uint32_t*)(bytes);
    switch (magic){
        case FAT_MAGIC:
        case FAT_CIGAM:{
            struct fat_header fat_header = *(struct fat_header *)bytes;
            if(magic == FAT_CIGAM){swap_fat_header(&fat_header, NX_LittleEndian);}
            for(uint32_t nimg = 0;nimg < fat_header.nfat_arch;nimg++){
                struct fat_arch fat_arch = *(struct fat_arch *)(bytes + sizeof(struct fat_header) + nimg * sizeof(struct fat_arch));
                swap_fat_arch(&fat_arch, 1, NX_LittleEndian);
                imageOffset = fat_arch.offset;
                uint32_t inline_magic = *(uint32_t*)(bytes + fat_arch.offset);
                switch (inline_magic) {
                    case MH_MAGIC:
                    case MH_CIGAM:{
                        struct mach_header mach_header = *(struct mach_header *)(bytes + fat_arch.offset);
                        if (inline_magic == MH_CIGAM){swap_mach_header(&mach_header, NX_LittleEndian);}
                        if(mach_header.cputype == cpu_type){
                            ncmds = mach_header.ncmds;
                        }
                    }break;
                    case MH_MAGIC_64:
                    case MH_CIGAM_64:{
                        struct mach_header_64 mach_header_64 = *(struct mach_header_64 *)(bytes + fat_arch.offset);
                        if (inline_magic == MH_CIGAM_64){swap_mach_header_64(&mach_header_64, NX_LittleEndian);}
                        if(mach_header_64.cputype == cpu_type){
                            ncmds = mach_header_64.ncmds;
                        }
                    }break;
                    default:{ break;}
                }
            }
        } break;
            
        case MH_MAGIC:
        case MH_CIGAM: {
            struct mach_header mach_header = *(struct mach_header *)bytes;
            if (magic == MH_CIGAM){swap_mach_header(&mach_header, NX_LittleEndian);}
            if(mach_header.cputype == cpu_type){ ncmds = mach_header.ncmds; }
        } break;
            
        case MH_MAGIC_64:
        case MH_CIGAM_64: {
            struct mach_header_64 mach_header_64 = *(struct mach_header_64 *)bytes;
            if (magic == MH_CIGAM_64){swap_mach_header_64(&mach_header_64, NX_LittleEndian);}
            if(mach_header_64.cputype == cpu_type){ ncmds = mach_header_64.ncmds; }
        } break;
        default:{break;}
    }
    
    if(!ncmds) return;
    
    //----------------------------------------------------------------------------------------//
    uint64_t vmsize_total = 0;
    uint32_t fileOffset = imageOffset + (!is_64 ? sizeof(struct mach_header) : sizeof(struct mach_header_64));
    for (uint32_t ncmd = 0; ncmd < ncmds; ++ncmd){
        MATCH_STRUCT(load_command,fileOffset)
        switch (load_command->cmd) {
            case LC_SEGMENT:{
                MATCH_STRUCT(segment_command, fileOffset)
                if (!strcmp(segment_command->segname, SEG_PAGEZERO)) {  continue; }
                vmsize_total += alignMem(segment_command->vmsize, 0x1000);
            }break;
            case LC_SEGMENT_64:{
                MATCH_STRUCT(segment_command_64,fileOffset)
                if (!strcmp(segment_command_64->segname, SEG_PAGEZERO)) {  continue; }
                vmsize_total += alignMem(segment_command_64->vmsize, 0x1000);
            }break;
            default:break;
        }
        fileOffset += load_command->cmdsize;
    }
    
    if(vmsize_total == 0) return;
    void *mapped = MY_MMAP(NULL, vmsize_total, VM_PROT_READ | VM_PROT_WRITE, MAP_SHARED | MAP_ANON, 0, 0);
    if (mapped == MAP_FAILED) { err(1, "mmap(file) failed"); }
    uint64_t slide = (uint64_t)mapped;
    //----------------------------------------------------------------------------------------//
    
//    std::vector<uint64_t> rebases_64;
//    std::vector<uint64_t> rebases;
    
    std::map<uint64_t,std::pair<uint32_t,const char *> > bind_64;
    std::map<uint64_t,std::pair<uint32_t,const char *> > bind;
    
    std::vector<uint64_t> sel_ref_64;
    std::vector<uint64_t> sel_ref;
    
    std::vector<uint64_t>   dylibs_name_offset;
    
    struct section_64  const * __class_list_64 = nullptr,*__category_list_64 = nullptr;
    struct section  const * __class_list = nullptr,*__category_list = nullptr;
    
    struct dyld_info_command const * dyld_info_command = nullptr;
    uint64_t base_addr = 0;
    fileOffset = imageOffset + (!is_64 ? sizeof(struct mach_header) : sizeof(struct mach_header_64));
    for (uint32_t ncmd = 0; ncmd < ncmds; ++ncmd){
        MATCH_STRUCT(load_command,fileOffset)
        switch (load_command->cmd) {
            case LC_SEGMENT:{
                MATCH_STRUCT(segment_command, fileOffset)
                if (!strcmp(segment_command->segname, SEG_PAGEZERO)) {  continue; }
                int prot = 0;
                if (segment_command->initprot & VM_PROT_READ) { prot |= PROT_READ; }
                if (segment_command->initprot & VM_PROT_WRITE) { prot |= PROT_WRITE; }
                if (segment_command->initprot & VM_PROT_EXECUTE) { prot |= PROT_EXEC; }
                
                uint64_t filesize = segment_command->filesize;// alignMem(seg->filesize, 0x1000);
                if(filesize <= 0)continue;
                
                uint64_t vmaddr = segment_command->vmaddr + slide;
                
                void *ret = memcpy((void *)vmaddr, bytes + segment_command->fileoff + imageOffset, filesize);
                if(!ret){err(1, "memcpy fail\n");}
                
                if(MY_MPROTECT((void*)vmaddr, alignMem(segment_command->vmsize, 0x1000), prot) != 0){
                    printf("*********warning:********* change protect  fail:%d\n",errno);
                }
                
                if (segment_command->fileoff == 0 && segment_command->filesize != 0){
                    base_addr = segment_command->vmaddr;
                }
                
                for (uint32_t nsect = 0; nsect < segment_command->nsects; ++nsect){
                    uint32_t sectionloc = fileOffset + sizeof(struct segment_command) + nsect * sizeof(struct section);
                    MATCH_STRUCT(section,sectionloc)
                    
                    if(!strcmp(section->segname, "__OBJC2") ||
                       !strcmp(section->segname, "__DATA")){
                        if(!strcmp(section->sectname, "__class_list") ||
                           !strcmp(section->sectname, "__objc_classlist")){
                            __class_list = section;
                        }
                        else if (!strcmp(section->sectname, "__category_list") ||
                                 !strcmp(section->sectname, "__objc_catlist")){
                            __category_list = section;
                        }
                    }
                    
                    switch (section->flags & SECTION_TYPE) {
                        case S_LITERAL_POINTERS:{
                            NSRange range = NSMakeRange(section->offset + imageOffset,0);
                            while (NSMaxRange(range) < section->offset + imageOffset + section->size) {
                                uint64_t ptr = read_uint32(range,bytes);
                                sel_ref.push_back(ptr);
                            }
                        } break;
                        case S_MOD_INIT_FUNC_POINTERS:
                        case S_MOD_TERM_FUNC_POINTERS:
                        case S_LAZY_SYMBOL_POINTERS:
                        case S_NON_LAZY_SYMBOL_POINTERS:
                        case S_LAZY_DYLIB_SYMBOL_POINTERS:
                        case S_SYMBOL_STUBS:
                            break;
                        default:
                            break;
                    }
                    
                }
            }break;
            case LC_SEGMENT_64:{
                MATCH_STRUCT(segment_command_64,fileOffset)
                if (!strcmp(segment_command_64->segname, SEG_PAGEZERO)) {  continue; }
                int prot = 0;
                if (segment_command_64->initprot & VM_PROT_READ) { prot |= PROT_READ; }
                if (segment_command_64->initprot & VM_PROT_WRITE) { prot |= PROT_WRITE; }
                if (segment_command_64->initprot & VM_PROT_EXECUTE) { prot |= PROT_EXEC; }
                
                uint64_t filesize = segment_command_64->filesize;// alignMem(seg->filesize, 0x1000);
                if(filesize <= 0)continue;
                
                uint64_t vmaddr = segment_command_64->vmaddr + slide;
                
                void *ret = memcpy((void *)vmaddr, bytes + segment_command_64->fileoff + imageOffset, filesize);
                if(!ret){err(1, "memcpy fail\n");}
                
                if(MY_MPROTECT((void*)vmaddr, alignMem(segment_command_64->vmsize, 0x1000), prot) != 0){
                    printf("*********warning:********* change protect  fail:%d\n",errno);
                }
                
                if (segment_command_64->fileoff == 0 && segment_command_64->filesize != 0){
                    base_addr = segment_command_64->vmaddr;
                }
                
                for (uint32_t nsect = 0; nsect < segment_command_64->nsects; ++nsect){
                    uint32_t sectionloc = fileOffset + sizeof(struct segment_command_64) + nsect * sizeof(struct section_64);
                    MATCH_STRUCT(section_64,sectionloc)
                    
                    if(!strcmp(section_64->segname, "__OBJC2") ||
                       !strcmp(section_64->segname, "__DATA")){
                        if(!strcmp(section_64->sectname, "__class_list") ||
                           !strcmp(section_64->sectname, "__objc_classlist__DATA")){
                            __class_list_64 = section_64;
                        }
                        else if (!strcmp(section_64->sectname, "__category_list__DATA") ||
                                 !strcmp(section_64->sectname, "__objc_catlist")){
                            __category_list_64 = section_64;
                        }
                    }
                    
                    switch (section_64->flags & SECTION_TYPE) {
                        case S_LITERAL_POINTERS:{
                            NSRange range = NSMakeRange(section_64->offset + imageOffset,0);
                            while (NSMaxRange(range) < section_64->offset + imageOffset + section_64->size) {
                                uint64_t ptr = read_uint64(range,bytes);
                                sel_ref_64.push_back(ptr);
                            }
                        } break;
                        case S_MOD_INIT_FUNC_POINTERS:
                        case S_MOD_TERM_FUNC_POINTERS:
                        case S_LAZY_SYMBOL_POINTERS:
                        case S_NON_LAZY_SYMBOL_POINTERS:
                        case S_LAZY_DYLIB_SYMBOL_POINTERS:
                        case S_SYMBOL_STUBS:
                            break;
                        default:
                            break;
                    }
                    
                }
            }break;
            case LC_ID_DYLIB:
            case LC_LOAD_DYLIB:
            case LC_LOAD_WEAK_DYLIB:
            case LC_REEXPORT_DYLIB:
            case LC_LAZY_LOAD_DYLIB:
            case LC_LOAD_UPWARD_DYLIB:{
                MATCH_STRUCT(dylib_command,fileOffset)
                if (load_command->cmd != LC_ID_DYLIB) {
//                    dylibs_name_offset.push_back(fileOffset + dylib_command->dylib.name.offset);
                    NSRange range = NSMakeRange(fileOffset + dylib_command->dylib.name.offset, 0);
                    const char *dllName = read_string(range, bytes);
                    void *handle = dlopen(dllName, RTLD_LAZY | RTLD_GLOBAL);
                    if(!handle){
                        printf("warning: open dll fail ==> %s\n",dllName);
                    }
                }
            }break;
            case LC_DYLD_INFO:
            case LC_DYLD_INFO_ONLY: dyld_info_command = (struct dyld_info_command const *)load_command; break;
            default:
                break;
        }
        fileOffset += load_command->cmdsize;
    }
    
    if(!dyld_info_command){return;}
    
    if (dyld_info_command->rebase_off * dyld_info_command->rebase_size > 0){
        uint64_t ptrSize = (!is_64 ? sizeof(uint32_t) : sizeof(uint64_t));
        uint64_t address = base_addr;
        uint32_t type = 0;
        bool isDone = false;
        uint32_t doRebaseLocation = dyld_info_command->rebase_off + imageOffset;
        NSRange range = NSMakeRange(doRebaseLocation,0);
        while (NSMaxRange(range) < dyld_info_command->rebase_off + imageOffset + dyld_info_command->rebase_size && !isDone) {
            uint8_t byte = *(bytes + NSMaxRange(range));
            range  = NSMakeRange(NSMaxRange(range), sizeof(uint8_t));
            uint8_t opcode = byte & REBASE_OPCODE_MASK;
            uint8_t immediate = byte & REBASE_IMMEDIATE_MASK;
            
            switch (opcode) {
                case REBASE_OPCODE_DONE:
                    isDone = YES;
                    break;
                case REBASE_OPCODE_SET_TYPE_IMM:
                    type = immediate;
                    break;
                case REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:{
                    uint32_t segmentIndex = immediate;
                    uint64_t offset = read_uleb128(range, bytes);
                    if (segmentIndex >= ncmds){
                        [NSException raise:@"Segment" format:@"index is out of range %u", segmentIndex];
                    }
                    
                    fileOffset = imageOffset + (!is_64 ? sizeof(struct mach_header) : sizeof(struct mach_header_64));
                    for(uint32_t i = 0;i < ncmds;i++){
                        MATCH_STRUCT(load_command,fileOffset)
                        if(i == segmentIndex){
                            switch (load_command->cmd) {
                                case LC_SEGMENT:{
                                    MATCH_STRUCT(segment_command, fileOffset)
                                    address = segment_command->vmaddr + offset;
                                }break;
                                case LC_SEGMENT_64:{
                                    MATCH_STRUCT(segment_command_64,fileOffset)
                                    address = segment_command_64->vmaddr + offset;
                                }break;
                                default:break;
                            }
                        }
                        fileOffset += load_command->cmdsize;
                    }
                } break;
                    
                case REBASE_OPCODE_ADD_ADDR_ULEB:{
                    uint64_t offset = read_uleb128(range, bytes);
                    address += offset;
                } break;
                    
                case REBASE_OPCODE_ADD_ADDR_IMM_SCALED:{
                    uint32_t scale = immediate;
                    address += scale * ptrSize;
                } break;
                    
                case REBASE_OPCODE_DO_REBASE_IMM_TIMES:{
                    uint32_t count = immediate;
                    for (uint32_t index = 0; index < count; index++){
//                        is_64 ? rebases_64.push_back(address) : rebases.push_back(address);
                        doRebase(address, slide, is_64 ? sel_ref_64 : sel_ref);
                        address += ptrSize;
                    }
                    doRebaseLocation = NSMaxRange(range);
                } break;
                    
                case REBASE_OPCODE_DO_REBASE_ULEB_TIMES:{
                    uint32_t startNextRebase = NSMaxRange(range);
                    uint64_t count = read_uleb128(range, bytes);
                    for (uint64_t index = 0; index < count; index++) {
//                        is_64 ? rebases_64.push_back(address) : rebases.push_back(address);
                        doRebase(address, slide, is_64 ? sel_ref_64 : sel_ref);
                        address += ptrSize;
                    }
                    doRebaseLocation = startNextRebase;
                    
                } break;
                    
                case REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB:{
                    uint32_t startNextRebase = NSMaxRange(range);
                    uint64_t offset = read_uleb128(range,bytes);
//                    is_64 ? rebases_64.push_back(address) : rebases.push_back(address);
                    doRebase(address, slide, is_64 ? sel_ref_64 : sel_ref);
                    address += ptrSize + offset;
                    doRebaseLocation = startNextRebase;
                } break;
                    
                case REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB: {
                    uint32_t startNextRebase = NSMaxRange(range);
                    uint64_t count = read_uleb128(range,bytes);
                    uint64_t skip = read_uleb128(range,bytes);
                    for (uint64_t index = 0; index < count; index++)  {
//                        is_64 ? rebases_64.push_back(address) : rebases.push_back(address);
                        doRebase(address, slide, is_64 ? sel_ref_64 : sel_ref);
                        address += ptrSize + skip;
                    }
                    doRebaseLocation = startNextRebase;
                    
                } break;
                    
                default:
                    [NSException raise:@"Rebase info" format:@"Unknown opcode (%u %u)", 
                     ((uint32_t)-1 & opcode), ((uint32_t)-1 & immediate)];
            }
        }
    }
    
    if (dyld_info_command->bind_off * dyld_info_command->bind_size > 0){
        createBinding(slide,dyld_info_command->bind_off + imageOffset, dyld_info_command->bind_size, base_addr, is_64, bytes, ncmds, imageOffset + (!is_64 ? sizeof(struct mach_header) : sizeof(struct mach_header_64)),NodeTypeBind, bind_64, bind);
    }
    
    if (dyld_info_command->weak_bind_off * dyld_info_command->weak_bind_size > 0){
        createBinding(slide,dyld_info_command->weak_bind_off + imageOffset, dyld_info_command->weak_bind_size, base_addr, is_64, bytes, ncmds, imageOffset + (!is_64 ? sizeof(struct mach_header) : sizeof(struct mach_header_64)),NodeTypeWeakBind, bind_64, bind);
    }
    
    if (dyld_info_command->lazy_bind_off * dyld_info_command->lazy_bind_size > 0){
         createBinding(slide,dyld_info_command->lazy_bind_off + imageOffset, dyld_info_command->lazy_bind_size, base_addr, is_64, bytes, ncmds, imageOffset + (!is_64 ? sizeof(struct mach_header) : sizeof(struct mach_header_64)),NodeTypeLazyBind, bind_64, bind);
    }
    
    if (dyld_info_command->export_off * dyld_info_command->export_size > 0){
        printSymbols("",dyld_info_command->export_off + imageOffset, 0, base_addr, bytes);
    }
    
    if(is_64){
        if(__class_list_64){
            
        }
        if(__category_list_64){
            
        }
    }
    else{
        if(__class_list){
        
        }
        if(__category_list){
            
        }
    }
    
    
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值