没有context,动态hookApplication

542 阅读1分钟

ContextHelper.hookApplication()

public class ContextHelper {
    private static String TAG = "ContextHelper";
    private static Application sApp = null;


    public static Application hookApplication() {
        if (sApp != null)
            return sApp;

        Reflection.exemptAll();
        if (sApp == null) {
            sApp = hookActivityThreadInitialApplication();
            Log.d(TAG, "hookActivityThreadInitialApplication:" + sApp);
        }

        if (sApp == null) {
            sApp = hookActivityThreadGetApplication();
            Log.d(TAG, "hookActivityThreadGetApplication:" + sApp);
        }

        return sApp;
    }

    private static Application hookActivityThreadInitialApplication() {
        Application application = null;
        Class<?> activityThreadClass;
        try {
            activityThreadClass = Class.forName("android.app.ActivityThread");
            Field appField = activityThreadClass
                    .getDeclaredField("mInitialApplication");
            // Object object = activityThreadClass.newInstance();
            final Method methodActivityThread = activityThreadClass.getMethod(
                    "currentActivityThread");
            // 得到当前的ActivityThread对象
            Object localObject = methodActivityThread.invoke(null, (Object[]) null);
            appField.setAccessible(true);
            application = (Application) appField.get(localObject);
            // appField.
        } catch (Exception e) {
            e.printStackTrace();
        }

        return application;
    }

    private static Application hookActivityThreadGetApplication() {
        Application application = null;
        Class<?> activityThreadClass;
        try {
            activityThreadClass = Class.forName("android.app.ActivityThread");
            final Method currentActivityThread = activityThreadClass.getMethod(
                    "currentActivityThread");
            // 得到当前的ActivityThread对象
            Object localObject = currentActivityThread.invoke(null, (Object[]) null);

            final Method method = activityThreadClass
                    .getMethod("getApplication");
            application = (Application) method.invoke(localObject, (Object[]) null);

        } catch (Exception e) {
            e.printStackTrace();
        }
        return application;
    }
}

hideApi 适配 setHiddenApiExemptions

androidxref.com/9.0.0_r3/xr…

public class Reflection {
    private static final String TAG = "Reflection";

    private static Object sVmRuntime;
    private static Method setHiddenApiExemptions;

    static {
        if (SDK_INT >= Build.VERSION_CODES.P) {
            try {
                Method forName = Class.class.getDeclaredMethod("forName", String.class);
                Method getDeclaredMethod = Class.class.getDeclaredMethod("getDeclaredMethod", String.class, Class[].class);

                Class<?> vmRuntimeClass = (Class<?>) forName.invoke(null, "dalvik.system.VMRuntime");
                Method getRuntime = (Method) getDeclaredMethod.invoke(vmRuntimeClass, "getRuntime", null);
                setHiddenApiExemptions = (Method) getDeclaredMethod.invoke(vmRuntimeClass, "setHiddenApiExemptions", new Class[]{String[].class});
                sVmRuntime = getRuntime.invoke(null);
            } catch (Throwable e) {
                Log.w(TAG, "reflect bootstrap failed:", e);
            }
        }
    }

    /**
     * make the method exempted from hidden API check.
     *
     * @param method the method signature prefix.
     * @return true if success.
     */
    public static boolean exempt(String method) {
        return exempt(new String[]{method});
    }

    /**
     * make specific methods exempted from hidden API check.
     *
     * @param methods the method signature prefix, such as "Ldalvik/system", "Landroid" or even "L"
     * @return true if success
     */
    public static boolean exempt(String... methods) {
        if (sVmRuntime == null || setHiddenApiExemptions == null) {
            return false;
        }

        try {
            setHiddenApiExemptions.invoke(sVmRuntime, new Object[]{methods});
            return true;
        } catch (Throwable e) {
            return false;
        }
    }

    /**
     * Make all hidden API exempted.
     *
     * @return true if success.
     */
    public static boolean doExemptAll() {
        return exempt(new String[]{"L"});
    }

    private static AtomicBoolean sExemptFlg= new AtomicBoolean(false);
    public static int exemptAll() {
        if (SDK_INT < Build.VERSION_CODES.P) {
            // Below Android P, ignore
            return 0;
        }

        if(sExemptFlg.compareAndSet(false, true))
        {
            Log.d(TAG, "exemptAll:" + sExemptFlg.get());
            // try exempt API first.
            if (doExemptAll()) {
                return 0;
            }
        }

        return -1;
    }
}