为何需要hook日志:
1.控制台输出的日志太多太杂了,导致看不见关键信息.
2.或者有些输出的日志search不到源码,但是需要知道从哪儿调用的?(比如想知道哪个第三方库调用的)
哪些方式:
1.控制台右下角文本过滤,这个就不说了....
2.设置xcode环境变量 OS_ACTIVITY_MODE 为 Disable,将会所有log不可见,不论系统log还是自行输出log
3.自定义宏代替NSLog宏
#ifdef _DEBUG
#define DLog(fmt, ...) NSLog((@"[Line %d] " fmt), __LINE__, ##__VA_ARGS__);
#else
#define DLog(...)
#endif
4.还有一些Log可能是在第三方的库里面打印的,所以我们无法采用第三种方式.我们可以采用method_swizzle来进行方法替换,但是NSLog和printf是函数,这时候就需要用到fishhook来进行函数实现替换
原理:
简单说就是修改系统函数地址(自定义函数不可hook),达到函数实现交换的目的.详见https://github.com/facebook/fishhook
用法
A.替换nslog
static void (*orig_nslog)(NSString *format, ...);
void my_nslog(NSString *format, ...) {
va_list vl;
va_start(vl, format);
NSString *str = [[NSString alloc] initWithFormat:format arguments:vl];
va_end(vl);
//此处类似method_swizzle
orig_nslog([NSString stringWithFormat:@"test - %@",str]);
}
//启动后执行下面这句话即可实现NSLog() hook
struct rebinding nslog_rebinding = {"NSLog",my_nslog,(void*)&orig_nslog};
//1代表后面有一个函数实现需要重新绑定
rebind_symbols((struct rebinding[1]){nslog_rebinding}, 1);
以下为hook之后的log
B.替换NSLogv,有些极少的情况,可能还需要hook NSLogv()
static void (*orig_nslogv)(NSString *format,va_list args);
void my_nslogv(NSString *format,va_list args) {
orig_nslogv(format,args);
}
struct rebinding nslogv_rebinding = {"NSLogv",my_nslogv,(void*)&orig_nslogv};
rebind_symbols((struct rebinding[1]){nslogv_rebinding}, 1);
C.替换printf
static void (*orig_printf)(const char *path, ...);
void my_printf(const char *path,...) {
orig_printf(path);
}
struct rebinding printf_rebinding = {"printf",my_printf,(void*)&orig_printf};
rebind_symbols((struct rebinding[1]){printf_rebinding}, 1);
hook效果如下
通过以上方式可以在hook住的时候看见左边的调用堆栈信息,也许有一些帮助