首页
社区
课程
招聘
[原创] hook objc_msgSend方法以获取OC方法入参
发表于: 2022-1-24 20:24 48255

[原创] hook objc_msgSend方法以获取OC方法入参

2022-1-24 20:24
48255

objc_msgSend是iOS里最重要的方法。

按道理来说,hook objc_msgSend就可以获取到app中所有调用的OC方法名和参数等。

所有的OC方法都需要经过objc_msgSend方法消息转发寻找方法IMP。

参考hook objc_msgSend从而获得OC方法执行时间

objc_msgSend源码参考 苹果openSource

此方法考虑效率,使用汇编编写,此方法大致上有4个关键步骤:

综上看,这个方法是一个"跳板"函数,并且它是线程安全的。

上述的4个步骤中,1,2,4是线程安全的,3步骤利用一些trick保障了线程安全,具体超出了本文的范围,可查看剖析objc_msgSend,其中对objc_msgSend方法的汇编实现,逐行讲解。

因为根据 #include <objc/message.h>objc_msgSend函数的定义如下:

所以将它视为普通的C函数,利用 fishhook / cydia substrate hook,结合va_list分析传入的参数,应该就可以。

但是,不可以。通过据这里介绍,arm 64位上的va_list结构改变了,不能使用va_list了,因此此方法不能实现。

没有验证正确性。

既然利用va_list获取参数不可行。

参考objc_msgSend源码,因为在arm 64上,x0 - x8寄存器用于传参,所以结合汇编代码,应该可以hook,crx0715已经成功,具体可以查看它的讲解。

使用fishhook很好,因为fishhook是导出表hook,不会修改原方法的实现。

大概实现如下:

其中,保存寄存器,即 使用stp命令,将寄存器保存到栈上。

提高栈帧SP,减小地址即可。因为iOS上内存栈帧由高地址向低地址,即后入的参数在内存低地址。

偏移寻址的标记后多了一个 !,在执行完上文的 stp 指令后,还会使 sp 寄存器也产生偏移。

同理,还原寄存器,使用ldp命令降低栈帧SP。

既然fishhook可行,inline hook也可以。

区别在于inline hook会修改原始方法的前3条指令,备份函数会将这前3条指令备份下来,然后br跳转到原始方法的第四条指令。如此调用备份函数就好像调用原始objc_msgSend一样。具体inline hook的如何修改的原理就不赘述了。

具体流程和fishhook一致,不过经过实验有个坑,就是在before_objc_msgSend_inlineafter_objc_msgSend_inline中暂时不能调用OC方法,因为会造成如下死循环。

由于参数保存在x0-x8寄存器中,那么在before_objc_msgSend中对寄存器分析,就可以获取到入参。

这里有个坑,self参数,在一些app中会引入引用计数问题导致崩溃,还没有具体查询。作为TODO吧,现在

的printSpecificParam_fish参数入参需要修改一下,将self去除:

可以看到打印了所有的OC方法的方法名和参数。

完成代码可以参考github地址

 
 
 
 
 
id _Nullable objc_msgSend(id _Nullable self, SEL _Nonnull op, ...)
id _Nullable objc_msgSend(id _Nullable self, SEL _Nonnull op, ...)
 
 
 
 

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

最后于 2022-1-25 11:13 被LeoW丨编辑 ,原因: 更换图片
收藏
免费 2
支持
分享
最新回复 (7)
雪    币: 5
活跃值: (116)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
太强了 TQL
2022-1-24 22:09
0
雪    币: 3836
活跃值: (4142)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
666666666
2022-1-25 08:55
0
雪    币: 5482
活跃值: (3272)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
4
mark 支持一下
2022-1-25 17:27
0
雪    币: 249
活跃值: (508)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
实测了一把,有两个小问题:1.如何打印方法对应的类名,2.这种打印方式,消耗内存,启动速度明显变慢。不过大佬的思路不错,在fishhook中有对寄存器的操作,优秀。
2022-2-18 18:51
0
雪    币: 436
活跃值: (486)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
6
chenxia0 实测了一把,有两个小问题:1.如何打印方法对应的类名,2.这种打印方式,消耗内存,启动速度明显变慢。不过大佬的思路不错,在fishhook中有对寄存器的操作,优秀。
1. 打印类名后来注释了,有偶现的崩溃,还不稳定。可以修改一下代码,x0即为self,把x0传入printSpecificParam_fish方法,利用object_getClassName方法就能获取到类名。
2. hook会导致启动速度变慢,还需要优化,回头搞一下
2022-4-7 16:38
0
雪    币: 120
活跃值: (1597)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
mark 支持一下
2022-4-14 20:36
0
雪    币: 0
活跃值: (296)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
mark 支持一下
2022-4-20 11:48
0
游客
登录 | 注册 方可回帖
返回
//