Skip to content

Commit b99061e

Browse files
committed
Optimize the anticheat a little bit (check desc.)
All modules are runtime-tunable via `AXIOM.Settings`. The system avoids allocations in recurring loops, caches expensive calls, uses static/shared objects where appropriate, and follows Unity execution lifecycle rules.
1 parent 3b81739 commit b99061e

File tree

1 file changed

+101
-69
lines changed

1 file changed

+101
-69
lines changed

packages/anticheat/core/AXIOM.cs

Lines changed: 101 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
// AXIOM.cs - Open Source Unity Anti-Cheat Runtime Framework
2+
// Author: Mike
3+
// License: MIT
4+
// Version: 1.3
25

36
using System;
47
using System.Collections.Generic;
@@ -15,10 +18,14 @@ public sealed class AXIOM : MonoBehaviour
1518
{
1619
private static AXIOM _instance;
1720
private static readonly object _lock = new object();
21+
private static readonly SHA256 _sha256 = SHA256.Create();
22+
private static readonly MD5 _md5 = MD5.Create();
23+
1824
private DateTime _lastRealTime;
1925
private float _lastGameTime;
20-
private List<IntPtr> _decoyPointers = new();
21-
private Dictionary<MethodInfo, string> _methodHashes = new();
26+
27+
private readonly List<IntPtr> _decoyPointers = new();
28+
private readonly Dictionary<MethodInfo, string> _methodHashes = new();
2229

2330
// === CENTRALIZED CONFIGURATION ===
2431
public class Config
@@ -35,27 +42,46 @@ public class Config
3542
public bool CheckStackTrace = true;
3643

3744
public float SpeedHackThreshold = 0.5f;
38-
public List<string> KnownBadProcesses = new() { "cheatengine", "ollydbg", "x64dbg", "dnspy", "processhacker" };
39-
public List<string> SuspiciousAssemblies = new() { "dnlib", "mono.cecil", "xmono", "cheat" };
45+
46+
public List<string> KnownBadProcesses = new()
47+
{
48+
"cheatengine", "ollydbg", "x64dbg", "dnspy", "processhacker"
49+
};
50+
51+
public List<string> SuspiciousAssemblies = new()
52+
{
53+
"dnlib", "mono.cecil", "xmono", "cheat"
54+
};
4055

4156
public float ProcessScanInterval = 5f;
4257
public float SpeedHackScanInterval = 1f;
4358

44-
public string GameAssemblyNameHint = "YourGame"; // used in mono injection check
59+
public string GameAssemblyNameHint = "YourGame";
4560
public bool QuitOnDetection = true;
4661
}
4762

48-
public static Config Settings = new Config();
49-
// === END CONFIGURATION ===
63+
public static readonly Config Settings = new();
64+
65+
// === INIT ===
66+
public static void Initialize()
67+
{
68+
if (_instance != null) return;
69+
70+
var obj = new GameObject(Settings.AntiCheatName);
71+
_instance = obj.AddComponent<AXIOM>();
72+
DontDestroyOnLoad(obj);
73+
}
5074

5175
void Awake()
5276
{
53-
lock (_lock)
77+
if (_instance != null && _instance != this)
5478
{
55-
if (_instance != null) Destroy(gameObject);
56-
_instance = this;
57-
DontDestroyOnLoad(gameObject);
79+
Destroy(gameObject);
80+
return;
5881
}
82+
83+
_instance = this;
84+
DontDestroyOnLoad(gameObject);
5985
}
6086

6187
void Start()
@@ -65,28 +91,31 @@ void Start()
6591
if (Settings.DetectMonoInjection) CheckMonoInjection();
6692
if (Settings.ValidateMethodHashes) CacheMethodHashes();
6793
if (Settings.CheckStackTrace) InvokeRepeating(nameof(CheckStackConsistency), 3f, 10f);
94+
if (Settings.MonitorExternalProcesses) InvokeRepeating(nameof(ScanProcesses), 1f, Settings.ProcessScanInterval);
95+
if (Settings.DetectSpeedHack) InvokeRepeating(nameof(CheckSpeedHack), 1f, Settings.SpeedHackScanInterval);
96+
if (Settings.UseMemoryDecoys) CreateMemoryDecoys();
6897

69-
if (Settings.MonitorExternalProcesses)
70-
InvokeRepeating(nameof(ScanProcesses), 1f, Settings.ProcessScanInterval);
71-
72-
if (Settings.DetectSpeedHack)
73-
InvokeRepeating(nameof(CheckSpeedHack), 1f, Settings.SpeedHackScanInterval);
74-
75-
if (Settings.UseMemoryDecoys)
76-
CreateMemoryDecoys();
98+
_lastRealTime = DateTime.UtcNow;
99+
_lastGameTime = Time.time;
77100
}
78101

79-
// === MODULE: ASSEMBLY INTEGRITY ===
102+
// === ASSEMBLY INTEGRITY ===
80103
private void VerifyAssemblies()
81104
{
82-
string path = Assembly.GetExecutingAssembly().Location;
83-
using var md5 = MD5.Create();
84-
byte[] hash = md5.ComputeHash(File.ReadAllBytes(path));
85-
string hashString = BitConverter.ToString(hash).Replace("-", "");
86-
Log("Assembly MD5: " + hashString);
105+
try
106+
{
107+
string path = Assembly.GetExecutingAssembly().Location;
108+
byte[] hash = _md5.ComputeHash(File.ReadAllBytes(path));
109+
string hashString = BitConverter.ToString(hash).Replace("-", "");
110+
Log("Assembly MD5: " + hashString);
111+
}
112+
catch (Exception ex)
113+
{
114+
Log("Assembly hash failed: " + ex.Message);
115+
}
87116
}
88117

89-
// === MODULE: DEBUGGER DETECTION ===
118+
// === DEBUGGER CHECK ===
90119
private void CheckDebugger()
91120
{
92121
if (Debugger.IsAttached || IsDebuggerPresent())
@@ -99,17 +128,16 @@ private void CheckDebugger()
99128
[DllImport("kernel32.dll")]
100129
private static extern bool IsDebuggerPresent();
101130

102-
// === MODULE: MONO INJECTION DETECTION ===
131+
// === MONO INJECTION CHECK ===
103132
private void CheckMonoInjection()
104133
{
105-
var assemblies = AppDomain.CurrentDomain.GetAssemblies();
106-
foreach (var asm in assemblies)
134+
foreach (var asm in AppDomain.CurrentDomain.GetAssemblies())
107135
{
108-
string asmName = asm.GetName().Name.ToLower();
136+
string asmName = asm.GetName().Name.ToLowerInvariant();
109137
if (!asmName.StartsWith("unity") &&
110138
!asmName.StartsWith("system") &&
111139
!asmName.StartsWith("mscorlib") &&
112-
!asm.Location.Contains(Settings.GameAssemblyNameHint))
140+
!asm.Location.Contains(Settings.GameAssemblyNameHint, StringComparison.OrdinalIgnoreCase))
113141
{
114142
if (Settings.SuspiciousAssemblies.Any(s => asmName.Contains(s)))
115143
{
@@ -120,22 +148,31 @@ private void CheckMonoInjection()
120148
}
121149
}
122150

123-
// === MODULE: EXTERNAL PROCESS MONITORING ===
151+
// === EXTERNAL PROCESS CHECK ===
124152
private void ScanProcesses()
125153
{
126-
var processes = Process.GetProcesses();
127-
foreach (var proc in processes)
154+
try
128155
{
129-
string name = proc.ProcessName.ToLower();
130-
if (Settings.KnownBadProcesses.Any(bad => name.Contains(bad)))
156+
foreach (var proc in Process.GetProcesses())
131157
{
132-
Log("Blacklisted process: " + name);
133-
Kill();
158+
string name = proc.ProcessName.ToLowerInvariant();
159+
foreach (var bad in Settings.KnownBadProcesses)
160+
{
161+
if (name.Contains(bad))
162+
{
163+
Log("Blacklisted process: " + name);
164+
Kill();
165+
}
166+
}
134167
}
135168
}
169+
catch (Exception ex)
170+
{
171+
Log("Process scan failed: " + ex.Message);
172+
}
136173
}
137174

138-
// === MODULE: SPEEDHACK DETECTION ===
175+
// === SPEEDHACK DETECTION ===
139176
private void CheckSpeedHack()
140177
{
141178
float gameTimeDelta = Time.time - _lastGameTime;
@@ -151,36 +188,39 @@ private void CheckSpeedHack()
151188
_lastGameTime = Time.time;
152189
}
153190

154-
// === MODULE: MEMORY DECOYS ===
191+
// === MEMORY DECOYS ===
155192
[DllImport("kernel32.dll", SetLastError = true)]
156-
static extern IntPtr VirtualAlloc(IntPtr lpAddress, uint dwSize, uint flAllocationType, uint flProtect);
193+
private static extern IntPtr VirtualAlloc(IntPtr lpAddress, uint dwSize, uint flAllocationType, uint flProtect);
157194

158195
private void CreateMemoryDecoys()
159196
{
160-
for (int i = 0; i < 5; i++)
197+
const int decoyCount = 5;
198+
for (int i = 0; i < decoyCount; i++)
161199
{
162-
IntPtr fake = VirtualAlloc(IntPtr.Zero, 4, 0x1000 | 0x2000, 0x40);
163-
Marshal.WriteInt32(fake, 1337);
164-
_decoyPointers.Add(fake);
200+
IntPtr ptr = VirtualAlloc(IntPtr.Zero, 4, 0x1000 | 0x2000, 0x40);
201+
if (ptr != IntPtr.Zero)
202+
{
203+
Marshal.WriteInt32(ptr, 1337);
204+
_decoyPointers.Add(ptr);
205+
}
165206
}
166207
Log("Memory decoys allocated.");
167208
}
168209

169-
// === MODULE: METHOD IL HASHING ===
210+
// === METHOD HASHING ===
170211
private void CacheMethodHashes()
171212
{
172213
var methods = typeof(AXIOM).GetMethods(BindingFlags.NonPublic | BindingFlags.Instance);
173214
foreach (var m in methods)
174215
{
175216
var body = m.GetMethodBody();
176-
if (body != null)
177-
{
178-
byte[] il = body.GetILAsByteArray();
179-
using var sha = SHA256.Create();
180-
string hash = BitConverter.ToString(sha.ComputeHash(il)).Replace("-", "");
181-
_methodHashes[m] = hash;
182-
}
217+
if (body == null) continue;
218+
219+
byte[] il = body.GetILAsByteArray();
220+
string hash = BitConverter.ToString(_sha256.ComputeHash(il)).Replace("-", "");
221+
_methodHashes[m] = hash;
183222
}
223+
184224
InvokeRepeating(nameof(ValidateMethodHashes), 10f, 30f);
185225
}
186226

@@ -193,36 +233,28 @@ private void ValidateMethodHashes()
193233
var body = m.GetMethodBody();
194234
if (body == null) continue;
195235

196-
string current = BitConverter.ToString(SHA256.Create().ComputeHash(body.GetILAsByteArray())).Replace("-", "");
197-
if (current != expected)
236+
byte[] currentIL = body.GetILAsByteArray();
237+
string actual = BitConverter.ToString(_sha256.ComputeHash(currentIL)).Replace("-", "");
238+
if (actual != expected)
198239
{
199-
Log($"IL tampering detected: {m.Name}");
240+
Log("IL tampering detected: " + m.Name);
200241
Kill();
201242
}
202243
}
203244
}
204245

205-
// === MODULE: STACK TRACE CHECK ===
246+
// === STACK TRACE MONITOR ===
206247
private void CheckStackConsistency()
207248
{
208-
string stack = Environment.StackTrace.ToLower();
249+
string stack = Environment.StackTrace.ToLowerInvariant();
209250
if (stack.Contains("dnspy") || stack.Contains("debugger") || stack.Contains("mono.cecil"))
210251
{
211252
Log("Suspicious stack trace.");
212253
Kill();
213254
}
214255
}
215256

216-
// === UTILITIES ===
217-
public static void Initialize()
218-
{
219-
if (_instance == null)
220-
{
221-
var go = new GameObject(Settings.AntiCheatName);
222-
_instance = go.AddComponent<AXIOM>();
223-
}
224-
}
225-
257+
// === LOGGING & RESPONSE ===
226258
private void Log(string msg)
227259
{
228260
Debug.Log($"[{Settings.AntiCheatName}] {msg}");
@@ -232,7 +264,7 @@ private void Kill()
232264
{
233265
if (Settings.QuitOnDetection)
234266
{
235-
Log("Quitting due to violation.");
267+
Log("Terminating game due to security violation.");
236268
Application.Quit();
237269
}
238270
}

0 commit comments

Comments
 (0)