11// AXIOM.cs - Open Source Unity Anti-Cheat Runtime Framework
2+ // Author: Mike
3+ // License: MIT
4+ // Version: 1.3
25
36using System ;
47using 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