Hook ObjC方法中的传入的block类型的参数,当然,你必须先分析出这个block它本身需要传入什么参数。
比如我现在需要Hook -[ViewController executeBlockOrig:]这个实例方法,我们已经分析出它的唯一一个参数是block类型的,定义如下。
typedef void (^AddBlock)(int a, int b);
可以看出这个block类型本身需要两个int类型的参数。
而block的实质其实就是C函数(不是最准确的描述,但是这样理解起来相对容易),那么给 -[ViewController executeBlockOrig:]这个实例方法传入的则是这个C函数的地址,于是我们构造一个函数签名相同的block再传给那个实例方法即可。
以下直接上代码吧。
// // ViewController.m // Hook Block Parameter // // Created by Ryza 15/4/23. // Copyright (c) 2015年 Ryza. All rights reserved. // #import "ViewController.h" #import <objc/runtime.h> @implementation ViewController #pragma mark #pragma mark - Hook static IMP originExecuteBlock = NULL; /*! * @brief Hook代码 * * @param block 已知具体参数类型的block */ - (void)executeBlockHook:(void *)block { void (^hookBlock)(int a, int b) = ^(int a, int b){ printf("[HOOK] Original: a is %d, b is %d\n",a,b); /*! * @brief 更改一下a, b的值呀什么的 */ a = a * 2; b = b * 2; printf("[HOOK] Modified: a is %d, b is %d\n",a,b); void (^originBlock)(int a, int b); long long blockPtr = reinterpret_cast<long long>(block); memcpy((void *)&originBlock, (void *)&blockPtr, sizeof(long long)); originBlock(a,b); }; ((void (*)(id, SEL, void *))originExecuteBlock)(self, NSSelectorFromString(@"executeBlockOrig:"),(__bridge void *)hookBlock); } #pragma mark #pragma mark - Origin typedef void (^AddBlock)(int a, int b); - (void)executeBlockOrig:(AddBlock)block { block(1,3); } - (void)appCall { /*! * @brief 调用 */ AddBlock p = ^(int a, int b) { printf("Result is %d\n",a+b); }; [self executeBlockOrig:p]; } - (void)viewDidLoad { [super viewDidLoad]; /*! * @brief 模拟dylib注入 */ Method m = class_getInstanceMethod(NSClassFromString(@"ViewController"), NSSelectorFromString(@"executeBlockOrig:")); originExecuteBlock = method_getImplementation(m); method_exchangeImplementations(m, class_getInstanceMethod(NSClassFromString(@"ViewController"), @selector(executeBlockHook:))); /*! * @brief 模拟原有的App调用 */ [self appCall]; } @end
我想请教一下,这段
void (^originBlock)(int a, int b);
long long blockPtr = reinterpret_cast(block);
memcpy((void *)&originBlock, (void *)&blockPtr, sizeof(long long));
originBlock(a,b);
我想做成通用的,等外面的方法传一个代码来做对block的动态添加代码块工作,应该需要怎样做?因为我不知道originblock的类型。
需要先通过其它方式知道originblock的类型才行呢,比如用lldb、Hopper或者IDA之类的来调试/反编译等等