参考:
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
- 找到Block的方法签名(NSMethodSignature)
- 设置target
- 有参数插入参数(下标从1开始)
- 调用invoke执行
- 如果有返回值调用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);
网友评论