Aspect
tips:
- 未识别消息转发流程:
1.resolveInstanceMethod (给类动态添加方法)
2.forwardingTargetForSelector(寻找其他的实例去处理方法)
3.forwardInvocation(完整的invocation 可以转发)
- NSInvovation:
NSInvocation文档 。包含objectiveC的消息的所有元素。目标对象,方法,参数,和返回值。
- NSMethodSignature:
通过一个字符串数组记录方法的返回值和参数
Type Encodings
- Block 获取方法签名
苹果并没有提供一个开放的接口,供开发者获取 Block 的方法签名。不过根据 LLVM 对 Block 结构的描述,我们可以通过操作指针获取签名字符串。以下是 Block 的结构:
// Block internals.
typedef NS_OPTIONS(int, AspectBlockFlags) {
AspectBlockFlagsHasCopyDisposeHelpers = (1 << 25),
AspectBlockFlagsHasSignature = (1 << 30)
};
typedef struct _AspectBlock {
__unused Class isa;
AspectBlockFlags flags;
__unused int reserved;
void (__unused *invoke)(struct _AspectBlock *block, ...);
struct {
unsigned long int reserved;
unsigned long int size;
// requires AspectBlockFlagsHasCopyDisposeHelpers
void (*copy)(void *dst, const void *src);
void (*dispose)(const void *);
// requires AspectBlockFlagsHasSignature
const char *signature;
const char *layout;
} *descriptor;
// imported variables
} *AspectBlockRef;
获取descriptor拿到signature。
static NSMethodSignature *aspect_blockMethodSignature(id block, NSError **error) {
//通过layout获取对应的block签名
AspectBlockRef layout = (__bridge void *)block;
//无签名
if (!(layout->flags & AspectBlockFlagsHasSignature)) {
NSString *description = [NSString stringWithFormat:@"The block %@ doesn't contain a type signature.", block];
AspectError(AspectErrorMissingBlockSignature, description);
return nil;
}
//desc
void *desc = layout->descriptor;
//跳过
// unsigned long int reserved;
// unsigned long int size;
desc += 2 * sizeof(unsigned long int);
// 跳过
if (layout->flags & AspectBlockFlagsHasCopyDisposeHelpers) {
desc += 2 * sizeof(void *);
}
if (!desc) {
NSString *description = [NSString stringWithFormat:@"The block %@ doesn't has a type signature.", block];
AspectError(AspectErrorMissingBlockSignature, description);
return nil;
}
const char *signature = (*(const char **)desc);
return [NSMethodSignature signatureWithObjCTypes:signature];
}
基本原理
1,生成要hook方法的自己的方法的NSInVocation 的相关参数。
2,将要hook的方法指向objc_msgForward/_objc_msgForward_stret。并保存原有的执行函数。
3,hook对象的forwardInvocation方法指向自己的方法。
4,当系统调用hook的方法。会调用自己的forwardInvocation。然后执行里面的相关方法。
网友评论