English | 한국어
A very simple XOR-based secure value library for defending against memory tampering (Cheat Engine and friends).
It provides drop-in structs for C# primitives — Security.Int32, Security.Single, and so on — that keep their
value XOR-encrypted in memory at all times.
Unity example project included.
- No plaintext in memory — values are stored XOR-encrypted and only decrypted on read.
- Rotating key and slot — every write regenerates the XOR key and moves the storage slot inside a 3-cell backing store (
ValueArray<T>). The same logical value looks different in memory every time. - Tamper detection by dual copies — in the default mode two encrypted copies (
m_chiper,m_chiperCmp) are kept; every write compares them and reports a hack on mismatch. - Detection callbacks —
SecurityListenerdelivers hack-detected and internal-error events. - Behaves like a primitive — implements
IComparable,IEquatable,IFormattable, with an implicit conversion back to the primitive type.
| Security | Primitive |
|---|---|
Security.Boolean |
bool |
Security.Byte |
byte |
Security.Int16 |
short |
Security.Int32 |
int |
Security.Int64 |
long |
Security.Single |
float |
Security.UInt16 |
ushort |
Security.UInt32 |
uint |
Security.UInt64 |
ulong |
Copy Security/Security/bin/Debug/Security.dll into your project's Assets/Plugins/.
(The example project already ships it at Exmaple/Assets/Plugins/Security.dll.)
To use the sources directly instead, copy Security/Security/*.cs anywhere under Assets/.
Add the Security/Security/ project to your solution, or reference the built DLL.
using Security;
public class Player
{
public Int32 Gold;
private Boolean _isClear;
void Init()
{
// Register hack-detection / error listeners
SecurityListener.SetOnHackDetectListener(OnHackDetected);
SecurityListener.SetOnErrorListener(OnError);
// Initialize through the constructor
Gold = new Int32(8801);
// Or assign through the Value property
Gold.Value = 8801;
// Conversion to the primitive type is implicit
int total = Gold.Value + 100;
_isClear = new Boolean(false);
if (_isClear) { /* Security.Boolean -> bool, implicit */ }
}
void OnHackDetected(string message)
{
Debug.LogError(message);
Application.Quit();
}
void OnError(string error)
{
Debug.LogError(error);
}
}Security.Int32 gold = 100; does not compile.
(The corresponding implicit operator is commented out in the sources.)
Use new Int32(100) or gold.Value = 100.
| Symbol | Where | Effect |
|---|---|---|
| (none, default) | — | Keeps two copies and compares them on write → tamper detection enabled |
SIMPLE_SECURITY |
each type's .cs |
Keeps a single copy. Still encrypts, but performs no tamper detection (lighter) |
NO_SECURITY |
each type's .cs |
Stores the raw value with no encryption. For debugging / performance comparison |
UNITY_EDITOR |
defined by Unity | Also keeps a plaintext m_debugValue and checks it against the decrypted value (self-check). Exposes the editor-only ErrorValue property |
SHIFT_WHEN_GET |
Security.cs |
Also rotates key and slot on read. Stronger, at the cost of read performance |
FAST_FLOAT |
Security.cs (on by default) |
Decodes Single with bit operations and a static buffer instead of BitConverter.GetBytes |
ErrorValue (editor only) deliberately desyncs the copies so you can exercise the hack-detection path.
- On
SetValue():KeyGenerator.NewIndex()moves the storage slot one step forward or back (3-slot cycle)- A fresh XOR key is taken from
KeyGenerator(keys increment per call, seeded randomly) value ^ keyis written into that slot
GetValue()XORs the stored value with the key to restore it- In the default mode, both copies are decrypted and compared right before a write — a mismatch calls
SecurityListener.OnHackDetect() Booleanencodestrueas 13 andfalseas 20 before XOR, and decodes by odd/evenSingleis split into 4 bytes, each XOR-ed individually
- This is not cryptographic security. It is a single-byte/word XOR, and the key lives in the same process memory. The goal is only to make naive memory scanning and value freezing harder.
- Not thread-safe.
KeyGenerator's keys andSingle's decode buffer arestatic. Do not touch these values from multiple threads. - It costs something. Every read does an XOR; every write generates a key and (in the default mode) updates two copies. Not suited for values in per-frame hot loops — use it for currency, score, stats, and other tamper targets.
- Not directly serializable. The internal representation differs run to run, so read
.Valueand persist/transmit the primitive instead.
Exmaple/ — a Unity 2018.3.0f2 project. Open Assets/Examples/Scenes/ExampleScene.unity and play;
SecurityExample.cs demonstrates value creation, assignment, and listener registration.
MIT License. Copyright (c) 2019 Minu Baek. See LICENSE for details.