整理Android XposedHook使用中的一些问题

0x00 Xposed安装

网上有很多Xposed安装教程,下面给出我的nexus5真机中系统为Android4.4.4中的安装教程和资源:

https://download.csdn.net/download/wenrennaoda/10733892

网上也有很多类似的教程和资源,这里不再赘述。

0x01 Xposed的配置与demo实现

作者rovo89提供了非常详细的使用方法及其原理简要介绍:

https://github.com/rovo89/XposedBridge/wiki/Development-tutorial

下面这篇文章基本重现了使用方法:

https://www.52pojie.cn/thread-738254-1-1.html

0x02 常用Xposedhook API介绍

Xposed框架提供的API都是静态函数,直接通过类调用函数即可。

一、APP过滤

如Demo中所示模块入口:public interface IXposedHookLoadPackage extends IXposedMod 用于hook应用的代码,自定义的类实现该类并重载 handleLoadPackage(final XC_LoadPackage.LoadPackageParam lpparam)方法,在内部进行一系列的Hook操作。参数XC_LoadPackage.LoadPackageParam lpparam.packageName:获取包名,用来过滤需要Hook的APP应用。

        //过滤包
        if (!PACKAGE_NAME.equals(lpparam.packageName)) {
            return;
        }

二、定位Hook

1、一般方法

Hook某个函数:通过XposedHelpers.findAndHookMethod静态方法找到类的函数:

Hook类中所有函数名相同的重载函数:XposedBridge.hookAllMethods

2、构造函数

Hook某个构造函数:XposedHelpers.findAndHookConstructor

Hook类中所有构造函数:XposedBridge.hookAllConstructors

若要改变static区域代码中设置的变量值,可Hook构造函数在函数结尾通过反射进行重新设置

三、寻找自定义类型

hook定位函数时参数列表类型经常会遇到APP自定义的类,则需要获取这些类型。通过获取类加载器调用反射函数获取即可。见下文找不到类中的两个实例代码中注释部分的代码。

实际上Xposed封装了找类的函数: XposedHelpers.findClass("ClassName",classloader);//classloader可以是前文的loadPackageParam.classLoader获取,但是有时候获取不到类。需要使用到下文找不到类的方法获取正确的classLoader

四、Hook代码实现

在二中的回调中重载下述方法进行代码插桩:

protected void beforeHookedMethod(MethodHookParam param) 在函数开头执行

protected void afterHookedMethod(MethodHookParam param) 在函数结尾执行

参数param有以下用法:

param.args[i];//获取或者设置第i个参数
param.setResult(value);//设置返回值
param.getResult(value);//获取返回值
param.thisObject//获取本类对象实例,获取Object后,通过java反射方式获取类中的成员和调用实例函数
                //Object obj = param.thisObject;
                //Class<?> clazz = obj.getClass();
                //Field var1 = clazz.getDeclaredField("mVarName");// clazz.getField()
                //var1.setAccessible(true);//private变成可访问
                //var1.set(obj,value);
                   

 

0x03 找不到类(ClassNotFoundError)的解决方案

   如果仅使用上述Demo中所述的方法进行Hook类函数,在很多稍微大点的APK中经常会出现如下错误:

de.robv.android.xposed.XposedHelpers$ClassNotFoundError: java.lang.ClassNotFoundException: XXX.XXX.XXX

  发生这种错误一般是由于下述三个原因引起。 

1、类名

    确保Hook的类名是否书写正确。

2、多dex

   一般稍微大点的APK都是多dex的,可通过解压出的APK文件中看是否存在多dex情形。

多dex情形

在dex文件格式的DexHeader部分描述了整个dex文件的结构,其中包括方法的偏移位置methodIdsoff以及从该位置解析的方法个数methodIdsSize。然而个数是u4类型的也就是uint32_t,所以一个dex能表示远远超过65536个方法。如下所示:

非虫的dex文件格式图片部分

那为何超过65536时需要分dex呢?原因是在Dalvik指令集里,调用方法的invoke-kind指令中,method reference index只给了16bits,最多能调用65535个方法,所以在生成dex文件的过程中,当方法数超过65535就会报错。细看指令集,除了method,field和class的index也是16bits,所以也存在65535的问题。

而一般handleLoadPackage函数中XC_LoadPackage.LoadPackageParam lpparam参数获取的lpparam.classLoader只能Hook到默认的其中一个dex文件中的类,即APK包中的classes.dex。如果要获取其它dex中的类将失败。针对Mutidex情形使用下述方式进行Hook:

public class HookMain implements IXposedHookLoadPackage{
    @Override
    public void handleLoadPackage(XC_LoadPackage.LoadPackageParam loadPackageParam) throws Throwable {
        if (!loadPackageParam.packageName.equals("com.XXX.packageName")) return
            XposedHelpers.findAndHookMethod(Application.class, "attach", Context.class, new XC_MethodHook(){
                @Override
                protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                    ClassLoader cl = ((Context) param.args[0]).getClassLoader();
                    //cl.loadclass("className")找其他类
                    //Class.forName("className",true,cl)
                    Class<?> hookclass = null;
                    try {
                        hookclass = cl.loadClass("XXX.XXX.ClassName");
                    } catch (Exception e) {
                        Log.e("MutiDex", "寻找XXX.XXX.ClassName失败", e);
                        return;
                    }
                    Log.e("MutiDex", "寻找XXX.XXX.ClassName成功");

                    XposedHelpers.findAndHookMethod(
                            hookclass,
                            "methodName",//方法名称
                            args.class,//参数列表
                            new XC_MethodHook(){
                                @Override
                                protected void beforeHookedMethod(MethodHookParam param){
                                    //Hook自定义功能
                            }) ;
                }
            });

        }
}

原理很简单:每个APK运行在加载完所有dex文件后,就会调用Application.attach方法,并且该方法是final无法被覆盖。其参数就是上下文Context,而Context类getClassloader方法可以获取一个类加载器,该加载器能够获取包中存在的所有类,包括所有dex。

Context.getClassLoader Hook多dex原理

 

参照文章:https://blog.csdn.net/jyy208/article/details/54577120

3、动态加载

最后一种则是动态加载jar、dex和apk中的类,这些类不在本APK中的dex文件中,所以多dex的上下文Context的类加载器也就找不到。通过hook ClassLoader类的 loadclass方法获取需要的类。示例代码如下:

public class IncomeHook implements IXposedHookLoadPackage {
    public static final String PACKAGE_NAME = "com.XXX.package";

    @Override
    public void handleLoadPackage(final XC_LoadPackage.LoadPackageParam lpparam) throws Throwable {

        //过滤包
        if (!PACKAGE_NAME.equals(lpparam.packageName)) {
            return;
        }

        findAndHookMethod(ClassLoader.class, "loadClass", String.class, new XC_MethodHook() {
            @Override
            protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                if (param.hasThrowable()) return;

                String classname = (String) param.args[0]; //步骤1
                if (classname.equals("XXX.XXX.XXX")) { //步骤2
                   // clazz.getClassLoader().loadClass("YYY.YYY.YYY");找其他类
                   //Class.forName("className",true,clazz.getClassLoader())
                    Class<?> clazz = (Class<?>) param.getResult();//步骤3
                    findAndHookMethod(clazz, "methodName", args.class, new XC_MethodHook() {//步骤4
                        @Override
                        protected void beforeHookedMethod(MethodHookParam param) throws Throwable {//步骤5
                            // TODO:自定义功能
                        }
                    });

                }
            }
        });
    }
}

原理也很简单:APK运行需要通过安卓虚拟机将类加载进内存,使用的方法就是ClassLoader.loadClass。所有类的加载都会经过该函数,只要Hook该函数就可以拿到所有加载进内存中类。该方法注释如下:

loadclass用处

 

原文出处: https://blog.csdn.net/XXOOYC/article/details/80608197

其中直接使用 loadclass方法就能解决多dex的情形,以后在hook函数中其实直接可以使用loadclass的方法去hook,这样不用考虑太多就能Hook成功了。

0x04 免重启框架

    网络上的大神提供了两种免重启方案,一种是改变xposed框架中的源码,另一种是使用动态加载实现免重启的方案。直接依次给出链接。

1、https://bbs.pediy.com/thread-223713.htm

2、https://blog.csdn.net/u011956004/article/details/78612502?utm_source=blogxgwz1

动态加载免重启的方式比较容易理解,但是代码稍多点。目前对Xposed原理细节还没有研究,所以使用了动态加载的方式。

0x05 网络协议分析中常用Hook关键点

若要分析网络协议中的一些字段含义或者加密数据,必须需要定位到具体代码进行分析处理流程。例如:

一个HTTP协议

如果想要知道data是如何组织出来或者加密的,则需要定位到具体代码进行分析。一般的做法:

1、从点击事件或发生的功能开始往下跟代码。但是代码复杂、工作效率低不建议。

2、对应Http中若有关键字段,可在反编译的JEB中搜索字符串定位处理代码。但是对于没有特征的或者纯TCP加密的数据则无法查找定位。

但是我们了解到大多数数据会使用一些常用的数据操作API,例如

1、Cipher加密类。很多加解密算法DES、AES、RSA等算法都会调用其中国的Dofinal方法开始加密解密。

2、Base64编码

3、程序中也经常用到输入输出流进行数据传输。例如java.io.OutputStream.write方法可能被用于向http发送流中写数据。InputStream.read会读取数据。

4、一些常用的网络库。例如HttpClient中hook函数org.apache.http.impl.client.AbstractHttpClient.execute函数能够定位到发送接受处

5、DatagramSocket.send函数发送udp数据

6、Hook一些socket

通过Hook这些常用的API,打印数据,如果发现是我们需要的数据,则在该处添加堆栈打印函数,重新hook并运行。最后通过打印出的栈进行代码流程分析,最终得到数据处理方法并还原。

 Hook点和你平时关注点有关,你想要分析哪类数据,分析其一般处理特征并Hook这些函数进行分析。目标是形成自己的一套定位Hook工具。并随时进行完善,你将发现定位将会变得越来越容易,直接拿来工具定位数据处理位置。

©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页