This is Valve's attempt at a non-trivial DRM. When you download a game from Steam that has CEG enabled, Steam will generate a unique EXE just for you. The easiest way to defeat CEG is through LumaCEG. LumaCEG can be found in cs.rin's Main Forum -> Releases section (thread ID 64354). The important files to grab here are the x86 and x64 plugins, but grabbing the main injection file as well is a good idea for your toolkit. Defeating CEG with LumaCEG has two stages:
-
A legitimate owner of the game must inject LumaCEG into their Steam client, so that the CEG EXE will be anonymized at download time from Steam. This EXE can then be shared with others.
-
A user will take an anonymized EXE, then inject the LumaCEG dll into the game at runtime, auto-defeating CEG
Stage 1 requires a Windows installation of Steam, because LumaCEG's injection method was never replicated for Steam on Linux. I personally don't like the idea of hacking into a running Steam client to create these EXEs from my legitimate games, because I don't want to get unlucky and have my Steam account be banned for tampering. Luckily, anyone can create and upload these anonymized EXEs, and CEG is old tech that was only used on ~100 games ever, so I prefer to use the ones that others have generated instead. You can find a thread full of these EXEs on cs.rin with the title "Collection of LumaCEG Binaries" (thread ID 71822). If you'd rather not rely on others and want to generate your own anonymized EXEs that is also a great option.
Stage 2 requires LumaCEG to be injected into the game at runtime. Thankfully, there's a project named Koaloader that makes this a lot easier. Grab the latest version of this for your toolkit.
August 2025 NOTE: There's a new open source project named NoCEG that can patch CEG functions directly in the executable instead of emulating them at runtime as LumaCEG does. This would be ideal for us primarily because it's open source, but I'm not currently able to get it to work under Linux (last version tested: v1.1.0). It doesn't do anything other than generate an opening log entry and close. I tested 3 CEG-protected games through legitimate Steam directly and through airgapped Lutris with fake Steam emulation. If you're trying this yourself, make sure you wait for a few minutes after Steam downloads your game so that it can apply the CEG protection to the executable - this needs to happen before NoCEG can use its patching process. I'm keeping my eye on this tool in case it's improved a bit further and can replace LumaCEG for our purposes, but in the meantime there's nothing wrong with LumaCEG other than it being closed-source. It's worth noting that NoCEG's author seems opinionated about keeping hardware/user-identifying info in the patched executable whereas historically LumaCEG-based methods prefer to keep that anonymized. Removing the identifying info yourself is apparently trivial by downloading the executable twice and zeroing out the sections that don't match, so that can be circumvented regardless. Also, we would prefer to patch CEG ourselves for traceability's sake, but since there are only a handful of CEG games and people will inevitably zero-out, patch, and upload the CEG executables to cs.rin, you could also just download a NoCEG-processed copy that a Windows user has done if you want to cheat a bit. More discussion on this tool will probably be found in the latest posts in the LumaCEG thread under Main Forum -> Releases section (thread ID 64354), unless discussion gets moved to its own thread or etc.
For our walkthrough we'll be cracking the CEG DRM on the Windows version of "Saints Row - The Third" (hereafter referred to as SRTT for my sanity). This game is easy to source via cs.rin's Main Forum (thread ID 60550), or you can follow along with your own CEG-protected game. SRTT is protected with CEG and Steamworks API.
-
Source SRTT and extract it to your workspace
-
Defeat Steamworks API protection (this will usually be present on a game if CEG is present)
-
Source SRTT's anonymized CEG EXEs (read the intro of this page if you're lost)
-
Overwrite
SaintsRowTheThird.exeandSaintsRowTheThird_DX11.exewith the two new anonymized EXEs -
Since SRTT is 32-bit, we'll copy
LumaCEG_Plugin_x86.dllandLumaCEGPlugin.inifrom LumaCEG into the SRTT directory -
Now LumaCEG is ready to auto-defeat CEG, but it needs to get injected into the runtime first. To inject LumaCEG, we're going to use a general purpose injection tool named Koaloader. Refer to the Koaloader Guide for more information on how this tool works.
-
At this point, we need to determine which Koaloader DLL the game will reach out and grab. Since SRTT is a 32-bit game, we'll use 32-bit Koaloader DLLs. As a first try, let's use
glu32.dll. -
Copy
glu32.dllfrom theglu32-32Koaloader folder into the SRTT directory. -
Copy
Koaloader.config.jsonfrom Koaloader's root folder into the SRTT directory, and edit the configuration so it reads as follows:{ "logging": true, "enabled": true, "auto_load": false, "targets": [ "SaintsRowTheThird.exe", "SaintsRowTheThird_DX11.exe" ], "modules": [ { "path": "LumaCEG_Plugin_x86.dll", "required": true } ] } -
Koaloader is almost ready to be injected, but since we're using Wine, we need to tell Wine to leave our DLL alone. By default, Wine hijacks some DLLs that load and replaces them with its own versions at runtime. We're going to explicitly tell Wine that if it sees our DLL, it should let it load without interfering. If it doesn't see the DLL we specify, then it will try to load its own DLL as normal.
-
We can inform Wine of this configuration by using Lutris. If you use another tool, there should be a section somewhere for this, or worst-case you can use the
WINEDLLOVERRIDESenvironment variable, likeWINEDLLOVERRIDES="glu32=n,b". To do this in Lutris, open your game's configuration and navigate toRunner Options->DLL Overrides. Inputglu32as a key andn,bas a value.n,bstands for "Native, then Built-in", aka Wine should preferentially let the game's local DLL load if available, or fallback to the Built-in Wine version if it's not. -
Now Koaloader is ready to be injected the next time the game runs.
-
Start SRTT and observe that nothing happens. At the very least, we're looking for a file named
Koaloader.log.logto be created in the directory, which means that the game attempted to load our disguised DLL. -
Back to the drawing board - let's try another DLL. You can pick whatever DLL variant you want to try next, but since I'm omniscient I know that one of the right answers for SRTT is
winmm.dll. Other games will need other variants of Koaloader in order to work. The Koaloader guide has a section on deterministically finding a DLL name, if you don't like guessing. -
Delete
glu32.dllfrom the directory and replace it with the 32-bit version ofwinmm.dllfrom Koaloader. -
Replace our
glu32DLL Override key withwinmm -
Start the game again. This time it launches! We can read
Koaloader.log.logand see that the following happened:🟩│ 14:08:13.824 │ 206:koaloader.cpp ┃ 🐨 Koaloader 📥 v3.0.2 | Compiled at 'Sat Jan 14 03:33:31 2023' ⬛│ 14:08:13.824 │ 209:koaloader.cpp ┃ Executable path: "C:\Games\Saints Row the Third\SaintsRowTheThird_DX11.exe" [32-bit] ⬛│ 14:08:13.824 │ 210:koaloader.cpp ┃ Current working directory: "C:\Games\Saints Row the Third" ⬛│ 14:08:13.824 │ 211:koaloader.cpp ┃ Koaloader directory: "C:\Games\Saints Row the Third" ⬛│ 14:08:13.824 │ 31:koaloader.cpp ┃ Target found: 'SaintsRowTheThird_DX11.exe' ⬛│ 14:08:13.824 │ 136:koaloader.cpp ┃ Beginning search in "C:\Games\Saints Row the Third" 🟩│ 14:08:13.842 │ 64:koaloader.cpp ┃ ✅ Loaded module: "LumaCEG_Plugin_x86.dll" 🟩│ 14:08:13.842 │ 227:koaloader.cpp ┃ 🚀 Initialization complete -
CEG is now defeated!


