"A Mandalorian never removes their helmet. But some doors demand a creed."
A beginner CrackMe written in JavaScript — a focused runtime-obfuscation exercise themed around The Mandalorian. The project demonstrates how to serialize a self-contained validator, encrypt it at build-time, and reconstruct it at runtime so the validation logic isn't plainly visible in the distributable.
The challenge: figure out what to say when the program asks you to Speak the Creed.
node MandoCrackme.js
██╗ ██╗██╗ ██╗ ██████╗ ██╗███████╗
██║ ██║██║ ██║██╔═══██╗ ██║██╔════╝
██║ █╗ ██║███████║██║ ██║ ██║███████╗
██║███╗██║██╔══██║██║ ██║ ██║╚════██║
╚███╔███╔╝██║ ██║╚██████╔╝ ██║███████║
╚══╝╚══╝ ╚═╝ ╚═╝ ╚═════╝ ╚═╝╚══════╝
████████╗██╗ ██╗███████╗
██╔══╝██║ ██║██╔════╝
██║ ███████║█████╗
██║ ██╔══██║██╔══╝
██║ ██║ ██║███████╗
╚═╝ ╚═╝ ╚═╝╚══════╝
W A Y
┌─────────────────────────────────────────┐
│ A Mandalorian never removes their │
│ helmet. But some doors demand a creed. │
└─────────────────────────────────────────┘
Speak the Creed, Foundling: _
If you speak truly, the Covert welcomes you. If not — I have spoken.
Just Node.js. No dependencies, no npm install.
node --version # anything v14+ worksThis project is an exercise in runtime code obfuscation — the validation logic is not present in plaintext inside the distributable. Instead the validator is serialized and encrypted at build-time, then rebuilt and executed at runtime.
[Encrypt.js] (build time, run once)
│
│ 1. serialize validate() to a string
│ 2. XOR-encrypt it with key 0x1337
│ 3. output: encrypted byte array
│
▼
[MandoCrackme.js] (ships to the user)
│
│ at runtime:
│ 4. XOR-decrypt the byte array → JS source string
│ 5. eval() the string → live function
│ 6. call it with the user's input
│
▼
Correct / Wrong
A concise mapping of the project's build-time and runtime steps (all in JavaScript):
- Build-time serialization:
Function.prototype.toString()turns thevalidate()function into source text. - Build-time encryption:
Encrypt.jsXOR-encodes the serialized source into a numeric byte array (ENCRYPTED_PAYLOAD). - Embedded payload: the runtime script ships the encrypted numeric array; the validator's source isn't present in plain text.
- Runtime reconstruction:
xorDecrypt()converts the byte array back to the original source string, andeval("(" + funcSource + ")")recreates the callable function. - Execution: call the reconstructed
validate(input)to check user input. - Purpose: keep validation logic out of plaintext to raise the bar for casual static analysis.
This is the file the player runs. It contains:
ENCRYPTED_PAYLOAD— the serializedvalidate()source, XOR-encrypted and stored as a numeric array.xorDecrypt()— decrypts the payload at runtime using key0x1337.- Reconstruction & execution — the decrypted source is parsed (via
eval) into a function and executed with the user's input. - The flag comparison is case-sensitive.
// Runtime flow (simplified)
const funcSource = xorDecrypt(ENCRYPTED_PAYLOAD, 0x1337);
const validateFn = eval("(" + funcSource + ")");
return validateFn(input);You don't need this to play the crackme. Run it when you want to generate or update the encrypted payload embedded in MandoCrackme.js.
It does three things:
- Defines a self-contained
validate()function (store any secret data inside the function so it does not rely on outer scope). - Serializes it to a source string via
Function.prototype.toString(). - XOR-encrypts the serialized source using key
0x1337and prints the numeric array for embedding.
Run it to re-generate the payload:
node Encrypt.js
# outputs the new ENCRYPTED_PAYLOAD array → paste into Mando crackme.jsThis demo shows a common pitfall in JavaScript: if a validator depends on outer-scope variables (a closure), serializing it and re-evaluating it in a new, isolated scope severs that closure and those outer variables are no longer available.
The demo uses new Function(src) to simulate evaluating serialized code in an isolated context. It contrasts a broken validator that references an outer variable with a fixed, self-contained validator that keeps the secret data inside a local array.
node RodataBugDemo.js- How to serialize and reconstruct live functions at runtime in JS
- XOR encryption/decryption with a multi-byte key
- Why self-contained code matters when it's relocated (closure-severing)
- How runtime reconstruction raises the bar for static analysis
MIT — do whatever you want with it. This is the Way.