博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Objective-C runtime 拾遗 (二)——Log message send
阅读量:6260 次
发布时间:2019-06-22

本文共 3363 字,大约阅读时间需要 11 分钟。

原因

最近在考虑对App中所有的message进行Log,资料不少,前人也有一些实现,做些记录。

对Objc_msgSend进行Hook

OC的Messaging都是通过改函数的调用的。如[foo bar],会被转化成:Objc_msgSend(foo,@selector(bar))。这个大家应该都知道,不多说。具体参见Apple文档:和

如果能够对其进行Hook,那就可以进行Log了。Facebook出品了,很多,在载入符号表时进行替换,不多说。但最后问题是,Hook之后怎么将原来的参数传递给原来的实现呢?好像也不是很straightforward,这个后面再写一篇文章来讨论这个问题。但目前想要简单的通过HookObjc_msgSend来对message进行Log并不方便

系统提供的方法

因为其实最开始并不想做Hook,所以先看看系统是否提供Log所有Message的方法。果然,Simulator上是有方法的。

开启instrumentObjcMessageSends

方法并不唯一

在lldb中

(lldb)p (void)instrumentObjcMessageSends(YES)

开启之后Log日志放在/private/tmp/msgSends-%d%d是进程pid

在code中

instrumentObjcMessageSends(YES);

要注意的是,使用前记得声明一下:

extern void instrumentObjcMessageSends(BOOL);

当然可以稍微geek一点来调用:

通过dlsym

typedef void functype(BOOL);void *libobjc = dlopen("/usr/lib/libobjc.dylib", RTLD_LAZY);functype *instrumentObjcMessageSends = dlsym(libobjc, "instrumentObjcMessageSends");instrumentObjcMessageSends(YES);

日志还是放在同样的地方。

logMessageSend

上述只是开启instrumentObjcMessageSends,但是,具体Log的实现是系统的。如果开发者想要对Log的message进行过滤,似乎还要一些手段(当然可以通过处理msgSends-%d文件来实现,不过那样就不动态了)。

看看最新的,发现一段代码:

bool logMessageSend(bool isClassMethod,                    const char *objectsClass,                    const char *implementingClass,                    SEL selector){    ...}

这个就是系统实现Log方法,具体不展开解释了。

那么只需要对logMessageSend进行Hook一下就好了,现在可以愉快的使用fishhook了。

#import "fishhook.h"#import 
void (*orig_logMessageSend)(bool,const char *,const char *,SEL);void my_logMessageSend(bool,const char *,const char *,SEL);void my_logMessageSend(bool isClassMethod, const char *objectsClass, const char *implementingClass, SEL selector){ //实现自己的Log ...... //也可以不调用 orig_logMessageSend(isClassMethod,objectsClass,implementingClass,selector);}rebind_symbols((struct rebinding[1]){
{"logMessageSend", my_logMessageSend, (void *)&orig_logMessageSend}}, 1);

使用DTrace

sudo dtrace -q -n 'objc1234:::entry { printf("%s %s\n", probemod, probefunc); }'

没试过,参考:

总述&讨论

  • 上述方法只能在模拟器上,不支持iOS device。可以参见源码。

  • 该方法只能Log,其他也不能干什么。似乎还是得打objc_msgSend的主意。

已经有人这样干过了, 。这是个很好的参考。不过稍微有点年久失修,下次再讲讲原理和实践。

  • 在上面进行logMessageSendHook时还有点其他东西。原本有工程师发现以前的源码是支持从外部注入Log函数的。这是系统的实现,

typedef int    (*ObjCLogProc)(BOOL, const char *, const char *, SEL);__private_extern__ void    logObjcMessageSends      (ObjCLogProc    logProc){    if (logProc)    {        objcMsgLogProc = logProc;        objcMsgLogEnabled = 1;    }    else    {        objcMsgLogProc = logProc;        objcMsgLogEnabled = 0;    }    if (objcMsgLogFD != (-1))        fsync (objcMsgLogFD);}

只要找到logObjcMessageSends符号,调用即可。虽然被staic隐藏了,但不妨碍。除了上述dlsym。还有下面一种方法:

#import 
typedef int (*ObjCLogProc)(BOOL, const char *, const char *, SEL);typedef int (*LogObjcMessageSendsFunc)(ObjCLogProc);extern bool logMessageSend(bool isClassMethod, const char *objectsClass, const char *implementingClass, SEL selector);{ LogObjcMessageSendsFunc fcn; struct nlist nl[2]; bzero(&nl, sizeof(struct nlist) * 2); nl[0].n_un.n_name = "_instrumentObjcMessageSends"; nl[1].n_un.n_name = "_logObjcMessageSends"; typedef int (*LogObjcMessageSendsFunc)(ObjCLogProc); fcn = (LogObjcMessageSendsFunc)( (long) (&instrumentObjcMessageSends) + (nl[1].n_value-nl[0].n_value)); fcn(&my_logMessageSend);}

不太实用。因为新的实现已经没有这个方法。只是觉得比较有趣,记录一下。

原作写于segmentfault

转载地址:http://fthsa.baihongyu.com/

你可能感兴趣的文章
python模块学习(二)
查看>>
近期的爬虫工作杂谈
查看>>
机器学习之 k 近邻
查看>>
canvas核心技术-如何绘制图形
查看>>
netty源码分析之pipeline(二)
查看>>
面试:讲讲 Android 的事件分发机制
查看>>
计算机程序的思维逻辑 (95) - Java 8的日期和时间API
查看>>
计算机程序的思维逻辑 (8) - char的真正含义
查看>>
2019 年技术大趋势预测
查看>>
推荐一款基于vue的滚动条插件vuescroll
查看>>
安全圈有多大?也许就这么大!
查看>>
App基于手机壳颜色换肤?先尝试一下用 KMeans 来提取图像中的主色
查看>>
RecyclerView的滚动事件研究
查看>>
XXL-MQ v1.2.2 发布,分布式消息队列
查看>>
多线程:GCD
查看>>
深度解读 2018 JavaScript 趋势报告(含视频)
查看>>
以 RAIDs 分析作为架构驱动力
查看>>
Rust 2018 年度调查报告
查看>>
Tensorflow快餐教程(1) - 30行代码搞定手写识别
查看>>
聊聊flink Table的Set Operations
查看>>