检测与反检测, 调试与反调试

Posted by API Caller on April 20, 2019

记一下 Xposed 检测与反检测的手段.

是时候读一读 Xposed 的源码了.

直接反射拿到 sHookedMethodCallbacks 清除所有

对应 Xposed 源码位置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
    public static void disableXposed() {
        try {
            Class<?> clazz = ClassLoader.getSystemClassLoader().loadClass("de.robv.android.xposed.XposedBridge");
            Field field = clazz.getDeclaredField("sHookedMethodCallbacks");
            field.setAccessible(true);
            Map sHookedMethodCallbacks = (Map) field.get(null);
            Object doNothing = Class.forName("de.robv.android.xposed.XC_MethodReplacement", false, clazz.getClassLoader()).getField("DO_NOTHING").get(null);
            for (Object callbacks : sHookedMethodCallbacks.values()) {
                field = callbacks.getClass().getDeclaredField("elements");
                field.setAccessible(true);
                Object[] elements = (Object[]) field.get(callbacks);
                for (int i = 0; i < elements.length; ++i) {
                    elements[i] = doNothing;
                }
            }
        } catch (Throwable t) { // NOSONAR
            // do nothing
        }
    }

检测目标类是否存在, 利用 disableHooks 关闭 hook

对应 Xposed 源码位置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
package com.tencent.StubShell;
 
public class XposedCheck {
    private static final java.lang.String XPOSED_BRIDGE = "de.robv.android.xposed.XposedBridge";
    private static final java.lang.String XPOSED_HELPERS = "de.robv.android.xposed.XposedHelpers";
 
    private static boolean isXposedExistByThrow() {
        try {
            throw new java.lang.Exception("exe xp");
        } catch (java.lang.Exception e) {
            for (java.lang.StackTraceElement className : e.getStackTrace()) {
                if (className.getClassName().contains(XPOSED_BRIDGE)) {
                    return true;
                }
            }
            return false;
        }
    }
 
    private static boolean isXposedExists() {
        try {
            java.lang.ClassLoader.getSystemClassLoader().loadClass(XPOSED_HELPERS).newInstance();
            try {
                java.lang.ClassLoader.getSystemClassLoader().loadClass(XPOSED_BRIDGE).newInstance();
                return true;
            } catch (java.lang.InstantiationException e) {
                e.printStackTrace();
                return true;
            } catch (java.lang.IllegalAccessException e2) {
                e2.printStackTrace();
                return true;
            } catch (java.lang.ClassNotFoundException e3) {
                e3.printStackTrace();
                return false;
            }
        } catch (java.lang.InstantiationException e4) {
            e4.printStackTrace();
            return true;
        } catch (java.lang.IllegalAccessException e22) {
            e22.printStackTrace();
            return true;
        } catch (java.lang.ClassNotFoundException e32) {
            e32.printStackTrace();
            return false;
        }
    }
 
    public static boolean tryShutdownXposed() {
        if (!isXposedExistByThrow()) {
            return true;
        }
        try {
            java.lang.reflect.Field declaredField = java.lang.ClassLoader.getSystemClassLoader().loadClass(XPOSED_BRIDGE).getDeclaredField("disableHooks");
            declaredField.setAccessible(true);
            declaredField.set(null, java.lang.Boolean.valueOf(true));
            return true;
        } catch (java.lang.NoSuchFieldException e) {
            e.printStackTrace();
            return false;
        } catch (java.lang.ClassNotFoundException e2) {
            e2.printStackTrace();
            return false;
        } catch (java.lang.IllegalAccessException e3) {
            e3.printStackTrace();
            return false;
        }
    }
}