restore-symbol 学习

restore-symbol 学习

原理:基于 class-dump

1.先预处理读取mach-o


(lldb) bt
* thread #1, stop reason = breakpoint 40.1
    frame #0: 0x000000010002a340 restore-symbol`-[CDMachOFile ptrSize](self=0x0000600003900000, _cmd="ptrSize") at CDMachOFile.m:218:12
  * frame #1: 0x000000010001c011 restore-symbol`-[CDLCDyldInfo initWithDataCursor:](self=0x000060000261c000, _cmd="initWithDataCursor:", cursor=0x0000600000c0c000) at CDLCDyldInfo.m:86:20
    frame #2: 0x000000010002591a restore-symbol`+[CDLoadCommand loadCommandWithDataCursor:](self=CDLoadCommand, _cmd="loadCommandWithDataCursor:", cursor=0x0000600000c0c000) at CDLoadCommand.m:112:12
    frame #3: 0x00000001000297cd restore-symbol`-[CDMachOFile _readLoadCommands:count:](self=0x0000600003900000, _cmd="_readLoadCommands:count:", cursor=0x0000600000c0c000, count=62) at CDMachOFile.m:147:38
    frame #4: 0x00000001000295ae restore-symbol`-[CDMachOFile initWithData:filename:searchPathState:](self=0x0000600003900000, _cmd="initWithData:filename:searchPathState:", data=1652576 bytes, filename=@"/Users/lee/Desktop/Reverse_Engineering/Tool/restore-symbol/test/PopClip", searchPathState=0x0000000000000000) at CDMachOFile.m:130:9
    frame #5: 0x0000000100026bd2 restore-symbol`+[CDFile fileWithContentsOfFile:searchPathState:](self=CDFile, _cmd="fileWithContentsOfFile:searchPathState:", filename=@"/Users/lee/Desktop/Reverse_Engineering/Tool/restore-symbol/test/PopClip", searchPathState=0x0000000000000000) at CDFile.m:129:30
    frame #6: 0x00000001000049d0 restore-symbol`restore_symbol(inpath=@"/Users/lee/Desktop/Reverse_Engineering/Tool/restore-symbol/test/PopClip", outpath=@"/Users/lee/Desktop/Reverse_Engineering/Tool/restore-symbol/test/PopClip_", jsonPath=0x0000000000000000, oc_detect_enable=true, replace_restrict=false) at restore-symbol.m:67:22
    frame #7: 0x000000010000fa4c restore-symbol`main(argc=4, argv=0x00007ff7bfeff350) at main.m:127:5
    frame #8: 0x00007ff8021af41f dyld`start + 1903

在这里插入图片描述

CDLCDyldInfo会执行动态符号绑定


(lldb) bt
* thread #1, stop reason = breakpoint 45.1
  * frame #0: 0x000000010001d5ab restore-symbol`-[CDLCDyldInfo bindAddress:type:symbolName:flags:addend:libraryOrdinal:](self=0x0000600002600180, _cmd="bindAddress:type:symbolName:flags:addend:libraryOrdinal:", address=4296149112, type='\x01', symbolName="_kTISPropertyLocalizedName", flags='\0', addend=0, libraryOrdinal=5) at CDLCDyldInfo.m:440:34
    frame #1: 0x000000010001d172 restore-symbol`-[CDLCDyldInfo logBindOps:end:isLazy:](self=0x0000600002600180, _cmd="logBindOps:end:isLazy:", start="\U00000012@_OBJC_CLASS_$_SRGlobalShortcutMonitor", end="@__ZdlPv", isLazy=NO) at CDLCDyldInfo.m:384:17
    frame #2: 0x000000010001c8f0 restore-symbol`-[CDLCDyldInfo parseBindInfo](self=0x0000600002600180, _cmd="parseBindInfo") at CDLCDyldInfo.m:264:5
    frame #3: 0x000000010001bf6d restore-symbol`-[CDLCDyldInfo machOFileDidReadLoadCommands:](self=0x0000600002600180, _cmd="machOFileDidReadLoadCommands:", machOFile=0x0000600003900000) at CDLCDyldInfo.m:99:5
    frame #4: 0x0000000100029def restore-symbol`-[CDMachOFile _readLoadCommands:count:](self=0x0000600003900000, _cmd="_readLoadCommands:count:", cursor=0x0000600000c14000, count=62) at CDMachOFile.m:180:9
    frame #5: 0x000000010002945e restore-symbol`-[CDMachOFile initWithData:filename:searchPathState:](self=0x0000600003900000, _cmd="initWithData:filename:searchPathState:", data=1652576 bytes, filename=@"/Users/lee/Desktop/Reverse_Engineering/Tool/restore-symbol/test/PopClip", searchPathState=0x0000000000000000) at CDMachOFile.m:130:9
    frame #6: 0x0000000100026a82 restore-symbol`+[CDFile fileWithContentsOfFile:searchPathState:](self=CDFile, _cmd="fileWithContentsOfFile:searchPathState:", filename=@"/Users/lee/Desktop/Reverse_Engineering/Tool/restore-symbol/test/PopClip", searchPathState=0x0000000000000000) at CDFile.m:129:30
    frame #7: 0x0000000100004720 restore-symbol`restore_symbol(inpath=@"/Users/lee/Desktop/Reverse_Engineering/Tool/restore-symbol/test/PopClip", outpath=@"/Users/lee/Desktop/Reverse_Engineering/Tool/restore-symbol/test/PopClip_", jsonPath=0x0000000000000000, oc_detect_enable=true, replace_restrict=false) at restore-symbol.m:67:22
    frame #8: 0x000000010000f79c restore-symbol`main(argc=4, argv=0x00007ff7bfeff350) at main.m:127:5
    frame #9: 0x00007ff8021af41f dyld`start + 1903

普通绑定、弱绑定和懒绑定
在 Mach-O 文件格式里,绑定是把符号引用和它的实际定义关联起来的过程。普通绑定、弱绑定和懒绑定是三种不同的绑定机制,它们在绑定时机、处理未定义符号的方式等方面存在差异。下面为你详细介绍:
普通绑定(Regular Binding)

绑定时机:在程序加载时就完成绑定。
处理未定义符号的方式:要是存在未定义的符号,程序加载会失败。
应用场景:适用于程序启动阶段必须要用到的符号。
示例:程序启动时就需要调用的基础库函数,像 printf。
弱绑定(Weak Binding)

绑定特性:符号引用属于弱引用。即便符号未被定义,程序依旧可以加载和运行。
绑定时机:在程序加载时进行绑定。
处理未定义符号的方式:当符号未定义时,会将其解析为 NULL(在运行时可以检查)。
应用场景:用于可选的功能模块,或者实现向后兼容。
示例:在较新的系统版本中存在某个函数,但在旧版本中不存在,此时可以使用弱绑定。
懒绑定(Lazy Binding)

绑定时机:符号引用在第一次被使用时才进行绑定,而非程序加载时。
实现机制:借助延迟绑定表(lazy_symbol_bindings)和动态链接器来实现。
优势:能够加快程序的启动速度,因为不需要在启动时绑定所有符号。
应用场景:适用于那些不一定会被调用的函数,比如回调函数。
示例:GUI 应用中的菜单回调函数,用户不点击菜单就不会调用。
代码示例

下面通过一个简单的代码示例,来展示这三种绑定的不同用法:

#include <stdio.h>
#include <dlfcn.h>

// 普通绑定:直接调用标准库函数
void regular_binding() {
    printf("This is a regular binding example.\n");
}

// 弱绑定:使用弱引用的外部函数
__attribute__((weak)) void weak_function();
void weak_binding() {
    if (weak_function) {
        weak_function(); // 如果函数存在则调用
    } else {
        printf("weak_function is not available.\n");
    }
}

// 懒绑定:使用 dlsym 在运行时动态解析符号
void lazy_binding() {
    void (*lazy_function)() = dlsym(RTLD_DEFAULT, "lazy_function");
    if (lazy_function) {
        lazy_function(); // 第一次调用时才会绑定
    } else {
        printf("lazy_function not found.\n");
    }
}

int main() {
    regular_binding();
    weak_binding();
    lazy_binding();
    return 0;
}

只有被用到的符号采集才会保留动态绑定信息

在这里插入图片描述

2.读取 symbol

加载符号


* thread #1, stop reason = breakpoint 10.1
  * frame #0: 0x0000000100023bdc restore-symbol`-[CDLCSymbolTable loadSymbols](self=0x000060000261c060, _cmd="loadSymbols") at CDLCSymbolTable.m:177:27
    frame #1: 0x000000010002ff81 restore-symbol`-[CDObjectiveCProcessor process](self=0x0000600000c12880, _cmd="process") at CDObjectiveCProcessor.m:137:9
    frame #2: 0x0000000100013415 restore-symbol`-[CDClassDump processObjectiveCData](self=0x000060000211c230, _cmd="processObjectiveCData") at CDClassDump.m:189:9
    frame #3: 0x0000000100004600 restore-symbol`restore_symbol(inpath=@"/Users/lee/Desktop/Reverse_Engineering/Tool/restore-symbol/test/PopClip", outpath=@"/Users/lee/Desktop/Reverse_Engineering/Tool/restore-symbol/test/PopClip_", jsonPath=0x0000000000000000, oc_detect_enable=true, replace_restrict=false) at restore-symbol.m:100:13
    frame #4: 0x000000010000f3b8 restore-symbol`main(argc=4, argv=0x00007ff7bfeff350) at main.m:128:5
    frame #5: 0x00007ff80427e41f dyld`start + 1903

在这里插入图片描述

3.读取 protocol


* thread #1, stop reason = breakpoint 23.1
  * frame #0: 0x0000000100037661 restore-symbol`-[CDObjectiveC2Processor loadMethodsAtAddress:extendedMethodTypesCursor:](self=0x0000600000c0e520, _cmd="loadMethodsAtAddress:extendedMethodTypesCursor:", address=4296239600, extendedMethodTypesCursor=0x0000600000c349f0) at CDObjectiveC2Processor.m:425:14
    frame #1: 0x0000000100033e49 restore-symbol`-[CDObjectiveC2Processor protocolAtAddress:](self=0x0000600000c0e520, _cmd="protocolAtAddress:", address=4296443720) at CDObjectiveC2Processor.m:119:36
    frame #2: 0x000000010003341e restore-symbol`-[CDObjectiveC2Processor loadProtocols](self=0x0000600000c0e520, _cmd="loadProtocols") at CDObjectiveC2Processor.m:34:9
    frame #3: 0x000000010002f7f3 restore-symbol`-[CDObjectiveCProcessor process](self=0x0000600000c0e520, _cmd="process") at CDObjectiveCProcessor.m:140:9
    frame #4: 0x00000001000127f5 restore-symbol`-[CDClassDump processObjectiveCData](self=0x00006000021144b0, _cmd="processObjectiveCData") at CDClassDump.m:189:9
    frame #5: 0x00000001000039e0 restore-symbol`restore_symbol(inpath=@"/Users/lee/Desktop/Reverse_Engineering/Tool/restore-symbol/test/PopClip", outpath=@"/Users/lee/Desktop/Reverse_Engineering/Tool/restore-symbol/test/PopClip_", jsonPath=0x0000000000000000, oc_detect_enable=true, replace_restrict=false) at restore-symbol.m:100:13
    frame #6: 0x000000010000e798 restore-symbol`main(argc=4, argv=0x00007ff7bfeff350) at main.m:128:5
    frame #7: 0x00007ff80427e41f dyld`start + 1903


- (void)process;
{
    if (self.machOFile.isEncrypted == NO && self.machOFile.canDecryptAllSegments) {
        [self.machOFile.symbolTable loadSymbols];
        [self.machOFile.dynamicSymbolTable loadSymbols];

        [self loadProtocols];
        [self.protocolUniquer createUniquedProtocols];

        // Load classes before categories, so we can get a dictionary of classes by address.
        [self loadClasses];
        [self loadCategories];
    }
}

4.读取 class



(lldb) bt
* thread #1, stop reason = breakpoint 19.1
  * frame #0: 0x00000001000376b8 restore-symbol`-[CDObjectiveC2Processor loadMethodsAtAddress:extendedMethodTypesCursor:](self=0x0000600000c20360, _cmd="loadMethodsAtAddress:extendedMethodTypesCursor:", address=0, extendedMethodTypesCursor=0x0000000000000000) at CDObjectiveC2Processor.m:429:13
    frame #1: 0x0000000100033e49 restore-symbol`-[CDObjectiveC2Processor protocolAtAddress:](self=0x0000600000c20360, _cmd="protocolAtAddress:", address=4296443528) at CDObjectiveC2Processor.m:119:36
    frame #2: 0x000000010003341e restore-symbol`-[CDObjectiveC2Processor loadProtocols](self=0x0000600000c20360, _cmd="loadProtocols") at CDObjectiveC2Processor.m:34:9
    frame #3: 0x000000010002f7f3 restore-symbol`-[CDObjectiveCProcessor process](self=0x0000600000c20360, _cmd="process") at CDObjectiveCProcessor.m:140:9
    frame #4: 0x00000001000127f5 restore-symbol`-[CDClassDump processObjectiveCData](self=0x00006000021180a0, _cmd="processObjectiveCData") at CDClassDump.m:189:9
    frame #5: 0x00000001000039e0 restore-symbol`restore_symbol(inpath=@"/Users/lee/Desktop/Reverse_Engineering/Tool/restore-symbol/test/PopClip", outpath=@"/Users/lee/Desktop/Reverse_Engineering/Tool/restore-symbol/test/PopClip_", jsonPath=0x0000000000000000, oc_detect_enable=true, replace_restrict=false) at restore-symbol.m:100:13
    frame #6: 0x000000010000e798 restore-symbol`main(argc=4, argv=0x00007ff7bfeff350) at main.m:128:5
    frame #7: 0x00007ff80427e41f dyld`start + 1903

通过读取类 __objc_classrefs ,获取方法名和地址


(lldb) bt
* thread #1, stop reason = breakpoint 15.1
  * frame #0: 0x0000000100037651 restore-symbol`-[CDObjectiveC2Processor loadMethodsAtAddress:extendedMethodTypesCursor:](self=0x0000600000c1a8b0, _cmd="loadMethodsAtAddress:extendedMethodTypesCursor:", address=4296237768, extendedMethodTypesCursor=0x0000000000000000) at CDObjectiveC2Processor.m:425:14
    frame #1: 0x00000001000371cd restore-symbol`-[CDObjectiveC2Processor loadMethodsAtAddress:](self=0x0000600000c1a8b0, _cmd="loadMethodsAtAddress:", address=4296237768) at CDObjectiveC2Processor.m:387:12
    frame #2: 0x0000000100037170 restore-symbol`-[CDObjectiveC2Processor loadMethodsOfMetaClassAtAddress:](self=0x0000600000c1a8b0, _cmd="loadMethodsOfMetaClassAtAddress:", address=4296424296) at CDObjectiveC2Processor.m:382:12
    frame #3: 0x0000000100036392 restore-symbol`-[CDObjectiveC2Processor loadClassAtAddress:](self=0x0000600000c1a8b0, _cmd="loadClassAtAddress:", address=4296424256) at CDObjectiveC2Processor.m:298:32
    frame #4: 0x000000010003352b restore-symbol`-[CDObjectiveC2Processor loadClasses](self=0x0000600000c1a8b0, _cmd="loadClasses") at CDObjectiveC2Processor.m:44:29
    frame #5: 0x000000010002f82b restore-symbol`-[CDObjectiveCProcessor process](self=0x0000600000c1a8b0, _cmd="process") at CDObjectiveCProcessor.m:144:9
    frame #6: 0x00000001000127e5 restore-symbol`-[CDClassDump processObjectiveCData](self=0x00006000021043c0, _cmd="processObjectiveCData") at CDClassDump.m:189:9
    frame #7: 0x0000000100003990 restore-symbol`restore_symbol(inpath=@"/Users/lee/Desktop/Reverse_Engineering/Tool/restore-symbol/test/PopClip", outpath=@"/Users/lee/Desktop/Reverse_Engineering/Tool/restore-symbol/test/PopClip_", jsonPath=0x0000000000000000, oc_detect_enable=true, replace_restrict=false) at restore-symbol.m:100:13
    frame #8: 0x000000010000e748 restore-symbol`main(argc=4, argv=0x00007ff7bfeff350) at main.m:128:5
    frame #9: 0x00007ff80427e41f dyld`start + 1903

5.将符号恢复为方法名


(lldb) bt
* thread #1, stop reason = breakpoint 4.1
  * frame #0: 0x000000010000ff57 restore-symbol`-[RSSymbolCollector addSymbol:](self=0x0000600000210180, _cmd="addSymbol:", symbol=0x00006000002867e0) at RSSymbolCollector.m:34:6
    frame #1: 0x000000010000ed02 restore-symbol`-[RSScanMethodVisitor visitClassMethod:](self=0x0000600000d59110, _cmd="visitClassMethod:", method=0x0000600000c3f3f0) at RSScanMethodVisitor.m:85:5
    frame #2: 0x000000010003da4e restore-symbol`-[CDOCProtocol visitMethods:propertyState:](self=0x000060000261c540, _cmd="visitMethods:propertyState:", visitor=0x0000600000d59110, propertyState=0x00006000002d0520) at CDOCProtocol.m:197:9
    frame #3: 0x0000000100039481 restore-symbol`-[CDOCClass recursivelyVisit:](self=0x000060000261c540, _cmd="recursivelyVisit:", visitor=0x0000600000d59110) at CDOCClass.m:87:9
    frame #4: 0x00000001000302a6 restore-symbol`-[CDObjectiveCProcessor recursivelyVisit:](self=0x0000600000c1a2e0, _cmd="recursivelyVisit:", visitor=0x0000600000d59110) at CDObjectiveCProcessor.m:198:9
    frame #5: 0x0000000100012a3e restore-symbol`-[CDClassDump recursivelyVisit:](self=0x0000600002110230, _cmd="recursivelyVisit:", visitor=0x0000600000d59110) at CDClassDump.m:200:9
    frame #6: 0x0000000100003a04 restore-symbol`restore_symbol(inpath=@"/Users/lee/Desktop/Reverse_Engineering/Tool/restore-symbol/test/PopClip", outpath=@"/Users/lee/Desktop/Reverse_Engineering/Tool/restore-symbol/test/PopClip_", jsonPath=0x0000000000000000, oc_detect_enable=true, replace_restrict=false) at restore-symbol.m:105:13
    frame #7: 0x000000010000e748 restore-symbol`main(argc=4, argv=0x00007ff7bfeff350) at main.m:128:5
    frame #8: 0x00007ff80427e41f dyld`start + 1903

6.生成缺失的符号的恢复表


* thread #1, stop reason = breakpoint 22.1
  * frame #0: 0x00000001000104f2 restore-symbol`-[RSSymbolCollector generateAppendStringTable:appendSymbolTable:](self=0x000060000021c520, _cmd="generateAppendStringTable:appendSymbolTable:", stringTable=0x00007ff7bfefedf0, symbolTable=0x00007ff7bfefede8) at RSSymbolCollector.m:87:33
    frame #1: 0x0000000100003beb restore-symbol`restore_symbol(inpath=@"/Users/lee/Desktop/Reverse_Engineering/Tool/restore-symbol/test/PopClip", outpath=@"/Users/lee/Desktop/Reverse_Engineering/Tool/restore-symbol/test/PopClip_", jsonPath=0x0000000000000000, oc_detect_enable=true, replace_restrict=false) at restore-symbol.m:133:5
    frame #2: 0x000000010000e748 restore-symbol`main(argc=4, argv=0x00007ff7bfeff350) at main.m:128:5
    frame #3: 0x00007ff80427e41f dyld`start + 1903

7.将恢复表插入符号表后面


    // must first insert string
    [outData replaceBytesInRange:NSMakeRange(origin_string_table_offset + origin_string_table_size , 0) withBytes:(const void *)string_table_append_data.bytes   length:increase_size_string_tab + string_table_padding];
    
    [outData replaceBytesInRange:NSMakeRange(origin_symbol_table_offset + origin_symbol_table_num * NListSize , 0) withBytes:(const void *)symbol_table_append_data.bytes   length:increase_size_symtab];

8.symbol table 中 string_table 和 symbol_table 的区别

NSData *string_table_append_data = nil;
NSData *symbol_table_append_data = nil;
[collector generateAppendStringTable:&string_table_append_data appendSymbolTable:&symbol_table_append_data];

原程序
原程序

完整添加符号的程序
完整添加符号的程序

没有添加string_table 的程序没有添加string_table 的程序

可以看到 添加符号号后 符号表增大,如果只添加了 symbol_table 则所有符号表增大同样大小,但是 会显示不了符号;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值