漫漫编码路之 Hook

条条大路通罗马

  • Method Swizzling:

    突发奇想,我要Hook一个init:

@implementation NSArray (Swizzling)

+ (void)load{

    Method orig_init = class_getInstanceMethod([self class], @selector(init));
    Method amer_init = class_getInstanceMethod([self class], @selector(amer_init));

    method_exchangeImplementations(orig_init, amer_init);
}

- (instancetype)amer_init{

    NSLog(@"-[NSArray init] is hooked!");

    // invoke 'origin_init'
    return [self amer_init];
}

@end

Unexpected results——我意料之外的事
做完上面的事情,我并没动手调用init创建一个NSArray实例,只是cmd+B 并且 cmd+R

完整的打印结果
2016-11-04 14:10:31.166 HookTest[3436:335400] -[NSArray init] is hooked!
2016-11-04 14:10:31.168 HookTest[3436:335367] -[NSArray init] is hooked!
2016-11-04 14:10:31.167 HookTest[3436:335399] -[NSArray init] is hooked!
2016-11-04 14:10:31.168 HookTest[3436:335367] -[CADisplay amer_init]: unrecognized selector sent to instance 0x600000030bc0
2016-11-04 14:10:31.170 HookTest[3436:335399] -[NSUserDefaults amer_init]: unrecognized selector sent to instance 0x60000004a6e0
2016-11-04 14:10:31.170 HookTest[3436:335367] -[NSArray init] is hooked!
2016-11-04 14:10:31.170 HookTest[3436:335400] -[NSArray init] is hooked!
2016-11-04 14:10:31.170 HookTest[3436:335399] -[NSArray init] is hooked!
2016-11-04 14:10:31.170 HookTest[3436:335367] -[NSArray init] is hooked!
2016-11-04 14:10:31.170 HookTest[3436:335400] -[__NSBundleTables amer_init]: unrecognized selector sent to instance 0x600000261500
2016-11-04 14:10:31.170 HookTest[3436:335399] -[NSArray init] is hooked!
2016-11-04 14:10:31.171 HookTest[3436:335400] -[NSArray init] is hooked!
2016-11-04 14:10:31.171 HookTest[3436:335400] -[NSArray init] is hooked!
2016-11-04 14:10:31.174 HookTest[3436:335367] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[CADisplay amer_init]: unrecognized selector sent to instance 0x600000030bc0'
*** First throw call stack:
(
    0   CoreFoundation                      0x00000001086d734b __exceptionPreprocess + 171
    1   libobjc.A.dylib                     0x000000010813821e objc_exception_throw + 48
    2   CoreFoundation                      0x0000000108746f34 -[NSObject(NSObject) doesNotRecognizeSelector:] + 132
    3   CoreFoundation                      0x000000010865cc15 ___forwarding___ + 1013
    4   CoreFoundation                      0x000000010865c798 _CF_forwarding_prep_0 + 120
    5   HookTest                            0x0000000107b5c74c -[NSArray(Swizzling) amer_init] + 60
    6   QuartzCore                          0x000000010d242c66 -[CADisplay _initWithDisplay:] + 45
    7   QuartzCore                          0x000000010d2429a2 _ZL15ensure_displaysv + 688
    8   QuartzCore                          0x000000010d242c16 +[CADisplay mainDisplay] + 9
    9   BackBoardServices                   0x000000010c016af0 BKSDisplayServicesStart + 295
    10  UIKit                               0x0000000108afb04b _UIApplicationMainPreparations + 221
    11  UIKit                               0x0000000108afaf04 UIApplicationMain + 111
    12  HookTest                            0x0000000107b5da37 main + 583
    13  libdyld.dylib                       0x000000010b4b268d start + 1
    14  ???                                 0x0000000000000001 0x0 + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException
(lldb) 

Explore the unexpected——探讨意料之外的事

  1. 我的hook成功了,可喜可贺!
  2. 应用启动初始化时候创建了NSArray对象
  3. 从First throw call stack看来:
    • dyld启动 ->
    • start()->
    • main()->
    • UIApplicationMain->
    • 链接UIKit->
    • BackBoardServices->
    • 链接QuartzCore ->
    • CADisplay调用init(CADisplay无init方法)->
    • 方法查找super class(super 未实现init方法)->
    • 逐级查找最终调用NSObject的init方法(此时发现init方法是amer_init)->
    • 在NSObject 方法调度表中未查找amer_init(因为amer_init是NSObject子类NSArray的方法)->
    • CF_forwarding_prep_0准备进入消息转发->
    • 消息转发失败->
    • objc_exception_throw 程序抛出异常

Unexpected harvest——意料之外的收获

子类继承父类的方法,但是并没有默认重写父类方法。Hook要从在low-level层做,在一个子类最Hook,如果该方法是父类且子类没有重写,则父类的相应方法会被Hook。

The solution——解决方案

@implementation NSArray (Swizzling)

+ (void)load{

    Method orig_init = class_getInstanceMethod([self class], @selector(init));
    Method amer_init = class_getInstanceMethod([self class], @selector(amer_init));

    method_exchangeImplementations(orig_init, amer_init);
}

- (instancetype)amer_init{

    NSLog(@"-[NSArray init] is hooked!");

    // invoke 'origin_init'
    return [self amer_init];
}

- (instancetype)init{

    NSLog(@"-[NSArray init],origin init");
    if (self= [super init]) {
      // do some things
    }

    return self;
}
@end
  • FishHook:
    正在使用,有时间再做总结
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值