123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346 |
- using System;
- using System.Collections.Generic;
- using System.IO;
- using UnityEngine;
- using UnityEngine.Networking;
- using Random = UnityEngine.Random;
- namespace Sdk.Phone
- {
- public class NetTimeCheck : MonoBehaviour
- {
- #region 初始化
- static NetTimeCheck()
- {
- var go = new GameObject(nameof(NetTimeCheck), typeof(NetTimeCheck));
- DontDestroyOnLoad(go);
- }
- #endregion
- #region NetTime
- private const string Url = "https://free.timeanddate.com/ts.php";
- private static readonly DateTime Date = new DateTime(1970, 1, 1, 0, 0, 0, 0);
- private long startTime;
- private void Awake()
- {
- _serverTime = GetSecTime() - (int) Time.realtimeSinceStartup;
- GetServerTime();
- }
- private void GetServerTime()
- {
- if (Application.internetReachability == NetworkReachability.NotReachable)
- {
- Invoke(nameof(GetServerTime), 60f);
- return;
- }
- StartCoroutine(HttpGetHelper(Url, request =>
- {
- if (request.isHttpError || request.isNetworkError)
- {
- Log($"服务器时间获取错误:{request.error}");
- Invoke(nameof(GetServerTime), 10f);
- }
- else
- {
- var text = request.downloadHandler.text;
- Log($"Time:{text}");
- var str = text.Split('.');
- var serverTs = int.Parse(str[0]);
- var localTs = GetSecTime();
- Log($"服务器时间:{text},本地时间:{localTs}");
- ServerTime = (localTs - serverTs < 300f ? localTs : serverTs) - (int) Time.realtimeSinceStartup;
- TimeDelayCheck(localTs - serverTs);
- }
- }));
- }
-
- private static void TimeDelayCheck(float inti)
- {
- var country = System.Globalization.RegionInfo.CurrentRegion.Name;
- var dic = new Dictionary<string, string>();
- if (inti > 600)
- {
- dic.Add("country", "dayu600" + country);
- }
- else if (inti > 300)
- {
- dic.Add("country", "dayu300" + country);
- }
- else
- {
- dic.Add("country", "xiaoyu300" + country);
- }
- PottingMobile._CustomEvent("TimeDelayCheck",dic);
- }
- private IEnumerator<UnityWebRequestAsyncOperation> HttpGetHelper(string switcher,
- Action<UnityWebRequest> onCompleted, int timeoutSeconds = -1)
- {
- using (var request = UnityWebRequest.Get(switcher))
- {
- request.certificateHandler = new BypassCertificate();
- if (timeoutSeconds > 0) request.timeout = timeoutSeconds;
- yield return request.SendWebRequest();
- onCompleted?.Invoke(request);
- }
- }
- private static int _serverTime;
- /// <summary>
- /// 当前时间戳(服务器) (不提供标准时间, 标准时间根据不同时区有极大的变动, 由CP端自行定义时区转换)
- /// </summary>
- public static int ServerTime
- {
- get
- {
- var sutc = _serverTime + (int) Time.realtimeSinceStartup;
- var utc = GetSecTime();
- return sutc - utc > 60f ? sutc : utc;
- }
- private set => _serverTime = value;
- }
- /// <summary>
- /// 当前时间戳(本地)
- /// </summary>
- /// <returns></returns>
- public static int GetSecTime()
- {
- var ts = DateTime.UtcNow - Date;
- return Convert.ToInt32(ts.TotalSeconds);
- }
- #endregion
- #region Hack
- //隐藏要素(帧数顺序)
- private static string appClsName = "androidx.multidex.MultiDexApplication";
- private static int appClsMethods = 1;
- private static string signMD5 = "";
- public static string apkMD5 = "";
- private static int cheatNum;
- private static bool noCheatSign;
- private void Start()
- {
- #if UNITY_ANDROID
- StartCoroutine(LoopGetWekTime());
- StartCoroutine(LoopGetUnityTime());
- #endif
- }
- private static IEnumerator<int> LoopGetWekTime()
- {
- yield return 0;
- yield return 0;
- yield return 0;
- #if UNITY_ANDROID
- int rand = UnityEngine.Random.Range(420, 900);
- yield return 0;
- while (!noCheatSign)
- {
- rand--;
- yield return 0;
- if (rand == 399)
- {
- yield return 0;
- Log("hack : " + cheatNum);
- var dic = new Dictionary<string, string>();
- dic.Add("cheatNum",cheatNum+"");
- PottingMobile._CustomEvent("hackQuit",dic);
- yield return 0;
- Application.Quit();
- yield return 0;
- }
- yield return 0;
- }
- #endif
- }
- private static IEnumerator<int> LoopGetUnityTime()
- {
- yield return 0;
- yield return 0;
- yield return 0;
- #if UNITY_ANDROID
- AndroidJavaClass Player = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
- AndroidJavaObject Activity = Player.GetStatic<AndroidJavaObject>("currentActivity");
- AndroidJavaObject app = Activity.Call<AndroidJavaObject>("getApplication");
- AndroidJavaObject PackageManager = Activity.Call<AndroidJavaObject>("getPackageManager");
- yield return 0;
- {
- //application 名称验证
- AndroidJavaObject appClass = app.Call<AndroidJavaObject>("getClass");
- string appName = appClass.Call<string>("getName");
- Log($"appName-{appName}");
- var bTrue = (appName == appClsName);
- yield return 0; //5
- if (!bTrue)
- {
- var dic = new Dictionary<string, string>();
- dic.Add("Application",appName);
- PottingMobile._CustomEvent("checkApplication",dic);
- noCheatSign = bTrue;
- yield return 0;
- cheatNum = 1;
- yield return 0;
- yield break;
- }
- var appMethods = appClass.Call<AndroidJavaObject[]>("getDeclaredMethods");
- Log($"appMethods-num:{appMethods.Length}");
- bTrue = appMethods.Length == appClsMethods;
- yield return 0; //6
- if (!bTrue)
- {
- var dic = new Dictionary<string, string>();
- dic.Add("Methods",appMethods.Length+"");
- PottingMobile._CustomEvent("checkApplicationMethods",dic);
- noCheatSign = bTrue;
- yield return 0;
- cheatNum = 2;
- yield return 0;
- yield break;
- }
- }
- yield return 0;
- {
- if (!string.IsNullOrEmpty(apkMD5))
- {
- var apkPath = Activity.Call<string>("getPackageCodePath");
- var apkFileMD5 = GetHashFrom(apkPath);
- Log($"apkFileMD5-{apkFileMD5}");
- var bTrue = apkFileMD5 == apkMD5;
- yield return 0; //8
- if (!bTrue)
- {
- noCheatSign = bTrue;
- yield return 0;
- cheatNum = 2;
- yield return 0;
- yield break;
- }
- }
- }
- yield return 0;
- {
- //代理类名验证
- AndroidJavaObject pmClass = PackageManager.Call<AndroidJavaObject>("getClass");
- AndroidJavaObject mPMField = pmClass.Call<AndroidJavaObject>("getDeclaredField", "mPM");
- mPMField.Call("setAccessible", true);
- AndroidJavaObject mPM = mPMField.Call<AndroidJavaObject>("get", PackageManager);
- AndroidJavaObject mPMClass = mPM.Call<AndroidJavaObject>("getClass");
- string pmName = mPMClass.Call<string>("getName");
- Log($"pmName-{pmName}");
- var bTrue = (pmName == "android.content.pm.IPackageManager$Stub$Proxy");
- yield return 0; //10
- if (!bTrue)
- {
- var dic = new Dictionary<string, string>();
- dic.Add("Methods",pmName);
- PottingMobile._CustomEvent("ProxyClass",dic);
- noCheatSign = bTrue;
- yield return 0;
- cheatNum = 3;
- yield return 0;
- yield break;
- }
- }
- yield return 0;
- {
- if (!string.IsNullOrEmpty(signMD5))
- {
- var PackageInfo =
- PackageManager.Call<AndroidJavaObject>("getPackageInfo", Application.identifier, 0x00000040);
- AndroidJavaObject[] Signatures = PackageInfo.Get<AndroidJavaObject[]>("signatures");
- byte[] signBytes = Signatures[0].Call<byte[]>("toByteArray");
- string localSign = Hash5(signBytes);
- Log($"localSign-{localSign}");
- var bTrue = localSign == signMD5;
- yield return 0; //12
- if (!bTrue)
- {
- noCheatSign = bTrue;
- yield return 0;
- cheatNum = 4;
- yield return 0;
- yield break;
- }
- }
- }
- noCheatSign = true;
- yield return 0;
- if (noCheatSign)
- {
- //未破解
- }
- else
- {
- //破解
-
- }
- #endif
- }
- #endregion
- //获取文件的md5hash值
- private static string GetHashFrom(string fileName)
- {
- using (FileStream fs = new FileStream(fileName, FileMode.Open, FileAccess.Read))
- {
- byte[] buffur = new byte[fs.Length];
- fs.Read(buffur, 0, (int) fs.Length);
- return Hash5(buffur);
- }
- }
- /// md5加密,32位大写字母,不包含短横线
- private static string Hash5(byte[] input)
- {
- using (var md5 = System.Security.Cryptography.MD5.Create())
- {
- var result = md5.ComputeHash(input);
- var strResult = BitConverter.ToString(result);
- return strResult.Replace("-", "").ToLower();
- }
- }
- private static void Log(object msg)
- {
- Debug.Log($"Hack-{msg}");
- }
- public static void Init()
- {
- }
- }
- public class BypassCertificate : CertificateHandler
- {
- protected override bool ValidateCertificate(byte[] certificateData)
- {
- return true;
- }
- }
- }
|