Skip to content

About

XOR-encrypted primitive types for C#/Unity - keeps ints, floats and bools ciphered in memory to blunt Cheat Engine-style tampering.

Topics

Resources

Stars

0 stars

Watchers

1 watching

Forks

Latest commit

 

History

6 Commits

Folders and files

Repository files navigation

super-simple-security

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.

Features

  • 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 — SecurityListener delivers hack-detected and internal-error events.
  • Behaves like a primitive — implements IComparable, IEquatable, IFormattable, with an implicit conversion back to the primitive type.

Supported types

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

Installation

Unity

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/.

Plain .NET

Add the Security/Security/ project to your solution, or reference the built DLL.

Usage

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);
    }
}

Caution: there is no implicit primitive → Security conversion

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.

Compile symbols

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.

How it works

  1. 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 ^ key is written into that slot
  2. GetValue() XORs the stored value with the key to restore it
  3. In the default mode, both copies are decrypted and compared right before a write — a mismatch calls SecurityListener.OnHackDetect()
  4. Boolean encodes true as 13 and false as 20 before XOR, and decodes by odd/even
  5. Single is split into 4 bytes, each XOR-ed individually

Limitations

  • 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 and Single's decode buffer are static. 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 .Value and persist/transmit the primitive instead.

Example project

Exmaple/ — a Unity 2018.3.0f2 project. Open Assets/Examples/Scenes/ExampleScene.unity and play; SecurityExample.cs demonstrates value creation, assignment, and listener registration.

License

MIT License. Copyright (c) 2019 Minu Baek. See LICENSE for details.

About

XOR-encrypted primitive types for C#/Unity - keeps ints, floats and bools ciphered in memory to blunt Cheat Engine-style tampering.

Topics

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages