← All stories
2006

muo.lv: twelve years of running a game I didn't have the source code for

In August 2005 a friend suggested starting a private MuOnline server to compete with the biggest one in Latvia. I took the programming. We opened on 21 February 2006; within weeks there were 300–400 players online, and the project lived on for more than ten years and six game seasons.

The catch: the game server was a closed binary. I could not change its core — so I attacked it from every side I could reach:

  • DLL injection on both ends — into the game client for the anti-cheat, and into the server process to hook its network layer;
  • a proxy in front of the server that saw every packet;
  • triggers in the game’s database that saved extra information the server itself never recorded;
  • log scanning to react to what happened in the game.

Everything that made muo.lv different was built around the closed core.

The website was the product. About 40k lines of PHP on MS SQL: a player market (the feature that brought players over from the competitor), item and character auctions, a credit exchange, quests, rankings and online charts, guilds, private messages, VIP, account recovery by phone, SMS and PayPal payments — and a GM panel of ~50 pages: dupe search, item generator and decoder, chat and trade logs, bans, server restarts. Every item got a unique serial and a history, which killed item duplication.

My own anti-cheat (2009). A client DLL hooked network calls, library loading and OpenGL frames: it detected speedhacks by comparing two clocks, blocked memory editors and injected DLLs, and wrapped the network protocol in its own encryption, sending a hardware fingerprint and MD5 of the client files.

A proxy in front of every game server. Since I couldn’t change the server, I put a C# man-in-the-middle in front of it. It decrypted the anti-cheat layer, refused clients with modified files, enforced bans by IP and hardware ID, parsed game packets, logged chat, pushed global messages from the website, and caught an exploit in the item-crafting machine by checking forbidden recipe combinations before the server saved them.

Ops, by hand, before it was called DevOps. A watchdog agent on every server process restarted crashes and accepted commands over TCP; about fifteen processes were orchestrated from a config on the website. A launcher updated the client file by file by MD5, CPU load went into the database, and a “disconnect from web” button kicked a stuck character.

A bot that ran events. The website queued commands in SQL; the watchdog typed them into a real game client with admin rights. A state machine announced a PvP event in global chat, counted down, teleported registered players to random spots in an arena and found the winner from the kill logs.

What it taught me: when you can’t change the core, build a layer around it — proxy, hooks, queues — and make the product there.