美文网首页
root 检测、Xposed 检测、Cydia 检测

root 检测、Xposed 检测、Cydia 检测

作者: that_is_this | 来源:发表于2018-09-06 15:13 被阅读405次

    1. root 检测

    public class Root_check {
    
        private static String LOG_TAG = "Wooo";
    
        public static void checkRoot() {
            try {
                /*  源码 adb.c 内
                int adb_main(int is_daemon)
        {
        ......
        property_get("ro.secure", value, "");
        if (strcmp(value, "1") == 0) {
            // don't run as root if ro.secure is set...
            secure = 1;
            ......
        }
    
        if (secure) {
            ......
                 */
                Object obj = utils.invokeStaticMethod("android.os.SystemProperties", "get",  new Class[]{String.class}, new Object[]{"ro.secure"}); // ro.secure  service.adb.root
                Log.i("Wooo", "checkRoot -> " + obj);
                if (obj != null) {
                    if (obj.equals("1")) {
                        Log.i("Wooo", "checkRoot may not root");
                    }
                    if (obj.equals("0")) {
                        Log.i("Wooo", "checkRoot mast rooted");
                    }
                }
    
                checkRelease();
                checkSUfile();
    //            checkRootWhichSU();   // 执行 which su
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
        private static void checkRelease() {
            String buildTags = Build.TAGS;
            Log.i("Wooo", "cheeckRelease tag is : " + buildTags);
            if (buildTags != null && buildTags.contains("test-keys")) {
                Log.i("Wooo", "cheeckRelease -> debug");
            }
            if (buildTags != null && buildTags.contains("release-keys")) {
                Log.i("Wooo", "cheeckRelease -> release");
            }
        }
    
        private static void checkSUfile() {
            // "/sbin/su", "/system/bin/su", "/system/xbin/su", "/data/local/xbin/su", "/data/local/bin/su", "/system/sd/xbin/su", "/system/bin/failsafe/su", "/data/local/su"
            String file[] = {"/system/bin/", "/system/xbin/", "/system/sbin/", "/sbin/", "/vendor/bin/", "/su/bin/"};
            for (int i = 0; i < file.length; i++) {
                String sNm = file[i] + "su";
                File f = new File(sNm);
                if (f.exists()) {
                    Log.i("Wooo", "checkRoot " + sNm + " file exists");
                } else {
                    Log.i("Wooo", "checkRoot " + sNm + " file no exists");
                }
            }
        }
    
        public static boolean checkRootWhichSU() {
            String[] strCmd = new String[] {"/system/xbin/which","su"};
            ArrayList<String> execResult = executeCommand(strCmd);
            if (execResult != null){
                Log.i("Wooo","execResult="+execResult.toString());
                return true;
            }else{
                Log.i("Wooo","execResult=null");
                return false;
            }
        }
    
        private static ArrayList<String> executeCommand(String[] shellCmd){     // 执行 linux 的 shell 命令
            String line = null;
            ArrayList<String> fullResponse = new ArrayList<String>();
            Process localProcess = null;
            try {
                Log.i(LOG_TAG,"to shell exec which for find su :");
                localProcess = Runtime.getRuntime().exec(shellCmd);
            } catch (Exception e) {
                return null;
            }
            BufferedWriter out = new BufferedWriter(new OutputStreamWriter(localProcess.getOutputStream()));
            BufferedReader in = new BufferedReader(new InputStreamReader(localProcess.getInputStream()));
            try {
                while ((line = in.readLine()) != null) {
                    Log.i(LOG_TAG,"–> Line received: " + line);
                    fullResponse.add(line);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            Log.i(LOG_TAG,"–> Full response was: " + fullResponse);
            return fullResponse;
        }
    }
    
    

    2. Xposed 检测

    public class Xposed_check {
        private static String TAG = "Wooo Xposed";
        private static StringBuffer sb = new StringBuffer();
    
        // https://blog.csdn.net/jiangwei0910410003/article/details/80037971
        // https://www.52pojie.cn/thread-691584-1-1.html
        // https://tech.meituan.com/android_anti_hooking.html
        // https://segmentfault.com/a/1190000009976827
        public static void checkXposed(Context ctx) {
            checkCache();
            checkJarClass();
            checkJarFile();
            disableHooks();
            checkMaps();
            checkPackage(ctx);
            checkException();
        }
    
        private static void checkPackage(Context ctx) {
            PackageManager packageManager = ctx.getPackageManager();
            List<ApplicationInfo> applicationInfoList = packageManager.getInstalledApplications(PackageManager.GET_META_DATA);
            for (ApplicationInfo applicationInfo : applicationInfoList) {
                if (applicationInfo.packageName.equals("de.robv.android.xposed.installer")) {
                    Log.i(TAG, "found xposed package installed");
                }
            }
        }
    
        private static void checkException() {
            try {
                throw new Exception("xppp");
            } catch (Exception e) {
                for (StackTraceElement stackTraceElement : e.getStackTrace()) {
                    if (stackTraceElement.getClassName().equals("de.robv.android.xposed.XposedBridge")) {       // stackTraceElement.getMethodName()
                        Log.i(TAG, "found exception of xposed");
                    }
                }
            }
        }
    
    
    /*
    bool is_xposed()
    {
       bool rel = false;
       FILE *fp = NULL;
       char* filepath = "/proc/self/maps";
       ...
       string xp_name = "XposedBridge.jar";
       fp = fopen(filepath,"r"))
       while (!feof(fp))
       {
           fgets(strLine,BUFFER_SIZE,fp);
           origin_str = strLine;
           str = trim(origin_str);
           if (contain(str,xp_name))
           {
               rel = true; //检测到Xposed模块
               break;
           }
       }
        ...
    }
    */
        private static void checkMaps() {
            String jarName = "XposedBridge.jar";
            try {
                BufferedReader bufferedReader = new BufferedReader(new FileReader("/proc/" + Process.myPid() + "/maps"));
                while (true) {
                    String str = bufferedReader.readLine();
                    if (str == null) {
                        break;
                    }
                    if (str.endsWith("jar")) {
                        if (str.contains(jarName)) {
                            Log.i(TAG, "proc/pid/maps find Xposed.jar -> " + str);
                        }
                    }
    //                if (str.contains("hack|inject|hook|call")) {      // 检测 maps 内的关键字
    //
    //                }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
        private static void checkCache() {
            ClassLoader cl = ClassLoader.getSystemClassLoader();
            String xpHelper = "de.robv.android.xposed.XposedHelpers";
    
            Log.i(TAG, "checkCache IN");
            try {
                Object XPHelpers = cl.loadClass(xpHelper).newInstance();        // 在 nexus6 的 7.1 系统上获取失败,抛出异常
                if (XPHelpers != null) {
                    filterField(XPHelpers, "fieldCache");
                    filterField(XPHelpers, "methodCache");
                    filterField(XPHelpers, "constructorCache");
                } else {
                    Log.i(TAG, "cannot find Xposed framework");
                }
                Log.i(TAG, "cache content -> " + sb.length() + " -> " + sb);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
        private static void filterField(Object xpHelper, String cacheName) {
            try {
                Field f = xpHelper.getClass().getDeclaredField(cacheName);
                f.setAccessible(true);
                HashMap caMap = (HashMap)f.get(xpHelper);
                if (caMap == null) {
                    return;
                }
                Set caSet = caMap.keySet();
                if (caSet.isEmpty()) {
                    return;
                }
                Log.i(TAG, "filter -> " + cacheName + " , size -> " + caSet.size());
                Iterator iterator = caSet.iterator();
                while (iterator.hasNext()) {
                    String key = (String) iterator.next();
                    Log.i(TAG, "filter key -> " + key);
                    if (key == null) {
                        continue;
                    }
                    key = key.toLowerCase();
                    if (key.length() <= 0) {
                        continue;
                    }
                    if (key.startsWith("android.support")) {
                        continue;
                    }
                    if (key.startsWith("javax.")) {
                        continue;
                    }
                    if (key.startsWith("android.webkit")) {
                        continue;
                    }
                    if (key.startsWith("java.util")) {
                        continue;
                    }
                    if (key.startsWith("android.widget")) {
                        continue;
                    }
                    if (key.startsWith("sun.")) {
                        continue;
                    }
                    sb.append(key);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
        private static void checkJarFile() {
            File f = new File("/system/framework/XposedBridge.jar");
            if (f.exists()) {
                Log.i(TAG, "system may installed Xposed find jar file");
            } else {
                Log.i(TAG, "system not install Xposed cannot find jar file");
            }
        }
    
        private static void checkJarClass() {
            try {
                ClassLoader cl = ClassLoader.getSystemClassLoader();
                Class clazz = cl.loadClass("de.robv.android.xposed.XposedBridge");
    
                if (clazz != null) {
                    Log.i(TAG, "system installed Xposed Class");
                } else {
                    Log.i(TAG, "system not install Xposed Class");
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
        // disable
        private static void disableHooks() {
            Object obj2 = utils.getStaticFieldOjbectCL("de.robv.android.xposed.XposedBridge", "disableHooks");
            Log.i(TAG, "disableHooks seted  -> " + obj2);
    
            Log.i(TAG, "disableHooks seted ");
            utils.setStaticOjbectCL("de.robv.android.xposed.XposedBridge", "disableHooks", true);
    
            Object obj = utils.getStaticFieldOjbectCL("de.robv.android.xposed.XposedBridge", "disableHooks");
            Log.i(TAG, "disableHooks seted  -> " + obj);
        }
    }
    
    

    3. Cydia 检测

    public class Cydia_check {
        private static String TAG = "Wooo Cydia";
    
        public static void checkCydia() {
            checkMaps();
        }
    
        /*  当检测到有对应的 so 文件后,然后根据路径去获取对应的函数地址,如果能获取,说明被加载。有 9 个导出函数。
        void* dlopen = lookup_symbol("/data/app-lib/com.saurik.substrate-2/libsubstrate-dvm.so", "MSJavaHookMethod");
    void* lookup_symbol(char* libraryname,char* symbolname)
    {
        void *imagehandle = dlopen(libraryname, RTLD_GLOBAL | RTLD_NOW);
        if (imagehandle != NULL){
            void * sym = dlsym(imagehandle, symbolname);
            if (sym != NULL){
                return sym; //发现Cydia Substrate相关模块
                }
          ...
    }
        */
        private static void checkMaps() {
            String so1 = "libsubstrate.so";
            String so2 = "libsubstrate-dvm.so";
            try {
                BufferedReader bufferedReader = new BufferedReader(new FileReader("/proc/" + Process.myPid() + "/maps"));
                while (true) {
                    String str = bufferedReader.readLine();
                    if (str == null) {
                        break;
                    }
                    if (str.endsWith("so")) {
                        if (str.contains(so1)) {
                            Log.i(TAG, "proc/pid/maps find libsubstrate.so -> " + str);
                        }
                        if (str.contains(so2)) {
                            Log.i(TAG, "proc/pid/maps find libsubstrate_dvm.so -> " + str);
                        }
                    }
    //                if (str.contains("hack|inject|hook|call")) {      // 检测 maps 内的关键字
    //
    //                }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
        // 第二种方法:通过检测/proc/self/maps下的加载so库列表得到各个库文件绝度路径,通过fopen函数将so库的内容以16进制读进来放在内存里面进行规则比对,采用字符串模糊查找来检测是否命中黑名单中的方法特征码。
        // 参考美团:https://tech.meituan.com/android_anti_hooking.html
    }
    
    
    

    相关文章

      网友评论

          本文标题:root 检测、Xposed 检测、Cydia 检测

          本文链接:https://www.haomeiwen.com/subject/lzsxgftx.html