(2020.7.6)Android Xposed防护总结

(转载公司内部论坛本人文章2020.7.6)

xposed原理

Android系统中,Zygote进程在启动的过程中,会创建一个Dalvik虚拟机实例,同时将Java运行时库加载到进程中来,以及注册一些Android核心类的JNI方法到Dalvik虚拟机实例中去。
而我们知道,系统其它所有进程都是由Zygote进程孵化的。Zygote在启动新的app进程时,都会将自身的Dalvik虚拟机实例复制到该App进程里,形成该App独立的Dalvik虚拟机实例,同时还会与Zygote进程一起共享Java运行时库。所以Xposed通过替换/system/bin/app_process程序控制zygote进程,使得app_process在启动过程中会加载XposedBridge.jar这个jar包,也进而使XposedBridge.jar加载到了每一个Android app进程里。
Xposed可以实现在不修改APK源码的情况下,hook app里的任意java方法,实现方法的修改和替换。

Xposed简单使用教程

手机可以通过 Xposed Installer 安装Xposed服务,但是需要ROOT权限。如果不想ROOT手机,也可以通过安装一个自带Xposed的虚拟系统,效果也是一样的。
想要hook apk的方法,首先要知道apk内该方法的具体路径,这个涉及到 apk反编译 的过程,这里不做细说。
通过Xposed Hook方法主要运用到 XposedHelpers.findAndHookMethod() 方法,demo代码如下:

public class Hooktest implements IXposedHookLoadPackage {

    public void handleLoadPackage(XC_LoadPackage.LoadPackageParam loadPackageParam) throws Throwable {

        if (loadPackageParam.packageName.equals("想要hook apk的包名")) {

            Class clazz = loadPackageParam.classLoader.loadClass("想要hook的类名");

            XposedHelpers.findAndHookMethod(clazz, "想要hook的方法名", new XC_MethodHook() {

                protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
                    super.beforeHookedMethod(param);
                }

                protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                    param.setResult("修改返回结果");
                }

            });

        }

    }

}

具体过程请查看教程

Xposed检测与防护

Xposed的防护思路:App检测系统是否安装了Xposed模块,一旦检测到,便强制退出App。
因此Xposed防护的重点在于如何检测到系统是否安装了Xposed模块。
Xposed检测可以分为Java层Native层

Java层检测

1.检测系统是否安装了Xposed Installer软件包

通过PackageManager遍历系统中App的安装情况,判断系统是否有安装Xposed Installer相关的软件包。

    public static boolean hasXposed(Context context) {
        PackageManager packageManager = context.getPackageManager();
        List<ApplicationInfo> applicationInfoList = packageManager.getInstalledApplications(PackageManager.GET_META_DATA);
        for (ApplicationInfo applicationInfo: applicationInfoList) {
            if (applicationInfo.packageName.equals("de.robv.android.xposed.installer")) {
                return true;
            }
        }
        return false;
    }
2.自抛异常,读取堆栈信息判断

如果系统安装了Xposed Installer框架,程序方法异常栈中就会出现Xposed的 de.robv.android.xposed.XposedHelpersde.robv.android.xposed.XposedBridge 相关日志。因此可以通过自抛异常并Catch来读取异常堆栈信息,检测系统是否安装了Xposed Installer

    public static boolean isXposedExistByThrow() {
        try {
            throw new Exception("gg");
        } catch (Exception e) {
            for (StackTraceElement stackTraceElement : e.getStackTrace()) {
                if (stackTraceElement.getClassName().contains("de.robv.android.xposed.XposedHelpers")) {
                    return true;
                } else if (stackTraceElement.getClassName().contains("de.robv.android.xposed.XposedBridge")){
                    return true;
                }
            }
            return false;
        }
    }
3.检查关键Java方法被变为Native JNI方法

如果App中的Java方法变成了Native JNI方法,则非常有可能被Xposed Hook了。因此,检查关键方法是不是变成Native JNI方法,也可以检测系统是否安装了Xposed Installer框架。

    public  boolean isXposedMethod() {
        try {
            Method method = getClass().getDeclaredMethod("方法名");
            return Modifier.isNative(method.getModifiers());
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
        return false;
    }

但是Xposed同样可以篡改isNative这个方法的返回值,让其返回false。

4.尝试反射XposedHelper类字段,判断是否ClassNotFoundException
    public static boolean isXposedExists() {
        try {
            ClassLoader.getSystemClassLoader().loadClass("de.robv.android.xposed.XposedHelpers").newInstance();
            ClassLoader.getSystemClassLoader().loadClass("de.robv.android.xposed.XposedBridge").newInstance();
        } catch (InstantiationException e) {
            e.printStackTrace();
            return true;
        } catch (IllegalAccessException e) {
            e.printStackTrace();
            return true;
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }

总结: Java层检测Xposed方法有很多,但是前面我提到过,Xposed可以hook app里的任意java方法,自然也可以修改我们检测方法isXposedExists的返回值,所以理论上Java层的防护是没有太大作用。

Native层检测

无论在Java层做何种检测,Xposed都可以通过Hook相关检测方法,修改检测结果绕过检测,所以仅Java层检测是不够的。
但是前面我们提到,xposed hook方法还需要知道该方法的具体路径。因此我们把检测代码放在so库中,这样可以增加反编译拿到检测代码的位置的成本。同时由于Xposed Installer通常只能Hook Java层,这样也能避免检测方法被直接hook。

extern "C"
JNIEXPORT void
JNICALL
Java_com_tencent_signndk_Sign_sign(JNIEnv *env, jobject instance)
{

    FILE *fp = NULL;
    int BUFFER_SIZE = 1024;
    char strLine[BUFFER_SIZE];
    char* filepath = "/proc/self/maps";
    char* xp_name = "XposedBridge.jar";
    fp = fopen(filepath,"r");
    while (!feof(fp))
    {
        fgets(strLine,BUFFER_SIZE,fp);
        char* origin_str = strLine;
        char* str = trim(origin_str);
        if(strstr(str, xp_name) != NULL)
//        if (contain(str,xp_name))
        {
            jclass jcls = env->FindClass("java/lang/IllegalArgumentException");
            env->ThrowNew(jcls, "Argument cannot be null.");
            break;
        }
    }
}

其他

在安全对抗领域,攻防都是一个长期的过程。如果只是客户端的防护是不够的,就这个wifi信息泄露这个例子,我们也进行了后台层面的防护,返回wifi信息的接口做了更加严格的判断。

END。

参考:
https://tech.meituan.com/2018/02/02/android-anti-hooking.html

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值