iOS Hook block without libffi

作者: WELCommand | 来源:发表于2018-04-13 17:39 被阅读62次

    基础知识

    关于block原理的文章已经有很多,这里就没必要再复述一遍。只列出一些和主题密切相关的知识点。

    block是什么?

    block就是block
    block是一个NSBlock对象。
    block是一个指针,指向下面这个结构体。

    struct Block_layout {
            void *isa;
            volatile int32_t flags; // contains ref count
            int32_t reserved; 
            void (*invoke)(void *, ...);
            struct Block_descriptor_1 *descriptor;
            // imported variables
        };
    

    调用block的时候发生了什么

    block内的代码会被编译成一个C函数。block的invoke指针,指向这个函数,调用block等于调用这个函数。


    怎么hook一个block

    hook一个block需要两步。

    1 让block调用的时候不去调用原本的函数,而是调用自己的函数。
    2 自己的函数再去调用block原本的函数。

    第一步很简单,只需要把block的invoke指针指向自己的函数就可以了。
    第二步是这篇文章的重点,接下来逐一讲述。

    block和普通对象一样,支持消息转发

    如果我们把block的invoke指针指向_objc_msgForward。调用block,会触发消息转发。我们会在forwardInvocation:中拿到一个参数已经被放好了的NSInvocation对象。走到这里,形式已经一片大好。

    当NSInvocation对象的target为block时,调用其invoke方法,会发生什么?

    使用hopper观察[NSInvocation invoke]的实现。得到如下结果:

    未命名.png

    大概解释一下这个方法的流程,invoke最终通过invoking完成调用。在调用前,其第一个参数 $r15 会被赋值为objc_msgSend或objc_msgSend_stret。接着,遍历target的superClass,查看是否继承自NSBlock。如果继承自NSBlock,就把target的首地址+0x10赋值给 $r15。而block的首地址+16就是block的invoke指针。由此不难看出,NSInvocation本身是便完美支持target作为block使用。

    有了NSInvocation的支持,就可以安心的通过invoke去调用block。

    还需要一个假block

    最后,整体的流程大概是这样:

    在准备hook一个block时,我们需要先copy这个block,并让block持有copy结果。这里copy的主要的目的是复制外部变量。

    设置block的invoke指针为_objc_msgForward,调用block触发消息转发。

    在forwardInvocation:中执行完自己的逻辑后,将invocation的target设置为刚刚copy的block,执行invoke。完成Hook。

    PS: 在FishBind中,hookBlock被作为其中的一个功能点。有兴趣的朋友可以去看相关的具体实现。

    相关文章

      网友评论

      • JoeTong:请问 我想hook一个block的返回 有办法吗
      • lcus:fishbind hook blcok的取argument得那个方法 是不是有问题 * 和@的 写反了

      本文标题:iOS Hook block without libffi

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