Hook是什么?
Hook 又叫“钩子”,它可以在事件传送的过程中截获并监控事件的传输,将自身的代码与系统方法进行融入。
这样当这些方法被调用时,也就可以执行我们自己的代码,这也是面向切面编程的思想(AOP)。
它只在java层,只能通过替换对象达到目的,适用范围较小。但是,调用反射和动态代理并不存在适配问题,实现起来较简单。
它主要应用于java层的java Application和java Framwork。反射和动态代理是虚拟机提供的标准编程接口,可靠性较高。通过反射API可以帮助我们们访问到private属性并修改,动态代理可以直接从Interface中动态的构造出代理对象,并去监控这个对象。
常见的用法是,用动态代理构造出一个代理对象,然后用反射API去替换进程中的对象,从而达到hook的目的。如:对Java Framework API的修改常用这种方法,修改ActivityThread、修当前进程的系统调用等。
Android使用Hook技术能做什么
1.修改应用行为: 通过Hook技术,您可以拦截和修改应用程序的方法调用,从而改变其行为。这可以用于修改应用程序的默认设置、更改UI元素等。
2.日志记录: 您可以使用Hook技术来拦截应用程序的方法调用并记录相关信息,以便进行调试或分析应用程序的运行时行为。
3.破解与逆向工程: Hook技术常常被用于逆向工程和破解应用程序,以绕过一些安全措施或获取应用程序的内部信息。
4.插件开发: 您可以使用Hook技术来实现插件化开发,使得您可以在不修改应用程序源代码的情况下,添加新功能或修改现有功能。
5.广告屏蔽: 通过拦截应用程序的广告相关方法,您可以实现广告屏蔽,使应用程序不显示广告内容。
6.性能优化: 您可以使用Hook技术来监控应用程序的性能,并进行一些优化操作,例如缓存数据、减少不必要的操作等。
7.安全增强: 在某些情况下,Hook技术也可以用于增强应用程序的安全性,例如在特定方法调用前进行安全检查。
8.动态加载类和资源: 您可以使用Hook技术动态加载类和资源,实现一些动态特性或主题切换。
示例:Hook 修改任何view上的文本
点击事件的方法:
将OnClickListener对象赋予给了ListenerInfo对象的mOnClickListener。
public void setOnClickListener(@Nullable OnClickListener l) {
if (!isClickable()) {
setClickable(true);
}
getListenerInfo().mOnClickListener = l;
}
@UnsupportedAppUsage
ListenerInfo getListenerInfo() {
if (mListenerInfo != null) {
return mListenerInfo;
}
mListenerInfo = new ListenerInfo();
return mListenerInfo;
}
ListenerInfo类是View的抽象内部类,声明了View的各种事件listener,而我们要找的mOnClickListener就在其中。
static class ListenerInfo {
@UnsupportedAppUsage
ListenerInfo() {
}
protected OnFocusChangeListener mOnFocusChangeListener;
private ArrayList<OnLayoutChangeListener> mOnLayoutChangeListeners;
protected OnScrollChangeListener mOnScrollChangeListener;
public OnClickListener mOnClickListener;
protected OnLongClickListener mOnLongClickListener;
private OnKeyListener mOnKeyListener;
private OnTouchListener mOnTouchListener;
private OnHoverListener mOnHoverListener;
private OnDragListener mOnDragListener;
实现思路:
1.利用反射获取 ListenerInfo 对象
2.获取原始的 OnClickListener事件方法
3.用在原有方法执行过程中,用动态代码替换原有OnClickListener,执行自己点击事件方法
代码实现:
HookHelper类:
public class HookHelper {
/**
* 在不修改以上代码的情况下,通过Hook把 ((Button) view).getText()内给修改
*
* @param view view对象
*/
public static void hookClickListener(View view) throws Exception {
//之前的还是用户写的实现代码
//为了获取ListenerInfo对象,需要执行这个方法 ListenerInfo getListenerInfo() ,才能拿到
Class<?> viewClass = Class.forName("android.view.View");
Method getListenerInfoMethod = viewClass.getDeclaredMethod("getListenerInfo");
getListenerInfoMethod.setAccessible(true);
Object listenerInfo = getListenerInfoMethod.invoke(view); //获取ListenerInfo对象
//替换 public OnClickListener mOnClickListener; 替换为我们自己的
Class<?> listenerInfoClass = Class.forName("android.view.View$ListenerInfo");
Field field = listenerInfoClass.getField("mOnClickListener");
Object mOnClickListenerObj = field.get(listenerInfo); //获取该view下的mOnClickListener对象
//1.监听onClick,当用户点击按钮的时候-->onClick,我们自己要先拦截这个事件,动态代理
//第一个参数:类加载器
//第二个参数:要监听的接口,监听什么接口,就返回什么接口
//第三个参数:监听接口方法里面的回调
Object onClickListenerProxy = Proxy.newProxyInstance(MainActivity.class.getClassLoader(), new Class[]{View.OnClickListener.class}, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Log.i("minfo", "拦截到了OnClickListener方法了");
//使用hook的方法,让任何带文字的按钮,文字都被指定性地修改
if (view instanceof TextView) {
((TextView)view).setText("被hook的textview");
}
//让系统片段,正常的执行下去
return method.invoke(mOnClickListenerObj, view);
}
});
//把系统的mOnClickListener,换成我们自己写的动态代理
field.set(listenerInfo, onClickListenerProxy);
}
}
MainActivity中执行代码:
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
var button = findViewById<Button>(R.id.button)
button.setOnClickListener {
Toast.makeText(this@MainActivity, "" + (it as Button).text, Toast.LENGTH_SHORT).show()
}
HookHelper.hookClickListener(button)
}
}
Github代码地址:
https://github.com/running-libo/HookProject
参考:
Android Hook 机制之简单实战
https://blog.csdn.net/lu202032/article/details/131754789