首次提交

This commit is contained in:
Bob.Song
2026-03-05 18:07:55 +08:00
commit e125bb869e
4534 changed files with 563920 additions and 0 deletions

21
.gitignore vendored Normal file
View File

@@ -0,0 +1,21 @@
/Library
/Logs
/obj
/Build
/Temp
/.vs
/copydll.bat
/Debug
/.idea/
/update_unity_libil2cpp.bat
/*.csproj
/*.sln
/UserSettings/Layouts
/Release
/Assembly-CSharp-Editor.csproj.user
/Assets/StreamingAssets
/Assets/ResRaw/Effect/Z_Test
/Assets/ResRaw/Effect/Z_Test.meta
/Bundles/
Assets/Scripts/sync.ffs_db
Assets/Scripts/sync.ffs_db.meta

8
Assets/Plugins.meta Normal file
View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 3698f814f47cca649b4fb0cab847eda7
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: cd0e9f4a4927f6145887bbb2b491ffe9
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 52c313066dda63c459f7c826dbb8eed1
folderAsset: yes
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,2 @@
Please, check out latest Anti-Cheat Toolkit Code Library API Docs here:
https://codestage.net/uas_files/actk/api/

View File

@@ -0,0 +1,6 @@
fileFormatVersion: 2
guid: f4c375fd5bde53c42b0ebc6ee503f7a1
TextScriptImporter:
userData:
assetBundleName:
assetBundleVariant:

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,6 @@
fileFormatVersion: 2
guid: a707e4914fc9f014790c02a3cd0b455d
TextScriptImporter:
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: ac5220baa6a51bb47a5c640ddf6c0ce8
folderAsset: yes
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,23 @@
{
"name": "ACTk.Editor",
"references": [
"ACTk.Runtime"
],
"includePlatforms": [
"Editor"
],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": [],
"versionDefines": [
{
"name": "com.unity.modules.audio",
"expression": "",
"define": "UNITY_AUDIO_MODULE"
}
],
"noEngineReferences": false
}

View File

@@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: 8ef82b58ed1acc8419a02b8a05286620
timeCreated: 1554196096
licenseType: Store
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 1ff6bc3cba85fba4e922af0d4a624023
folderAsset: yes
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,48 @@
#region copyright
// ------------------------------------------------------
// Copyright (C) Dmitriy Yukhanov [https://codestage.net]
// ------------------------------------------------------
#endregion
namespace CodeStage.AntiCheat.EditorCode
{
using System.IO;
using System.Linq;
using UnityEngine;
internal static class ACTkEditorConstants
{
internal static class Conditionals
{
public const string WallhackLinkXML = "ACTK_WALLHACK_LINK_XML";
public const string ExcludeObfuscation = "ACTK_EXCLUDE_OBFUSCATION";
public const string PreventReadPhoneState = "ACTK_PREVENT_READ_PHONE_STATE";
public const string PreventInternetPermission = "ACTK_PREVENT_INTERNET_PERMISSION";
public const string ObscuredAutoMigration = "ACTK_OBSCURED_AUTO_MIGRATION";
public const string ThirdPartyIntegration = "ACTK_IS_HERE";
public const string UsExportCompatible = "ACTK_US_EXPORT_COMPATIBLE";
public const string NewtonsoftJson = "ACTK_NEWTONSOFT_JSON";
public const string InjectionDebug = "ACTK_INJECTION_DEBUG";
public const string InjectionDebugVerbose = "ACTK_INJECTION_DEBUG_VERBOSE";
public const string InjectionDebugParanoid = "ACTK_INJECTION_DEBUG_PARANOID";
public const string WallhackDebug = "ACTK_WALLHACK_DEBUG";
public const string DetectionBacklogs = "ACTK_DETECTION_BACKLOGS";
public const string GenericDevLogs = "ACTK_DEV_LOGS";
}
public const string SettingsProviderPath = "Code Stage/Anti-Cheat Toolkit";
public const string MenuPath = "Code Stage/🕵 Anti-Cheat Toolkit/";
public const string ToolsMenuPath = "Tools/" + MenuPath;
public const string GameObjectMenuPath = "GameObject/Create Other/" + MenuPath;
public static readonly string ProjectFolder = Path.GetFullPath(Path.Combine(Application.dataPath, "../"));
public static readonly string ProjectTempFolder = Path.Combine(ProjectFolder, "Temp");
public static readonly string LinkXmlPath = Path.Combine(ProjectTempFolder, "actk-link.xml");
public static readonly string ProjectLibraryFolder = Path.Combine(ProjectFolder, "Library");
public static readonly string ProjectSettingsFolder = Path.Combine(ProjectFolder, "ProjectSettings");
public static readonly string AssetsFolder = Path.Combine(ProjectFolder, "Assets");
public static readonly string[] HexTable = Enumerable.Range(0, 256).Select(v => v.ToString("x2")).ToArray();
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: a9ee7d4a58674ac69c27bc7c29417309
timeCreated: 1552925230

View File

@@ -0,0 +1,41 @@
#region copyright
// ------------------------------------------------------
// Copyright (C) Dmitriy Yukhanov [https://codestage.net]
// ------------------------------------------------------
#endregion
namespace CodeStage.AntiCheat.EditorCode
{
using UnityEditor;
using UnityEngine;
/// <summary>
/// Use it to guess current directory of the Anti-Cheat Toolkit.
/// </summary>
public class ACTkMarker : ScriptableObject
{
/// <summary>
/// Returns raw path of the ACTkMarker script for further reference.
/// </summary>
/// <returns>Path of the ACTkMarker ScriptableObject asset.</returns>
public static string GetAssetPath()
{
string result;
var tempInstance = CreateInstance<ACTkMarker>();
var script = MonoScript.FromScriptableObject(tempInstance);
if (script != null)
{
result = AssetDatabase.GetAssetPath(script);
}
else
{
result = AssetDatabase.FindAssets("ACTkMarker")[0];
result = AssetDatabase.GUIDToAssetPath(result);
}
DestroyImmediate(tempInstance);
return result;
}
}
}

View File

@@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: 00b850c709170d1469bcd89e6f80b16c
timeCreated: 1557660868
licenseType: Store
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,134 @@
#region copyright
// ------------------------------------------------------
// Copyright (C) Dmitriy Yukhanov [https://codestage.net]
// ------------------------------------------------------
#endregion
namespace CodeStage.AntiCheat.EditorCode
{
using Detectors;
using UnityEditor;
using Common;
using PostProcessors;
using UnityEngine;
using Processors;
internal static class ACTkMenuItems
{
// ---------------------------------------------------------------
// Main menu items
// ---------------------------------------------------------------
[MenuItem(ACTkEditorConstants.ToolsMenuPath + "Settings...", false, 100)]
private static void ShowSettingsWindow()
{
ACTkSettings.Show();
}
[MenuItem(ACTkEditorConstants.ToolsMenuPath + "Injection Detector Whitelist Editor...", false, 1000)]
private static void ShowAssembliesWhitelistWindow()
{
UserWhitelistEditor.ShowWindow();
}
[MenuItem(ACTkEditorConstants.ToolsMenuPath + "Calculate external build hashes", false, 1200)]
private static async void HashExternalBuild()
{
var buildHashes = await CodeHashGeneratorPostprocessor.CalculateExternalBuildHashesAsync(null, true);
if (buildHashes == null || buildHashes.FileHashes.Count == 0)
{
Debug.LogError(ACTk.LogPrefix + "External build hashing was not successful. " +
"See previous log messages for possible details.");
}
}
[MenuItem(ACTkEditorConstants.ToolsMenuPath + "Configure proguard-user.txt", false, 1201)]
private static void CheckProGuard()
{
BuildPreProcessor.CheckProGuard(true);
}
[MenuItem(ACTkEditorConstants.ToolsMenuPath + "Migrate/Migrate obscured types on prefabs...", false, 1500)]
private static void MigrateObscuredTypesOnPrefabs()
{
MigrateUtils.MigrateObscuredTypesOnPrefabs("ObscuredFloat", "ObscuredDouble", "ObscuredVector2", "ObscuredVector3", "ObscuredQuaternion");
}
[MenuItem(ACTkEditorConstants.ToolsMenuPath + "Migrate/Migrate obscured types in opened scene(s)...", false, 1501)]
private static void MigrateObscuredTypesInScene()
{
MigrateUtils.MigrateObscuredTypesInScene("ObscuredFloat", "ObscuredDouble", "ObscuredVector2", "ObscuredVector3", "ObscuredQuaternion");
}
[MenuItem(ACTkEditorConstants.ToolsMenuPath + "Validate/Validate obscured types in assets...", false, 1500)]
private static void ValidateObscuredTypesInAssets()
{
ObscuredTypesValidator.ValidateProjectAssets();
}
[MenuItem(ACTkEditorConstants.ToolsMenuPath + "Validate/Validate obscured types in opened scene(s)...", false, 1501)]
private static void ValidateObscuredTypesInOpenedScenes()
{
ObscuredTypesValidator.ValidateOpenedScenes();
}
/* will be needed when obsolete string internals will be deprecated along with automatic migration */
//[MenuItem(ACTkEditorConstants.ToolsMenuPath + "Migrate/Migrate ObscuredString on prefabs...", false, 1600)]
private static void MigrateObscuredStringOnPrefabs()
{
MigrateUtils.MigrateObscuredTypesOnPrefabs("ObscuredString");
}
//[MenuItem(ACTkEditorConstants.ToolsMenuPath + "Migrate/Migrate ObscuredString in opened scene(s)...", false, 1601)]
private static void MigrateObscuredStringInScene()
{
MigrateUtils.MigrateObscuredTypesInScene("ObscuredString");
}
// ---------------------------------------------------------------
// GameObject menu items
// ---------------------------------------------------------------
[MenuItem(ACTkEditorConstants.GameObjectMenuPath + "All detectors", false, 0)]
private static void AddAllDetectorsToScene()
{
AddInjectionDetectorToScene();
AddObscuredCheatingDetectorToScene();
AddSpeedHackDetectorToScene();
AddWallHackDetectorToScene();
AddTimeCheatingDetectorToScene();
}
[MenuItem(ACTkEditorConstants.GameObjectMenuPath + InjectionDetector.ComponentName, false, 1)]
private static void AddInjectionDetectorToScene()
{
DetectorTools.SetupDetectorInScene<InjectionDetector>();
}
[MenuItem(ACTkEditorConstants.GameObjectMenuPath + ObscuredCheatingDetector.ComponentName, false, 1)]
private static void AddObscuredCheatingDetectorToScene()
{
DetectorTools.SetupDetectorInScene<ObscuredCheatingDetector>();
}
[MenuItem(ACTkEditorConstants.GameObjectMenuPath + SpeedHackDetector.ComponentName, false, 1)]
private static void AddSpeedHackDetectorToScene()
{
DetectorTools.SetupDetectorInScene<SpeedHackDetector>();
}
[MenuItem(ACTkEditorConstants.GameObjectMenuPath + WallHackDetector.ComponentName, false, 1)]
private static void AddWallHackDetectorToScene()
{
DetectorTools.SetupDetectorInScene<WallHackDetector>();
}
[MenuItem(ACTkEditorConstants.GameObjectMenuPath + TimeCheatingDetector.ComponentName, false, 1)]
private static void AddTimeCheatingDetectorToScene()
{
DetectorTools.SetupDetectorInScene<TimeCheatingDetector>();
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: e10289b3bdb7db64c8f2c624b337d331
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,10 @@
#region copyright
// ------------------------------------------------------
// Copyright (C) Dmitriy Yukhanov [https://codestage.net]
// ------------------------------------------------------
#endregion
using System.Runtime.CompilerServices;
[assembly: InternalsVisibleTo("CodeStage.ACTk.Service")]
[assembly: InternalsVisibleTo("CodeStage.ACTk.Tests.Editor")]

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: a1cc293465f841498ad940f7813ccedd
timeCreated: 1588809689

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: d9e6164ee563b444d87cbe3437d6012a
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 14398b80f1b8c7e4ea405ef47a17e38c
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,198 @@
#region copyright
// -------------------------------------------------------
// Copyright (C) Dmitriy Yukhanov [https://codestage.net]
// -------------------------------------------------------
#endregion
namespace CodeStage.EditorCommon.Tools
{
using System;
using UnityEditor;
using UnityEngine;
internal static class CSColorTools
{
internal enum ColorKind
{
Green,
Red,
Purple
}
public const string GreenHex = "02C85F";
public const string GreenDarkHex = "02981F";
public const string PurpleHex = "A76ED1";
public const string PurpleDarkHex = "7030A0";
public const string RedHex = "FF4040";
public const string RedAltHex = "FF6060";
public const string RedDarkHex = "FF1010";
public const string BrightGreyHex = "E5E5E5";
public readonly static Color32 Green = new Color32(2, 200, 95, 255);
public readonly static Color32 GreenDark = new Color32(2, 152, 31, 255);
public readonly static Color32 Purple = new Color32(167, 110, 209, 255);
public readonly static Color32 PurpleDark = new Color32(112, 48, 160, 255);
public readonly static Color32 RedAlt = new Color32(255, 96, 96, 255);
public readonly static Color32 RedDark = new Color32(255, 16, 16, 255);
public readonly static Color32 BrightGrey = new Color32(229, 229, 229, 255);
public static string EditorGreenHex
{
get
{
return EditorGUIUtility.isProSkin ? GreenHex : GreenDarkHex;
}
}
public static string EditorPurpleHex
{
get
{
return EditorGUIUtility.isProSkin ? PurpleHex : PurpleDarkHex;
}
}
public static string EditorRedHex
{
get
{
return EditorGUIUtility.isProSkin ? RedAltHex : RedDarkHex;
}
}
public static Color EditorGreen
{
get
{
return EditorGUIUtility.isProSkin ? Green : GreenDark;
}
}
public static Color EditorPurple
{
get
{
return EditorGUIUtility.isProSkin ? Purple : PurpleDark;
}
}
public static Color EditorRed
{
get
{
return EditorGUIUtility.isProSkin ? RedAlt : RedDark;
}
}
public static Color DimmedColor
{
get
{
return ChangeAlpha(GUI.skin.label.normal.textColor, 150);
}
}
public static Color BrightGreyDimmed
{
get
{
return ChangeAlpha(BrightGrey, 150);
}
}
public static Color GreenColor
{
get
{
return LerpToGreen(GUI.skin.label.normal.textColor, 0.3f);
}
}
public static Color RedColor
{
get
{
return LerpToRed(GUI.skin.label.normal.textColor, 0.3f);
}
}
public static Color BackgroundGreenTint
{
get
{
return EditorGUIUtility.isProSkin ? new Color32(0, 255, 0, 150) : new Color32(0, 255, 0, 30);
}
}
public static Color BackgroundRedTint
{
get
{
return EditorGUIUtility.isProSkin ? new Color32(255, 0, 0, 150) : new Color32(255, 0, 0, 30);
}
}
public static string WrapBool(bool value)
{
return WrapString(value.ToString(), value ? ColorKind.Green : ColorKind.Red);
}
public static string WrapString(string inputGood, string inputBad, bool good)
{
return WrapString(good ? inputGood : inputBad, good ? ColorKind.Green : ColorKind.Red);
}
public static string WrapString(string input, bool good)
{
return WrapString(input, good ? ColorKind.Green : ColorKind.Red);
}
public static string WrapString(string input, ColorKind colorKind)
{
switch (colorKind)
{
case ColorKind.Green:
return WrapString(input, EditorGreenHex);
case ColorKind.Red:
return WrapString(input, EditorRedHex);
case ColorKind.Purple:
return WrapString(input, EditorPurpleHex);
default:
throw new ArgumentOutOfRangeException("colorKind", colorKind, null);
}
}
public static string WrapString(string input, Color color)
{
var colorString = ColorUtility.ToHtmlStringRGBA(color);
return WrapString(input, colorString);
}
// color argument should be in rrggbbaa format or match standard html color name, without '#'
public static string WrapString(string input, string color)
{
return "<color=#" + color + ">" + input + "</color>";
}
public static Color32 LerpToRed(Color32 inValue, float greenAmountPercent)
{
return Color.Lerp(inValue, Color.red, greenAmountPercent);
}
public static Color32 LerpToGreen(Color32 inValue, float greenAmountPercent)
{
return Color.Lerp(inValue, Color.green, greenAmountPercent);
}
public static Color32 LerpToYellow(Color32 inValue, float greenAmountPercent)
{
return Color.Lerp(inValue, Color.yellow, greenAmountPercent);
}
private static Color32 ChangeAlpha(Color32 inValue, byte alphaValue)
{
inValue.a = alphaValue;
return inValue;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: b18cacce4700f664e8a56903e2090843
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,35 @@
#region copyright
// -------------------------------------------------------
// Copyright (C) Dmitriy Yukhanov [https://codestage.net]
// -------------------------------------------------------
#endregion
namespace CodeStage.EditorCommon.Tools
{
using UnityEngine;
internal static class CSEditorIcons
{
public static Texture AssetStore { get { return CSTextureLoader.GetIconTexture("Asset Store", ImageKind.InternalIcon); } }
public static Texture Error { get { return CSTextureLoader.GetIconTexture("console.erroricon", ImageKind.InternalIcon); } }
public static Texture ErrorSmall { get { return CSTextureLoader.GetIconTexture("console.erroricon.sml", ImageKind.InternalIcon); } }
public static Texture Favorite { get { return CSTextureLoader.GetIconTexture("Favorite", ImageKind.InternalIcon); } }
public static Texture FavoriteIcon { get { return CSTextureLoader.GetIconTexture("Favorite Icon", ImageKind.InternalIcon); } }
public static Texture FilterByType { get { return CSTextureLoader.GetIconTexture("FilterByType", ImageKind.InternalIcon); } }
public static Texture Folder { get { return CSTextureLoader.GetIconTexture("Folder Icon", ImageKind.InternalIcon); } }
public static Texture GameObject { get { return CSTextureLoader.GetTypeImage(typeof(GameObject)); } }
public static Texture Help { get { return CSTextureLoader.GetIconTexture("_Help", ImageKind.InternalIcon); } }
public static Texture HierarchyView { get { return CSTextureLoader.GetIconTexture("UnityEditor.SceneHierarchyWindow", ImageKind.InternalIcon); } }
public static Texture Info { get { return CSTextureLoader.GetIconTexture("console.infoicon", ImageKind.InternalIcon); } }
public static Texture InfoSmall { get { return CSTextureLoader.GetIconTexture("console.infoicon.sml", ImageKind.InternalIcon); } }
public static Texture Inspector { get { return CSTextureLoader.GetIconTexture("UnityEditor.InspectorWindow", ImageKind.InternalIcon); } }
public static Texture Prefab { get { return UnityEditorInternal.InternalEditorUtility.FindIconForFile("dummy.prefab"); } }
public static Texture ProjectView { get { return CSTextureLoader.GetIconTexture("Project", ImageKind.InternalIcon); } }
public static Texture Scene { get { return UnityEditorInternal.InternalEditorUtility.FindIconForFile("dummy.unity"); } }
public static Texture Script { get { return UnityEditorInternal.InternalEditorUtility.FindIconForFile("dummy.cs"); } }
public static Texture Search { get { return CSTextureLoader.GetIconTexture("Search Icon", ImageKind.InternalIcon); } }
public static Texture Settings { get { return CSTextureLoader.GetIconTexture("Settings", ImageKind.InternalIcon); } }
public static Texture Warn { get { return CSTextureLoader.GetIconTexture("console.warnicon", ImageKind.InternalIcon); } }
public static Texture WarnSmall { get { return CSTextureLoader.GetIconTexture("console.warnicon.sml", ImageKind.InternalIcon); } }
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 0262830fc851659438acad57bb020619
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,27 @@
#region copyright
// -------------------------------------------------------
// Copyright (C) Dmitriy Yukhanov [https://codestage.net]
// -------------------------------------------------------
#endregion
namespace CodeStage.EditorCommon.Tools
{
using System.IO;
internal static class CSFileTools
{
public static void DeleteFile(string path)
{
if (!File.Exists(path)) return;
RemoveReadOnlyAttribute(path);
File.Delete(path);
}
private static void RemoveReadOnlyAttribute(string filePath)
{
var attributes = File.GetAttributes(filePath);
if ((attributes & FileAttributes.ReadOnly) == FileAttributes.ReadOnly)
File.SetAttributes(filePath, attributes & ~FileAttributes.ReadOnly);
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 47e5a8270a3c78c4191b11b026ac7c2d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,114 @@
#region copyright
// -------------------------------------------------------
// Copyright (C) Dmitriy Yukhanov [https://codestage.net]
// -------------------------------------------------------
#endregion
namespace CodeStage.EditorCommon.Tools
{
using System;
using System.Collections.Generic;
using System.IO;
using UnityEditor;
using UnityEngine;
internal enum ImageKind
{
External,
InternalTexture,
InternalIcon
}
internal static class CSTextureLoader
{
public static string ExternalTexturesFolder { get; set; }
public static string LogPrefix { get; set; }
private static readonly Dictionary<string, Texture> CachedTextures = new Dictionary<string, Texture>();
public static Texture GetTexture(string fileName)
{
return GetTexture(fileName, false);
}
public static Texture GetIconTexture(string fileName, ImageKind kind = ImageKind.External)
{
return GetTexture(fileName, true, kind);
}
private static Texture GetTexture(string fileName, bool icon, ImageKind kind = ImageKind.External)
{
Texture result;
var isDark = EditorGUIUtility.isProSkin;
var textureName = fileName;
if (isDark)
textureName = "d_" + textureName;
if (CachedTextures.ContainsKey(textureName))
{
result = CachedTextures[textureName];
}
else
{
var path = fileName;
if (kind == ImageKind.External)
{
fileName = textureName;
path = Path.Combine(ExternalTexturesFolder, "Textures");
if (icon)
path = Path.Combine(path, "Icons");
path = Path.Combine(path, fileName);
if (!File.Exists(Path.GetFullPath(path)) && !Path.HasExtension(path))
{
path = Path.ChangeExtension(path, "png");
}
if (!File.Exists(Path.GetFullPath(path)))
{
Debug.LogWarning("Couldn't find icon " + fileName + " at path " + path);
return null;
}
}
switch (kind)
{
case ImageKind.External:
result = AssetDatabase.LoadAssetAtPath(path, typeof(Texture2D)) as Texture2D;
break;
case ImageKind.InternalTexture:
result = EditorGUIUtility.FindTexture(path);
break;
case ImageKind.InternalIcon:
result = EditorGUIUtility.IconContent(path).image;
break;
default:
throw new ArgumentOutOfRangeException("kind", kind, null);
}
if (result == null)
Debug.LogError(LogPrefix + "Some error occurred while looking for image\n" + path);
else
CachedTextures[textureName] = result;
}
return result;
}
public static Texture GetTypeImage(Type type)
{
var key = type.ToString();
if (CachedTextures.ContainsKey(key))
{
return CachedTextures[key];
}
var texture = EditorGUIUtility.ObjectContent(null, type).image;
CachedTextures.Add(key, texture);
return texture;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 5e42f0f68a093d74ea97ddfbd9a5ef4d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: f0c63cf6cabe3a547a0b46de95bff055
folderAsset: yes
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,64 @@
#region copyright
// ------------------------------------------------------
// Copyright (C) Dmitriy Yukhanov [https://codestage.net]
// ------------------------------------------------------
#endregion
namespace CodeStage.AntiCheat.EditorCode.Editors
{
using Detectors;
using UnityEditor;
using UnityEngine;
[CustomEditor(typeof (InjectionDetector))]
internal class InjectionDetectorEditor : KeepAliveBehaviourEditor<InjectionDetector>
{
protected override bool DrawUniqueDetectorProperties()
{
if (!ACTkSettings.Instance.InjectionDetectorEnabled)
{
using (GUITools.Vertical(GUITools.PanelWithBackground))
{
EditorGUILayout.Separator();
EditorGUILayout.HelpBox("Injection Detector support is not enabled! Injection Detector will not work properly",
MessageType.Error, true);
using (new GUILayout.HorizontalScope())
{
if (GUILayout.Button("Enable Now"))
{
ACTkSettings.Instance.InjectionDetectorEnabled = true;
}
if (GUILayout.Button("Enable In settings..."))
{
ACTkSettings.Show();
}
}
EditorGUILayout.Separator();
}
return true;
}
if (SettingsUtils.IsIL2CPPEnabled())
{
EditorGUILayout.HelpBox("Mono Injections are not possible in IL2CPP, this detector is not needed in IL2CPP builds",
MessageType.Info, true);
return true;
}
if (!InjectionRoutines.IsTargetPlatformCompatible())
{
EditorGUILayout.HelpBox("Injection Detection is only supported in Standalone and Android builds",
MessageType.Warning, true);
return true;
}
return false;
}
}
}

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 6025f911d895a7e43a5d5c6229254129
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,94 @@
#region copyright
// ------------------------------------------------------
// Copyright (C) Dmitriy Yukhanov [https://codestage.net]
// ------------------------------------------------------
#endregion
namespace CodeStage.AntiCheat.EditorCode.Editors
{
using Common;
using UnityEditor;
using UnityEngine;
internal class KeepAliveBehaviourEditor<T> : Editor where T: KeepAliveBehaviour<T>
{
protected T self;
private SerializedProperty autoStart;
private SerializedProperty autoDispose;
private SerializedProperty keepAlive;
private SerializedProperty detectionEvent;
private SerializedProperty detectionEventHasListener;
public virtual void OnEnable()
{
autoStart = serializedObject.FindProperty("autoStart");
autoDispose = serializedObject.FindProperty("autoDispose");
keepAlive = serializedObject.FindProperty("keepAlive");
detectionEvent = serializedObject.FindProperty("detectionEvent");
detectionEventHasListener = serializedObject.FindProperty("detectionEventHasListener");
self = (T)target;
FindUniqueDetectorProperties();
}
public override void OnInspectorGUI()
{
if (self == null) return;
serializedObject.Update();
EditorGUIUtility.labelWidth = 140;
EditorGUILayout.Space();
DrawHeader("Base settings");
EditorGUILayout.PropertyField(autoStart);
detectionEventHasListener.boolValue = EditorTools.CheckUnityEventHasActivePersistentListener(detectionEvent);
CheckAdditionalEventsForListeners();
if (autoStart.boolValue && !detectionEventHasListener.boolValue && !AdditionalEventsHasListeners())
{
EditorGUILayout.LabelField(new GUIContent("You need to add at least one active item to the Events in order to use Auto Start feature!"), GUITools.BoldLabel);
}
else if (!autoStart.boolValue)
{
EditorGUILayout.LabelField(new GUIContent("Don't forget to start detection!", "You should start detector from code using ObscuredCheatingDetector.StartDetection() method. See readme for details."), GUITools.BoldLabel);
EditorGUILayout.Separator();
}
EditorGUILayout.PropertyField(autoDispose);
EditorGUILayout.PropertyField(keepAlive);
EditorGUILayout.Separator();
if (DrawUniqueDetectorProperties())
{
EditorGUILayout.Separator();
}
//DrawHeader("Events");
EditorGUILayout.PropertyField(detectionEvent);
DrawAdditionalEvents();
serializedObject.ApplyModifiedProperties();
EditorGUIUtility.labelWidth = 0;
}
protected virtual void DrawHeader(string text)
{
GUITools.DrawHeader(text);
}
protected virtual bool AdditionalEventsHasListeners()
{
return true;
}
protected virtual void FindUniqueDetectorProperties() {}
protected virtual bool DrawUniqueDetectorProperties() { return false; }
protected virtual void CheckAdditionalEventsForListeners() {}
protected virtual void DrawAdditionalEvents() {}
}
}

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 6b59c308aff5e054991de809a3b5985b
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,45 @@
#region copyright
// ------------------------------------------------------
// Copyright (C) Dmitriy Yukhanov [https://codestage.net]
// ------------------------------------------------------
#endregion
namespace CodeStage.AntiCheat.EditorCode.Editors
{
using Detectors;
using UnityEditor;
using UnityEngine;
[CustomEditor(typeof (ObscuredCheatingDetector))]
internal class ObscuredCheatingDetectorEditor : KeepAliveBehaviourEditor<ObscuredCheatingDetector>
{
private SerializedProperty doubleEpsilon;
private SerializedProperty floatEpsilon;
private SerializedProperty vector2Epsilon;
private SerializedProperty vector3Epsilon;
private SerializedProperty quaternionEpsilon;
protected override void FindUniqueDetectorProperties()
{
doubleEpsilon = serializedObject.FindProperty("doubleEpsilon");
floatEpsilon = serializedObject.FindProperty("floatEpsilon");
vector2Epsilon = serializedObject.FindProperty("vector2Epsilon");
vector3Epsilon = serializedObject.FindProperty("vector3Epsilon");
quaternionEpsilon = serializedObject.FindProperty("quaternionEpsilon");
}
protected override bool DrawUniqueDetectorProperties()
{
DrawHeader("Specific settings");
EditorGUILayout.PropertyField(doubleEpsilon);
EditorGUILayout.PropertyField(floatEpsilon);
EditorGUILayout.PropertyField(vector2Epsilon, new GUIContent("Vector2 Epsilon"));
EditorGUILayout.PropertyField(vector3Epsilon, new GUIContent("Vector3 Epsilon"));
EditorGUILayout.PropertyField(quaternionEpsilon);
return true;
}
}
}

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 8df36b70906d65d43bcb3ddce3fe36ba
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,70 @@
#region copyright
// ------------------------------------------------------
// Copyright (C) Dmitriy Yukhanov [https://codestage.net]
// ------------------------------------------------------
#endregion
namespace CodeStage.AntiCheat.EditorCode.Editors
{
using Detectors;
using UnityEditor;
using UnityEditor.EditorTools;
using UnityEngine;
using EditorTools = EditorCode.EditorTools;
[CustomEditor(typeof (SpeedHackDetector))]
internal class SpeedHackDetectorEditor : KeepAliveBehaviourEditor<SpeedHackDetector>
{
private SerializedProperty interval;
private SerializedProperty threshold;
private SerializedProperty maxFalsePositives;
private SerializedProperty coolDown;
private SerializedProperty useDsp;
protected override void FindUniqueDetectorProperties()
{
interval = serializedObject.FindProperty("interval");
threshold = serializedObject.FindProperty("threshold");
maxFalsePositives = serializedObject.FindProperty("maxFalsePositives");
coolDown = serializedObject.FindProperty("coolDown");
useDsp = serializedObject.GetProperty(nameof(SpeedHackDetector.UseDsp));
}
protected override bool DrawUniqueDetectorProperties()
{
DrawHeader("Specific settings");
EditorGUILayout.PropertyField(interval);
EditorGUILayout.PropertyField(threshold);
EditorGUILayout.PropertyField(maxFalsePositives);
EditorGUILayout.PropertyField(coolDown);
#if UNITY_2020_1_OR_NEWER
EditorGUILayout.PropertyField(useDsp);
#else
EditorGUILayout.PropertyField(useDsp, new GUIContent( ObjectNames.NicifyVariableName(nameof(SpeedHackDetector.UseDsp)), useDsp.tooltip));
#endif
if (useDsp.boolValue)
EditorGUILayout.HelpBox("Dsp timers may cause false positives on some hardware.\nMake sure to test on target devices before using this in production.", MessageType.Warning);
#if UNITY_AUDIO_MODULE
if (!EditorTools.IsAudioManagerEnabled())
{
EditorGUILayout.HelpBox("Dsp option is not available since Disable Unity Audio option is enabled.", MessageType.Error);
if (GUILayout.Button("Open Audio Settings"))
{
SettingsService.OpenProjectSettings("Project/Audio");
#if UNITY_2021_3_OR_NEWER
Highlighter.Highlight("Project Settings", EditorTools.GetAudioManagerEnabledPropertyPath(), HighlightSearchMode.Identifier);
#endif
}
}
#else
EditorGUILayout.HelpBox("Dsp option is not available since built-in Audio module is disabled.", MessageType.Error);
#endif
return true;
}
}
}

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 199f39969debe8f46afc5f32b333be3b
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,74 @@
#region copyright
// ------------------------------------------------------
// Copyright (C) Dmitriy Yukhanov [https://codestage.net]
// ------------------------------------------------------
#endregion
namespace CodeStage.AntiCheat.EditorCode.Editors
{
using Detectors;
using UnityEditor;
using UnityEngine;
[CustomEditor(typeof(TimeCheatingDetector))]
internal class TimeCheatingDetectorEditor : KeepAliveBehaviourEditor<TimeCheatingDetector>
{
#if !ACTK_PREVENT_INTERNET_PERMISSION
private SerializedProperty requestUrl;
private SerializedProperty requestMethod;
private SerializedProperty timeoutSeconds;
private SerializedProperty interval;
private SerializedProperty realCheatThreshold;
private SerializedProperty wrongTimeThreshold;
private SerializedProperty ignoreSetCorrectTime;
protected override void FindUniqueDetectorProperties()
{
requestUrl = serializedObject.FindProperty("requestUrl");
requestMethod = serializedObject.FindProperty("requestMethod");
timeoutSeconds = serializedObject.FindProperty("timeoutSeconds");
interval = serializedObject.FindProperty("interval");
realCheatThreshold = serializedObject.FindProperty("realCheatThreshold");
wrongTimeThreshold = serializedObject.FindProperty("wrongTimeThreshold");
ignoreSetCorrectTime = serializedObject.FindProperty("ignoreSetCorrectTime");
}
protected override bool DrawUniqueDetectorProperties()
{
DrawHeader("Specific settings");
EditorGUIUtility.labelWidth += 10;
EditorGUILayout.PropertyField(ignoreSetCorrectTime);
EditorGUIUtility.labelWidth -= 10;
EditorGUI.BeginChangeCheck();
EditorGUILayout.PropertyField(requestUrl, new GUIContent("URL", requestUrl.tooltip));
if (EditorGUI.EndChangeCheck())
{
self.RequestUrl = requestUrl.stringValue;
}
#if UNITY_WEBGL
GUILayout.Label("<b>To avoid CORS limitations while running in WebGL, URL will be changed to the current domain, if it does points to any other domain</b>", GUITools.RichMiniLabel);
EditorGUILayout.Space();
#endif
EditorGUILayout.PropertyField(requestMethod, new GUIContent("Method", requestMethod.tooltip));
EditorGUILayout.PropertyField(timeoutSeconds);
EditorGUILayout.PropertyField(interval);
EditorGUILayout.PropertyField(realCheatThreshold);
EditorGUILayout.PropertyField(wrongTimeThreshold);
return true;
}
#else
protected override bool DrawUniqueDetectorProperties()
{
GUILayout.Label("<b>Detector disabled with ACTK_PREVENT_INTERNET_PERMISSION conditional symbol</b>", GUITools.RichLabel);
return true;
}
#endif
}
}

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 2fb4c7beaf58d554ab0f85d86b53726e
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:

View File

@@ -0,0 +1,139 @@
#region copyright
// ------------------------------------------------------
// Copyright (C) Dmitriy Yukhanov [https://codestage.net]
// ------------------------------------------------------
#endregion
namespace CodeStage.AntiCheat.EditorCode.Editors
{
using Detectors;
using UnityEditor;
using UnityEngine;
[CustomEditor(typeof (WallHackDetector))]
internal class WallHackDetectorEditor : KeepAliveBehaviourEditor<WallHackDetector>
{
private SerializedProperty wireframeDelay;
private SerializedProperty raycastDelay;
private SerializedProperty spawnPosition;
private SerializedProperty maxFalsePositives;
private SerializedProperty checkRigidbody;
private SerializedProperty checkController;
private SerializedProperty checkWireframe;
private SerializedProperty checkRaycast;
protected override void FindUniqueDetectorProperties()
{
raycastDelay = serializedObject.FindProperty("raycastDelay");
wireframeDelay = serializedObject.FindProperty("wireframeDelay");
spawnPosition = serializedObject.FindProperty("spawnPosition");
maxFalsePositives = serializedObject.FindProperty("maxFalsePositives");
checkRigidbody = serializedObject.FindProperty("checkRigidbody");
checkController = serializedObject.FindProperty("checkController");
checkWireframe = serializedObject.FindProperty("checkWireframe");
checkRaycast = serializedObject.FindProperty("checkRaycast");
}
protected override bool DrawUniqueDetectorProperties()
{
var detector = self;
if (detector == null) return false;
DrawHeader("Specific settings");
if (PropertyFieldChanged(checkRigidbody, new GUIContent("Rigidbody")))
{
detector.CheckRigidbody = checkRigidbody.boolValue;
}
if (PropertyFieldChanged(checkController, new GUIContent("Character Controller")))
{
detector.CheckController = checkController.boolValue;
}
if (PropertyFieldChanged(checkWireframe, new GUIContent("Wireframe")))
{
detector.CheckWireframe = checkWireframe.boolValue;
}
EditorGUI.indentLevel++;
EditorGUILayout.PropertyField(wireframeDelay, new GUIContent("Delay"));
EditorGUI.indentLevel--;
if (PropertyFieldChanged(checkRaycast, new GUIContent("Raycast")))
{
detector.CheckRaycast = checkRaycast.boolValue;
}
EditorGUI.indentLevel++;
EditorGUILayout.PropertyField(raycastDelay, new GUIContent("Delay"));
EditorGUI.indentLevel--;
EditorGUILayout.Separator();
EditorGUILayout.PropertyField(spawnPosition);
if (Vector3.Distance(spawnPosition.vector3Value, Vector3.zero) <= 0.001f)
{
EditorGUILayout.HelpBox("Please consider placing spawn position as far from your moving objects as possible to avoid false positives", MessageType.Warning);
EditorGUILayout.Space();
}
EditorGUILayout.PropertyField(maxFalsePositives);
EditorGUILayout.Separator();
if (checkWireframe.boolValue && !SettingsGUI.IsWallhackDetectorShaderIncluded())
{
using (GUITools.Vertical(GUITools.PanelWithBackground))
{
EditorGUILayout.Separator();
EditorGUILayout.HelpBox("Wallhack Detector shader for Wireframe checks is not included into the build! Detector may work incorrectly",
MessageType.Error, true);
if (GUILayout.Button("Include in Settings..."))
{
ACTkSettings.Show();
}
EditorGUILayout.Separator();
}
}
if (checkRaycast.boolValue || checkController.boolValue || checkRigidbody.boolValue)
{
var layerId = LayerMask.NameToLayer("Ignore Raycast");
if (Physics.GetIgnoreLayerCollision(layerId, layerId))
{
EditorGUILayout.LabelField("IgnoreRaycast physics layer should collide with itself to avoid false positives! See readme's troubleshooting section for details.", EditorStyles.wordWrappedLabel);
if (GUILayout.Button("Edit in Physics settings"))
{
SettingsService.OpenProjectSettings("Project/Physics");
}
}
}
return true;
}
private static bool PropertyFieldChanged(SerializedProperty property, GUIContent content, params GUILayoutOption[] options)
{
var result = false;
EditorGUI.BeginChangeCheck();
if (content == null)
{
EditorGUILayout.PropertyField(property, options);
}
else
{
EditorGUILayout.PropertyField(property, content, options);
}
if (EditorGUI.EndChangeCheck())
{
result = true;
}
return result;
}
}
}

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 2f88f8bd1134b464fa26c27d9979e6db
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: b60780b31b4fac0448812d7db515e8a7
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 0eab0a2d46900f5498873b929a503bad
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 7ae78be353f2d8243b15efd15919c5f5
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,203 @@
#region copyright
// ------------------------------------------------------
// Copyright (C) Dmitriy Yukhanov [https://codestage.net]
// ------------------------------------------------------
#endregion
using System.Linq;
using System.Threading.Tasks;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using CodeStage.AntiCheat.Common;
using CodeStage.AntiCheat.Genuine.CodeHash;
using UnityEditor;
using UnityEditor.Build;
using UnityEditor.Build.Reporting;
using Debug = UnityEngine.Debug;
namespace CodeStage.AntiCheat.EditorCode.PostProcessors
{
/// <summary>
/// Does calculates code hash after build if you use option "Generate code hash".
/// Listen to HashesGenerated or look for hash for each build in the Editor Console.
/// </summary>
/// Resulting hash in most cases should match value you get from the \ref CodeStage.AntiCheat.Genuine.CodeHash.CodeHashGenerator "CodeHashGenerator"
public class CodeHashGeneratorPostprocessor : IPostprocessBuildWithReport
{
/// <summary>
/// Equals int.MaxValue to make sure this postprocessor will run as late as possible
/// so you could run own postprocessors before and subscribe to HashesGenerated event.
/// </summary>
/// Used at CodeHashGeneratorListener example.
public const int CallbackOrder = int.MaxValue;
/// <summary>
/// HashesGenerated event delegate.
/// </summary>
/// <param name="report">Standard post-build report from Unity.</param>
/// <param name="hashedBuilds">Build hashing results array.</param>
///
/// You may generate multiple actual builds within single build operation,
/// like multiple APKs when you use "Split APKs by target architecture" option,
/// so you may have more than one valid hashed builds for one actual build procedure.
public delegate void OnHashesGenerated(BuildReport report, IReadOnlyList<BuildHashes> hashedBuilds);
/// <summary>
/// You may listen to this event if you wish to post-process resulting code hash,
/// e.g. upload it to the server for the later runtime check with CodeHashGenerator.
/// </summary>
/// Make sure to enable "Generate code hash on build completion" option in the ACTk settings to make this event work.
public static event OnHashesGenerated HashesGenerated;
int IOrderedCallback.callbackOrder => CallbackOrder;
async void IPostprocessBuildWithReport.OnPostprocessBuild(BuildReport report)
{
if (!ACTkSettings.Instance.PreGenerateBuildHash || !CodeHashGenerator.IsTargetPlatformCompatible())
return;
await CalculateBuildReportHashesAsync(report, true, true);
}
/// <summary>
/// Calls selection dialog and calculates hashes for the selected build.
/// </summary>
/// <param name="buildPath">Path to the .apk / .aab or .exe file. Pass null to show file selection dialog.</param>
/// <param name="printToConsole">Path to the .apk / .aab or .exe file. Pass null to show file selection dialog.</param>
/// <returns>Valid BuildHashes instance or null in case of error / user cancellation.</returns>
public static BuildHashes CalculateExternalBuildHashes(string buildPath, bool printToConsole)
{
return AsyncHelpers.RunSync(() => CalculateExternalBuildHashesAsync(buildPath, printToConsole));
}
/// <summary>
/// Calls selection dialog and calculates hashes for the selected build.
/// </summary>
/// <param name="buildPath">Path to the .apk / .aab or .exe file. Pass null to show file selection dialog.</param>
/// <param name="printToConsole">Path to the .apk / .aab or .exe file. Pass null to show file selection dialog.</param>
/// <returns>Task with Valid BuildHashes instance or null in case of error / user cancellation.</returns>
public static async Task<BuildHashes> CalculateExternalBuildHashesAsync(string buildPath, bool printToConsole)
{
if (buildPath == null)
{
buildPath = EditorUtility.OpenFilePanel(
"Select Standalone Windows build exe or Android build apk / aab", "", "exe,apk,aab");
if (string.IsNullOrEmpty(buildPath))
{
Debug.Log(ACTk.LogPrefix + "Hashing cancelled by user.");
return null;
}
}
var extension = Path.GetExtension(buildPath);
if (string.IsNullOrEmpty(extension))
return null;
extension = extension.ToLower(CultureInfo.InvariantCulture);
try
{
EditorUtility.DisplayProgressBar("ACTk: Generating code hash", "Preparing...", 0);
BuildHashes hashes;
if (extension == ".apk" || extension == ".aab")
hashes = (await AndroidBuildHashGenerator.GetBuildHashes(new[] { buildPath })).FirstOrDefault();
else
hashes = (await WindowsBuildHashGenerator.GetBuildHashes(buildPath)).FirstOrDefault();
if (printToConsole)
hashes?.PrintToConsole();
return hashes;
}
catch (Exception e)
{
ACTk.PrintExceptionForSupport("Error while trying to hash build!", e);
}
finally
{
EditorUtility.ClearProgressBar();
}
return null;
}
/// <summary>
/// Calculates hashes for the given build report. Can be useful if you wish to hash build you just made with BuildPipeline.
/// </summary>
/// Will not trigger the HashesGenerated event.
/// <param name="report">BuildReport you wish to calculates hashes for</param>
/// <param name="printToConsole">Specifies if calculated hashes should be printed to Unity Console</param>
/// <returns>Readonly List of the BuildHashes, one per each resulting build from the BuildReport.</returns>
public static Task<IReadOnlyList<BuildHashes>> CalculateBuildReportHashesAsync(BuildReport report,
bool printToConsole)
{
return CalculateBuildReportHashesAsync(report, false, printToConsole);
}
private static async Task<IReadOnlyList<BuildHashes>> CalculateBuildReportHashesAsync(BuildReport report,
bool triggerEvent, bool printLogs)
{
if (EditorUserBuildSettings.GetPlatformSettings(report.summary.platformGroup.ToString(),
"CreateSolution") == "true")
{
Debug.Log(
ACTk.LogPrefix + "Build hashing is skipped due to the 'Create Visual Studio Solution' option.");
return null;
}
try
{
EditorUtility.DisplayProgressBar("ACTk: Generating code hash", "Preparing...", 0);
var hashedBuilds = await GetHashedBuilds(report);
if (hashedBuilds == null || hashedBuilds.Count == 0)
{
Debug.Log(ACTk.LogPrefix + "Couldn't pre-generate code hash. " +
"Please run your build and generate hash with CodeHashGenerator.");
return null;
}
if (printLogs)
{
foreach (var hashedBuild in hashedBuilds)
{
hashedBuild.PrintToConsole();
}
}
if (triggerEvent)
HashesGenerated?.Invoke(report, hashedBuilds);
return hashedBuilds;
}
catch (Exception e)
{
ACTk.PrintExceptionForSupport("Error while trying to hash build!", e);
}
finally
{
EditorUtility.ClearProgressBar();
}
return null;
}
private static async Task<IReadOnlyList<BuildHashes>> GetHashedBuilds(BuildReport report)
{
var platform = report.summary.platform;
switch (platform)
{
case BuildTarget.StandaloneWindows64:
case BuildTarget.StandaloneWindows:
return await WindowsBuildHashGenerator.GetBuildHashes(report.summary.outputPath);
case BuildTarget.Android:
return await AndroidBuildHashGenerator.GetBuildHashes(report);
default:
return null;
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: c82c021ded9a49b44b3701f1859341cd
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 881ba0c65bee45139ca757895221c6ab
timeCreated: 1680806941

View File

@@ -0,0 +1,184 @@
#region copyright
// ------------------------------------------------------
// Copyright (C) Dmitriy Yukhanov [https://codestage.net]
// ------------------------------------------------------
#endregion
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using CodeStage.AntiCheat.Common;
using CodeStage.AntiCheat.EditorCode.ICSharpCode.SharpZipLib.Zip;
using CodeStage.AntiCheat.Genuine.CodeHash;
using CodeStage.AntiCheat.Utils;
using UnityEditor;
using UnityEditor.Build.Reporting;
using Debug = UnityEngine.Debug;
namespace CodeStage.AntiCheat.EditorCode.PostProcessors
{
internal static class AndroidBuildHashGenerator
{
private static readonly object ProgressLock = new object();
public static async Task<BuildHashes[]> GetBuildHashes(BuildReport report)
{
if ((report.summary.options & BuildOptions.PatchPackage) != 0)
{
Debug.Log(ACTk.LogPrefix + "Patch hashing is skipped, only full build hashing is supported.");
return Array.Empty<BuildHashes>();
}
#if UNITY_2022_1_OR_NEWER
var files = report.GetFiles();
#else
var files = report.files;
#endif
var filePaths = new string[files.Length];
for (var i = 0; i < filePaths.Length; i++)
{
filePaths[i] = files[i].path;
}
return await GetBuildHashes(filePaths);
}
public static async Task<BuildHashes[]> GetBuildHashes(string[] files)
{
var result = new List<BuildHashes>();
foreach (var path in files)
{
var extension = Path.GetExtension(path);
if (!string.IsNullOrEmpty(extension))
extension = extension.ToLower(CultureInfo.InvariantCulture);
if (extension != ".apk" && extension != ".aab")
continue;
var progress = FilesProgress.CreateNew("ACTk: Generating code hash");
var filters = GetFilters();
var buildHashes = await Task.Run(() => HashSuitableFilesInZipFile(path, filters,
progress));
if (buildHashes != null)
result.Add(buildHashes);
}
if (result.Count == 0)
{
if (!EditorUserBuildSettings.exportAsGoogleAndroidProject)
ACTk.PrintExceptionForSupport("Couldn't find compiled APK or AAB build!");
else
Debug.LogWarning("Couldn't find compiled APK or AAB build! " +
"This is fine if you use Export Project feature.");
}
return result.ToArray();
}
private static BuildHashes HashSuitableFilesInZipFile(string path, FilteringData filters,
IProgress<FilesProgress> progress)
{
ZipFile zf = null;
try
{
var sw = Stopwatch.StartNew();
var latestPercent = 0;
var filesChecked = 0;
var fileHashes = new ConcurrentBag<FileHash>();
var fs = File.OpenRead(path);
zf = new ZipFile(fs);
var count = zf.Count;
var options = new ParallelOptions { MaxDegreeOfParallelism = Environment.ProcessorCount };
var sha1Pool = new ThreadSafeDisposablesPool<SHA1Wrapper>(() => new SHA1Wrapper());
Parallel.ForEach(zf.Cast<ZipEntry>(), options, zipEntry =>
{
string entryFileName = null;
var skipped = true;
try
{
// skip folders since we can't hash them
if (!zipEntry.IsFile)
return;
entryFileName = zipEntry.Name;
if (filters.IsIgnored(entryFileName))
return;
if (!filters.IsIncluded(entryFileName))
return;
using (var zipStream = zf.GetInputStream(zipEntry))
{
fileHashes.Add(new FileHash(entryFileName, zipStream, sha1Pool));
}
skipped = false;
}
catch (Exception e)
{
Console.WriteLine(e);
throw;
}
finally
{
lock (ProgressLock)
{
filesChecked++;
if (!skipped)
progress?.ReportPercent(ref latestPercent, filesChecked, count, Path.GetFileName(entryFileName));
}
}
});
sha1Pool.Dispose();
progress?.Report(FilesProgress.None());
sw.Stop();
if (fileHashes.Count == 0)
return null;
var result = new BuildHashes(path, fileHashes.ToArray())
{
DurationSeconds = sw.Elapsed.TotalSeconds
};
return result;
}
catch (Exception e)
{
ACTk.PrintExceptionForSupport("Error while calculating code hash!", e);
}
finally
{
if (zf != null)
{
zf.IsStreamOwner = true;
zf.Close();
}
}
return null;
}
private static FilteringData GetFilters()
{
var il2Cpp = false;
#if UNITY_EDITOR
il2Cpp = SettingsUtils.IsIL2CPPEnabled();
#elif ENABLE_IL2CPP
il2Cpp = true;
#endif
return FiltersProducer.GetFileFiltersAndroid(il2Cpp);
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 9717d52c2bf842caaa8575f8f2947afa
timeCreated: 1680806503

View File

@@ -0,0 +1,49 @@
#region copyright
// ------------------------------------------------------
// Copyright (C) Dmitriy Yukhanov [https://codestage.net]
// ------------------------------------------------------
#endregion
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
using CodeStage.AntiCheat.Common;
using CodeStage.AntiCheat.Genuine.CodeHash;
namespace CodeStage.AntiCheat.EditorCode.PostProcessors
{
internal static class WindowsBuildHashGenerator
{
public static async Task<IReadOnlyList<BuildHashes>> GetBuildHashes(string buildPath)
{
var folder = Path.GetDirectoryName(buildPath);
if (folder == null)
{
ACTk.PrintExceptionForSupport("Could not found build folder for this file: " + buildPath);
return Array.Empty<BuildHashes>();
}
var progress = FilesProgress.CreateNew("ACTk: Generating code hash");
var filters = GetFilters();
var buildHashes = await Task.Run(()=> StandaloneWindowsWorker.GetBuildHashes(folder, filters, Environment.ProcessorCount,
progress));
if (buildHashes == null)
return Array.Empty<BuildHashes>();
return new [] { buildHashes };
}
private static FilteringData GetFilters()
{
var il2Cpp = false;
#if UNITY_EDITOR
il2Cpp = SettingsUtils.IsIL2CPPEnabled();
#elif ENABLE_IL2CPP
il2Cpp = true;
#endif
return FiltersProducer.GetFileFiltersStandaloneWindows(il2Cpp);
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 02b38fd3639d4fd7a1a6732fadbeebc8
timeCreated: 1680806778

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 59e19c7338f04be697d7788c76f0cde6
timeCreated: 1552927805

View File

@@ -0,0 +1,70 @@
#region copyright
// ------------------------------------------------------
// Copyright (C) Dmitriy Yukhanov [https://codestage.net]
// ------------------------------------------------------
#endregion
namespace CodeStage.AntiCheat.EditorCode
{
using System;
/// <summary>
/// Describes assembly which is added to the InjectionDetector "white list".
/// </summary>
[Serializable]
public class AllowedAssembly
{
[Obsolete("Please use Name property instead.", false)]
public string name => Name;
[Obsolete("Please use Hashes property instead.", false)]
public int[] hashes => Hashes;
/// <summary>
/// Assembly name, i.e.: ACTk.Runtime.
/// </summary>
public string Name { get; }
/// <summary>
/// Array of whitelisted hashes for the assembly with given Name.
/// </summary>
public int[] Hashes { get; private set; }
/// <summary>
/// Constructs new instance.
/// </summary>
/// <param name="name">Sets Name property.</param>
/// <param name="hashes">Sets Hashes property.</param>
public AllowedAssembly(string name, int[] hashes)
{
Name = name;
Hashes = hashes;
}
/// <summary>
/// Allows adding new hash to the Hashes collection.
/// </summary>
/// <param name="hash">New whitelisted hash for the assembly with specified Name.</param>
/// <returns>True if hash was added and false otherwise (i.e. when hash already existed in the collection).</returns>
public bool AddHash(int hash)
{
if (Array.IndexOf(Hashes, hash) != -1) return false;
var oldLen = Hashes.Length;
var newLen = oldLen + 1;
var newHashesArray = new int[newLen];
Array.Copy(Hashes, newHashesArray, oldLen);
Hashes = newHashesArray;
Hashes[oldLen] = hash;
return true;
}
public override string ToString()
{
return Name + " (hashes: " + Hashes.Length + ")";
}
}
}

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 99e59ee643091664d874b8418be8b78e
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,23 @@
#region copyright
// ------------------------------------------------------
// Copyright (C) Dmitriy Yukhanov [https://codestage.net]
// ------------------------------------------------------
#endregion
namespace CodeStage.AntiCheat.EditorCode
{
using System.IO;
internal static class InjectionConstants
{
public const string LegacyWhitelistRelativePath = "InjectionDetectorData/UserWhitelist.bytes";
public const string PrefsKey = "ACTDIDEnabledGlobal";
public const string DataSeparator = ":";
public static readonly string ResourcesFolder = Path.Combine(ACTkEditorConstants.AssetsFolder, "Resources");
public static readonly string DataFilePath = Path.Combine(ResourcesFolder, DataFileName);
private const string DataFileName = "fndid.bytes";
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: fdb8abbb3fde4da3aa210fccf74e9524
timeCreated: 1552925592

View File

@@ -0,0 +1,229 @@
#region copyright
// ------------------------------------------------------
// Copyright (C) Dmitriy Yukhanov [https://codestage.net]
// ------------------------------------------------------
#endregion
#if (UNITY_STANDALONE || UNITY_ANDROID)
#define UNITY_SUPPORTED_PLATFORM
#endif
#define ACTK_DEBUG
#undef ACTK_DEBUG
#define ACTK_DEBUG_VERBOSE
#undef ACTK_DEBUG_VERBOSE
#define ACTK_DEBUG_PARANIOD
#undef ACTK_DEBUG_PARANIOD
#if ACTK_DEBUG_PARANIOD
#define ACTK_DEBUG
#define ACTK_DEBUG_VERBOSE
#endif
#if ACTK_DEBUG_VERBOSE
#define ACTK_DEBUG
#endif
namespace CodeStage.AntiCheat.EditorCode
{
using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using Common;
using ObscuredTypes;
using UnityEditor;
using UnityEngine;
internal static class InjectionRoutines
{
private static bool cleanupDone;
public static bool IsInjectionPossible()
{
return IsTargetPlatformCompatible() && !SettingsUtils.IsIL2CPPEnabled();
}
public static bool IsTargetPlatformCompatible()
{
#if UNITY_SUPPORTED_PLATFORM
return true;
#else
return false;
#endif
}
public static int GetAssemblyHash(AssemblyName ass)
{
var hashInfo = ass.Name;
var bytes = ass.GetPublicKeyToken();
if (bytes != null && bytes.Length == 8)
{
hashInfo += PublicKeyTokenToString(bytes);
}
// Jenkins hash function (http://en.wikipedia.org/wiki/Jenkins_hash_function)
var result = 0;
var len = hashInfo.Length;
for (var i = 0; i < len; ++i)
{
result += hashInfo[i];
result += (result << 10);
result ^= (result >> 6);
}
result += (result << 3);
result ^= (result >> 11);
result += (result << 15);
return result;
}
public static List<AllowedAssembly> MergeAllowedAssemblies(IEnumerable<AllowedAssembly> collection1, IEnumerable<AllowedAssembly> collection2)
{
var result = new List<AllowedAssembly>(collection1);
foreach (var whiteListedAssembly in collection2)
{
var exists = false;
foreach (var assembly in result)
{
if (assembly.Name != whiteListedAssembly.Name) continue;
exists = true;
foreach (var hash in whiteListedAssembly.Hashes)
{
if (Array.IndexOf(assembly.Hashes, hash) == -1)
{
assembly.AddHash(hash);
}
}
break;
}
if (!exists)
{
result.Add(whiteListedAssembly);
}
}
return result;
}
public static void InitCleanup()
{
cleanupDone = false;
}
public static void Cleanup()
{
if (cleanupDone) return;
cleanupDone = true;
TryMigrateSettings();
TryMigrateLegacyInjectionWhitelist();
if (File.Exists(InjectionConstants.DataFilePath))
{
#if ACTK_DEBUG
Debug.Log(ACTk.LogPrefix + "Data file found and going to be removed: " + InjectionConstants.DataFilePath);
#endif
EditorTools.DeleteFile(InjectionConstants.DataFilePath);
EditorTools.DeleteFile(AssetDatabase.GetTextMetaFilePathFromAssetPath(InjectionConstants.DataFilePath));
EditorTools.RemoveDirectoryIfEmpty(InjectionConstants.ResourcesFolder);
AssetDatabase.Refresh();
}
}
private static string PublicKeyTokenToString(byte[] bytes)
{
var result = "";
// AssemblyName.GetPublicKeyToken() returns 8 bytes
for (var i = 0; i < 8; i++)
{
result += ACTkEditorConstants.HexTable[bytes[i]];
}
return result;
}
private static void TryMigrateSettings()
{
if (!EditorPrefs.HasKey(InjectionConstants.PrefsKey)) return;
ACTkSettings.Instance.InjectionDetectorEnabled = EditorPrefs.GetBool(InjectionConstants.PrefsKey);
EditorPrefs.DeleteKey(InjectionConstants.PrefsKey);
}
private static void TryMigrateLegacyInjectionWhitelist()
{
if (!File.Exists(InjectionConstants.LegacyWhitelistRelativePath)) return;
var whitelistedAssemblies = LoadAndParseLegacyWhitelist();
ACTkSettings.Instance.InjectionDetectorWhiteList = MergeAllowedAssemblies(ACTkSettings.Instance.InjectionDetectorWhiteList, whitelistedAssemblies);
}
private static IEnumerable<AllowedAssembly> LoadAndParseLegacyWhitelist()
{
var result = new List<AllowedAssembly>();
string[] separator = { InjectionConstants.DataSeparator };
var fs = new FileStream(InjectionConstants.LegacyWhitelistRelativePath, FileMode.Open, FileAccess.Read, FileShare.Read);
var br = new BinaryReader(fs);
try
{
var count = br.ReadInt32();
for (var i = 0; i < count; i++)
{
var line = br.ReadString();
line = new string(ObscuredString.Encrypt(line, ACTk.StringKey));
var strArr = line.Split(separator, StringSplitOptions.RemoveEmptyEntries);
var stringsCount = strArr.Length;
if (stringsCount > 1)
{
var assemblyName = strArr[0];
var hashes = new int[stringsCount - 1];
for (var j = 1; j < stringsCount; j++)
{
var success = int.TryParse(strArr[j], out var parseResult);
if (success)
{
hashes[j - 1] = parseResult;
}
else
{
Debug.LogError(ACTk.LogPrefix + "Could not parse value: " + strArr[j] +
", line:\n" + line);
}
}
result.Add(new AllowedAssembly(assemblyName, hashes));
}
else
{
throw new Exception("Error parsing whitelist file line!");
}
}
}
catch (Exception e)
{
ACTk.PrintExceptionForSupport("Error while reading legacy whitelist!", e);
}
finally
{
br.Close();
fs.Close();
}
return result;
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 682e4f8bd25b4b3f9ab90c2c080decf5
timeCreated: 1552927820

View File

@@ -0,0 +1,234 @@
#region copyright
// ------------------------------------------------------
// Copyright (C) Dmitriy Yukhanov [https://codestage.net]
// ------------------------------------------------------
#endregion
#define ACTK_DEBUG
#undef ACTK_DEBUG
#define ACTK_DEBUG_VERBOSE
#undef ACTK_DEBUG_VERBOSE
#define ACTK_DEBUG_PARANIOD
#undef ACTK_DEBUG_PARANIOD
#if ACTK_DEBUG_PARANIOD
#define ACTK_DEBUG
#define ACTK_DEBUG_VERBOSE
#endif
#if ACTK_DEBUG_VERBOSE
#define ACTK_DEBUG
#endif
namespace CodeStage.AntiCheat.EditorCode
{
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using Common;
using Detectors;
using ObscuredTypes;
using PostProcessors;
using UnityEditor;
using Debug = UnityEngine.Debug;
#if ACTK_DEBUG
using System.Diagnostics;
#endif
internal static class InjectionWhitelistBuilder
{
private const string ProgressCaption = "ACTk: Building InjectionDetector Whitelist";
#if ACTK_DEBUG
private static Stopwatch sw;
#endif
public static void GenerateWhitelist()
{
try
{
GenerateWhitelistInternal();
}
catch (Exception e)
{
ACTk.PrintExceptionForSupport($"Something went wrong while building {nameof(InjectionDetector)} whitelist!", e);
}
finally
{
EditorUtility.ClearProgressBar();
}
}
private static void GenerateWhitelistInternal()
{
#if ACTK_DEBUG
sw = Stopwatch.StartNew();
sw.Stop();
Debug.Log("=== Injection Detector Whitelist Build Start ===");
sw.Start();
#endif
EditorUtility.DisplayProgressBar(ProgressCaption, "Gathering assemblies", 0);
var assembliesInBuild = GetAssembliesInBuild();
if (assembliesInBuild.Length == 0)
ACTk.PrintExceptionForSupport("Can't find any assemblies in build!");
var assembliesAllowedByUser = GetUserWhiteListAssemblies();
var allAllowedAssemblies = InjectionRoutines.MergeAllowedAssemblies(assembliesInBuild, assembliesAllowedByUser);
EditorUtility.DisplayProgressBar(ProgressCaption, "Writing assemblies hashes", 0);
WriteAllowedAssemblies(allAllowedAssemblies);
#if ACTK_DEBUG
sw.Stop();
Debug.Log(ACTk.LogPrefix + "WhiteList build duration: " + sw.ElapsedMilliseconds + " ms.");
#endif
AssetDatabase.Refresh();
}
private static AllowedAssembly[] GetAssembliesInBuild()
{
#if ACTK_DEBUG_VERBOSE
sw.Stop();
Debug.Log(ACTk.LogPrefix + "Trying to guess which assemblies can get into the build...");
sw.Start();
#endif
var libraries = BuildPostProcessor.GetGuessedLibrariesForBuild();
#if ACTK_DEBUG_VERBOSE
sw.Stop();
Debug.Log(ACTk.LogPrefix + "Total libraries candidates: " + libraries.Length);
sw.Start();
var invalidAssemblies = string.Empty;
#endif
var result = new List<AllowedAssembly>();
foreach (var libraryPath in libraries)
{
#if ACTK_DEBUG_PARANIOD
sw.Stop();
Debug.Log(ACTk.LogPrefix + "Checking library at the path: " + libraryPath);
sw.Start();
#endif
try
{
var assName = AssemblyName.GetAssemblyName(libraryPath);
var name = assName.Name;
var hash = InjectionRoutines.GetAssemblyHash(assName);
var allowed = result.FirstOrDefault(allowedAssembly => allowedAssembly.Name == name);
if (allowed != null)
{
allowed.AddHash(hash);
}
else
{
allowed = new AllowedAssembly(name, new[] { hash });
result.Add(allowed);
}
}
catch
{
// not a valid IL assembly, skipping
#if ACTK_DEBUG_VERBOSE
invalidAssemblies += libraryPath + "\n";
#endif
}
}
#if ACTK_DEBUG_VERBOSE
if (!string.IsNullOrEmpty(invalidAssemblies))
{
sw.Stop();
Debug.Log(ACTk.LogPrefix + "Not valid assemblies:\n" + invalidAssemblies);
sw.Start();
}
#endif
#if ACTK_DEBUG
sw.Stop();
var trace = ACTk.LogPrefix + "Found assemblies in build (" + result.Count + ", " + sw.ElapsedMilliseconds + " ms):\n";
foreach (var allowedAssembly in result)
{
trace += " Name: " + allowedAssembly.name + "\n";
trace = allowedAssembly.hashes.Aggregate(trace, (current, hash) => current + (" Hash: " + hash + "\n"));
}
Debug.Log(trace);
sw.Start();
#endif
return result.ToArray();
}
private static AllowedAssembly[] GetUserWhiteListAssemblies()
{
var userWhiteList = ACTkSettings.Instance.InjectionDetectorWhiteList;
#if ACTK_DEBUG
sw.Stop();
var trace = ACTk.LogPrefix + "User White List assemblies (" + userWhiteList.Count + "):\n";
foreach (var allowedAssembly in userWhiteList)
{
trace += " Name: " + allowedAssembly.name + "\n";
trace = allowedAssembly.hashes.Aggregate(trace, (current, hash) => current + (" Hash: " + hash + "\n"));
}
Debug.Log(trace);
sw.Start();
#endif
return userWhiteList.ToArray();
}
private static void WriteAllowedAssemblies(List<AllowedAssembly> assemblies)
{
Directory.CreateDirectory(InjectionConstants.ResourcesFolder);
var bw = new BinaryWriter(new FileStream(InjectionConstants.DataFilePath, FileMode.Create, FileAccess.Write, FileShare.Read), Encoding.Unicode);
bw.Write(assemblies.Count);
#if ACTK_DEBUG_VERBOSE
sw.Stop();
Debug.Log(ACTk.LogPrefix + "Writing assemblies data, count: " + assemblies.Count);
sw.Start();
#endif
foreach (var assembly in assemblies)
{
var name = assembly.Name;
var hashes = "";
for (var j = 0; j < assembly.Hashes.Length; j++)
{
hashes += assembly.Hashes[j].ToString(CultureInfo.InvariantCulture);
if (j < assembly.Hashes.Length - 1)
{
hashes += InjectionConstants.DataSeparator;
}
}
var line = ObscuredString.Encrypt(name + InjectionConstants.DataSeparator + hashes, ACTk.StringKey);
#if ACTK_DEBUG_PARANIOD
sw.Stop();
Debug.Log(ACTk.LogPrefix + "Writing assembly:\n" + name + InjectionConstants.DataSeparator + hashes + "\n" +
new string(line) + ", length: " + line.Length);
sw.Start();
#endif
bw.Write(line.Length);
bw.Write(line, 0, line.Length);
}
bw.Close();
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 4ed4f862c6dc42a49c1f47d1e9ee2fb5
timeCreated: 1552945114

View File

@@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: bb730acf6c1569848b1187cd6c0e312c
folderAsset: yes
timeCreated: 1552913902
licenseType: Store
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,93 @@
#region copyright
// ------------------------------------------------------
// Copyright (C) Dmitriy Yukhanov [https://codestage.net]
// ------------------------------------------------------
#endregion
namespace CodeStage.AntiCheat.EditorCode.PostProcessors
{
using System;
using System.IO;
using System.Text;
using Common;
using UnityEditor;
using UnityEditor.Build;
using UnityEditor.Build.Reporting;
internal class BuildPostProcessor : IPreprocessBuildWithReport, IPostBuildPlayerScriptDLLs, IPostprocessBuildWithReport
{
int IOrderedCallback.callbackOrder => int.MaxValue - 1;
public void OnPreprocessBuild(BuildReport report)
{
if (!ACTkSettings.Instance.InjectionDetectorEnabled ||
!InjectionRoutines.IsInjectionPossible())
{
return;
}
InjectionRoutines.InitCleanup();
Prepare();
}
public void OnPostBuildPlayerScriptDLLs(BuildReport report)
{
if (!ACTkSettings.Instance.InjectionDetectorEnabled ||
!InjectionRoutines.IsInjectionPossible())
{
return;
}
InjectionWhitelistBuilder.GenerateWhitelist();
}
public void OnPostprocessBuild(BuildReport report)
{
Cleanup();
}
public static string[] GetGuessedLibrariesForBuild()
{
var stagingAreaFolder = Path.Combine(ACTkEditorConstants.ProjectTempFolder, "StagingArea");
return EditorTools.FindLibrariesAt(stagingAreaFolder);
}
private void Prepare()
{
try
{
EditorApplication.LockReloadAssemblies();
if (!Directory.Exists(InjectionConstants.ResourcesFolder))
{
Directory.CreateDirectory(InjectionConstants.ResourcesFolder);
}
File.WriteAllText(InjectionConstants.DataFilePath, "please remove me", Encoding.Unicode);
AssetDatabase.Refresh();
EditorApplication.update += OnEditorUpdate;
}
catch (Exception e)
{
ACTk.PrintExceptionForSupport("Injection Detector preparation failed!", e);
}
finally
{
EditorApplication.UnlockReloadAssemblies();
}
}
private void OnEditorUpdate()
{
if (!BuildPipeline.isBuildingPlayer)
Cleanup();
}
private void Cleanup()
{
InjectionRoutines.Cleanup();
EditorApplication.update -= OnEditorUpdate;
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: e79f56c36f349f64995908c2bc571662
timeCreated: 1552680217
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,276 @@
#region copyright
// ------------------------------------------------------
// Copyright (C) Dmitriy Yukhanov [https://codestage.net]
// ------------------------------------------------------
#endregion
namespace CodeStage.AntiCheat.EditorCode
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using UnityEditor;
using UnityEngine;
internal class UserWhitelistEditor : EditorWindow
{
private const string InitialCustomName = "AssemblyName, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null";
private static List<AllowedAssembly> whitelist;
private static string whitelistPath;
private Vector2 scrollPosition;
private bool manualAssemblyWhitelisting;
private string manualAssemblyWhitelistingName = InitialCustomName;
internal static void ShowWindow()
{
EditorWindow myself = GetWindow<UserWhitelistEditor>(false, "Whitelist Editor", true);
myself.minSize = new Vector2(500, 200);
}
private void OnLostFocus()
{
manualAssemblyWhitelisting = false;
manualAssemblyWhitelistingName = InitialCustomName;
}
private void OnGUI()
{
if (whitelist == null)
{
whitelist = new List<AllowedAssembly>();
LoadAndParseWhitelist();
}
var tmpStyle = new GUIStyle(EditorStyles.largeLabel)
{
alignment = TextAnchor.MiddleCenter,
fontStyle = FontStyle.Bold
};
GUILayout.Label("User-defined Whitelist of Assemblies trusted by Injection Detector", tmpStyle);
scrollPosition = EditorGUILayout.BeginScrollView(scrollPosition);
var whitelistUpdated = false;
var count = whitelist.Count;
if (count > 0)
{
for (var i = 0; i < count; i++)
{
var assembly = whitelist[i];
using (GUITools.Horizontal())
{
GUILayout.Label(assembly.ToString());
if (GUILayout.Button(new GUIContent("-", "Remove Assembly from Whitelist"), GUILayout.Width(30)))
{
whitelist.Remove(assembly);
whitelistUpdated = true;
break;
}
}
}
}
else
{
tmpStyle = new GUIStyle(EditorStyles.largeLabel)
{
alignment = TextAnchor.MiddleCenter
};
GUILayout.Label("- no Assemblies added so far (use buttons below to add) -", tmpStyle);
}
if (manualAssemblyWhitelisting)
{
manualAssemblyWhitelistingName = EditorGUILayout.TextField(manualAssemblyWhitelistingName);
using (GUITools.Horizontal())
{
if (GUILayout.Button("Save"))
{
try
{
if (manualAssemblyWhitelistingName.StartsWith("Cause:"))
{
throw new Exception("Please remove Cause: from the assembly name!");
}
var assName = new AssemblyName(manualAssemblyWhitelistingName.Trim());
var res = TryWhitelistAssemblyName(assName, true);
if (res != WhitelistingResult.Exists)
{
whitelistUpdated = true;
}
manualAssemblyWhitelisting = false;
manualAssemblyWhitelistingName = InitialCustomName;
}
catch (Exception e)
{
ShowNotification(new GUIContent(e.Message));
}
GUI.FocusControl("");
}
if (GUILayout.Button("Cancel"))
{
manualAssemblyWhitelisting = false;
manualAssemblyWhitelistingName = InitialCustomName;
GUI.FocusControl("");
}
}
}
EditorGUILayout.EndScrollView();
using (GUITools.Horizontal())
{
GUILayout.Space(20);
if (GUILayout.Button("Add Assembly"))
{
var assemblyPath = EditorUtility.OpenFilePanel("Choose an Assembly to add", "", "dll");
if (!string.IsNullOrEmpty(assemblyPath))
{
whitelistUpdated |= TryWhitelistAssemblies(new[] {assemblyPath}, true);
}
}
if (GUILayout.Button("Add Assemblies from Folder"))
{
var selectedFolder = EditorUtility.OpenFolderPanel("Choose a Folder with Assemblies", "", "");
if (!string.IsNullOrEmpty(selectedFolder))
{
var libraries = EditorTools.FindLibrariesAt(selectedFolder);
whitelistUpdated |= TryWhitelistAssemblies(libraries);
}
}
if (!manualAssemblyWhitelisting)
{
if (GUILayout.Button("Add Assembly manually"))
{
manualAssemblyWhitelisting = true;
}
}
if (count > 0)
{
if (GUILayout.Button("Clear"))
{
if (EditorUtility.DisplayDialog("Please confirm",
"Are you sure you wish to completely clear your Injection Detector whitelist?", "Yes", "No"))
{
whitelist.Clear();
whitelistUpdated = true;
}
}
}
GUILayout.Space(20);
}
GUILayout.Space(20);
if (whitelistUpdated)
{
WriteWhitelist();
}
}
private bool TryWhitelistAssemblies(IList<string> libraries, bool singleFile = false)
{
var added = 0;
var updated = 0;
var count = libraries.Count;
for (var i = 0; i < count; i++)
{
var libraryPath = libraries[i];
try
{
var assName = AssemblyName.GetAssemblyName(libraryPath);
var whitelistingResult = TryWhitelistAssemblyName(assName, singleFile);
switch (whitelistingResult)
{
case WhitelistingResult.Added:
added++;
break;
case WhitelistingResult.Updated:
updated++;
break;
case WhitelistingResult.Exists:
break;
default:
throw new ArgumentOutOfRangeException();
}
}
catch
{
if (singleFile)
ShowNotification(new GUIContent("Selected file is not a valid .NET assembly!"));
}
}
if (!singleFile)
{
ShowNotification(new GUIContent("Assemblies added: " + added + ", updated: " + updated));
}
return added > 0 || updated > 0;
}
private WhitelistingResult TryWhitelistAssemblyName(AssemblyName assName, bool singleFile)
{
var result = WhitelistingResult.Exists;
var assNameString = assName.Name;
var hash = InjectionRoutines.GetAssemblyHash(assName);
var allowed = whitelist.FirstOrDefault(allowedAssembly => allowedAssembly.Name == assNameString);
if (allowed != null)
{
if (allowed.AddHash(hash))
{
if (singleFile) ShowNotification(new GUIContent("New hash added!"));
result = WhitelistingResult.Updated;
}
else
{
if (singleFile) ShowNotification(new GUIContent("Assembly already exists!"));
}
}
else
{
allowed = new AllowedAssembly(assNameString, new[] {hash});
whitelist.Add(allowed);
if (singleFile) ShowNotification(new GUIContent("Assembly added!"));
result = WhitelistingResult.Added;
}
return result;
}
private static void LoadAndParseWhitelist()
{
whitelist = ACTkSettings.Instance.InjectionDetectorWhiteList;
}
private static void WriteWhitelist()
{
ACTkSettings.Instance.InjectionDetectorWhiteList = whitelist;
}
//////////////////////////////////////
private enum WhitelistingResult : byte
{
Exists,
Added,
Updated
}
}
}

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: bd28be63d7a09224da0cac7e3178896d
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: d1140a4b6184eae45916fdae3da40a10
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,253 @@
#region copyright
// ------------------------------------------------------
// Copyright (C) Dmitriy Yukhanov [https://codestage.net]
// ------------------------------------------------------
#endregion
namespace CodeStage.AntiCheat.EditorCode
{
using Common;
using UnityEditor;
public static partial class MigrateUtils
{
private static bool MigrateObscuredDouble(SerializedProperty sp)
{
var hiddenValue = sp.FindPropertyRelative("hiddenValue");
if (hiddenValue == null)
return false;
var fakeValue = sp.FindPropertyRelative("fakeValue");
var migratedVersion = sp.FindPropertyRelative("migratedVersion");
if (migratedVersion != null)
{
if (migratedVersion.stringValue == MigrationVersion)
{
if (!fakeValue.prefabOverride)
return false;
}
migratedVersion.stringValue = MigrationVersion;
}
var hiddenValueOldProperty = sp.FindPropertyRelative("hiddenValueOldByte8");
var hiddenValueOld = default(ACTkByte8);
var oldValueExists = false;
if (hiddenValueOldProperty?.FindPropertyRelative("b1") != null)
{
hiddenValueOld.b1 = (byte)hiddenValueOldProperty.FindPropertyRelative("b1").intValue;
hiddenValueOld.b2 = (byte)hiddenValueOldProperty.FindPropertyRelative("b2").intValue;
hiddenValueOld.b3 = (byte)hiddenValueOldProperty.FindPropertyRelative("b3").intValue;
hiddenValueOld.b4 = (byte)hiddenValueOldProperty.FindPropertyRelative("b4").intValue;
hiddenValueOld.b5 = (byte)hiddenValueOldProperty.FindPropertyRelative("b5").intValue;
hiddenValueOld.b6 = (byte)hiddenValueOldProperty.FindPropertyRelative("b6").intValue;
hiddenValueOld.b7 = (byte)hiddenValueOldProperty.FindPropertyRelative("b7").intValue;
hiddenValueOld.b8 = (byte)hiddenValueOldProperty.FindPropertyRelative("b8").intValue;
if (hiddenValueOld.b1 != 0 ||
hiddenValueOld.b2 != 0 ||
hiddenValueOld.b3 != 0 ||
hiddenValueOld.b4 != 0 ||
hiddenValueOld.b5 != 0 ||
hiddenValueOld.b6 != 0 ||
hiddenValueOld.b7 != 0 ||
hiddenValueOld.b8 != 0)
{
oldValueExists = true;
}
}
if (!oldValueExists)
return false;
var union = new LongBytesUnion {b8 = hiddenValueOld};
union.b8.Shuffle();
hiddenValue.longValue = union.l;
hiddenValueOldProperty.FindPropertyRelative("b1").intValue = 0;
hiddenValueOldProperty.FindPropertyRelative("b2").intValue = 0;
hiddenValueOldProperty.FindPropertyRelative("b3").intValue = 0;
hiddenValueOldProperty.FindPropertyRelative("b4").intValue = 0;
hiddenValueOldProperty.FindPropertyRelative("b5").intValue = 0;
hiddenValueOldProperty.FindPropertyRelative("b6").intValue = 0;
hiddenValueOldProperty.FindPropertyRelative("b7").intValue = 0;
hiddenValueOldProperty.FindPropertyRelative("b8").intValue = 0;
return true;
}
private static bool MigrateObscuredFloat(SerializedProperty sp)
{
var hiddenValue = sp.FindPropertyRelative("hiddenValue");
if (hiddenValue == null)
return false;
var fakeValue = sp.FindPropertyRelative("fakeValue");
var migratedVersion = sp.FindPropertyRelative("migratedVersion");
if (migratedVersion != null)
{
if (migratedVersion.stringValue == MigrationVersion)
{
if (!fakeValue.prefabOverride)
return false;
}
migratedVersion.stringValue = MigrationVersion;
}
var hiddenValueOldProperty = sp.FindPropertyRelative("hiddenValueOldByte4");
var hiddenValueOld = default(ACTkByte4);
var oldValueExists = false;
if (hiddenValueOldProperty?.FindPropertyRelative("b1") != null)
{
hiddenValueOld.b1 = (byte)hiddenValueOldProperty.FindPropertyRelative("b1").intValue;
hiddenValueOld.b2 = (byte)hiddenValueOldProperty.FindPropertyRelative("b2").intValue;
hiddenValueOld.b3 = (byte)hiddenValueOldProperty.FindPropertyRelative("b3").intValue;
hiddenValueOld.b4 = (byte)hiddenValueOldProperty.FindPropertyRelative("b4").intValue;
if (hiddenValueOld.b1 != 0 ||
hiddenValueOld.b2 != 0 ||
hiddenValueOld.b3 != 0 ||
hiddenValueOld.b4 != 0)
{
oldValueExists = true;
}
}
if (!oldValueExists)
return false;
var union = new FloatIntBytesUnion {b4 = hiddenValueOld};
union.b4.Shuffle();
hiddenValue.longValue = union.i;
hiddenValueOldProperty.FindPropertyRelative("b1").intValue = 0;
hiddenValueOldProperty.FindPropertyRelative("b2").intValue = 0;
hiddenValueOldProperty.FindPropertyRelative("b3").intValue = 0;
hiddenValueOldProperty.FindPropertyRelative("b4").intValue = 0;
return true;
}
private static bool MigrateObscuredVector2(SerializedProperty sp)
{
var hiddenValue = sp.FindPropertyRelative("hiddenValue");
if (hiddenValue == null)
return false;
var fakeValue = sp.FindPropertyRelative("fakeValue");
var migratedVersion = sp.FindPropertyRelative("migratedVersion");
if (migratedVersion != null)
{
if (migratedVersion.stringValue == MigrationVersion)
{
if (!fakeValue.prefabOverride)
return false;
}
migratedVersion.stringValue = MigrationVersion;
}
var hiddenValueX = hiddenValue.FindPropertyRelative("x");
var hiddenValueY = hiddenValue.FindPropertyRelative("y");
var union = new FloatIntBytesUnion {i = hiddenValueX.intValue};
union.b4.Shuffle();
hiddenValueX.intValue = union.i;
union.i = hiddenValueY.intValue;
union.b4.Shuffle();
hiddenValueY.intValue = union.i;
return true;
}
private static bool MigrateObscuredVector3(SerializedProperty sp)
{
var hiddenValue = sp.FindPropertyRelative("hiddenValue");
if (hiddenValue == null)
return false;
var fakeValue = sp.FindPropertyRelative("fakeValue");
var migratedVersion = sp.FindPropertyRelative("migratedVersion");
if (migratedVersion != null)
{
if (migratedVersion.stringValue == MigrationVersion)
{
if (!fakeValue.prefabOverride)
return false;
}
migratedVersion.stringValue = MigrationVersion;
}
var hiddenValueX = hiddenValue.FindPropertyRelative("x");
var hiddenValueY = hiddenValue.FindPropertyRelative("y");
var hiddenValueZ = hiddenValue.FindPropertyRelative("z");
var union = new FloatIntBytesUnion {i = hiddenValueX.intValue};
union.b4.Shuffle();
hiddenValueX.intValue = union.i;
union.i = hiddenValueY.intValue;
union.b4.Shuffle();
hiddenValueY.intValue = union.i;
union.i = hiddenValueZ.intValue;
union.b4.Shuffle();
hiddenValueZ.intValue = union.i;
return true;
}
private static bool MigrateObscuredQuaternion(SerializedProperty sp)
{
var hiddenValue = sp.FindPropertyRelative("hiddenValue");
if (hiddenValue == null)
return false;
var fakeValue = sp.FindPropertyRelative("fakeValue");
var migratedVersion = sp.FindPropertyRelative("migratedVersion");
if (migratedVersion != null)
{
if (migratedVersion.stringValue == MigrationVersion)
{
if (!fakeValue.prefabOverride)
return false;
}
migratedVersion.stringValue = MigrationVersion;
}
var hiddenValueX = hiddenValue.FindPropertyRelative("x");
var hiddenValueY = hiddenValue.FindPropertyRelative("y");
var hiddenValueZ = hiddenValue.FindPropertyRelative("z");
var hiddenValueW = hiddenValue.FindPropertyRelative("w");
var union = new FloatIntBytesUnion {i = hiddenValueX.intValue};
union.b4.Shuffle();
hiddenValueX.intValue = union.i;
union.i = hiddenValueY.intValue;
union.b4.Shuffle();
hiddenValueY.intValue = union.i;
union.i = hiddenValueZ.intValue;
union.b4.Shuffle();
hiddenValueZ.intValue = union.i;
union.i = hiddenValueW.intValue;
union.b4.Shuffle();
hiddenValueW.intValue = union.i;
return true;
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 7e1925e5a5f04349bee0d734c5705598
timeCreated: 1621638102

View File

@@ -0,0 +1,160 @@
#region copyright
// ------------------------------------------------------
// Copyright (C) Dmitriy Yukhanov [https://codestage.net]
// ------------------------------------------------------
#endregion
namespace CodeStage.AntiCheat.EditorCode
{
using Common;
using System.Runtime.InteropServices;
using ObscuredTypes;
using PropertyDrawers;
using UnityEditor;
using UnityEngine;
using Object = UnityEngine.Object;
/// <summary>
/// Class with utility functions to help with ACTk migrations after updates.
/// </summary>
public static partial class MigrateUtils
{
private const string MigrationVersion = "2";
/// <summary>
/// Checks all prefabs in project for old version of obscured types and tries to migrate values to the new version.
/// </summary>
public static void MigrateObscuredTypesOnPrefabs(params string[] typesToMigrate)
{
if (!EditorUtility.DisplayDialog("ACTk Obscured types migration",
"Are you sure you wish to scan all prefabs in your project and automatically migrate values to the new format?\n" +
GetWhatMigratesString(typesToMigrate),
"Yes", "No"))
{
Debug.Log(ACTk.LogPrefix + "Obscured types migration was canceled by user.");
return;
}
EditorTools.TraverseSerializedScriptsAssets(ProcessProperty, typesToMigrate);
}
/// <summary>
/// Checks all scenes in project for old version of obscured types and tries to migrate values to the new version.
/// </summary>
public static void MigrateObscuredTypesInScene(params string[] typesToMigrate)
{
if (!EditorUtility.DisplayDialog("ACTk Obscured types migration",
"Are you sure you wish to scan all opened scenes and automatically migrate values to the new format?\n" +
GetWhatMigratesString(typesToMigrate),
"Yes", "No"))
{
Debug.Log(ACTk.LogPrefix + "Obscured types migration was canceled by user.");
return;
}
EditorTools.TraverseSerializedScriptsInScenes(ProcessProperty, typesToMigrate);
}
private static bool ProcessProperty(Object target, SerializedProperty sp, string label, string type)
{
var modified = false;
switch (type)
{
case "ObscuredDouble":
{
modified = MigrateObscuredDouble(sp);
break;
}
case "ObscuredFloat":
{
modified = MigrateObscuredFloat(sp);
break;
}
case "ObscuredVector2":
{
modified = MigrateObscuredVector2(sp);
break;
}
case "ObscuredVector3":
{
modified = MigrateObscuredVector3(sp);
break;
}
case "ObscuredQuaternion":
{
modified = MigrateObscuredQuaternion(sp);
break;
}
case "ObscuredString":
{
modified = MigrateObscuredStringIfNecessary(sp);
break;
}
}
if (modified)
Debug.Log($"{ACTk.LogPrefix}Migrated property {sp.displayName}:{type} at the object {label}");
return modified;
}
internal static bool MigrateObscuredStringIfNecessary(SerializedProperty sp)
{
var hiddenValueProperty = sp.FindPropertyRelative("hiddenValue");
if (hiddenValueProperty == null) return false;
var currentCryptoKeyOldProperty = sp.FindPropertyRelative("currentCryptoKey");
if (currentCryptoKeyOldProperty == null) return false;
var currentCryptoKeyOld = currentCryptoKeyOldProperty.stringValue;
if (string.IsNullOrEmpty(currentCryptoKeyOld)) return false;
var hiddenCharsProperty = sp.FindPropertyRelative("hiddenChars");
if (hiddenCharsProperty == null) return false;
var hiddenValue = ObscuredStringDrawer.GetBytesObsolete(hiddenValueProperty);
var decrypted =
ObscuredString.EncryptDecryptObsolete(ObscuredString.GetStringObsolete(hiddenValue),
currentCryptoKeyOld);
var currentCryptoKey = ObscuredString.GenerateKey();
var hiddenChars = ObscuredString.InternalEncryptDecrypt(decrypted.ToCharArray(), currentCryptoKey);
ObscuredStringDrawer.SetChars(hiddenCharsProperty, hiddenChars);
var currentCryptoKeyProperty = sp.FindPropertyRelative("cryptoKey");
ObscuredStringDrawer.SetChars(currentCryptoKeyProperty, currentCryptoKey);
hiddenValueProperty.arraySize = 0;
currentCryptoKeyOldProperty.stringValue = null;
return true;
}
private static string GetWhatMigratesString(string[] typesToMigrate)
{
return string.Join(", ", typesToMigrate) + " will migrated.";
}
[StructLayout(LayoutKind.Explicit)]
private struct LongBytesUnion
{
[FieldOffset(0)]
public readonly long l;
[FieldOffset(0)]
public ACTkByte8 b8;
}
[StructLayout(LayoutKind.Explicit)]
private struct FloatIntBytesUnion
{
[FieldOffset(0)]
public int i;
[FieldOffset(0)]
public ACTkByte4 b4;
}
}
}

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: c1c7ff960ccd8a243ad385a3fe965e9e
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: dfff86e18b5565b499779c37590c4d83
folderAsset: yes
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,122 @@
#region copyright
// ------------------------------------------------------
// Copyright (C) Dmitriy Yukhanov [https://codestage.net]
// ------------------------------------------------------
#endregion
namespace CodeStage.AntiCheat.EditorCode.PropertyDrawers
{
using System.Numerics;
using ObscuredTypes;
using UnityEditor;
using UnityEngine;
[CustomPropertyDrawer(typeof(ObscuredBigInteger))]
internal class ObscuredBigIntegerDrawer : PropertyDrawer
{
public override void OnGUI(Rect position, SerializedProperty sp, GUIContent label)
{
var hiddenValue = sp.FindPropertyRelative(nameof(ObscuredBigInteger.hiddenValue));
var cryptoKey = sp.FindPropertyRelative(nameof(ObscuredBigInteger.currentCryptoKey));
var inited = sp.FindPropertyRelative(nameof(ObscuredBigInteger.inited));
var fakeValue = sp.FindPropertyRelative(nameof(ObscuredBigInteger.fakeValue));
var fakeValueActive = sp.FindPropertyRelative(nameof(ObscuredBigInteger.fakeValueActive));
var currentCryptoKey = (uint)cryptoKey.intValue;
BigInteger val = 0;
if (!inited.boolValue)
{
if (currentCryptoKey == 0)
{
currentCryptoKey = ObscuredBigInteger.GenerateKey();
cryptoKey.intValue = (int)currentCryptoKey;
}
var encrypted = ObscuredBigInteger.Encrypt(0, currentCryptoKey);
SetBigInteger(hiddenValue, encrypted);
inited.boolValue = true;
SetBigInteger(fakeValue, 0);
}
else
{
val = ObscuredBigInteger.Decrypt(GetBigInteger(hiddenValue), currentCryptoKey);
}
label = EditorGUI.BeginProperty(position, label, sp);
EditorGUI.BeginChangeCheck();
#if UNITY_2022_1_OR_NEWER
var bigIntString = EditorGUI.DelayedTextField(position, label, val.ToString());
#else
var bigIntString = EditorGUI.TextField(position, label, val.ToString());
#endif
if (EditorGUI.EndChangeCheck())
{
if (!BigInteger.TryParse(bigIntString, out var newValue))
newValue = 0;
var encrypted = ObscuredBigInteger.Encrypt(newValue, currentCryptoKey);
SetBigInteger(hiddenValue, encrypted);
SetBigInteger(fakeValue, newValue);
fakeValueActive.boolValue = true;
}
EditorGUI.EndProperty();
}
private static BigInteger GetBigInteger(SerializedProperty serializableBigInteger)
{
var result = new SerializableBigInteger();
var rawProperty = serializableBigInteger.FindPropertyRelative(nameof(SerializableBigInteger.raw));
var signProperty = rawProperty.FindPropertyRelative(nameof(SerializableBigInteger.BigIntegerContents.sign));
var bitsProperty = rawProperty.FindPropertyRelative(nameof(SerializableBigInteger.BigIntegerContents.bits));
var bits = ReadBitsArray(bitsProperty);
result.raw = new SerializableBigInteger.BigIntegerContents
{
sign = signProperty.intValue,
bits = bits
};
return result.value;
}
private static void SetBigInteger(SerializedProperty serializableBigInteger, BigInteger value)
{
var explicitStruct = new SerializableBigInteger
{
value = value
};
var sign = explicitStruct.raw.sign;
var bits = explicitStruct.raw.bits;
var rawProperty = serializableBigInteger.FindPropertyRelative(nameof(SerializableBigInteger.raw));
var signProperty = rawProperty.FindPropertyRelative(nameof(SerializableBigInteger.BigIntegerContents.sign));
var bitsProperty = rawProperty.FindPropertyRelative(nameof(SerializableBigInteger.BigIntegerContents.bits));
signProperty.intValue = sign;
WriteBitsArray(bitsProperty, bits);
}
private static uint[] ReadBitsArray(SerializedProperty bits)
{
var count = bits.arraySize;
if (count == 0)
return null;
var result = new uint[count];
for (var i = 0; i < count; i++)
result[i] = (uint)bits.GetArrayElementAtIndex(i).longValue;
return result;
}
private static void WriteBitsArray(SerializedProperty bitsProperty, uint[] bits)
{
bitsProperty.arraySize = bits?.Length ?? 0;
for (var i = 0; i < bits?.Length; i++)
bitsProperty.GetArrayElementAtIndex(i).longValue = bits[i];
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: c48a363379404a3f8ffa0970bd1f7653
timeCreated: 1653693062

View File

@@ -0,0 +1,54 @@
#region copyright
// ------------------------------------------------------
// Copyright (C) Dmitriy Yukhanov [https://codestage.net]
// ------------------------------------------------------
#endregion
namespace CodeStage.AntiCheat.EditorCode.PropertyDrawers
{
using ObscuredTypes;
using UnityEditor;
using UnityEngine;
[CustomPropertyDrawer(typeof(ObscuredBool))]
internal class ObscuredBoolDrawer : PropertyDrawer
{
public override void OnGUI(Rect position, SerializedProperty sp, GUIContent label)
{
var hiddenValue = sp.FindPropertyRelative(nameof(ObscuredBool.hiddenValue));
var cryptoKey = sp.FindPropertyRelative(nameof(ObscuredBool.currentCryptoKey));
var inited = sp.FindPropertyRelative(nameof(ObscuredBool.inited));
var fakeValue = sp.FindPropertyRelative(nameof(ObscuredBool.fakeValue));
var fakeValueActive = sp.FindPropertyRelative(nameof(ObscuredBool.fakeValueActive));
var currentCryptoKey = cryptoKey.intValue;
var val = false;
if (!inited.boolValue)
{
if (currentCryptoKey == 0)
currentCryptoKey = cryptoKey.intValue = ObscuredBool.GenerateKey();
inited.boolValue = true;
hiddenValue.intValue = ObscuredBool.Encrypt(false, (byte)currentCryptoKey);
}
else
{
val = ObscuredBool.Decrypt(hiddenValue.intValue, (byte)currentCryptoKey);
}
label = EditorGUI.BeginProperty(position, label, sp);
EditorGUI.BeginChangeCheck();
val = EditorGUI.Toggle(position, label, val);
if (EditorGUI.EndChangeCheck())
{
hiddenValue.intValue = ObscuredBool.Encrypt(val, (byte)currentCryptoKey);
fakeValue.boolValue = val;
fakeValueActive.boolValue = true;
}
EditorGUI.EndProperty();
}
}
}

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 2a0ae33a4804dd5468c37cee3d9e4a15
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,74 @@
#region copyright
// ------------------------------------------------------
// Copyright (C) Dmitriy Yukhanov [https://codestage.net]
// ------------------------------------------------------
#endregion
using System;
using System.Globalization;
using CodeStage.AntiCheat.ObscuredTypes;
using UnityEditor;
using UnityEngine;
namespace CodeStage.AntiCheat.EditorCode.PropertyDrawers
{
[CustomPropertyDrawer(typeof(ObscuredDateTime))]
internal class ObscuredDateTimeDrawer : PropertyDrawer
{
public override void OnGUI(Rect position, SerializedProperty prop, GUIContent label)
{
var hiddenValue = prop.FindPropertyRelative(nameof(ObscuredDateTime.hiddenValue));
var cryptoKey = prop.FindPropertyRelative(nameof(ObscuredDateTime.currentCryptoKey));
var inited = prop.FindPropertyRelative(nameof(ObscuredDateTime.inited));
var fakeValue = prop.FindPropertyRelative(nameof(ObscuredDateTime.fakeValue));
var fakeValueActive = prop.FindPropertyRelative(nameof(ObscuredDateTime.fakeValueActive));
var currentCryptoKey = cryptoKey.longValue;
var val = new DateTime(0);
if (!inited.boolValue)
{
if (currentCryptoKey == 0)
currentCryptoKey = cryptoKey.longValue = ObscuredDateTime.GenerateKey();
hiddenValue.longValue = ObscuredDateTime.Encrypt(new DateTime(0), currentCryptoKey);
inited.boolValue = true;
}
else
{
val = ObscuredDateTime.Decrypt(hiddenValue.longValue, currentCryptoKey);
}
var labelRect = position;
labelRect.width = position.width * 0.75f;
label = EditorGUI.BeginProperty(labelRect, label, prop);
EditorGUI.BeginChangeCheck();
var dateString = val.ToString("o", DateTimeFormatInfo.InvariantInfo);
var input = EditorGUI.DelayedTextField(labelRect, label, dateString);
if (EditorGUI.EndChangeCheck())
{
DateTime.TryParse(input, CultureInfo.InvariantCulture, DateTimeStyles.RoundtripKind, out val);
hiddenValue.longValue = ObscuredDateTime.Encrypt(val, currentCryptoKey);
fakeValue.longValue = val.ToBinary();
fakeValueActive.boolValue = true;
}
EditorGUI.EndProperty();
var kindRect = position;
kindRect.x = labelRect.xMax + 5;
kindRect.width = position.width * 0.25f - 5;
label = EditorGUI.BeginProperty(kindRect, GUIContent.none, prop);
EditorGUI.BeginChangeCheck();
var kind = val.Kind;
var kindInput = (DateTimeKind)EditorGUI.EnumPopup(kindRect, label, kind);
if (EditorGUI.EndChangeCheck())
{
val = DateTime.SpecifyKind(val, kindInput);
hiddenValue.longValue = ObscuredDateTime.Encrypt(val, currentCryptoKey);
fakeValue.longValue = val.ToBinary();
fakeValueActive.boolValue = true;
}
EditorGUI.EndProperty();
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: d4822eb673254d3fa09b8add898e8445
timeCreated: 1684493697

View File

@@ -0,0 +1,143 @@
#region copyright
// ------------------------------------------------------
// Copyright (C) Dmitriy Yukhanov [https://codestage.net]
// ------------------------------------------------------
#endregion
namespace CodeStage.AntiCheat.EditorCode.PropertyDrawers
{
using Common;
using ObscuredTypes;
using System.Globalization;
using System.Runtime.InteropServices;
using UnityEditor;
using UnityEngine;
[CustomPropertyDrawer(typeof(ObscuredDecimal))]
internal class ObscuredDecimalDrawer : PropertyDrawer
{
public override void OnGUI(Rect position, SerializedProperty prop, GUIContent label)
{
var hiddenValue = prop.FindPropertyRelative(nameof(ObscuredDecimal.hiddenValue));
var hiddenValue1 = hiddenValue.FindPropertyRelative(nameof(ACTkByte16.b1));
var hiddenValue2 = hiddenValue.FindPropertyRelative(nameof(ACTkByte16.b2));
var hiddenValue3 = hiddenValue.FindPropertyRelative(nameof(ACTkByte16.b3));
var hiddenValue4 = hiddenValue.FindPropertyRelative(nameof(ACTkByte16.b4));
var hiddenValue5 = hiddenValue.FindPropertyRelative(nameof(ACTkByte16.b5));
var hiddenValue6 = hiddenValue.FindPropertyRelative(nameof(ACTkByte16.b6));
var hiddenValue7 = hiddenValue.FindPropertyRelative(nameof(ACTkByte16.b7));
var hiddenValue8 = hiddenValue.FindPropertyRelative(nameof(ACTkByte16.b8));
var hiddenValue9 = hiddenValue.FindPropertyRelative(nameof(ACTkByte16.b9));
var hiddenValue10 = hiddenValue.FindPropertyRelative(nameof(ACTkByte16.b10));
var hiddenValue11 = hiddenValue.FindPropertyRelative(nameof(ACTkByte16.b11));
var hiddenValue12 = hiddenValue.FindPropertyRelative(nameof(ACTkByte16.b12));
var hiddenValue13 = hiddenValue.FindPropertyRelative(nameof(ACTkByte16.b13));
var hiddenValue14 = hiddenValue.FindPropertyRelative(nameof(ACTkByte16.b14));
var hiddenValue15 = hiddenValue.FindPropertyRelative(nameof(ACTkByte16.b15));
var hiddenValue16 = hiddenValue.FindPropertyRelative(nameof(ACTkByte16.b16));
var cryptoKey = prop.FindPropertyRelative(nameof(ObscuredDecimal.currentCryptoKey));
var inited = prop.FindPropertyRelative(nameof(ObscuredDecimal.inited));
//SerializedProperty fakeValue = prop.FindPropertyRelative("fakeValue");
var fakeValueActive = prop.FindPropertyRelative(nameof(ObscuredDecimal.fakeValueActive));
var currentCryptoKey = cryptoKey.longValue;
var union = new DecimalBytesUnion();
decimal val = 0;
if (!inited.boolValue)
{
if (currentCryptoKey == 0)
currentCryptoKey = cryptoKey.longValue = ObscuredDecimal.GenerateKey();
inited.boolValue = true;
union.d = ObscuredDecimal.Encrypt(0, currentCryptoKey);
hiddenValue1.intValue = union.b16.b1;
hiddenValue2.intValue = union.b16.b2;
hiddenValue3.intValue = union.b16.b3;
hiddenValue4.intValue = union.b16.b4;
hiddenValue5.intValue = union.b16.b5;
hiddenValue6.intValue = union.b16.b6;
hiddenValue7.intValue = union.b16.b7;
hiddenValue8.intValue = union.b16.b8;
hiddenValue9.intValue = union.b16.b9;
hiddenValue10.intValue = union.b16.b10;
hiddenValue11.intValue = union.b16.b11;
hiddenValue12.intValue = union.b16.b12;
hiddenValue13.intValue = union.b16.b13;
hiddenValue14.intValue = union.b16.b14;
hiddenValue15.intValue = union.b16.b15;
hiddenValue16.intValue = union.b16.b16;
}
else
{
union.b16.b1 = (byte)hiddenValue1.intValue;
union.b16.b2 = (byte)hiddenValue2.intValue;
union.b16.b3 = (byte)hiddenValue3.intValue;
union.b16.b4 = (byte)hiddenValue4.intValue;
union.b16.b5 = (byte)hiddenValue5.intValue;
union.b16.b6 = (byte)hiddenValue6.intValue;
union.b16.b7 = (byte)hiddenValue7.intValue;
union.b16.b8 = (byte)hiddenValue8.intValue;
union.b16.b9 = (byte)hiddenValue9.intValue;
union.b16.b10 = (byte)hiddenValue10.intValue;
union.b16.b11 = (byte)hiddenValue11.intValue;
union.b16.b12 = (byte)hiddenValue12.intValue;
union.b16.b13 = (byte)hiddenValue13.intValue;
union.b16.b14 = (byte)hiddenValue14.intValue;
union.b16.b15 = (byte)hiddenValue15.intValue;
union.b16.b16 = (byte)hiddenValue16.intValue;
val = ObscuredDecimal.Decrypt(union.d, currentCryptoKey);
}
label = EditorGUI.BeginProperty(position, label, prop);
EditorGUI.BeginChangeCheck();
#if UNITY_2022_1_OR_NEWER
var input = EditorGUI.DelayedTextField(position, label, val.ToString(CultureInfo.InvariantCulture));
#else
var input = EditorGUI.TextField(position, label, val.ToString(CultureInfo.InvariantCulture));
#endif
decimal.TryParse(input, NumberStyles.AllowDecimalPoint | NumberStyles.AllowLeadingSign, CultureInfo.InvariantCulture, out val);
if (EditorGUI.EndChangeCheck())
{
union.d = ObscuredDecimal.Encrypt(val, currentCryptoKey);
hiddenValue1.intValue = union.b16.b1;
hiddenValue2.intValue = union.b16.b2;
hiddenValue3.intValue = union.b16.b3;
hiddenValue4.intValue = union.b16.b4;
hiddenValue5.intValue = union.b16.b5;
hiddenValue6.intValue = union.b16.b6;
hiddenValue7.intValue = union.b16.b7;
hiddenValue8.intValue = union.b16.b8;
hiddenValue9.intValue = union.b16.b9;
hiddenValue10.intValue = union.b16.b10;
hiddenValue11.intValue = union.b16.b11;
hiddenValue12.intValue = union.b16.b12;
hiddenValue13.intValue = union.b16.b13;
hiddenValue14.intValue = union.b16.b14;
hiddenValue15.intValue = union.b16.b15;
hiddenValue16.intValue = union.b16.b16;
//fakeValue.doubleValue = 0;
fakeValueActive.boolValue = false;
}
EditorGUI.EndProperty();
}
[StructLayout(LayoutKind.Explicit)]
private struct DecimalBytesUnion
{
[FieldOffset(0)]
public decimal d;
[FieldOffset(0)]
public ACTkByte16 b16;
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: b695953c62fb4e84aa3bcf20ed203871
timeCreated: 1508363700
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,59 @@
#region copyright
// ------------------------------------------------------
// Copyright (C) Dmitriy Yukhanov [https://codestage.net]
// ------------------------------------------------------
#endregion
namespace CodeStage.AntiCheat.EditorCode.PropertyDrawers
{
using ObscuredTypes;
using UnityEditor;
using UnityEngine;
[CustomPropertyDrawer(typeof(ObscuredDouble))]
internal class ObscuredDoubleDrawer : PropertyDrawer
{
public override void OnGUI(Rect position, SerializedProperty prop, GUIContent label)
{
var hiddenValue = prop.FindPropertyRelative(nameof(ObscuredDouble.hiddenValue));
var cryptoKey = prop.FindPropertyRelative(nameof(ObscuredDouble.currentCryptoKey));
var inited = prop.FindPropertyRelative(nameof(ObscuredDouble.inited));
var fakeValue = prop.FindPropertyRelative(nameof(ObscuredDouble.fakeValue));
var fakeValueActive = prop.FindPropertyRelative(nameof(ObscuredDouble.fakeValueActive));
var currentCryptoKey = cryptoKey.longValue;
double val = 0;
if (!inited.boolValue)
{
if (currentCryptoKey == 0)
currentCryptoKey = cryptoKey.longValue = ObscuredDouble.GenerateKey();
inited.boolValue = true;
hiddenValue.longValue = ObscuredDouble.Encrypt(0, currentCryptoKey);
}
else
{
val = ObscuredDouble.Decrypt(hiddenValue.longValue, currentCryptoKey);
}
label = EditorGUI.BeginProperty(position, label, prop);
EditorGUI.BeginChangeCheck();
#if UNITY_2022_1_OR_NEWER
val = EditorGUI.DelayedDoubleField(position, label, val);
#else
val = EditorGUI.DoubleField(position, label, val);
#endif
if (EditorGUI.EndChangeCheck())
{
hiddenValue.longValue = ObscuredDouble.Encrypt(val, currentCryptoKey);
fakeValue.doubleValue = val;
fakeValueActive.boolValue = true;
}
EditorGUI.EndProperty();
}
}
}

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 5f1f384feecf6f94e9229f7d2b8ea644
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,59 @@
#region copyright
// ------------------------------------------------------
// Copyright (C) Dmitriy Yukhanov [https://codestage.net]
// ------------------------------------------------------
#endregion
namespace CodeStage.AntiCheat.EditorCode.PropertyDrawers
{
using ObscuredTypes;
using UnityEditor;
using UnityEngine;
[CustomPropertyDrawer(typeof(ObscuredFloat))]
internal class ObscuredFloatDrawer : PropertyDrawer
{
public override void OnGUI(Rect position, SerializedProperty prop, GUIContent label)
{
var hiddenValue = prop.FindPropertyRelative(nameof(ObscuredFloat.hiddenValue));
var cryptoKey = prop.FindPropertyRelative(nameof(ObscuredFloat.currentCryptoKey));
var inited = prop.FindPropertyRelative(nameof(ObscuredFloat.inited));
var fakeValue = prop.FindPropertyRelative(nameof(ObscuredFloat.fakeValue));
var fakeValueActive = prop.FindPropertyRelative(nameof(ObscuredFloat.fakeValueActive));
var currentCryptoKey = cryptoKey.intValue;
float val = 0;
if (!inited.boolValue)
{
if (currentCryptoKey == 0)
currentCryptoKey = cryptoKey.intValue = ObscuredFloat.GenerateKey();
inited.boolValue = true;
hiddenValue.intValue = ObscuredFloat.Encrypt(0, currentCryptoKey);
}
else
{
val = ObscuredFloat.Decrypt(hiddenValue.intValue, currentCryptoKey);
}
label = EditorGUI.BeginProperty(position, label, prop);
EditorGUI.BeginChangeCheck();
#if UNITY_2022_1_OR_NEWER
val = EditorGUI.DelayedFloatField(position, label, val);
#else
val = EditorGUI.FloatField(position, label, val);
#endif
if (EditorGUI.EndChangeCheck())
{
hiddenValue.intValue = ObscuredFloat.Encrypt(val, currentCryptoKey);
fakeValue.floatValue = val;
fakeValueActive.boolValue = true;
}
EditorGUI.EndProperty();
}
}
}

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 68a1078367903c94bb9914b21b55172d
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,57 @@
#region copyright
// ------------------------------------------------------
// Copyright (C) Dmitriy Yukhanov [https://codestage.net]
// ------------------------------------------------------
#endregion
namespace CodeStage.AntiCheat.EditorCode.PropertyDrawers
{
using ObscuredTypes;
using UnityEditor;
using UnityEngine;
[CustomPropertyDrawer(typeof(ObscuredInt))]
internal class ObscuredIntDrawer : PropertyDrawer
{
public override void OnGUI(Rect position, SerializedProperty prop, GUIContent label)
{
var hiddenValue = prop.FindPropertyRelative(nameof(ObscuredInt.hiddenValue));
var cryptoKey = prop.FindPropertyRelative(nameof(ObscuredInt.currentCryptoKey));
var inited = prop.FindPropertyRelative(nameof(ObscuredInt.inited));
var fakeValue = prop.FindPropertyRelative(nameof(ObscuredInt.fakeValue));
var fakeValueActive = prop.FindPropertyRelative(nameof(ObscuredInt.fakeValueActive));
var currentCryptoKey = cryptoKey.intValue;
var val = 0;
if (!inited.boolValue)
{
if (currentCryptoKey == 0)
currentCryptoKey = cryptoKey.intValue = ObscuredInt.GenerateKey();
hiddenValue.intValue = ObscuredInt.Encrypt(0, currentCryptoKey);
inited.boolValue = true;
}
else
{
val = ObscuredInt.Decrypt(hiddenValue.intValue, currentCryptoKey);
}
label = EditorGUI.BeginProperty(position, label, prop);
EditorGUI.BeginChangeCheck();
#if UNITY_2022_1_OR_NEWER
val = EditorGUI.DelayedIntField(position, label, val);
#else
val = EditorGUI.IntField(position, label, val);
#endif
if (EditorGUI.EndChangeCheck())
{
hiddenValue.intValue = ObscuredInt.Encrypt(val, currentCryptoKey);
fakeValue.intValue = val;
fakeValueActive.boolValue = true;
}
EditorGUI.EndProperty();
}
}
}

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 0d720256b4500364ba597cd9f71f28e1
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,53 @@
#region copyright
// ------------------------------------------------------
// Copyright (C) Dmitriy Yukhanov [https://codestage.net]
// ------------------------------------------------------
#endregion
namespace CodeStage.AntiCheat.EditorCode.PropertyDrawers
{
using ObscuredTypes;
using UnityEditor;
using UnityEngine;
[CustomPropertyDrawer(typeof(ObscuredLong))]
internal class ObscuredLongDrawer : PropertyDrawer
{
public override void OnGUI(Rect position, SerializedProperty prop, GUIContent label)
{
var hiddenValue = prop.FindPropertyRelative(nameof(ObscuredLong.hiddenValue));
var cryptoKey = prop.FindPropertyRelative(nameof(ObscuredLong.currentCryptoKey));
var inited = prop.FindPropertyRelative(nameof(ObscuredLong.inited));
var fakeValue = prop.FindPropertyRelative(nameof(ObscuredLong.fakeValue));
var fakeValueActive = prop.FindPropertyRelative(nameof(ObscuredLong.fakeValueActive));
var currentCryptoKey = cryptoKey.longValue;
long val = 0;
if (!inited.boolValue)
{
if (currentCryptoKey == 0)
currentCryptoKey = cryptoKey.longValue = ObscuredLong.GenerateKey();
hiddenValue.longValue = ObscuredLong.Encrypt(0, currentCryptoKey);
inited.boolValue = true;
}
else
{
val = ObscuredLong.Decrypt(hiddenValue.longValue, currentCryptoKey);
}
label = EditorGUI.BeginProperty(position, label, prop);
EditorGUI.BeginChangeCheck();
val = EditorGUI.LongField(position, label, val);
if (EditorGUI.EndChangeCheck())
{
hiddenValue.longValue = ObscuredLong.Encrypt(val, currentCryptoKey);
fakeValue.longValue = val;
fakeValueActive.boolValue = true;
}
EditorGUI.EndProperty();
}
}
}

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 98c9f8eb20d73134e96287318b713c39
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,90 @@
#region copyright
// ------------------------------------------------------
// Copyright (C) Dmitriy Yukhanov [https://codestage.net]
// ------------------------------------------------------
#endregion
namespace CodeStage.AntiCheat.EditorCode.PropertyDrawers
{
using ObscuredTypes;
using UnityEditor;
using UnityEngine;
[CustomPropertyDrawer(typeof(ObscuredQuaternion))]
internal class ObscuredQuaternionDrawer : PropertyDrawer
{
public override void OnGUI(Rect position, SerializedProperty prop, GUIContent label)
{
var hiddenValue = prop.FindPropertyRelative(nameof(ObscuredQuaternion.hiddenValue));
var cryptoKey = prop.FindPropertyRelative(nameof(ObscuredQuaternion.currentCryptoKey));
var inited = prop.FindPropertyRelative(nameof(ObscuredQuaternion.inited));
var fakeValue = prop.FindPropertyRelative(nameof(ObscuredQuaternion.fakeValue));
var fakeValueActive = prop.FindPropertyRelative(nameof(ObscuredQuaternion.fakeValueActive));
var hiddenValueX = hiddenValue.FindPropertyRelative(nameof(ObscuredQuaternion.RawEncryptedQuaternion.x));
var hiddenValueY = hiddenValue.FindPropertyRelative(nameof(ObscuredQuaternion.RawEncryptedQuaternion.y));
var hiddenValueZ = hiddenValue.FindPropertyRelative(nameof(ObscuredQuaternion.RawEncryptedQuaternion.z));
var hiddenValueW = hiddenValue.FindPropertyRelative(nameof(ObscuredQuaternion.RawEncryptedQuaternion.w));
var currentCryptoKey = cryptoKey.intValue;
var val = Quaternion.identity;
if (!inited.boolValue)
{
if (currentCryptoKey == 0)
currentCryptoKey = cryptoKey.intValue = ObscuredQuaternion.GenerateKey();
var ev = ObscuredQuaternion.Encrypt(Quaternion.identity, currentCryptoKey);
hiddenValueX.intValue = ev.x;
hiddenValueY.intValue = ev.y;
hiddenValueZ.intValue = ev.z;
hiddenValueW.intValue = ev.w;
inited.boolValue = true;
fakeValue.quaternionValue = Quaternion.identity;
}
else
{
var ev = new ObscuredQuaternion.RawEncryptedQuaternion
{
x = hiddenValueX.intValue,
y = hiddenValueY.intValue,
z = hiddenValueZ.intValue,
w = hiddenValueW.intValue
};
val = ObscuredQuaternion.Decrypt(ev, currentCryptoKey);
}
label = EditorGUI.BeginProperty(position, label, prop);
EditorGUI.BeginChangeCheck();
val = Vector4ToQuaternion(EditorGUI.Vector4Field(position, label, QuaternionToVector4(val)));
if (EditorGUI.EndChangeCheck())
{
var ev = ObscuredQuaternion.Encrypt(val, currentCryptoKey);
hiddenValueX.intValue = ev.x;
hiddenValueY.intValue = ev.y;
hiddenValueZ.intValue = ev.z;
hiddenValueW.intValue = ev.w;
fakeValue.quaternionValue = val;
fakeValueActive.boolValue = true;
}
EditorGUI.EndProperty();
}
public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
{
return EditorGUIUtility.wideMode ? EditorGUIUtility.singleLineHeight : EditorGUIUtility.singleLineHeight * 2f;
}
private Vector4 QuaternionToVector4(Quaternion value)
{
return new Vector4(value.x, value.y, value.z, value.w);
}
private Quaternion Vector4ToQuaternion(Vector4 value)
{
return new Quaternion(value.x, value.y, value.z, value.w);
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 1cd362a81eab4155a2f1585c5d7ba876
timeCreated: 1544725257

View File

@@ -0,0 +1,57 @@
#region copyright
// ------------------------------------------------------
// Copyright (C) Dmitriy Yukhanov [https://codestage.net]
// ------------------------------------------------------
#endregion
namespace CodeStage.AntiCheat.EditorCode.PropertyDrawers
{
using ObscuredTypes;
using UnityEditor;
using UnityEngine;
[CustomPropertyDrawer(typeof(ObscuredShort))]
internal class ObscuredShortDrawer : PropertyDrawer
{
public override void OnGUI(Rect position, SerializedProperty prop, GUIContent label)
{
var hiddenValue = prop.FindPropertyRelative(nameof(ObscuredShort.hiddenValue));
var cryptoKey = prop.FindPropertyRelative(nameof(ObscuredShort.currentCryptoKey));
var inited = prop.FindPropertyRelative(nameof(ObscuredShort.inited));
var fakeValue = prop.FindPropertyRelative(nameof(ObscuredShort.fakeValue));
var fakeValueActive = prop.FindPropertyRelative(nameof(ObscuredShort.fakeValueActive));
var currentCryptoKey = (short)cryptoKey.intValue;
short val = 0;
if (!inited.boolValue)
{
if (currentCryptoKey == 0)
currentCryptoKey = (short)(cryptoKey.intValue = ObscuredShort.GenerateKey());
hiddenValue.intValue = ObscuredShort.Encrypt(0, currentCryptoKey);
inited.boolValue = true;
}
else
{
val = ObscuredShort.Decrypt((short)hiddenValue.intValue, currentCryptoKey);
}
label = EditorGUI.BeginProperty(position, label, prop);
EditorGUI.BeginChangeCheck();
#if UNITY_2022_1_OR_NEWER
val = (short)EditorGUI.DelayedIntField(position, label, val);
#else
val = (short)EditorGUI.IntField(position, label, val);
#endif
if (EditorGUI.EndChangeCheck())
{
hiddenValue.intValue = ObscuredShort.Encrypt(val, currentCryptoKey);
fakeValue.intValue = val;
fakeValueActive.boolValue = true;
}
EditorGUI.EndProperty();
}
}
}

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: eaf7a22e1b4319f40b23596cea6556a4
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:

View File

@@ -0,0 +1,137 @@
#region copyright
// ------------------------------------------------------
// Copyright (C) Dmitriy Yukhanov [https://codestage.net]
// ------------------------------------------------------
#endregion
namespace CodeStage.AntiCheat.EditorCode.PropertyDrawers
{
using ObscuredTypes;
using System;
using UnityEditor;
using UnityEngine;
[CustomPropertyDrawer(typeof(ObscuredString))]
internal class ObscuredStringDrawer : PropertyDrawer
{
public override void OnGUI(Rect position, SerializedProperty sp, GUIContent label)
{
MigrateUtils.MigrateObscuredStringIfNecessary(sp);
var hiddenChars = sp.FindPropertyRelative(nameof(ObscuredString.hiddenChars));
var cryptoKey = sp.FindPropertyRelative(nameof(ObscuredString.cryptoKey));
var inited = sp.FindPropertyRelative(nameof(ObscuredString.inited));
var fakeValue = sp.FindPropertyRelative(nameof(ObscuredString.fakeValue));
var fakeValueActive = sp.FindPropertyRelative(nameof(ObscuredString.fakeValueActive));
var currentCryptoKey = GetChars(cryptoKey);
var val = string.Empty;
if (!inited.boolValue)
{
if (currentCryptoKey.Length == 0)
{
currentCryptoKey = ObscuredString.GenerateKey();
SetChars(cryptoKey, currentCryptoKey);
}
inited.boolValue = true;
EncryptAndSetChars(val.ToCharArray(), hiddenChars, currentCryptoKey);
fakeValue.stringValue = val;
}
else
{
var size = hiddenChars.FindPropertyRelative("Array.size");
var showMixed = size.hasMultipleDifferentValues;
if (!showMixed)
{
for (var i = 0; i < hiddenChars.arraySize; i++)
{
showMixed |= hiddenChars.GetArrayElementAtIndex(i).hasMultipleDifferentValues;
if (showMixed) break;
}
}
if (!showMixed)
val = Decrypt(hiddenChars, currentCryptoKey);
else
EditorGUI.showMixedValue = true;
}
if (label.text.IndexOf('[') != -1)
{
var dataIndex = sp.propertyPath.IndexOf("Array.data[", StringComparison.Ordinal);
if (dataIndex >= 0)
{
dataIndex += 11;
var index = "Element " + sp.propertyPath.Substring(dataIndex, sp.propertyPath.IndexOf("]", dataIndex, StringComparison.Ordinal) - dataIndex);
label.text = index;
}
}
label = EditorGUI.BeginProperty(position, label, sp);
EditorGUI.BeginChangeCheck();
#if UNITY_2022_1_OR_NEWER
val = EditorGUI.DelayedTextField(position, label, val);
#else
val = EditorGUI.TextField(position, label, val);
#endif
if (EditorGUI.EndChangeCheck())
{
EncryptAndSetChars(val.ToCharArray(), hiddenChars, currentCryptoKey);
fakeValue.stringValue = val;
fakeValueActive.boolValue = true;
}
EditorGUI.showMixedValue = false;
EditorGUI.EndProperty();
}
private static void EncryptAndSetChars(char[] val, SerializedProperty prop, char[] key)
{
var encrypted = ObscuredString.InternalEncryptDecrypt(val, key);
SetChars(prop, encrypted);
}
private static string Decrypt(SerializedProperty hiddenChars, char[] currentCryptoKey)
{
var chars = new char[hiddenChars.arraySize];
for (var i = 0; i < hiddenChars.arraySize; i++)
chars[i] = (char)hiddenChars.GetArrayElementAtIndex(i).intValue;
return ObscuredString.Decrypt(chars, currentCryptoKey);
}
public static byte[] GetBytesObsolete(SerializedProperty property)
{
var length = property.arraySize;
var result = new byte[length];
for (var i = 0; i < length; i++)
result[i] = (byte)property.GetArrayElementAtIndex(i).intValue;
return result;
}
public static void SetChars(SerializedProperty property, char[] array)
{
property.ClearArray();
property.arraySize = array.Length;
for (var i = 0; i < array.Length; i++)
property.GetArrayElementAtIndex(i).intValue = array[i];
}
private static char[] GetChars(SerializedProperty property)
{
var length = property.arraySize;
var result = new char[length];
for (var i = 0; i < length; i++)
result[i] = (char)property.GetArrayElementAtIndex(i).intValue;
return result;
}
}
}

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: db9197f5c028e5b4497f66a9b3217395
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,57 @@
#region copyright
// ------------------------------------------------------
// Copyright (C) Dmitriy Yukhanov [https://codestage.net]
// ------------------------------------------------------
#endregion
namespace CodeStage.AntiCheat.EditorCode.PropertyDrawers
{
using ObscuredTypes;
using UnityEditor;
using UnityEngine;
[CustomPropertyDrawer(typeof(ObscuredUInt))]
internal class ObscuredUIntDrawer : PropertyDrawer
{
public override void OnGUI(Rect position, SerializedProperty prop, GUIContent label)
{
var hiddenValue = prop.FindPropertyRelative(nameof(ObscuredUInt.hiddenValue));
var cryptoKey = prop.FindPropertyRelative(nameof(ObscuredUInt.currentCryptoKey));
var inited = prop.FindPropertyRelative(nameof(ObscuredUInt.inited));
var fakeValue = prop.FindPropertyRelative(nameof(ObscuredUInt.fakeValue));
var fakeValueActive = prop.FindPropertyRelative(nameof(ObscuredUInt.fakeValueActive));
var currentCryptoKey = (uint)cryptoKey.intValue;
uint val = 0;
if (!inited.boolValue)
{
if (currentCryptoKey == 0)
cryptoKey.intValue = (int)(currentCryptoKey = ObscuredUInt.GenerateKey());
hiddenValue.intValue = (int)ObscuredUInt.Encrypt(0, currentCryptoKey);
inited.boolValue = true;
}
else
{
val = ObscuredUInt.Decrypt((uint)hiddenValue.intValue, currentCryptoKey);
}
label = EditorGUI.BeginProperty(position, label, prop);
EditorGUI.BeginChangeCheck();
#if UNITY_2022_1_OR_NEWER
val = (uint)EditorGUI.DelayedIntField(position, label, (int)val);
#else
val = (uint)EditorGUI.IntField(position, label, (int)val);
#endif
if (EditorGUI.EndChangeCheck())
{
hiddenValue.intValue = (int)ObscuredUInt.Encrypt(val, currentCryptoKey);
fakeValue.intValue = (int)val;
fakeValueActive.boolValue = true;
}
EditorGUI.EndProperty();
}
}
}

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 914802edc5dc95349a9903ac64be6343
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:

View File

@@ -0,0 +1,53 @@
#region copyright
// ------------------------------------------------------
// Copyright (C) Dmitriy Yukhanov [https://codestage.net]
// ------------------------------------------------------
#endregion
namespace CodeStage.AntiCheat.EditorCode.PropertyDrawers
{
using ObscuredTypes;
using UnityEditor;
using UnityEngine;
[CustomPropertyDrawer(typeof(ObscuredULong))]
internal class ObscuredULongDrawer : PropertyDrawer
{
public override void OnGUI(Rect position, SerializedProperty prop, GUIContent label)
{
var hiddenValue = prop.FindPropertyRelative(nameof(ObscuredULong.hiddenValue));
var cryptoKey = prop.FindPropertyRelative(nameof(ObscuredULong.currentCryptoKey));
var inited = prop.FindPropertyRelative(nameof(ObscuredULong.inited));
var fakeValue = prop.FindPropertyRelative(nameof(ObscuredULong.fakeValue));
var fakeValueActive = prop.FindPropertyRelative(nameof(ObscuredULong.fakeValueActive));
var currentCryptoKey = (ulong)cryptoKey.longValue;
ulong val = 0;
if (!inited.boolValue)
{
if (currentCryptoKey == 0)
cryptoKey.longValue = (long)(currentCryptoKey = ObscuredULong.GenerateKey());
hiddenValue.longValue = (long)ObscuredULong.Encrypt(0, currentCryptoKey);
inited.boolValue = true;
}
else
{
val = ObscuredULong.Decrypt((ulong)hiddenValue.longValue, currentCryptoKey);
}
label = EditorGUI.BeginProperty(position, label, prop);
EditorGUI.BeginChangeCheck();
val = (ulong)EditorGUI.LongField(position, label, (long)val);
if (EditorGUI.EndChangeCheck())
{
hiddenValue.longValue = (long)ObscuredULong.Encrypt(val, currentCryptoKey);
fakeValue.longValue = (long)val;
fakeValueActive.boolValue = true;
}
EditorGUI.EndProperty();
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: ae392b1c42e591945a2aa46d35119192
timeCreated: 1484857585
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,71 @@
#region copyright
// ------------------------------------------------------
// Copyright (C) Dmitriy Yukhanov [https://codestage.net]
// ------------------------------------------------------
#endregion
namespace CodeStage.AntiCheat.EditorCode.PropertyDrawers
{
using ObscuredTypes;
using UnityEditor;
using UnityEngine;
[CustomPropertyDrawer(typeof(ObscuredVector2))]
internal class ObscuredVector2Drawer : PropertyDrawer
{
public override void OnGUI(Rect position, SerializedProperty prop, GUIContent label)
{
var hiddenValue = prop.FindPropertyRelative(nameof(ObscuredVector2.hiddenValue));
var cryptoKey = prop.FindPropertyRelative(nameof(ObscuredVector2.currentCryptoKey));
var inited = prop.FindPropertyRelative(nameof(ObscuredVector2.inited));
var fakeValue = prop.FindPropertyRelative(nameof(ObscuredVector2.fakeValue));
var fakeValueActive = prop.FindPropertyRelative(nameof(ObscuredVector2.fakeValueActive));
var hiddenValueX = hiddenValue.FindPropertyRelative(nameof(ObscuredVector2.RawEncryptedVector2.x));
var hiddenValueY = hiddenValue.FindPropertyRelative(nameof(ObscuredVector2.RawEncryptedVector2.y));
var currentCryptoKey = cryptoKey.intValue;
var val = Vector2.zero;
if (!inited.boolValue)
{
if (currentCryptoKey == 0)
currentCryptoKey = cryptoKey.intValue = ObscuredVector2.GenerateKey();
var ev = ObscuredVector2.Encrypt(Vector2.zero, currentCryptoKey);
hiddenValueX.intValue = ev.x;
hiddenValueY.intValue = ev.y;
inited.boolValue = true;
fakeValue.vector2Value = Vector2.zero;
}
else
{
var ev = new ObscuredVector2.RawEncryptedVector2
{
x = hiddenValueX.intValue,
y = hiddenValueY.intValue
};
val = ObscuredVector2.Decrypt(ev, currentCryptoKey);
}
label = EditorGUI.BeginProperty(position, label, prop);
EditorGUI.BeginChangeCheck();
val = EditorGUI.Vector2Field(position, label, val);
if (EditorGUI.EndChangeCheck())
{
var ev = ObscuredVector2.Encrypt(val, currentCryptoKey);
hiddenValueX.intValue = ev.x;
hiddenValueY.intValue = ev.y;
fakeValue.vector2Value = val;
fakeValueActive.boolValue = true;
}
EditorGUI.EndProperty();
}
public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
{
return EditorGUIUtility.wideMode ? EditorGUIUtility.singleLineHeight : EditorGUIUtility.singleLineHeight * 2f;
}
}
}

Some files were not shown because too many files have changed in this diff Show More