本文博客地址: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应用的无响应或者崩溃。
来源:oschina
链接:https://my.oschina.net/u/4275902/blog/4462241