xposed创建教程参考 Android Studio Xposed模块编写
没有Android基础都能学会的Xposed基础教程
推荐一个xposed入门的很好的公众号:安卓Xposed框架交流
最后创建完毕就是这个样子
这里我已经编译好了,可以直接用我的模块修改就行 https://github.com/la0s/XposedHookDemo
这里针对一个APP进行逆向,打印一下它的某些关键参数和签名
使用JEB进行反编译后
我们使用xposed来hook一下getSign方法 它的参数和返回值
代码解释
public class XposedHook implements IXposedHookLoadPackage {
@Override
public void handleLoadPackage(XC_LoadPackage.LoadPackageParam loadPackageParam) throws Throwable {
if (loadPackageParam.packageName.equals("cn.thecover.www.covermedia")) { //过滤包名
Class clasz = loadPackageParam.classLoader.loadClass("cn.thecover.www.covermedia.data.entity.HttpRequestEntity"); //要hook的方法所在的类名
XposedHelpers.findAndHookMethod(clasz, "getSign",String.class,String.class,String.class, new XC_MethodHook() { //要hook的方法名和参数类型,此处为三个String类型
@Override //重写XC_MethodHook()的回调方法
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
Log.i("hook before param1:", (String) param.args[0]); //打印第一个参数
Log.i("hook before param2:", (String) param.args[1]);
Log.i("hook before param3:", (String) param.args[2]);
}
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
Log.i("hook after result:",param.getResult().toString()); //打印返回值(String类型)
}
});
}
}
}
上面findAndHookMethod有两种写法
findAndHookMethod(String className,ClassLoader classLoader,String methodName, Object... parameter TypesAndCallback)
findAndHookMethod(Class<?> clazz, String methodName,Object... parameter TypesAndCallback) //其中clazz使用classLoader.loadClass和 XposedHelpers.findClass两种方法都可以
所以看到后面的代码不要奇怪,两种方法都是可以的。另外也可以先设置为new XC_MethodHook/XC_MethodReplacement的回调参数,然后再调用此参数,这种写法在循环hook中很常见(组合不定的参数列表和回调类参数,前者使用一个list或者array来存储),见TrustMeAlready和xposed新思路。
装上模块后重启,点击应用,打开DDMS过滤
是不是觉得xposed很简单,然而事情并不是想象中这样,这个应用有两个dex,这里的方法所在的类恰好是第一个class.dex(主dex),所以我们能够hook成功,但是如果像下图这个方法是在另一个dex文件里就不这么顺利了(hook会报错经典的ClassNotFound)
原因是Android5.0以下hook一个某个方法,而这个方法不在主dex,而存在分包dex。此时xposed会在没有加载分包dex的时候进行回调handleLoadPackage,类加载器(ClassLoader)并没有加载分包里面的类 会导致XposedHelpers.findAndHookMethod抛出异常。对于multidex的问题,xposed作者给出的建议是hook Appliation的attach方法来解决多dex文件,详情见Multidex support,如下图(其实看到后面会发现有一个更巧妙更简单的办法)
上面这个新闻APP到了最新版4.2.0之后变成了梆梆加壳,那么我们再想使用xposed来hook的话就不能采用上面这种普通的方法了,会报错class not found。其实Hook加固应用Hook不到的原因是,Xposed模块中handleLoadPackage被调用时壳没有启动,所以并没有将应用的类装载进VM(Xposed的实现原理,其只能Hook已经真实存在的方法,如果某个方法在内存中并不存在或者暂时还不存在,Xposed是无法进行预先Hook的),这里介绍三种方法
1.第一种姿势:先以360为例,从manifest.xml中android:name=”com.stub.StubApp”可知壳入口,先从壳里获取到context参数,然后就可以通过context获得到360的classloader,之后只需要用这个classloader就可以hook了,见使用xposed来hook使用360加固的应用
public class XposedHook implements IXposedHookLoadPackage{
private String TAG = "Hook";
@Override
public void handleLoadPackage(XC_LoadPackage.LoadPackageParam loadPackageParam) throws Throwable {
if (loadPackageParam.packageName.equals("com.peopledailychina.activity")) {
XposedBridge.log("开始hook....");
//hook加固后的包,首先hook attachBaseContext这个方法来获取context对象
XposedHelpers.findAndHookMethod("com.stub.StubApp", loadPackageParam.classLoader, "attachBaseContext", Context.class, new XC_MethodHook() {
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
super.afterHookedMethod(param);
//获取到的参数args[0]就是360的Context对象,通过这个对象来获取classloader
Context context = (Context) param.args[0];
//获取360的classloader,之后hook加固后的就使用这个classloader
ClassLoader classLoader =context.getClassLoader();
//下面就是强classloader修改成360的classloader就可以成功的hook了
XposedHelpers.findAndHookMethod("com.peopledaily.common.encrtption.MD5Helper", classLoader, "getMD5Str", String.class, new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
XposedBridge.log(param.method + " params: " + Arrays.toString(param.args));
//Log.i("params: " , Arrays.toString(param.args));
}
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
XposedBridge.log(param.method + " return: " + param.getResult());
//Log.i( " return: " , param.method,param.getResult());
}
});
}
});
}}}
腾讯的壳(其他的梆梆和爱加密壳同理,第一步都是先找到壳的attachBaseContext然后hook就好说了。另外不得不提就是阿里的壳,因为类和方法抽取到native层了,这个用xposed是获取不到的,除了frida目前没有别的好办法)
2.第二种姿势:使用ClassLoader的loadClass方法进行类名匹配,Hook loadClass方法,就能得到所有的类,见Xposed Hook Apk不在classes.dex中定义的类,这也是那个xposed公众号里的文章。这是一种通用的方法,multidex,动态加载dex等问题都可以用这种姿势解决!
public class XposedHook implements IXposedHookLoadPackage {
@Override
public void handleLoadPackage(LoadPackageParam lpp) throws Throwable {
if (!"cn.thecover.www.covermedia".equals(lpp.packageName)) return;
// 第一步:Hook方法ClassLoader#loadClass(String)
findAndHookMethod(ClassLoader.class, "loadClass", String.class, new XC_MethodHook() {
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
if (param.hasThrowable()) return;
Class<?> cls = (Class<?>) param.getResult();
String name = cls.getName();
if ("cn.thecover.www.covermedia.data.entity.HttpRequestEntity".equals(name)) {
// 所有的类都是通过loadClass方法加载的
// 所以这里通过判断全限定类名,查找到目标类
// 第二步:Hook目标方法
findAndHookMethod(cls, "getSign", String.class, String.class,String.class, new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
XposedBridge.log(param.method + " params: " + Arrays.toString(param.args));
//Log.i("params: " , Arrays.toString(param.args));
}
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
XposedBridge.log(param.method + " return: " + param.getResult());
//Log.i( " return: " , param.method,param.getResult());
}
});
}
}
});
} }
装上模块并重启
接着在此基础上再来看结合复杂参数的hook方式
我们要hook上面的方法必须要考虑方法参数的正确写法,否则会报NoSuchMethod错误,感谢看雪前辈提供的思路[原创]安卓Hook函数的复杂参数如何给定?,因为应用是经过加固的,使用XposedHelpers的findClass方法获取类会提示找不到类,这个只要在ClassLoader.loadClass匹配到类名之后方法之后再调用就好了,下面给出我的脚本
public class XposedHook implements IXposedHookLoadPackage {
@Override
public void handleLoadPackage(final LoadPackageParam lpp) throws Throwable {
if (!"com.tima.android.afmpn".equals(lpp.packageName)) return;
// 第一步:Hook方法ClassLoader#loadClass(String)
findAndHookMethod(ClassLoader.class, "loadClass", String.class, new XC_MethodHook() {
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
if (param.hasThrowable()) return;
Class<?> cls = (Class<?>) param.getResult();
String name = cls.getName();
if ("com.timanetworks.timasync.android.base.AsyncSender".equals(name)) {
// 所有的类都是通过loadClass方法加载的
// 所以这里通过判断全限定类名,查找到目标类
// 第二步:Hook目标方法
final Class<?> ArgTBase= XposedHelpers.findClass("org.apache.thrift.TBase", lpp.classLoader);//在ClassLoader.loadClass匹配到类名之后方法之后再调用就不会报错了
final Class<?> ArgClass= XposedHelpers.findClass("java.lang.Class", lpp.classLoader);
findAndHookMethod(cls, "send", ArgTBase , ArgClass, new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
XposedBridge.log(param.method + " params: " + Arrays.toString(param.args));
//Log.i("params: " , Arrays.toString(param.args));
}
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
XposedBridge.log(param.method + " return: " + param.getResult());
//Log.i( " return: " , param.method,param.getResult());
}
});
}
}
});
}
}
3.第三种姿势:选择hook时机onNewActivity,即新Activity创建时,一般也代表着相关类早已加载完成,我们就可以成功hook了,这里使用xposed的一个Timing模板来hook加固后的应用,步骤参考三分钟学会Hook加固后应用,最后使用模板创建完了如下图,这里获得加壳应用的方法名可以用TraceView打印或者用FDex2脱壳后逆向查找
同样我把创建好了的AS项目源码放在了我的仓库里XposedShell ,直接下载编译即可,装了之后重启,运行APP,查看xposed日志
可以看到xposed成功hook到了加壳的APP的方法的参数和返回值,最后来看如何利用xposed打印堆栈,参考Xposed打印函数调用堆栈的几种方法