m

mellow

V1

2023/02/15阅读:17主题:默认主题

code

// 解析符号地址(不依赖任何系统api)
uintptr_t OCSResolveSymbolAddressInAllImages(CFStringRef functionName) {
    const char *targetSymbolName = [(__bridge NSString *)functionName UTF8String];
    std::string mangleName = OCSMangleName(targetSymbolName);
    if (mangleName.empty()) {
        return (uintptr_t)nullptr;
    }
    targetSymbolName = mangleName.c_str();
    
    uint32_t count = _dyld_image_count();
    for (uint32_t i = 0; i < count; i++) {
        const struct mach_header *image_header = _dyld_get_image_header(i);
        Dl_info info;
        if (dladdr(image_header, &info) == 0) {
            continue;
        }
        // info.dli_fbase 就是mach-o的起始地址。
        const MTMachHeader *mach_header = (MTMachHeader *)info.dli_fbase;
        uintptr_t targetSymbolAddr = OCSResolveSymbolAddress(targetSymbolName, mach_header);
        if (targetSymbolAddr) {
            return targetSymbolAddr;
        }
    }
    return (uintptr_t)nullptr;
}
uintptr_t targetSymbolAddr = (uintptr_t)nullptr;
// 通过__TEXT段的地址和模块基址来计算模块的ASLR(地址空间随机化)偏移
OCSSegmentCommand *textLoadCmd = nullptr;
// 符号表位于__LINKEDIT段
OCSSegmentCommand *linkEditLoadCmd = nullptr;
// 符号表的加载命令,里面指明了符号表的位置等信息
OCSSymtabCommand *symbolTableLoadCmd = nullptr;
uintptr_t pos = (uintptr_t)machHeader + sizeof(OCSMachHeader);
for (uint32_t i = 0; i < machHeader->ncmds; ++i) {
    OCSLoadCommand *loadCmd = (OCSLoadCommand *)pos;
    if (loadCmd->cmd == OCS_LOAD_COMMAND_SEGMENT) {
        OCSSegmentCommand *segmentLoadCmd = (OCSSegmentCommand *)loadCmd;
        if (strcmp(segmentLoadCmd->segname, OCS_SEG_TEXT) == 0) {
            textLoadCmd = segmentLoadCmd;
        } else if (strcmp(segmentLoadCmd->segname, OCS_SEG_LINKEDIT) == 0) {
            linkEditLoadCmd = segmentLoadCmd;
        }
    } else if (loadCmd->cmd == OCS_LOAD_COMMAND_SYMTAB) {
        symbolTableLoadCmd = (OCSSymtabCommand *)loadCmd;
    }
    if (!textLoadCmd || !linkEditLoadCmd || !symbolTableLoadCmd) {
        pos += loadCmd->cmdsize;
        continue;
    }
    
    // 地址空间随机化(ASLR)引入的偏移
    const intptr_t moduleSlide = (uintptr_t)machHeader - textLoadCmd->vmaddr;
    const uintptr_t linkEditBaseAddr = linkEditLoadCmd->vmaddr + moduleSlide;
    
    // 计算符号表的地址
    // 符号表相对__LINKEDIT段的偏移
    const intptr_t symbolTableOffsetOfLinkEdit = symbolTableLoadCmd->symoff - linkEditLoadCmd->fileoff;
    const uintptr_t symbolTableAddr = linkEditBaseAddr + symbolTableOffsetOfLinkEdit;
    
    // 计算字符串表的地址
    // 字符串表相对__LINKEDIT段的偏移
    const intptr_t stringTableOffsetOfLinkEdit = symbolTableLoadCmd->stroff - linkEditLoadCmd->fileoff;
    const uintptr_t stringTableAddr = linkEditBaseAddr + stringTableOffsetOfLinkEdit;
    
    // 遍历符号表,并将每个符号的名字和目标符号比较,如果相同,则判断是否为导出符号,找到则返回,否则继续遍历到最后
    for (uint32_t j = 0; j < symbolTableLoadCmd->nsyms; ++j) {
        OCSSymbol *symbol = (OCSSymbol *)(symbolTableAddr + j * sizeof(OCSSymbol));
        // 字符串相对于字符串表起始位置的索引,即偏移
        const uint32_t stringIndex = symbol->n_un.n_strx;
        const char *str = (const char *)(stringTableAddr + stringIndex);
        if (strcmp(str, targetSymbolName) == 0 && OCSCheckExportSymbol(symbol) && symbol->n_value) {
            targetSymbolAddr = symbol->n_value + moduleSlide;
            break;
        }
    }
    break; // 符号解析完毕,不用继续枚举load command
}
// 计算完毕,targetSymbolAddr 为目标地址
// 遍历符号表,并将每个符号的名字和目标符号比较
// 如果相同,则判断是否为导出符号,找到则返回,否则继续遍历到最后
for (uint32_t j = 0; j < symbolTableLoadCmd->nsyms; ++j) {
    OCSSymbol *symbol = (OCSSymbol *)(symbolTableAddr + j * sizeof(OCSSymbol));
    // 字符串相对于字符串表起始位置的索引,即偏移
    const uint32_t stringIndex = symbol->n_un.n_strx;
    const char *str = (const char *)(stringTableAddr + stringIndex);
    if (strcmp(str, targetSymbolName) == 0 && OCSCheckExportSymbol(symbol) && symbol->n_value) {
        targetSymbolAddr = symbol->n_value + moduleSlide;
        break;
    }
}

分类:

后端

标签:

后端

作者介绍

m
mellow
V1