美文网首页
iOS符号绑定的过程分析

iOS符号绑定的过程分析

作者: 大冯宇宙 | 来源:发表于2020-06-19 08:19 被阅读0次

iOS程序在加载到内存时候,会有一个符号绑定的过程。有两种方式,一种是Non-Lazy,一种是Lazy(懒加载)。
通过MachOView,可以看出系统的大部分函数都是懒加载。


以NSLog为例

NSLog在MachO的偏移8010个字节,就是NSLog的符号
编写一段代码,功能是通过fishhook Hook NSLog函数

- (void)viewDidLoad {
    [super viewDidLoad];
    //HOOK -- NSLog函数!
    NSLog(@"123");
    //指定交换的函数
    struct rebinding nslog;
    nslog.name = "NSLog";
    nslog.replacement = myNSLog;
    //fishhook 运行的时刻,动态的获取到NSLog的地址。
    nslog.replaced = (void *)&sys_nslog;
    //结构体数组
    struct rebinding rebs[1] = {nslog};
    rebind_symbols(rebs, 1);
}
  1. 运行上边的代码,在NSLog(@"123");打个断点
    控制台打印Demo的Mach-O在内存中的起始位置,0x0000000100bc4000
(lldb) image list
[  0] F7B52DBD-C1FF-3BDD-8220-BCC8493609FB 0x0000000100bc4000 /绝对路径/fishHookDemo.app/fishHookDemo 
  1. 将上边获得的两个地址Mach-O内存中的起始位置和NSLog的便宜位置相加,获得NSLog的符号内存地址
    0x0000000100bc4000 + 8010 = 0x100BCC010
    读一下内存,并且打印一下汇编代码。从汇编代码中看到目前没有绑定NSLog的实际地址。
(lldb) memory read 0x100BCC010
0x100bcc010: b4 a9 bc 00 01 00 00 00 b0 13 8b 94 01 00 00 00  ................
0x100bcc020: a0 7a 59 98 01 00 00 00 20 aa bc 00 01 00 00 00  .zY..... .......
(lldb) dis -s 0x0100bca9b4 // iOS是小端模式,倒着读前八个字节
    0x100bca9b4: ldr    w16, 0x100bca9bc
    0x100bca9b8: b      0x100bca99c
    0x100bca9bc: udf    #0x0
    0x100bca9c0: ldr    w16, 0x100bca9c8
    0x100bca9c4: b      0x100bca99c
    0x100bca9c8: udf    #0xd
    0x100bca9cc: ldr    w16, 0x100bca9d4
    0x100bca9d0: b      0x100bca99c
  1. 然后断点单步走一个,运行NSLog(@"123");重新打印内存和汇编,可以看到NSLog的符号绑定成功。得出结论,NSLog符号为懒加载。
(lldb) memory read 0x100BCC010
0x100bcc010: c0 c2 8b 94 01 00 00 00 b0 13 8b 94 01 00 00 00  ................
0x100bcc020: a0 7a 59 98 01 00 00 00 20 aa bc 00 01 00 00 00  .zY..... .......
(lldb) dis -s 0x01948bc2c0
Foundation`NSLog:
    0x1948bc2c0 <+0>:  sub    sp, sp, #0x20             ; =0x20 
    0x1948bc2c4 <+4>:  stp    x29, x30, [sp, #0x10]
    0x1948bc2c8 <+8>:  add    x29, sp, #0x10            ; =0x10 
    0x1948bc2cc <+12>: adrp   x8, 264921
    0x1948bc2d0 <+16>: ldr    x8, [x8, #0x110]
    0x1948bc2d4 <+20>: ldr    x8, [x8]
    0x1948bc2d8 <+24>: str    x8, [sp, #0x8]
    0x1948bc2dc <+28>: add    x8, x29, #0x10            ; =0x10 
  1. 接下来过掉断点,执行完rebind_symbols,然后进入lldb调试模式,打印内存和汇编,通过fishhook成功的替换掉了NSLog的实现。
    由此可见,fishhook的原理就是先找到符号的实际地址,然后替换掉地址的值。
(lldb) memory read 0x100BCC010
0x100bcc010: 88 9c bc 00 01 00 00 00 b0 13 8b 94 01 00 00 00  ................
0x100bcc020: a0 7a 59 98 01 00 00 00 c4 c9 14 94 01 00 00 00  .zY.............
(lldb) dis -s 0x0100bc9c88
fishHookDemo`myNSLog:
    0x100bc9c88 <+0>:  sub    sp, sp, #0x30             ; =0x30 
    0x100bc9c8c <+4>:  stp    x29, x30, [sp, #0x20]
    0x100bc9c90 <+8>:  add    x29, sp, #0x20            ; =0x20 
    0x100bc9c94 <+12>: mov    x8, #0x0
    0x100bc9c98 <+16>: stur   x8, [x29, #-0x8]
    0x100bc9c9c <+20>: sub    x9, x29, #0x8             ; =0x8 
    0x100bc9ca0 <+24>: str    x0, [sp, #0x10]
    0x100bc9ca4 <+28>: mov    x0, x9

后续
苹果有一个技术叫做共享缓存技术,就是程序中引用系统库的函数整个系统只有一份。
通过上边的分析,我们看到了NSLog的符号地址,使用 dis -s 0x01948bc2c0打印出了NSLog的汇编。结合共享缓存技术,可以猜到在一次系统启动后,任何程序中的0x01948bc2c0地址都是NSLog符号。当我们知道了所有的系统函数的符号地址,是不是能针对某一个app做点什么

相关文章

网友评论

      本文标题:iOS符号绑定的过程分析

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