Hook Block

参考:
Apple Block 源码
CTObjectiveCRuntimeAdditions
Aspects

二级标题

下载Apple Block打开


Blocks源码

Block_private.h文件中

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描述

#define BLOCK_DESCRIPTOR_1 1
struct Block_descriptor_1 {
    uintptr_t reserved;
    uintptr_t size;
};

#define BLOCK_DESCRIPTOR_2 1
struct Block_descriptor_2 {
    // requires BLOCK_HAS_COPY_DISPOSE
    void (*copy)(void *dst, const void *src);
    void (*dispose)(const void *);
};

#define BLOCK_DESCRIPTOR_3 1
struct Block_descriptor_3 {
    // requires BLOCK_HAS_SIGNATURE
    const char *signature;
    const char *layout;     // contents depend on BLOCK_HAS_EXTENDED_LAYOUT
};

Block的flags

// Values for Block_layout->flags to describe block objects
enum {
    BLOCK_DEALLOCATING =      (0x0001),  // runtime
    BLOCK_REFCOUNT_MASK =     (0xfffe),  // runtime
    BLOCK_NEEDS_FREE =        (1 << 24), // runtime
    BLOCK_HAS_COPY_DISPOSE =  (1 << 25), // compiler
    BLOCK_HAS_CTOR =          (1 << 26), // compiler: helpers have C++ code
    BLOCK_IS_GC =             (1 << 27), // runtime
    BLOCK_IS_GLOBAL =         (1 << 28), // compiler
    BLOCK_USE_STRET =         (1 << 29), // compiler: undefined if !BLOCK_HAS_SIGNATURE
    BLOCK_HAS_SIGNATURE  =    (1 << 30), // compiler
    BLOCK_HAS_EXTENDED_LAYOUT=(1 << 31)  // compiler
};

通过NSInvocation调用Block实现Hook

  1. 找到Block的方法签名(NSMethodSignature)
  2. 设置target
  3. 有参数插入参数(下标从1开始)
  4. 调用invoke执行
  5. 如果有返回值调用getReturnValue方法接收返回值

具体实现步骤(添加前缀不与系统的Block冲突)

定义Block的结构

struct GMY_Block_descriptor {
    uintptr_t reserved;
    uintptr_t size;
    
    void (*copy)(void *dst, const void *src);
    void (*dispose)(const void *);
    
    const char *signature;
    const char *layout;     // contents depend on BLOCK_HAS_EXTENDED_LAYOUT
};

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

在Block中找到关键的flags重新定义使用

enum {
    GMYBLOCK_HAS_COPY_DISPOSE =  (1 << 25), // compiler
    GMYBLOCK_HAS_SIGNATURE  =    (1 << 30), // compiler
};

代码

//定义block
void (^block)(NSString *) = ^(NSString *str){
    NSLog(@"block: %@", str);
};
//转化
struct GMY_Block_layout *blockLayout = (__bridge struct GMY_Block_layout *)block;
//根据flags的容错判断
volatile int32_t blockFlags = blockLayout->flags;
if (blockFlags & GMYBLOCK_HAS_SIGNATURE) {//判断方法签名
    void *blockDesc = blockLayout->descriptor;
    blockDesc += 2 * sizeof(uintptr_t);//指针偏移
    
    if (blockFlags & GMYBLOCK_HAS_COPY_DISPOSE) {
        blockDesc += sizeof(void (*)(void *dst, const void *src));
        blockDesc += sizeof(void (*)(const void *));//指针偏移
    }
    
    const char *signature = (*(const char **)blockDesc);//根据指针取值
    //由NSInvocation对象调用
    NSMethodSignature *blockSignature = [NSMethodSignature signatureWithObjCTypes:signature];
    NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:blockSignature];
    [invocation setTarget:block];
    NSString *str = @"block";
    [invocation setArgument:&str atIndex:1];
    [invocation invoke];
}

通过函数指针void (*invoke)(void *, ...);调用Block实现Hook

代码

void (^block)(void) = ^{
    NSLog(@"block");
};

struct GMY_Block_layout *myBlock = (__bridge struct GMY_Block_layout *)block;
myBlock->invoke(myBlock);
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容