루팅된 앱을 탐지하는 방법에 관하여

기본적으로 명확하게 딱 나오는 경우도 없고

요즘 루팅앱이나 위변조 앱들을 보면 , 계속해서 이름을 바꾸는 ( 게임가디언도 그러더라 ) 식으로

요리조리 피해가므로 , 완전한 해결책 이라기 보다는 ..

아주 기본적으로 체크해야하고 효과 대비 별 비용이 안드는 방법을 기록해놓는다.

우선은, Android.os.Build 에서 제공하는 정보들을 받아와보자.

이 방법은 T or F 로 루팅을 판별한다기 보다는, 각종 정보를 긁어서 운영 서버에 올리거나 로그를 찍어놓아서

나중에 수상한 유저일 경우 조회해 볼 수 있게 한다던가 하는 방법으로 써야할 것 같다.

    public static string GetData()
    {
        string result = "";
        if (Application.platform == RuntimePlatform.Android)
        {
            var osBuild = new AndroidJavaClass("android.os.Build");
            string brand = osBuild.GetStatic<string>("BRAND");
            string fingerPrint = osBuild.GetStatic<string>("FINGERPRINT");
            string model = osBuild.GetStatic<string>("MODEL");
            string menufacturer = osBuild.GetStatic<string>("MANUFACTURER");
            string device = osBuild.GetStatic<string>("DEVICE");
            string product = osBuild.GetStatic<string>("PRODUCT");
            result += "Model : " + model;
            result += "/";
            result += "Menufacturer : " + menufacturer;
            result += "/";
            result += "Device : " + device;
            result += "/";
            result += "Fingerprint : " + fingerPrint;
            result += "/";
            result += "Product : " + product;
        }
    }

다음으로는 Application (Unity API) 객체에서 도움이 될만한 것들을 가져오는 것이다.

사실 이게 훨씬 더 쉬운 방법이다. (ㅎㅎ.)

참고로 이 방법은 유니티가 제공하는 API 라서,

아이폰이든 안드로이드든 별 상관 없이 잘 된다.

(크로스 플랫폼 만세! )

    public static string GetData()
    {
        string result = "";
        if (Application.platform == RuntimePlatform.Android)
        {
            result += Application.installerName; // 보통 구글스토어 또는 앱스토어를 나타낸다. 
            result += "/";
            result += Application.installMode.ToString(); //Debug 인지 릴리즈인지 뜬다 . 구글 검사봇의 경우에는 Debug 로 뜨니 유의하자. 
            result += "/";
            result += Application.buildGUID; // 빌드 시 마다 다른 고유 GUID 넘버다. 이걸 비교하는 것 만으로도 재 빌드된 변조앱임을 쉽게 유추 가능하다. 물론 GUID 가 들통나버리고 비교 부분이 변조되면 답은 없다 (...)
            result += "/";
            result += "Genuine :" + Application.genuine; //  T or F 로 리턴된다. APK 상태로 풀린뒤에 재 빌드되면 False 된다고 한다 ( 직접 본적이 없어서 .. )
        }
    }

한편, 루팅 감지로 시간을 꽤 보내고 얻은 결론은..

대부분 특정 경로가 존재하는지 체크한다는 것 .

그래도 대부분이 걸린다는 게 웃기긴 하지만 말이다.

에뮬레이터인지 검사하는 것은 주로 제작사 등을 비교하는 것 같은데 ,

요새 에뮬레이터가 하도 잘나와서 녹스 같은 경우에도

태블릿으로 하면 저걸로 잡히는데 폰 모드로 하면 안잡힌다 ‘-‘…

고로 전적인 신뢰는 하지말고 지속적으로 개량해야 할 듯.


    public static bool isRooted()
    {
        bool isRoot = false;

        if (Application.platform == RuntimePlatform.Android)
        {
            if (isRootedPrivate("/system/bin/su"))
                isRoot = true;
            if (isRootedPrivate("/system/xbin/su"))
                isRoot = true;
            if (isRootedPrivate("/system/app/SuperUser.apk"))
                isRoot = true;
            if (isRootedPrivate("/data/data/com.noshufou.android.su"))
                isRoot = true;
            if (isRootedPrivate("/sbin/su"))
                isRoot = true;
        }
        return isRoot;
    }
    public static bool IsEmulator()
    {
        if (Application.platform == RuntimePlatform.Android)
        {
            AndroidJavaClass osBuild;
        osBuild = new AndroidJavaClass("android.os.Build");
        string fingerPrint = osBuild.GetStatic<string>("FINGERPRINT");
        string model = osBuild.GetStatic<string>("MODEL");
        string menufacturer = osBuild.GetStatic<string>("MANUFACTURER");
        string brand = osBuild.GetStatic<string>("BRAND");
        string device = osBuild.GetStatic<string>("DEVICE");
        string product = osBuild.GetStatic<string>("PRODUCT");

        return fingerPrint.Contains("generic")
                || fingerPrint.Contains("unknown")
                  || model.Contains("google_sdk")
                || model.Contains("Emulator")
               || model.Contains("Android SDK built for x86")
          || menufacturer.Contains("Genymotion")
            || (brand.Contains("generic") && device.Contains("generic"))
    || product.Equals("google_sdk")
            || product.Equals("unknown");

        }
        if (Application.platform == RuntimePlatform.OSXEditor)
        {
            return true;
        }
        return false;
    }

    public static bool isRootedPrivate(string path)
    {
        bool boolTemp = false;

        if (File.Exists(path))
        {
            boolTemp = true;
        }

        return boolTemp;
    }