首页
社区
课程
招聘
[求助]xposed 如何 打印 hook 方法传进去的参数的属性
发表于: 2020-2-4 18:25 4809

[求助]xposed 如何 打印 hook 方法传进去的参数的属性

2020-2-4 18:25
4809
比如 
XXX.aaa(User user);
怎么hook了之后  把User的成员数据的值打印出来?

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

收藏
免费 0
支持
分享
最新回复 (7)
雪    币: 2510
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
2
帮顶
2020-2-4 18:41
3
雪    币: 1867
活跃值: (3983)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
3
我之前写过一个

package com.virjar.ratel.api.inspect;


import android.os.Bundle;

import com.virjar.ratel.api.rposed.FreeReflection;
import com.virjar.ratel.api.rposed.RposedHelpers;

import java.lang.annotation.Annotation;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

import external.org.apache.commons.lang3.ClassUtils;

/**
 * Created by virjar on 2018/9/25.<br>
 * 强制的,将一个对象的内部属性dump出来,忽略java pojo的getter规范,请注意这个功能是为了抓取使用,因为该转换不是幂等的,无法还原
 */
public class ForceFiledViewer {
    /**
     *
     * @param input any object
     * @return a view,just contain string,number,list,map;or it`s combination
     */
    public static Object toView(Object input) {
        return toView(input, new HashSet<>(), false);
    }

    public static Object toView(Object input, boolean withObjType) {
        return toView(input, new HashSet<>(), withObjType);
    }

    private static Object trimView(Object input) {
        if (input == null) {
            return null;
        }
        if (input instanceof Map && ((Map) input).size() == 0) {
            return null;
        }
        if (input.getClass().isArray() && Array.getLength(input) == 0) {
            return null;
        }
        if (input instanceof Collection && ((Collection) input).size() == 0) {
            return null;
        }
        return input;
    }

    private static Object toView(Object input, Set<Object> accessedObjects, boolean withObjType) {
        try {
            if (input == null) {
                return Collections.emptyMap();
            }
            if (skipTranslatePackage.isSubPackage(input.getClass().getName())) {
                return input;
            }
            return toViewInternal(input, accessedObjects, withObjType);
        } catch (Throwable throwable) {
            return null;
        }
    }

    private static Object toViewInternal(Object input, Set<Object> accessedObjects, boolean withObjType) {
        if (input == null) {
            return null;
        }
        Class<?> inputClass = input.getClass();
        // primary type,
        if (inputClass.isPrimitive() || ClassUtils.wrapperToPrimitive(inputClass) != null) {
            return input;
        }
        if (input instanceof CharSequence || input instanceof Number) {
            return input;
        }
        if (input instanceof Date) {
            return ((Date) input).getTime();
        }
        if (input instanceof byte[]) {
            return input;
        }

        if (accessedObjects.contains(input)) {
            return null;
        }
        //create a copy ,we just avoid cycle reference,so a object can appear on different subtree
        accessedObjects = new HashSet<>(accessedObjects);
        accessedObjects.add(input);

        if (input instanceof Collection) {
            List<Object> subRet = Lists.newArrayListWithCapacity(((Collection) input).size());
            boolean hint = false;
            for (Object o1 : (Collection) input) {
                Object view = trimView(toView(o1, accessedObjects, withObjType));
                if (view != null) {
                    hint = true;
                }
                subRet.add(view);
            }
            if (!hint) {
                subRet.clear();
            }
            return subRet;
        }

        if (input.getClass().isArray()) {
            List<Object> subRet = Lists.newArrayListWithCapacity(Array.getLength(input));
            boolean hint = false;
            for (int i = 0; i < Array.getLength(input); i++) {
                Object o1 = Array.get(input, i);
                Object view = trimView(toView(o1, accessedObjects, withObjType));
                if (view != null) {
                    hint = true;
                }
                subRet.add(view);
            }
            if (!hint) {
                subRet.clear();
            }
            return subRet;
        }


        if (input instanceof Map) {
            Map map = (Map) input;
            Map<String, Object> subRet = new TreeMap<>();
            Set set = map.entrySet();
            for (Object entry : set) {
                if (!(entry instanceof Map.Entry)) {
                    continue;
                }
                Map.Entry entry1 = (Map.Entry) entry;
                Object key = entry1.getKey();
                if (key == null) {
                    continue;
                }
                Object value = entry1.getValue();
                Object view = trimView(toView(value, accessedObjects, withObjType));
                if (view != null) {
                    if (key instanceof CharSequence || key.getClass().isPrimitive() || ClassUtils.wrapperToPrimitive(key.getClass()) != null) {
                        subRet.put(key.toString(), view);
                    } else if (key instanceof Class) {
                        subRet.put(((Class) key).getName(), view);
                    } else {
                        Map<String, Object> container = new HashMap<>();
                        container.put("key", trimView(toView(value, accessedObjects, withObjType)));
                        container.put("value", value);
                        subRet.put(key.getClass() + "@" + key.hashCode(), container);
                    }


                }
            }
            return subRet;
        }
        String className = input.getClass().getName();
        if (skipDumpPackage.isSubPackage(className) && !forceDumpPackage.isSubPackage(className)) {
            //框架内部对象,不抽取,这可能导致递归过深,而且没有意义
            return null;
        }
        if (Bundle.class.isAssignableFrom(input.getClass())) {
            Bundle bundle = (Bundle) input;
            //触发反序列化
            bundle.get("test");
        }

        Map<String, Object> ret = new TreeMap<>();

        Map<String, Field> fields = classFileds(input.getClass());
        for (Map.Entry<String, Field> field : fields.entrySet()) {
            Object o = null;
            try {
                o = field.getValue().get(input);
            } catch (IllegalAccessException e) {
                //ignore
            }
            if (o == null) {
                if (withObjType) {
                    Map<String, Object> container = new HashMap<>();
                    container.put("type", field.getValue().getType());
                    container.put("value", null);
                    ret.put(field.getKey(), container);
                }
                continue;
            }
            Object view = trimView(toView(o, accessedObjects, withObjType));
            if (view != null) {
                if (withObjType) {
                    Map<String, Object> container = new HashMap<>();
                    container.put("type", o.getClass());
                    container.put("value", view);
                    container.put("hash", o.hashCode());
                    ret.put(field.getKey(), container);
                } else {
                    ret.put(field.getKey(), view);
                }
            } else if (withObjType) {
                Map<String, Object> container = new HashMap<>();
                container.put("type", field.getValue().getType());
                container.put("value", null);
                container.put("hash", o.hashCode());
                ret.put(field.getKey(), container);
            }
        }
        return ret;
    }


    public static Map<String, Field> classFileds(Class clazz) {
        if (clazz == Object.class) {
            return Collections.emptyMap();
        }
        Map<String, Field> fields = fieldCache.get(clazz);
        if (fields != null) {
            return fields;
        }
        Class<? extends Annotation> gsonSerializeNameAnnotation = null;
        try {
            gsonSerializeNameAnnotation = (Class<? extends Annotation>) clazz.getClassLoader().loadClass("com.google.gson.annotations.SerializedName");
        } catch (Throwable throwable) {
            //ignore
        }
        synchronized (clazz) {
            fields = fieldCache.get(clazz);
            if (fields != null) {
                return fields;
            }

            fields = new HashMap<>();
            fields.putAll(classFileds(clazz.getSuperclass()));
            for (Field next : FreeReflection.getDeclaredField(clazz)) {
                if (Modifier.isStatic(next.getModifiers())) {
                    continue;
                }
                if (next.isSynthetic()) {
                    continue;
                }
                if (!next.isAccessible()) {
                    next.setAccessible(true);
                }
                String candidateName = next.getName();
                try {
                    if (gsonSerializeNameAnnotation != null && next.isAnnotationPresent(gsonSerializeNameAnnotation)) {
                        Annotation annotation = next.getAnnotation(gsonSerializeNameAnnotation);
                        String gsonName = (String) RposedHelpers.callMethod(annotation, "value");
                        if (gsonName != null) {
                            candidateName = gsonName;
                        }
                    }
                } catch (Throwable throwable) {
                    //ignore
                }

                if (fields.containsKey(candidateName)) {
                    candidateName = clazz.getName() + "." + candidateName;
                }
                int retryIndex = 0;
                while (fields.containsKey(candidateName)) {
                    retryIndex++;
                    candidateName = candidateName + retryIndex;
                }
                fields.put(candidateName, next);
            }

            fieldCache.put(clazz, fields);
        }
        return fields;
    }

    private static final ConcurrentMap<Class, Map<String, Field>> fieldCache = new ConcurrentHashMap<>();
    private static PackageTrie forceDumpPackage = new PackageTrie();
    private static PackageTrie skipDumpPackage = new PackageTrie();
    private static PackageTrie skipTranslatePackage = new PackageTrie();

    public static void addForceViewConfig(String basePackage) {
        forceDumpPackage.addToTree(basePackage);
    }

    public static void addSkipViewConfig(String basePackage) {
        skipDumpPackage.addToTree(basePackage);
    }

    public static void addSKipTranslateConfig(String basePackage) {
        skipTranslatePackage.addToTree(basePackage);
    }

    static {
        addSkipViewConfig("android");
        addSkipViewConfig("com.android");
        addSkipViewConfig("java");
        addSkipViewConfig("dalvik");

        addForceViewConfig("android.os.Bundle");
        addForceViewConfig("android.os.BaseBundle");
        addForceViewConfig("android.util.ArrayMap");
        addForceViewConfig("android.util.SparseArray");
        addForceViewConfig("android.util.ArraySet");
        addForceViewConfig("android.util.SparseBooleanArray");
        addForceViewConfig("android.util.SparseIntArray");
        addForceViewConfig("android.util.SparseLongArray");
        addForceViewConfig("android.util.StateSet");
        addForceViewConfig("android.content.Intent");
        addForceViewConfig("android.content.ClipData");
        addForceViewConfig("android.content.ClipData#Item");
        addForceViewConfig("android.content.ClipData.Item");
        addForceViewConfig("android.content.ComponentName");
        addForceViewConfig("android.content.Entity");
        addForceViewConfig("android.content.ContentValues");

        addSKipTranslateConfig("com.alibaba.fastjson");
        addSKipTranslateConfig("org.json");
        addSKipTranslateConfig("com.google.gson");
    }
}

2020-2-4 19:31
0
雪    币: 2484
活跃值: (3152)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
4
virjar 我之前写过一个 package&nbsp;com.virjar.ratel.api.inspect; import&nbsp;android.os.Bundle; ...
好的 我试试!谢谢!
您提供的这个类 不能直接使用呢
最后于 2020-2-4 20:09 被熊猫吃鱼编辑 ,原因:
2020-2-4 20:02
0
雪    币: 1867
活跃值: (3983)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
5
雨天不带鱼 virjar 我之前写过一个 package&amp;nbsp;com.virjar.ratel.api.inspect; imp ...
不全的内容,可以在这里找到代码: https://repo1.maven.org/maven2/com/virjar/ratel-api/1.3.2/ratel-api-1.3.2-sources.jar 下载下来,稍微补一补就好了
2020-2-5 08:54
0
雪    币: 2484
活跃值: (3152)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
6
virjar 不全的内容,可以在这里找到代码: https://repo1.maven.org/maven2/com/virjar/ratel-api/1.3.2/ratel-api-1.3.2-sources.j ...
       public int f5731id;
        public boolean inactive;
        public String lang_code;
        public String last_name;
        public boolean min;
        public boolean mutual_contact;
        public String phone;
        public UserProfilePhoto photo;
        public boolean restricted;
        public String restriction_reason;
        public boolean self;
        public boolean star;
        public UserStatus status;
        public String username;
        public boolean verified;

没有get\set 方法 然后它是通过某个a(xx,xx) 调用之后才给上面的成员变量赋值的
然后使用您的方法去获取  也是获取不到数据的!
请问对于这种的成员变量值输出 有什么好的建议吗
2020-2-5 12:15
0
雪    币: 1867
活跃值: (3983)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
7
雨天不带鱼 public int f5731id; public boolean inactive; public String lang_code; ...
我这个就没有调getter啊,反射出来的。一般来说不可能dump不出来的,这个类我都用了两年了。通杀方案,只是大对象容易引起性能问题而已
2020-2-5 13:17
0
雪    币: 2484
活跃值: (3152)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
8
virjar 我这个就没有调getter啊,反射出来的。一般来说不可能dump不出来的,这个类我都用了两年了。通杀方案,只是大对象容易引起性能问题而已
您好 
phone":{
        "accessible":true,
        "annotations":[

        ],
        "declaredAnnotations":[

        ],
        "declaringClass":"xxxxx.TLRPC$User",
        "dexFieldIndex":38552,
        "enumConstant":false,
        "genericType":"java.lang.String",
        "modifiers":1,
        "name":"phone",
        "offset":32,
        "synthetic":false,
        "type":"java.lang.String"
    },
使用您提供的这方法  我hook了a(xx,xx) 调用之后返回User 的数据,但是好像也是没最终的值?是我hook的问题吗?
最后于 2020-2-5 15:48 被熊猫吃鱼编辑 ,原因:
2020-2-5 15:47
0
游客
登录 | 注册 方可回帖
返回
//