# Backend Reversing

> Reverse-engineer a game or software backend from its compiled client and reconstruct an authoritative server emulator. Use this whenever the user is reversing a client-server protocol, analyzing netcode or packet formats, decompiling a Unity / Unreal / Godot client to recover its network structures, decoding captured Protobuf / FlatBuffers / gRPC / TLV payloads, analyzing a Diffie-Hellman / RSA / ECDHE handshake, or standing up a private or emulated server for a defunct, offline, or owned game. Trigger on phrases like "reverse engineer the server", "emulate the backend", "private server", "figure out the packet format", "decode this protocol", "what serialization is this", "map the game's API", "il2cpp dump", "recover the .proto", or "the client talks to a server I no longer have". Scope is AUTHORIZED work only — game preservation, security research on software you own or are cleared to test, interoperability, and CTF. It pairs every offensive finding with the matching server-side hardening, so it doubles as

- Skill: `stoica-mihai/backend-reversing` (Agent Skill, multi-file: 9 files)
- Install (CLI): `npx skillmds@latest add stoica-mihai/backend-reversing`
- Raw SKILL.md: https://api.skillmd.com/api/skills/stoica-mihai/backend-reversing/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Security
- Author: Stoica-Mihai (https://skillmd.com/u/stoica-mihai)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/stoica-mihai/backend-reversing

---


# Backend Reversing

Reconstruct a server from a client. The client is a deterministic state
machine that must parse, validate, and serialize everything the server
understands — so the compiled client already contains the complete shape of
the protocol. This skill walks that shape out of the binary and turns it into
a running emulator, and it pairs each step with the hardening that would have
stopped it.

## Before anything: scope and footing

This pipeline only makes sense — and is only appropriate — against a target
you are allowed to analyze. Confirm one of these holds before you start, and
say which in your report:

- **Preservation** — a defunct or offline game whose official servers are
  gone, or a game with an offline/single-player mode you are studying locally.
- **Ownership** — software you wrote or own.
- **Authorization** — a sanctioned engagement, bug-bounty scope, or written
  permission to test.
- **CTF / research** — a challenge target or a lab environment built for this.

Two things this skill deliberately does **not** do, because they move the work
out of that scope: circumventing live-service anti-cheat or DRM to force a
protected client into an analyzable state, and defeating certificate pinning or
instrumentation-detection on a production service. Analyze a target that is
already in a state you may study — an offline build, a local instance, a
defunct client — rather than breaking an active protection to get there. If the
user needs the protection gone first, that is where this skill stops.

## The pipeline

Seven phases. Most projects run them roughly in order, but they feed back into
each other — a serialization finding sends you back to the decompiler, a
handshake finding changes how you capture. Do not treat this as a waterfall.

1. **Client audit** — locate the game objects and the netcode in memory.
2. **Identify the engine** — the engine dictates every tool after this.
3. **Decompile** — recover class names, field offsets, and method signatures.
4. **Reach the plaintext** — capture buffers before encryption, and understand
   the handshake well enough to know you can.
5. **Model the protocol** — framing, compression, serialization, endpoints.
6. **Emulate** — a concurrent authoritative server that speaks the protocol.
7. **Harden** — for each finding, the server-side fix that closes it.

### Phase 1 — Client audit

Two complementary reads of the running (or on-disk) client.

**Memory and class discovery.** Runtime state — health, resources,
coordinates, status — lives contiguously in the process. A scanner (Cheat
Engine, or scripted with a memory-access library) isolates a value by *delta
scanning*: search a data type, change the value in-game, search again for the
new value, repeat until one address remains. Then a hardware breakpoint via the
debug registers ("find what writes to this address") halts on the instruction
that mutates it and exposes the offset form — `MOV [RCX + 0x18], EAX` says the
value sits at `+0x18` in the object `RCX` points at. Neighboring offsets are
usually the sibling fields the compiler grouped into the same object, so one
breakpoint often maps a whole class. Those offsets are the same fields the
server must track.

**Netcode hooking.** To read payloads *before* symmetric encryption or
compression, hook the send/receive path rather than the wire. On Windows the
targets are the Winsock calls `send`, `recv`, `WSASend`, `WSARecv`; a small
Detours-based DLL logs the buffer and passes the call through. That buffer is
plaintext — the client has to hand the socket cleartext, whatever it did
before. This is almost always faster than attacking the crypto (Phase 4).

Do this against a client already in an analyzable state (see scope). If the
target is a native (non-managed) binary, `x64dbg` / Ghidra / IDA on the on-disk
executable get you the same offsets statically.

### Phase 2 — Identify the engine

Everything downstream depends on it. Quick tells:

- **Unity** — `UnityPlayer.dll`, a `*_Data/` folder, `GameAssembly.dll` +
  `global-metadata.dat` (IL2CPP) or `Managed/*.dll` (Mono).
- **Unreal** — `*/Binaries/`, `*.pak` files, `*-Shipping.exe`, engine strings.
- **Godot** — a `.pck` next to the executable, or data appended to the exe;
  `project.godot` inside the pack.

Then read `references/engines.md` for the exact per-engine recovery route. Do
not proceed on memory of one engine's toolchain — the metadata formats, the
dumpers, and the failure modes differ sharply.

### Phase 3 — Decompile

Recover the type system: class names, field offsets, method signatures, and the
serialization functions. The output you want is a map from raw offsets and
native subroutines back to meaningful names, so that a captured buffer becomes
readable structs. The engine reference covers IL2CPP (Il2CppDumper / Cpp2IL,
dummy DLLs, Ghidra scripts, encrypted-metadata recovery), Unreal (GObjects /
GNames SDK generation), and Godot (`.pck` extraction, GDScript decompilation).

If the local save or config is encrypted, the same decompiled code holds the
key-derivation routine — trace the save/prefs initializer. A recurring pattern
is `Rfc2898DeriveBytes(folder_name + static_constant, static_salt)` feeding
AES-128-CBC. Recovering that lets you read local state, which often documents
field meanings the network protocol leaves implicit.

### Phase 4 — Reach the plaintext

You rarely break the crypto; you capture around it (Phase 1 hook) or you find
the key in memory (Phase 3). But you must understand the handshake to know
which is possible and to replicate it in the emulator, because the server side
has to perform the other half.

`references/crypto-handshakes.md` covers Diffie-Hellman (and ephemeral
DHE/ECDHE), RSA key transport, and the KDF-to-AES step, with the reversing
implications of each — most importantly that a static-RSA session can be
decrypted after the fact if the server key leaks, while an ephemeral exchange
cannot, which changes whether captured traffic alone is enough.

### Phase 5 — Model the protocol

Turn captured bytes into a schema. Order of operations on a raw buffer:

1. **Deframe.** Most custom protocols are Type-Length-Value. Split the stream
   into frames before anything else — `scripts/tlv_parse.py`.
2. **Decompress.** Large payloads are often compressed; the magic bytes tell
   you which — `scripts/identify_payload.py` detects and unwraps common
   formats and then guesses the serialization inside.
3. **Deserialize.** Protobuf, FlatBuffers, gRPC, or MessagePack. For a
   schemaless Protobuf capture, `scripts/decode_protobuf.py` walks the wire
   format with no `.proto`. The rest — FlatBuffers vtable tracing, gRPC vtable
   deconstruction in stripped C++ binaries, MessagePack reconstruction — is in
   `references/serialization.md`.

UDP protocols usually add a reliability layer (sequence numbers, ack flags) on
top of the framing; account for it before assuming a frame boundary.

### Phase 6 — Emulate

Build an authoritative server that speaks the recovered protocol and holds the
real game state. `references/emulator.md` covers the two dominant concurrency
models (Rust/Tokio async, C++/actor), persistence with a write-behind cache so
per-action DB writes don't bottleneck, loading client template data so the
server's math matches the client's, and replication managers for scaling world
state. The central rule: the server is authoritative and validates every
incoming payload — never trust the client's numbers.

### Phase 7 — Harden

The reason to keep the defensive pairing in view: a backend that survived this
process would have made each phase harder. Emit these alongside the findings —
they are the deliverable for anyone doing this *to* protect a service.

- **Server authority.** Treat the client as a compromised UI. Validate every
  payload against physics and game-state bounds before it touches the database.
  This defeats the Phase 1 memory edits and injection outright.
- **Centralize rules.** Keep drop tables, economy, and security checks on the
  server, never the client. A memory scanner can only reach what the client
  computes.
- **Modern, ephemeral crypto.** TLS or ECDHE gives forward secrecy — a leaked
  server key does not retroactively decrypt captured sessions.
- **Protect metadata.** Encrypting `global-metadata.dat` and stripping symbols
  does not stop a determined analyst, but it raises the cost of Phase 3.
- **Verify the client.** mTLS or a real handshake makes an unauthorized
  third-party emulator unable to connect to production.

## Bundled scripts

All four are pure-Python (standard library only), operate on data you have
already captured, and are safe to run repeatedly. Point them at a hex string or
a file.

| Script | Use it when |
|---|---|
| `scripts/identify_payload.py` | You have a raw buffer and do not know what it is — detects compression (gzip/zlib/bzip2/xz) and unwraps it, then guesses the serialization inside. Run this first on any unknown payload. |
| `scripts/tlv_parse.py` | The stream is Type-Length-Value framed and you need it split into frames. Configurable type/length width and endianness. |
| `scripts/decode_protobuf.py` | You captured a Protobuf message but do not have the `.proto`. Walks the wire format and prints a field tree, recursing into nested messages. |
| `scripts/il2cpp_metadata_probe.py` | A Unity IL2CPP `global-metadata.dat` fails to load — checks the header magic and version, and detects/recovers a single-byte XOR obfuscation of the header. |

Run any of them with `--help` for arguments. They compose: `tlv_parse.py`
splits frames, `identify_payload.py` triages each value, `decode_protobuf.py`
decodes the ones that are Protobuf.

## References

Read the one the current phase needs; do not preload all of them.

| File | Contents |
|---|---|
| `references/engines.md` | Per-engine decompilation: Unity IL2CPP (dumpers, dummy DLLs, Ghidra integration, encrypted metadata), Unreal (GObjects/GNames SDK generation), Godot (`.pck`, GDScript). |
| `references/serialization.md` | Protobuf vs FlatBuffers, `--decode_raw`, FlatBuffers vtable tracing, gRPC stripped-C++ vtable deconstruction, MessagePack. |
| `references/crypto-handshakes.md` | Diffie-Hellman, DHE/ECDHE, RSA transport, the KDF-to-AES step, and what each means for capture and emulation. |
| `references/emulator.md` | Concurrency models, persistence and write-behind, template data, replication managers, and the server-authority rules. |

## Output format

When you run this skill for a user, produce a running findings document, not a
lecture. Structure it as:

1. **Scope** — which authorized footing applies, and the target's state.
2. **What was recovered** — engine, key classes and offsets, protocol framing,
   serialization format, endpoint list, handshake type. Concrete: names,
   offsets, field numbers, not "the protocol was analyzed".
3. **Open unknowns** — what is not yet mapped and what would map it.
4. **Emulator plan** — concurrency model, persistence, the endpoints to
   implement first.
5. **Hardening** — the Phase 7 pairing for each finding.

Lead with what you actually recovered. A precise `Login = TLV type 0x02, body
is Protobuf, field 1 = username (string), field 2 = client_version (varint)` is
worth more than a page of methodology the user already has.

