查找和定位Android应用的按钮点击事件的代码位置基于Xposed Hook实现

若如初见. 提交于 2020-08-13 15:01:04

本文博客地址:https://blog.csdn.net/QQ1084283172/article/details/80956455

在进行Android程序的逆向分析的时候,经常需要通过Android应用程序的界面UI来定位代码的位置,比较常见的例子就是分析Android应用的网络协议时,用户点击登录按钮,实现客户端程序的登录,将用户的账号信息发送给服务器端进行验证,那么我们分析这个网络数据传输的流程中,首先要定位用户点击登录按钮的事件响应代码在哪里,当然了基于特征字符串的搜索和smali字节码的搜索都可以实现,感觉比较费时间或者效果不好,这里介绍一种基于Xposed Hook实现查找和定位Android应用的按钮点击事件的代码位置的方法,Xposed Hook的代码如下:

package com.xposed.enumeratorClassHook;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;

import android.view.View;
import android.widget.Button;

import de.robv.android.xposed.IXposedHookLoadPackage;
import de.robv.android.xposed.XC_MethodHook;
import de.robv.android.xposed.XposedBridge;
import de.robv.android.xposed.XposedHelpers;
import de.robv.android.xposed.callbacks.XC_LoadPackage.LoadPackageParam;
import static de.robv.android.xposed.XposedHelpers.findAndHookMethod;

// 自定义的回调函数接口
public class Module implements IXposedHookLoadPackage {
	
	static String strClassName = "";
	
	@Override
	public void handleLoadPackage(final LoadPackageParam lpparam) throws Throwable {
		
		// 被Hook操作的目标Android应用的包名,进行Hook操作的过滤
		String strPackageName = "com.guji.loveparty";
		if (lpparam.packageName.equals(strPackageName)) {
			
			XposedBridge.log("Loaded App:" + lpparam.packageName);
			
			// 不在Android应用默认的classes.dex文件中的类方法的Hook操作,例如:
			// 1.MultiDex情况下的,多dex文件中的类方法的Hook操作,例如:classes1.dex中的类方法
			// 2.主dex加载的jar(包含dex)情况下的,类方法的的Hook操作
			
			// Hook类方法ClassLoader#loadClass(String)
	        findAndHookMethod(ClassLoader.class, "loadClass", String.class, new XC_MethodHook() {
	        	
	        	// 在类方法loadClass执行之后执行的代码
	            @Override
	            protected void afterHookedMethod(MethodHookParam param) throws Throwable {
	            	
	            	// 参数的检查
	                if (param.hasThrowable()) {
	                	return;
	                }
	                
	                // 获取指定名称的类加载之后的Class<?>
	                Class<?> clazz = (Class<?>) param.getResult();
	                // 获取加载的指定类的名称
	                String strClazz = clazz.getName();
	                XposedBridge.log("LoadClass : "+strClazz);
	                
	                // 所有的类都是通过loadClass方法加载的
	                // 过滤掉Android系统的类以及一些常见的java类库
	                if (!strClazz.contains("xposed")) {
	                	// 或者只Hook加密算法类、网络数据传输类、按钮事件类等协议分析的重要类

	                	// 同步处理一下
	                	synchronized (this.getClass()) {
							
		                	// 获取被Hook的目标类的名称
		                	strClassName = strClazz;
			                //XposedBridge.log("HookedClass : "+strClazz);
		            		// 获取到指定名称类声明的所有方法的信息
		            		Method[] m = clazz.getDeclaredMethods();
		            		// 打印获取到的所有的类方法的信息
		                    for (int i = 0; i < m.length; i++) {
		                    	
		                    	//XposedBridge.log("HOOKED CLASS-METHOD: "+strClazz+"-"+m[i].toString());
		                        if (!Modifier.isAbstract(m[i].getModifiers())			// 过滤掉指定名称类中声明的抽象方法
		                        	 && !Modifier.isNative(m[i].getModifiers())			// 过滤掉指定名称类中声明的Native方法
		                        	 && !Modifier.isInterface(m[i].getModifiers())		// 过滤掉指定名称类中声明的接口方法
		                        	 ) {
		                     
		                        	// Hook处理类方法findViewById
		                        	// public final View findViewById(int id)
		                        	if ((m[i].getName()).contains("findViewById")) {
		                        		
			                        	// 对指定名称类中声明的非抽象方法进行java Hook处理
			                            XposedBridge.hookMethod(m[i], new XC_MethodHook() {
			                            	
			                            	// 被java Hook的类方法执行完毕之后,打印log日志
			                                @Override
			                                protected void afterHookedMethod(MethodHookParam param) throws Throwable {
			                                	
			                                	// 打印被java Hook的类方法的名称和参数类型等信息
			                                	XposedBridge.log("HOOKED METHOD: "+strClassName+"-"+param.method.toString()+"findViewById: "+param.args[0].toString());
//			                                	View view = (View)param.getResult();
//				                                XposedBridge.log("View-id: "+view.getId()+ "findViewById: "+param.args[0].toString());

			                                }
			                            });
		                        	}
		                        	
		                        	// public void setText(CharSequence text)
		                        	if ((m[i].getName()).contains("setText")) {
		                        		
			                        	// 对指定名称类中声明的非抽象方法进行java Hook处理
			                            XposedBridge.hookMethod(m[i], new XC_MethodHook() {
			                            	
			                            	// 被java Hook的类方法执行完毕之后,打印log日志
			                                @Override
			                                protected void afterHookedMethod(MethodHookParam param) throws Throwable {
			                                	
			                                	// 打印被java Hook的类方法的名称和参数类型等信息
			                                	XposedBridge.log("HOOKED METHOD: "+strClassName+"-"+param.method.toString()+ "setText: "+param.args[0].toString());
//			                                	View view = (View)param.thisObject;
//			                                	XposedBridge.log("View-id: "+view.getId()+ "setText: "+param.args[0].toString());
			                                }
			                            });
		                        	}
		                        	
		                        	// Hook处理类方法setOnClickListener
		                        	// public void setOnClickListener(OnClickListener l)
		                        	if ((m[i].getName()).contains("setOnClickListener")) {
			                        		
				                        	// 对指定名称类中声明的非抽象方法进行java Hook处理
				                            XposedBridge.hookMethod(m[i], new XC_MethodHook() {
				                            	
				                            	// 被java Hook的类方法执行完毕之后,打印log日志
				                                @Override
				                                protected void afterHookedMethod(MethodHookParam param) throws Throwable {
				                                	
				                                	// 打印被java Hook的类方法的名称和参数类型等信息
				                                	XposedBridge.log("HOOKED METHOD: "+strClassName+"-"+param.method.toString()+ "setOnClickListener: "+param.args[0].toString());
//				                                	View view = (View)param.thisObject;
//				                                	XposedBridge.log("View-id: "+view.getId()+ "setOnClickListener: "+param.args[0].toString());
				                                }
				                            });
		                        	}
		                        	
		                        	// Hook处理类方法onClick
		                        	// public void onClick(View v)
		                        	if ((m[i].getName()).contains("onClick")) {
			                        		
				                        	// 对指定名称类中声明的非抽象方法进行java Hook处理
				                            XposedBridge.hookMethod(m[i], new XC_MethodHook() {
				                            	
				                            	// 被java Hook的类方法执行完毕之后,打印log日志
				                                @Override
				                                protected void afterHookedMethod(MethodHookParam param) throws Throwable {
				                                	
				                                	// 打印被java Hook的类方法的名称和参数类型等信息
				                                	XposedBridge.log("HOOKED METHOD: "+strClassName+"-"+param.method.toString()+"onClick: "+param.args[0].toString());
//				                                	View view = (View)param.thisObject;
//				                                	XposedBridge.log("View-id: "+view.getId()+ "onClick: "+param.args[0].toString());
				                                }
				                            });
		                        	}
		                        	
		                        }
		                    }
						}
	                
	                }
	            }
	        });
		}
		
	}
	
    // 获取指定名称的类声明的类成员变量、类方法、内部类的信息
    public void dumpClass(Class<?> actions) {
    	
    	XposedBridge.log("Dump class " + actions.getName());
		XposedBridge.log("Methods");
		
		// 获取到指定名称类声明的所有方法的信息
		Method[] m = actions.getDeclaredMethods();
		// 打印获取到的所有的类方法的信息
        for (int i = 0; i < m.length; i++) {
        	
        	XposedBridge.log(m[i].toString());
        }
        
        XposedBridge.log("Fields");
        // 获取到指定名称类声明的所有变量的信息
        Field[] f = actions.getDeclaredFields();
        // 打印获取到的所有变量的信息
        for (int j = 0; j < f.length; j++) {
        	
        	XposedBridge.log(f[j].toString());
        }
        
        XposedBridge.log("Classes");
        // 获取到指定名称类中声明的所有内部类的信息
        Class<?>[] c = actions.getDeclaredClasses();
        // 打印获取到的所有内部类的信息
        for (int k = 0; k < c.length; k++) {
        	
        	XposedBridge.log(c[k].toString());
        }
	}
}
	
/**
 * Look up a method and place a hook on it. The last argument must be the callback for the hook.
 * @see #findMethodExact(Class, String, Object...)
 */
/* 目标java方法的Hook
public static XC_MethodHook.Unhook findAndHookMethod(Class<?> clazz, String methodName, Object... parameterTypesAndCallback) {
	if (parameterTypesAndCallback.length == 0 || !(parameterTypesAndCallback[parameterTypesAndCallback.length-1] instanceof XC_MethodHook))
		throw new IllegalArgumentException("no callback defined");

	XC_MethodHook callback = (XC_MethodHook) parameterTypesAndCallback[parameterTypesAndCallback.length-1];
	Method m = findMethodExact(clazz, methodName, getParameterClasses(clazz.getClassLoader(), parameterTypesAndCallback));

	return XposedBridge.hookMethod(m, callback);
}*/

/** @see #findAndHookMethod(Class, String, Object...) */
/* 目标java方法的Hook
 public static XC_MethodHook.Unhook findAndHookMethod(String className, ClassLoader classLoader, String methodName, Object... parameterTypesAndCallback) {
	return findAndHookMethod(findClass(className, classLoader), methodName, parameterTypesAndCallback);
}*/


/**
* Loads the class with the specified name. Invoking this method is
* equivalent to calling {@code loadClass(className, false)}.
* <p>
* <strong>Note:</strong> In the Android reference implementation, the
* second parameter of {@link #loadClass(String, boolean)} is ignored
* anyway.
* </p>
*
* @return the {@code Class} object.
* @param className
*            the name of the class to look for.
* @throws ClassNotFoundException
*             if the class can not be found.
*/
//public Class<?> loadClass(String className) throws ClassNotFoundException {
//        return loadClass(className, false);
//    }

基于Xposed Hook框架查找和定位Android应用的按钮点击事件的代码位置的效果如下图所示:


说明:Xposed Hook的代码写的比较简单,还有很多需要优化和改进的地方,比如怎么提高Xposed Hook框架的Hook效率,怎么防止这种低效的Hook操作导致的Android应用的无响应或者崩溃。


标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!