首页
社区
课程
招聘
[原创]xposed新思路,伪代码都见鬼去吧
发表于: 2019-4-4 14:06 13799

[原创]xposed新思路,伪代码都见鬼去吧

2019-4-4 14:06
13799
最近研究了两天xposed,发现真实个神器。本人对java略懂皮毛,对so一窍不通。总结出几个新思路,发出来抛砖引玉。
    /**
     * HOOK一个类加载器中的所有类的所有方法
     *
     * @param classLoader 类加载器
     */
    private void hookClassLoaderAnyMethod(ClassLoader classLoader) throws Exception {
        Object[] dexElements = (Object[]) getFieldValue(classLoader, "pathList", "dexElements");
        // 获取到dex文件
        DexFile dexFile = (DexFile) getFieldValue(dexElements[0], "dexFile");
        // 找到所有的类
        Enumeration<String> enumeration = dexFile.entries();
        while (enumeration.hasMoreElements()) {
            String clsName = enumeration.nextElement();
            Log.i(TAG, "hook ClassLoader By Class Name: " + clsName);
            Class<?> cls = XposedHelpers.findClass(clsName, classLoader);
            Method[] methods = cls.getDeclaredMethods();
            for (Method method : methods) {
                int paramSize = method.getParameterTypes().length;
                Object[] objs = new Object[paramSize + 1];
                System.arraycopy(method.getParameterTypes(), 0, objs, 0, paramSize);
                // 最后一个参数设置为回调
                objs[paramSize] = new XC_MethodHook() {
                    @Override
                    protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                        StringBuilder builder = new StringBuilder();
                        builder.append("call method:").append(method.toString());
                        // 记录参数
                        if (param.args != null && param.args.length > 0) {
                            for (int i = 0; i < param.args.length; i++) {
                                builder.append('\n');
                                builder.append("arg").append(i).append(":");
                                builder.append(param.args[i]);
                            }
                        }
                        // 记录结果
                        builder.append("\n").append("result:").append(param.getResult());
                        Log.i(TAG, builder.toString());
                    }
                };
                XposedHelpers.findAndHookMethod(cls, method.getName(), objs);
            }
        }
    }

    /**
     * HOOK一个类加载器中的所有类的所有方法
     *
     * @param classLoader 类加载器
     */
    private void hookClassLoaderAnyMethod(ClassLoader classLoader) throws Exception {
        Object[] dexElements = (Object[]) getFieldValue(classLoader, "pathList", "dexElements");
        // 获取到dex文件
        DexFile dexFile = (DexFile) getFieldValue(dexElements[0], "dexFile");
        // 找到所有的类
        Enumeration<String> enumeration = dexFile.entries();
        while (enumeration.hasMoreElements()) {
            String clsName = enumeration.nextElement();
            Log.i(TAG, "hook ClassLoader By Class Name: " + clsName);
            Class<?> cls = XposedHelpers.findClass(clsName, classLoader);
            Method[] methods = cls.getDeclaredMethods();
            for (Method method : methods) {
                int paramSize = method.getParameterTypes().length;
                Object[] objs = new Object[paramSize + 1];
                System.arraycopy(method.getParameterTypes(), 0, objs, 0, paramSize);
                // 最后一个参数设置为回调
                objs[paramSize] = new XC_MethodHook() {
                    @Override
                    protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                        StringBuilder builder = new StringBuilder();
                        builder.append("call method:").append(method.toString());
                        // 记录参数
                        if (param.args != null && param.args.length > 0) {
                            for (int i = 0; i < param.args.length; i++) {
                                builder.append('\n');
                                builder.append("arg").append(i).append(":");
                                builder.append(param.args[i]);
                            }
                        }
                        // 记录结果
                        builder.append("\n").append("result:").append(param.getResult());
                        Log.i(TAG, builder.toString());
                    }
                };
                XposedHelpers.findAndHookMethod(cls, method.getName(), objs);
            }
        }
    }

getFieldValue方法,就是通过反射递归获取对象属性值
    private Object getFieldValue(Object obj, String... fieldNames) throws Exception {
        if (obj == null) {
            return null;
        }
        for (String fieldName : fieldNames) {
            obj = getFieldValue(obj, fieldName);
        }
        return obj;
    }

    /**
     * 获取对象中的属性
     *
     * @param obj       对象
     * @param fieldName 属性名称
     * @return 属性值
     * @throws Exception 异常信息
     */
    private Object getFieldValue(Object obj, String fieldName) throws Exception {
        Field field = getField(obj.getClass(), fieldName);
        if (field == null) {
            return null;
        }
        // 设置允许访问
        field.setAccessible(true);
        return field.get(obj);
    }

    /**
     * 递归获取类的所有属性,直到找到指定属性为止
     *
     * @param cls       类
     * @param fieldName 属性名
     * @return 属性
     */
    private Field getField(Class<?> cls, String fieldName) {
        Field[] fields = cls.getDeclaredFields();
        if (fields != null && fields.length > 0) {
            for (Field field : fields) {
                if (field.getName().equals(fieldName)) {
                    return field;
                }
            }
        }
        Class<?> supperCls = cls.getSuperclass();
        if (!supperCls.equals(Object.class)) {
            return getField(supperCls, fieldName);
        }
        return null;
    }

    private Object getFieldValue(Object obj, String... fieldNames) throws Exception {
        if (obj == null) {
            return null;
        }
        for (String fieldName : fieldNames) {
            obj = getFieldValue(obj, fieldName);
        }
        return obj;
    }

    /**
     * 获取对象中的属性
     *
     * @param obj       对象
     * @param fieldName 属性名称
     * @return 属性值
     * @throws Exception 异常信息
     */
    private Object getFieldValue(Object obj, String fieldName) throws Exception {
        Field field = getField(obj.getClass(), fieldName);
        if (field == null) {
            return null;
        }
        // 设置允许访问
        field.setAccessible(true);
        return field.get(obj);
    }

    /**
     * 递归获取类的所有属性,直到找到指定属性为止
     *
     * @param cls       类
     * @param fieldName 属性名
     * @return 属性
     */
    private Field getField(Class<?> cls, String fieldName) {
        Field[] fields = cls.getDeclaredFields();
        if (fields != null && fields.length > 0) {
            for (Field field : fields) {
                if (field.getName().equals(fieldName)) {
                    return field;
                }
            }
        }
        Class<?> supperCls = cls.getSuperclass();
        if (!supperCls.equals(Object.class)) {
            return getField(supperCls, fieldName);
        }
        return null;
    }

在此我们只需要一个东西,就是类加载器对象,这个只要hook目标app的启动类就可以拿到。

启动app这时我们的控制台会哗哗哗的打印方法调用日志
作用一:
比如说我们要hook一个按钮,等app进入到某个界面,把日志清理掉,点一下那个按钮,看下那些个方法被调用了。
作用二:
比如说我们要找一个加密方法或解密方法,直接看日志,那个方法是明文进去密文出来或者哪个方法是密文进去明文出来的。

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

最后于 2019-4-4 16:01 被菜鸟学术编辑 ,原因:
收藏
免费 1
支持
分享
最新回复 (15)
雪    币: 36
活跃值: (1061)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
2
mark
2019-4-4 18:58
0
雪    币: 6266
活跃值: (1276)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
3
这好像就是Fdex的思路啊,但现在对于加壳的apk基本无效了(乐固和360除外)
2019-4-5 12:40
0
雪    币: 1385
活跃值: (5609)
能力值: ( LV3,RANK:25 )
在线值:
发帖
回帖
粉丝
4
方法很好,谢谢分享
2019-4-8 09:19
0
雪    币: 3907
活跃值: (5817)
能力值: ( LV12,RANK:200 )
在线值:
发帖
回帖
粉丝
5
谢谢分享
2019-4-9 17:49
0
雪    币: 2345
活跃值: (10422)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
非常感谢,
2019-4-19 14:34
0
雪    币: 574
活跃值: (405)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
很赞的思路
2019-4-22 11:42
0
雪    币: 33
活跃值: (15)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
什么新思路,秦朝的东西了
2019-4-22 13:58
0
雪    币: 2359
活跃值: (288)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
谢谢,我需要这个东东。
2019-4-26 12:33
0
雪    币: 151
活跃值: (66)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
10
不错,SO不需要。大部分直接找调用函数就可以了。
2019-5-2 22:01
0
雪    币: 23
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
11
谢谢老大分享
2019-5-4 12:15
0
雪    币: 634
活跃值: (1503)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
12
不算新的做法,你这个代码会碰到OOM
不如试试这个 https://github.com/monkeylord/XServer
2019-5-6 15:03
0
雪    币:
活跃值: (153)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
13
mark
2019-5-27 02:14
0
雪    币: 2270
活跃值: (5537)
能力值: ( LV8,RANK:146 )
在线值:
发帖
回帖
粉丝
14
大型app会导致app无法打开的
2019-8-25 10:30
0
雪    币: 201
活跃值: (145)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
15
大佬好 我刚使用了这个工具 感觉非常牛逼 想问一个问题

native方法需要context的类  该如何调用呢
2019-9-5 17:12
0
雪    币: 0
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
16
早有了,都玩烂了
2019-9-5 19:40
0
游客
登录 | 注册 方可回帖
返回
//