今天群里有朋友问怎么Hook ObjC的不定参数方法,比如NSDictionary的+ [NSDictionary dictionaryWithObjectsAndKeys:]
于是稍微研究了一下,其实和普通的ObjC的Hook差不多的。
#include <Cocoa/Cocoa.h>
#include <objc/objc.h>
#include <objc/runtime.h>
#include <stdarg.h>
/*!
* @brief 用于替换不定参数方法的实现
*
* @param self self
* @param op selector
* @param obj1 first param
* @param ... other params
*
* @return for this case, returns an instance of NSDictionary
*/
id dictionaryWithObjectsAndKeys(id self, SEL op,id obj1, ...);
id dictionaryWithObjectsAndKeys(id self, SEL op,id obj1, ...)
{
/*!
* @brief 用于保存Key和Value
*/
NSMutableArray *keys = [[NSMutableArray alloc] init];
NSMutableArray *values = [[NSMutableArray alloc] init];
/*!
* @brief 使用stdarg提供的函数获取参数
*/
va_list args;
va_start(args, obj1);
id obj = obj1;
int flag = 0;
while (obj != nil) {
/*!
* @brief 因为这里演示的是NSDictionary的dictionaryWithObjectsAndKeys方法
* 所以判断一下现在获取的是Key还是Value
*/
if (flag % 2 == 0) {
[keys addObject:obj];
printf("[Hook] Key: %sn",[obj description].UTF8String);
} else {
[values addObject:obj];
printf("[Hook] Value: %sn",[obj description].UTF8String);
}
obj = va_arg(args, id);
flag++;
}
va_end(args);
/*!
* @brief 自己实现一下等价的功能, 对于不定参数方法有时不一定方便调用%orig;
*/
NSMutableDictionary * result = [[NSMutableDictionary alloc] init];
for (int index = 0; index < keys.count; index++)
[result setValue:[values objectAtIndex:index] forKey:[keys objectAtIndex:index]];
return result;
}
int main(int argc, const char * argv[])
{
/*!
* @brief 替换原来NSDictionary的实现
*/
method_setImplementation( class_getClassMethod( NSClassFromString( @"NSDictionary" ), NSSelectorFromString( @"dictionaryWithObjectsAndKeys:" ) ), (IMP)dictionaryWithObjectsAndKeys );
NSDictionary * dict = [NSDictionary dictionaryWithObjectsAndKeys : @"Name", @"[data deleted]", @"Info", @{@"Blog" : @"Blog.[data deleted].com"}, nil];
NSLog(@"%@",dict);
return 0;
}
感觉这种应该是有汇编级的库支持才对
跟msg_send类似,把栈复位就可以了吧?
我想了一下,调用原函数是个比较让人恼火的地方,你举的例子恰好可以找到比较方便的代替函数,但对于NSLog,objc_msgSend这样的函数,你要怎么调用原函数?通过va_list系列函数拿到的参数,要怎么传给原函数?
最近几天试了一下,感觉难度挺大。。。