一.什么是钩子函数?
先来看一段百科:钩子函数是Windows消息处理机制的一部分,通过设置“钩子”,应用程序可以在系统级对所有消息、事件进行过滤,访问在正常情况下无法访问的消息。钩子的本质是一段用以处理系统消息的程序,通过系统调用,把它挂入系统。
get关键词,在系统级对所有消息进行过滤,就是说钩子函数是在一个事件触发的时候,在系统级捕获到了他,然后做一些操作。一段用以处理系统消息的程序,用以处理系统消息的程序,是说钩子函数是用于处理系统消息的。
总结一下:
钩子函数:
1、是个函数,在系统消息触发时被系统调用
2、不是用户自己触发的
钩子函数的名称是确定的,当系统消息触发,自动会调用。例如react的componentWillUpdate函数,用户只需要编写componentWillUpdate的函数体,当组件状态改变要更新时,系统就会调用componentWillUpdate。
常见的钩子函数:
react的生命周期函数、vue的生命周期函数等
二.Unity中可以用的Hook函数
分享公司大佬的Misaka Mikoto的https://github.com/easy66/MonoHooker,
特点:
- 运行时直接修改内存中的 jit 代码,不会修改 UnityEditor.dll 等文件,避免让别人修改文件的尴尬。
- 不影响调试。
- 同时支持 .net 2.x 与 .net 4.x。
- 目前测试支持 unity4.7.2, unity5.x, unity 2017 与 unity 2018。
- 使用很方便,在C#内定义签名与原始方法相同的两个方法然后注册一下就能用了。
- 目前已支持 Android Mono, Windows Mono/IL2CPP
三.在项目中遇到的问题中的使用
定位一个FxClear的cs,被添加两次,看着逻辑本身没有什么问题,还是不清楚哪里让Fxclear被添加两次。通过hook函数定位到问题在哪里了.
FxClear有[RequireComponent(typeof(ParticleLOD))],而ParticleLOD在Awake()里有gameObject.GetOrAddComponent
修改到Start();
particleSystem的Render 的enable被设置为false。之前在所有render被改为false的地方加断点,没断到。通过hook函数成功定位到了问题。
GetComponentsInChildren
当某个节点setactive(false)的时候,在子节点的render并不会被Get到。解决方案是GetComponentsInChildren
四.怎么做到呢
底层是汇编,在x8,x64上不同的处理,因为我也缺少汇编相关的知识,请大佬讲解了下,push作为一个函数的开始,ret是函数的结束。
在push函数地址替换成自己用的函数地址,执行完毕再继续执行原来的函数,通过这样达到hook,在不同的环境可以使用。当然也要函数长度满足8个字节长度。
因为也支持arm环境。发现设备环境确实有点不一样的。
同样不影响执行的效率。