Bringing a 2012 game back to life¶
Clash of Clans v1.70 shipped in 2012. It was built for the iPhones of that era: iOS only, compiled for 32-bit ARMv7. None of that survives in a usable form today — Apple dropped 32-bit support in iOS 11, the game long ago moved on to newer versions, and there's no source code. All that remains of v1.70 is a 4 MB binary.
The game itself is still online today — but the live servers only run the latest version and won't talk to a decade-old client, and there's no server source code to fall back on. So a 2012 client has nothing to connect to.
This project takes that binary and makes the game playable again — not in an emulator-of-an-emulator, but as a native app that runs on modern phones, desktops, and even in a web browser, talking to a brand-new server that speaks the original v1.70 protocol.
Why this version? v1.70 is the very first public release of Clash of Clans — the game in its original 2012 form, before a decade of updates reshaped it. The goal was to bring back exactly this version, with its original features intact — global and local rankings, the full battle simulation, alliances, chat, and more — as a living snapshot you can hold up against today's game to see how far it evolved.
Getting there means making two things work, and the second depends on the first:
- It has to run on modern platforms. The 32-bit iOS app won't launch on any current device, so the game first has to be recovered, translated off ARMv7, and given back the iOS environment it expects.
- It needs a complete, safe server. The game is online, and nothing it can reach still speaks its protocol. But a faithful, authoritative server can't be guessed from network captures — it has to run the identical game logic as the client, or the two desync. So recovering that logic sits underneath everything.
Those needs became four layers of the stack:
-
You can't port what you can't read
The only artifact is a stripped, optimized binary. We turn it back into readable, rebuildable assembly and C++ headers so the game logic can be studied — and re-built — one function at a time.
-
32-bit ARM won't run on modern CPUs
We built a static ARM recompiler that rewrites every ARM instruction as equivalent C++ ahead of time. The game becomes ordinary C++ that any modern compiler can target — arm64, x86, or WebAssembly.
-
The binary expects an iPhone from 2012
The game calls into iOS: UIKit, OpenGL ES, sockets, the filesystem,
malloc. We re-implemented that whole environment as a portable runtime, with a thin platform backend for each host. -
The live servers moved on
A 1.70 client can't talk to today's servers, and the original code is gone. We rebuilt a compatible server in C#, reusing the reverse-engineered game logic through a C++→C# transpiler — and reproduced the game's deterministic lockstep sync.
The whole stack at a glance¶
flowchart TB
subgraph SRC["The only input we had"]
BIN["Clash of Clans<br/>4 MB ARMv7 iOS binary · 2012"]
end
subgraph RE["1 · Reverse engineering"]
ASM[".S assembly + .h headers<br/><i>byte-identical, rebuildable</i>"]
end
subgraph CLIENT["The client"]
LIFT["2 · armv7re<br/>static ARM → C++ recompiler"]
CPP["Portable C++<br/><i>the whole game, as functions</i>"]
RT["3 · runtime<br/>iOS environment emulator"]
APP(["Native app<br/>arm64 · x86 · WebAssembly"])
end
subgraph BACKEND["The server"]
CPP2CS["cpp2cs<br/>C++ → C# transpiler"]
SRV["4 · C# game server<br/><i>safe, crash-resistant</i>"]
end
BIN -->|IDA + decomp pipeline| ASM
ASM -->|lifted at build time| LIFT --> CPP
CPP --> APP
RT --> APP
ASM -.->|game logic ported| CPP2CS --> SRV
APP <-->|"original 1.70 protocol<br/>(RC4 over TCP)"| SRV
The left-to-right story: a single binary becomes readable assembly; that assembly is recompiled into portable C++ that runs natively on any CPU; a runtime supplies the iOS environment the game expects; and a from-scratch C# server — populated with game logic transpiled straight from the same reverse-engineered code — gives it something to talk to.
Clash of Clans v1.70, rebuilt — running natively today.
How to read these docs¶
The four layers are independent enough to read in any order, but they were built in the order below, and each one explains why it was necessary before how it works:
- Reversing the binary — from a 4 MB blob to rebuildable source.
- The static recompiler — ARM instructions → C++, ahead of time.
- The iOS runtime — re-implementing iOS so the game feels at home.
- The C# server — a safe, modern reimplementation of the backend.
- Running it everywhere — the same game on macOS, iOS, Android, and the web.
Why not just use an emulator?
A general-purpose emulator (like a dynamic recompiler / JIT) can run the binary, but it can't ship on the App Store (JITs are banned), can't run in a browser, and pays an interpretation tax forever. By translating the game to C++ once, at build time, we get a normal native binary on every platform with no runtime translation cost. That trade-off is the spine of the whole project — see the recompiler chapter.