Mach-O --- Symbol Table

一般学习Mach-O 文件的同学,总是有一些特殊的需求驱动的,我也不例外。下面是一个简单的demo 来学习Symbol Table ,定位需要找的符号,最终达到定位符号或者函数的地址。

#if __LP64__ || (TARGET_OS_EMBEDDED && !TARGET_OS_IPHONE) ||  NS_BUILD_32_LIKE_64
#define  mach_header_t          mach_header_64
#define  segment_command_t      segment_command_64
#define  LC_SEGMENT_t           LC_SEGMENT_64
#define  section_t              section_64
#define  nlist_t                 nlist_64
#define  KArchitectureOffsetValue 0

#else
#define  mach_header_t          mach_header
#define  segment_command_t      segment_command
#define  LC_SEGMENT_t           LC_SEGMENT
#define  section_t              section
#define  KArchitectureOffsetValue 1
#define  nlist_t                nlist
#endif

#define kInvalidImageIndex -1

#import "ViewController.h"
#import 
#import 
#import 
#import 
#include 
#include 
#include 
#include 

@interface ViewController ()
@property (nonatomic,assign) const struct mach_header_t *machHeader;
@property (nonatomic,assign) intptr_t slide;
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    NSInteger imageIndex = [self getImageIndexWithFrameworkName:@"UIKit"];
    if (imageIndex != kInvalidImageIndex)
    {
        _slide = _dyld_get_image_vmaddr_slide((uint32_t)imageIndex);
        _machHeader = (const struct mach_header_t *)_dyld_get_image_header((uint32_t)imageIndex);
        [self printAllSymbolWithMachHeader:_machHeader withSlide:_slide];
    }
}

- (NSInteger)getImageIndexWithFrameworkName:(NSString *)frameworkName
{
    NSAssert(frameworkName.length, @"Framework can not be nil");
    NSInteger index = kInvalidImageIndex;
    if (frameworkName.length)
    {
        const char* targetName = [frameworkName UTF8String];
        size_t targetNameLength = strlen(targetName);
        uint32_t count = _dyld_image_count();
        for(uint32_t dyldIndex = 0; dyldIndex < count; dyldIndex++)
        {
            const char *dyld = _dyld_get_image_name(dyldIndex);
            int length = (int)strlen(dyld);
            int charIndex = length - 1;
            for(; charIndex>= 0; --charIndex)
            {
                if(dyld[charIndex] == '/')
                {
                    break;
                }
            }
            charIndex++;
            char *name = strndup(dyld + charIndex, length - charIndex);
            if (NULL != name)
            {
                if (strncmp(targetName, name, targetNameLength) == 0)
                {
                    index = dyldIndex;
                    free(name);
                    break;
                }
                free(name);
            }
        }
    }
    return index;
}

-(void)printAllSymbolWithMachHeader:(const struct mach_header_t *)machHeader withSlide:(intptr_t)slide
{
    struct symtab_command *symCommand      = NULL;
    struct segment_command_t *linkedit    = NULL;
    struct segment_command_t *textSegment = NULL;
    const uint8_t* linkEditBase            = NULL;
    const char *strtab                     = NULL;
    struct nlist_t *symTab                 = NULL;
    struct nlist_t *nl = NULL;
    textSegment = find_segment(machHeader, SEG_TEXT);
    if (!textSegment) {
        NSLog(@"找不到__TEXT\n");
        return;
    }
    linkedit = find_segment(machHeader, SEG_LINKEDIT);
    if (!linkedit)
    {
        NSLog(@"找不到__LINKEDIT\n");
        return;
    }else
    {
        linkEditBase = (uint8_t *)(slide + linkedit->vmaddr - linkedit->fileoff);
    }
    
    symCommand = (struct symtab_command *)find_load_command(machHeader, LC_SYMTAB);
    if (!symCommand)
    {
        NSLog(@"找不到Symbol\n");
        return;
    }
    char *symbolName;
    strtab = (const char *)(linkEditBase + symCommand->stroff);
    symTab = (struct nlist_t *)(linkEditBase + symCommand->symoff);
    nl = (struct nlist_t *)symTab;
    for (uint64_t i = 0;i < symCommand->nsyms;i++)
    {
        if (nl->n_un.n_strx != 0) {
            symbolName = (char *)strtab + nl->n_un.n_strx;
            
            ///< https://blog.sentry.io/2017/04/11/ios-symbolication-troubles.html
            if (strcmp(symbolName, "") != 0) {
                printf("Symbol :%s \n",symbolName);
            }
        }
        nl = (struct nlist_t *)((uint64_t)nl + sizeof(struct nlist_t));
    }
}


struct segment_command_t *find_segment(const struct mach_header_t *mh, const char *segname)
{
    struct load_command *lc;
    struct segment_command_t *seg, *foundseg = NULL;
    
    lc = (struct load_command *)((uint64_t)mh + sizeof(struct mach_header_t));
    while ((uint64_t)lc < (uint64_t)mh + (uint64_t)mh->sizeofcmds) {
        if (lc->cmd == LC_SEGMENT_t) {
            seg = (struct segment_command_t *)lc;
            if (strcmp(seg->segname, segname) == 0) {
                foundseg = seg;
                break;
            }
        }
        lc = (struct load_command *)((uint64_t)lc + (uint64_t)lc->cmdsize);
    }
    
    return foundseg;
}

struct load_command *find_load_command(const struct mach_header_t *mh, uint32_t cmd)
{
    struct load_command *lc = NULL;
    struct load_command *foundlc = NULL;
    
    lc = (struct load_command *)((uint64_t)mh + sizeof(struct mach_header_t));
    while ((uint64_t)lc < (uint64_t)mh + (uint64_t)mh->sizeofcmds)
    {
        if (lc->cmd == cmd) {
            foundlc = (struct load_command *)lc;
            break;
        }
        lc = (struct load_command *)((uint64_t)lc + (uint64_t)lc->cmdsize);
    }
    
    return foundlc;
}
 if (strcmp(symbolName, "") != 0) 
 {
     printf("Symbol :%s \n",symbolName);
 }

这里过滤了 符号,为什么?具体可以参考The Troubles With iOS Symbolication 。

你可能感兴趣的:(Mach-O --- Symbol Table)