Skip to content

Instantly share code, notes, and snippets.

@hardware
Created August 19, 2012 14:04
Show Gist options
  • Star 21 You must be signed in to star a gist
  • Fork 5 You must be signed in to fork a gist
  • Save hardware/3395025 to your computer and use it in GitHub Desktop.
Save hardware/3395025 to your computer and use it in GitHub Desktop.
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@ Reversing Steam CEG Protection @@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@ by Push_BirthDay_Ret @@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
Best viewed with notepad++
JUN 2012
Hallo to all readers out there. It has been a long time since I wrote a paper on
reverse engineering. But I couldn't hold myself with Valve's baby.
I want to make myself Clear. This paper does not intend to make any harm to Valve or any other
S/W house that uses this Tech. I will fully disclose the CEG protection and the way I worked
to reverse engineer it and bypass it. By using this information you will be able to defeat
CEG in a generic way but not bypass User/Game authentication on Steam. Use the information at
your own risk. I do not take any responsibility if the knowledge here is used for actions
that are considered illegal on any part of the world.
So, what is CEG? CEG stands for Custom Executable Generation and is part of Steam DRM. The CEG
is applied on binary files (DLLs, EXEs etc.). It "Binds" the game with the computer on which it
runs. So, even if somebody defeates the typical User/Game authentication, by moving the
game to another pc and run it, it won't make the game run. Let me give you an example with
an Authenticated user. Imagine that I am an authenticated user on Steam and I have bought
Game-1. I have installed Game-1 on PC-1. I now decide to copy the game to another PC, let
us say PC-2. So, I backup the game using Backup option in Steam Client on PC-1 and I Restore
it on PC-2. If I run the game on PC-2, dispite the fact that I am an authenticated user
for this game the game will not run on PC-2. This is because protection "Understands" that the
protected file/files are trying to run on a different PC. The game should connect on
Steam servers, servers will ask and get some information from PC-2 and a new version of the
binary/binaries that are protected with CEG will be created. Eventually, the binary files
will be replaced with new ones and after that, the game will run.
A full Steam DRM crack requires User/Game authentication bypass and CEG bypass. As I said
earlier, I will not give out information regarding User/Game authentication bypass. But you
can still check that CEG has been bypassed if you Restore the legit game to another PC,
login to Steam and change to Offline mode. Now Steam Client will not be able to overwrite the
CEG protected binary/binaries (because it is in Offline mode) and game will not run due
to CEG protection. By using the information in this paper you will be able to make it run.
The game I tested was FEAR3 in Windows XP SP3 machine. I used Olly debugger and Process Monitor.
I also used Protection ID tool to find out what files of the game are CEG protected (althought I
do not care because the way of bypassing CEG as you will later see is a more generic one).
The Protection ID tool showed me that file "F.E.A.R. 3.exe" is CEG protected. This is the
Main executable of the game.
I first created a VM box using VMware Player. So, the VM is on the Physical machine. I then Backed
up the game from the physical machine and I Restored it inside the VM. I logged into Steam and
changed the mode to Offline. Now I want to make the game run, but not from the Steam Client. I need
the game to run by running the main executable (F.E.A.R. 3.exe) in order to be able to debug it.
For doing this, I had to create a file inside the folder where the Main executable of the game exists.
In my case the Folder is:
C:\Program Files\Steam\steamapps\common\f.e.a.r. 3
The file you need to create is called "steam_appid.txt" and contains a number. This number is
the Application ID of the game. You can find the Application ID of any game just by searching
on Steam site. You do that. In my case and for that particular game the contents of the file is
5 bytes long:
21100
But how did I find out that I should create this file with this content? After debugging a little
I came accross the function SteamAPI_RestartAppIfNecessary(). I searched over the Internet
and here is the information I found:
----------------------------------------------------------------------------------------------------
// Detects if your executable was launched through the Steam client, and restarts your game through
// the client if necessary. The Steam client will be started if it is not running.
//
// Returns: true if your executable was NOT launched through the Steam client. This function will
// then start your application through the client. Your current process should exit.
//
// false if your executable was started through the Steam client or a steam_appid.txt file
// is present in your game's directory (for development). Your current process should continue.
//
// NOTE: This function should be used only if you are using CEG or not using Steam's DRM. Once applied
// to your executable, Steam's DRM will handle restarting through Steam if necessary.
S_API bool STEAM_CALL SteamAPI_RestartAppIfNecessary( uint32 unOwnAppID );
------------------------------------------------------------------------------------------------------
After running the game executable (F.E.A.R. 3.exe) , the game Terminates. So, what i did was to fire up
Process Monitor and see what happens to the application when it Terminates. The Log file revealed some useful
information (I have "shrink" the output a little in order to save some space):
12:01:49,0038683 pµ F.E.A.R. 3.exe 2164 CreateFile C:\WINDOWS\system32\1025 IS DIRECTORY...
12:01:49,0040101 pµ F.E.A.R. 3.exe 2164 CreateFile C:\WINDOWS\system32\1025 SUCCESS Desired...
12:01:49,0041236 pµ F.E.A.R. 3.exe 2164 QueryInformationVolume C:\WINDOWS\system32\1025 SUCCESS...
12:01:49,0042262 pµ F.E.A.R. 3.exe 2164 QueryAllInformationFile C:\WINDOWS\system32\1025 ...
12:01:49,0043198 pµ F.E.A.R. 3.exe 2164 CloseFile C:\WINDOWS\system32\1025 SUCCESS
Thread Exit SUCCESS Thread ID: 3524
Thread Exit SUCCESS Thread ID: 364
Thread Exit SUCCESS Thread ID: 4000
Thread Exit SUCCESS Thread ID: 3304
Thread Exit SUCCESS Thread ID: 136
Thread Exit SUCCESS Thread ID: 372
Thread Exit SUCCESS Thread ID: 252
Thread Exit SUCCESS Thread ID: 216
Thread Exit SUCCESS Thread ID: 392
Thread Exit SUCCESS Thread ID: 380
Thread Exit SUCCESS Thread ID: 1184
Thread Exit SUCCESS Thread ID: 268
Thread Exit SUCCESS Thread ID: 3992
Thread Exit SUCCESS Thread ID: 3904
Thread Exit SUCCESS Thread ID: 388
What I observe here is the following:
1) The application checks if a folder exists. This is done using the CreateFile API.
2) If Folder exists the application uses QueryInformationVolume/QueryAllInformationFile APIs
in order to collect information regarding the folder.
3) The information that QueryInformationVolume/QueryAllInformationFile APIs return is not what
CEG protection expects to be. Application starts terminating Threads.
4) The Process terminates.
There may also be the case that a Folder may not even exist. As a result, Threads will start terminate
just after the call to CreateFile API.
I wanted to see what happens in a lower level. I run the game under Olly debugger, place breakpoint at
CreateFile API and break on the ASM code. The thing is that CEG protection uses many Anti-Debug tricks.
In order to bypass those Tricks I used a plugin. I didn't have time to study those anti-X Shit.
I used Olly Advanced Plugin and turned the following options on:
a) UnhandledExceptionFilter
b) Process32Next
I finally managed to break into the following place inside ASM code, check my comments next to ASM code :
00F2D80F |. 8B1D 18013F01 MOV EBX,DWORD PTR DS:[<&KERNEL32.CreateFileW>]
00F2D80A E8 51B86EFF CALL F_E_A_R_.00619060
00F2D80F 8B1D 18013F01 MOV EBX,DWORD PTR DS:[<&KERNEL32.CreateFileW>] ---> First call to CreateFile API as shown
00F2D815 6A FF PUSH -1 in Process Monitor.
00F2D817 57 PUSH EDI
00F2D818 6A 03 PUSH 3
00F2D81A 57 PUSH EDI
00F2D81B 6A 07 PUSH 7
00F2D81D 68 00000080 PUSH 80000000
00F2D822 56 PUSH ESI
00F2D823 FFD3 CALL EBX
00F2D825 8BF8 MOV EDI,EAX
00F2D827 83FF FF CMP EDI,-1
00F2D82A 75 16 JNZ SHORT F_E_A_R_.00F2D842
00F2D82C 50 PUSH EAX
00F2D82D 68 00000002 PUSH 2000000
00F2D832 6A 03 PUSH 3
00F2D834 6A 00 PUSH 0
00F2D836 6A 07 PUSH 7
00F2D838 68 00000080 PUSH 80000000
00F2D83D 56 PUSH ESI
00F2D83E FFD3 CALL EBX ---> Second call to CreateFile API as shown
00F2D840 8BF8 MOV EDI,EAX in Process Monitor.
00F2D842 837D EC 00 CMP DWORD PTR SS:[EBP-14],0
00F2D846 5B POP EBX
00F2D847 74 16 JE SHORT F_E_A_R_.00F2D85F
00F2D85F 83FF FF CMP EDI,-1
00F2D862 74 64 JE SHORT F_E_A_R_.00F2D8C8
00F2D864 8D55 AC LEA EDX,DWORD PTR SS:[EBP-54]
00F2D867 52 PUSH EDX
00F2D868 57 PUSH EDI
00F2D869 FF15 14013F01 CALL DWORD PTR DS:[<&KERNEL32.GetFileInformationByHandle>] ----> Inside the call to GetFileInformationByHandle API exist
00F2D86F 85C0 TEST EAX,EAX ----> the calls to the 2 APIs -QueryInformationVolume, QueryAllInformationFile-
00F2D871 74 4E JE SHORT F_E_A_R_.00F2D8C1 ----> as shown in Process Monitor.
00F2D873 8D8D E4FEFFFF LEA ECX,DWORD PTR SS:[EBP-11C]
00F2D879 E8 D20C9DFF CALL F_E_A_R_.008FE550
00F2D87E 8B4D D8 MOV ECX,DWORD PTR SS:[EBP-28]
00F2D881 8B45 DC MOV EAX,DWORD PTR SS:[EBP-24]
00F2D884 6A 08 PUSH 8
00F2D886 8D55 E0 LEA EDX,DWORD PTR SS:[EBP-20]
00F2D889 894D E4 MOV DWORD PTR SS:[EBP-1C],ECX
00F2D88C 52 PUSH EDX
00F2D88D 8D8D E4FEFFFF LEA ECX,DWORD PTR SS:[EBP-11C]
00F2D893 8945 E0 MOV DWORD PTR SS:[EBP-20],EAX
00F2D896 E8 1582CEFF CALL F_E_A_R_.00C15AB0
00F2D89B 8D8D E4FEFFFF LEA ECX,DWORD PTR SS:[EBP-11C]
00F2D8A1 E8 2AE37EFF CALL F_E_A_R_.0071BBD0
00F2D8A6 68 FC0C4701 PUSH F_E_A_R_.01470CFC
00F2D8AB 8D4D 98 LEA ECX,DWORD PTR SS:[EBP-68]
00F2D8AE E8 CDE9D1FF CALL F_E_A_R_.00C4C280
00F2D8B3 8D8D E4FEFFFF LEA ECX,DWORD PTR SS:[EBP-11C]
00F2D8B9 8845 FF MOV BYTE PTR SS:[EBP-1],AL
00F2D8BC E8 CF0572FF CALL F_E_A_R_.0064DE90
00F2D8C1 57 PUSH EDI
00F2D8C2 FF15 68003F01 CALL DWORD PTR DS:[<&KERNEL32.CloseHandle>] ------> Call to CloseFile as shown in Process Monitor.
The basic thing here is that there are 2 APIs been called (as shown in Process Monitor -QueryInformationVolume and
QueryAllInformationFile-) inside GetFileInformationByHandle. But we do not care. We need to
see it from an abstract level, from GetFileInformationByHandle API. So what does this API do?
Here is the definition from MSDN:
----------------------------------------------------------------------------------------
BOOL WINAPI GetFileInformationByHandle(
__in HANDLE hFile,
__out LPBY_HANDLE_FILE_INFORMATION lpFileInformation
);
Retrieves file information for the specified file.
Parameters
hFile [in]
A handle to the file that contains the information to be retrieved.
This handle should not be a pipe handle.
lpFileInformation [out]
A pointer to a BY_HANDLE_FILE_INFORMATION structure that receives the file information.
Return value
If the function succeeds, the return value is nonzero and file information data is contained in the
buffer pointed to by the lpFileInformation parameter.
If the function fails, the return value is zero. To get extended error information, call GetLastError
----------------------------------------------------------------------------------------
The interesting part is the lpFileInformation parameter. It contains a pointer to the data returned from
the file. This data is used from CEG in order to "Bind" the CEG protected binaries with the FileSystem
on the PC. So, I understand that there is FileSystem emulation that should be done. The data structure
that is being returned contains 52d bytes. Here is an example of the data that the pointer points to:
10 00 00 00 F4 BF A8 DC 55 42 CD 01 08 FF 9D 18
E3 44 CD 01 F4 BF A8 DC 55 42 CD 01 27 39 D9 60
00 00 00 00 00 00 00 00 01 00 00 00 00 00 01 00
70 00 00 00
So, I emulated the FileSystem information needed (I will explain later -fully- any emulation, just wait).
I run the game on the same physical machine but on a different VM. The game runs just fine. After this, I
changed the Hard Disk on the physical machine, re-installed everything and run the game in the VM. The
game terminates. But it does not terminate because of the FileSystem. The reason is that it could not
find a registry key entry. I took a look in Process Monitor Log for the registry key that didn't exist:
HKEY_CLASSES_ROOT\CLSID\{8028480D-A20A-4F93-96A3-3BF9EA7FE1E2}
This key should have the following string value:
"Steam Service Class"
So, I searched for all keys in the PC that the game was running fine. In my case, there were 6 entries
in registry with the "Steam Service Class" string value. Here are the keys in my case:
Windows Registry Editor Version 5.00
;"Steam Service Class" string in CLSIDs
[HKEY_CLASSES_ROOT\CLSID\{8028480D-A20A-4F93-96A3-3BF9EA7FE1E2}]
[HKEY_CLASSES_ROOT\CLSID\{E4526A36-75A2-4F2D-A53F-245F584AF2C5}]
[HKEY_CLASSES_ROOT\CLSID\{5E9DEE15-F185-4EB0-A30E-09BA14CA43B3}]
[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{8028480D-A20A-4F93-96A3-3BF9EA7FE1E2}]
[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{E4526A36-75A2-4F2D-A53F-245F584AF2C5}]
[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{5E9DEE15-F185-4EB0-A30E-09BA14CA43B3}]
After creating the folling keys the game runs just fine. The final test was to run it
on a different Physical PC and make sure that CEG does not use H/W "identification"
for example CPU number, GPU number etc. I run it and the game run just fine.
So, now I was sure about the following things:
1) CEG uses FileSystem checks
2) CEG uses Registry checks.
3) CEG uses no other check than (1),(2).
But how can we find all the Folders/Registry entries to Emulate? And what values for structures will we use
for FileSystem Emulation?
Here is the beautiful part of this. When Steam servers validate all binary files of the game that are
protected with CEG and finds that are not valid, it uses the SAME API -GetFileInformationByHandle- in order
to get new information from the FileSystem. So, the structures that should be emulated are actually READ from
Steam Client and sent to Steam servers in order to produce the new binary file/files. Those structures
are stored encryped in 2 sections of the new binary file(s) created:
.rdata
.rsrc
This is why 2 binary files that were created on different PCs differ only on those sections. The CEG algo
is inside the code and is the same for the 2 binary files. Only the FileSystem/Registry data changes.
I will run Steam Client under Debugger and I will place a Breakpoint at GetFileInformationByHandle API. I noticed
that this API is used only by CEG protection on Steam for creating the new binary file(s). Each time the
debugger breaks, I will return the same structure data for ANY file. I choose the data. After the
update of binary file(s) have finished I have actually forced Steam Client to produce binary file/files that
think all Files should return the same data structure, which is my data structure. If I now hook the
GetFileInformationByHandle API during game runtime and always return my data structure, CEG will think
that everything is ok. It is fine to replace the GetFileInformationByHandle API with my code since this API is
only used by CEG. But if you have any problems with later games, you should just change your inline patch a little.
Here is the Hook I placed under the debugger for the GetFileInformationByHandle API:
7C810CFD GetFileInformationByHandle 60 PUSHAD --> save all registers
7C810CFE 9C PUSHFD --> save flag register
7C810CFF 8B4424 2C MOV EAX,DWORD PTR SS:[ESP+2C]--> Now EAX contains the lpFileInformation Pointer
7C810D03 C700 10000000 MOV DWORD PTR DS:[EAX],10 --> Next code just enters pre-defined 54d bytes of data
7C810D09 83C0 04 ADD EAX,4
7C810D0C C700 0098CAB6 MOV DWORD PTR DS:[EAX],B6CA9800
7C810D12 83C0 04 ADD EAX,4
7C810D15 C700 BC41CD01 MOV DWORD PTR DS:[EAX],1CD41BC
7C810D1B 83C0 04 ADD EAX,4
7C810D1E C700 1A6711F0 MOV DWORD PTR DS:[EAX],F011671A
7C810D24 83C0 04 ADD EAX,4
7C810D27 C700 3447CD01 MOV DWORD PTR DS:[EAX],1CD4734
7C810D2D 83C0 04 ADD EAX,4
7C810D30 C700 0098CAB6 MOV DWORD PTR DS:[EAX],B6CA9800
7C810D36 83C0 04 ADD EAX,4
7C810D39 C700 BC41CD01 MOV DWORD PTR DS:[EAX],1CD41BC
7C810D3F 83C0 04 ADD EAX,4
7C810D42 C700 0162B380 MOV DWORD PTR DS:[EAX],80B36201
7C810D48 83C0 04 ADD EAX,4
7C810D4B C700 00000000 MOV DWORD PTR DS:[EAX],0
7C810D51 83C0 04 ADD EAX,4
7C810D54 C700 00000000 MOV DWORD PTR DS:[EAX],0
7C810D5A 83C0 04 ADD EAX,4
7C810D5D C700 01000000 MOV DWORD PTR DS:[EAX],1
7C810D63 83C0 04 ADD EAX,4
7C810D66 C700 00000100 MOV DWORD PTR DS:[EAX],10000 ; UNICODE "=::=::\"
7C810D6C 83C0 04 ADD EAX,4
7C810D6F C700 40000000 MOV DWORD PTR DS:[EAX],40
7C810D75 9D POPFD
7C810D76 61 POPAD
7C810D77 90 NOP
7C810D78 C2 0800 RETN 8
The only thing left is to find out what Folders need to exist on the Disk and what Registry entries need to
exist in the Registry. This is easy to be found. Before Steam Client updates the Binary/Binaries and applies the
new structure signature data, make sure you open Process Monitor. When Client starts reading the new
file structures ProcMon will log calls to QueryInformationVolume and QueryAllInformationFile APIs, just like it does
when the game starts running. Then it will start searching for the same Folders, as it does when the game runs.
After the calls to the FileSystem, it will start checking Registry keys with string value "Steam Service Class".
You should write down all Folder names and Registry key names. After that, you can see TCP communication with
Steam servers, they are probably creating the new binary files.
Here are the Registry Keys and Folders in my case:
[HKEY_CLASSES_ROOT\CLSID\{8028480D-A20A-4F93-96A3-3BF9EA7FE1E2}]
[HKEY_CLASSES_ROOT\CLSID\{E4526A36-75A2-4F2D-A53F-245F584AF2C5}]
[HKEY_CLASSES_ROOT\CLSID\{5E9DEE15-F185-4EB0-A30E-09BA14CA43B3}]
[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{8028480D-A20A-4F93-96A3-3BF9EA7FE1E2}]
[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{E4526A36-75A2-4F2D-A53F-245F584AF2C5}]
[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{5E9DEE15-F185-4EB0-A30E-09BA14CA43B3}]
C:\WINDOWS\Connection Wizard
C:\Program Files\Steam\Graphics
C:\WINDOWS\system32\1033
C:\WINDOWS\Config
C:\Program Files\Steam\dumps
C:\WINDOWS\system32\1032
C:\WINDOWS\assembly
C:\Program Files\Steam\config
C:\WINDOWS\system32\1031
C:\WINDOWS\AppPatch
C:\Program Files\Steam\bin
C:\WINDOWS\system32\1028
C:\WINDOWS\addins
C:\Program Files\Steam\Backups
C:\WINDOWS\system32\1025
C:\WINDOWS\$NtUninstallXPSEPSCLP$
C:\Program Files\Steam\appcache
C:\WINDOWS\system32\mui
C:\WINDOWS\Fonts
By following the previous steps, you should be able to bypass CEG protection. You do not care
how many binary files are been updated, because we Hook in Windows API Level and NOT Application level.
To sum up, here are the steps:
1) Load Steam Client in debugger and Hook GetFileInformationByHandle API to return your structure. I have
included an ASM code sample of this Hook earlier in this paper.
2) Open ProcMon. Let Steam Client to apply CEG in the game (online). Note down Folders/Registry entries that
CEG needs, from ProcMon Log.
2) Make sure all necessary Folders exist.
3) Make sure all necessary Registry keys exist.
4) Load game in debugger and Hook GetFileInformationByHandle API to return your structure, same structure
you returned in (1). Since this API is only used for CEG you should not have any problem to overwrite the
API code. But if you do have problems in later games, you should change my inline patch to something else (eg.
check what file it is etc.)
Keep in mind that CEG protection continues to run during the game execution and does not only run
at start of the game. It also checks for Registry/Folders signatures with no specific order/frequency.
This is why you should follow my approach and hook the signature creation when CEG protection is
applied on the binaries. Only after that you can be sure that you have all Folder names and Registry entries in
your "list".
> Final Words <
Valve did a great Job with CEG. I really had a great time looking on this protection. It reminds me of
the good days where sharing was an art. I am sharing this information with you and I hope you will
do the same. Should I receive possitive feedback from you I will continue this paper serries.
Should I not, I'll stop.
Wish you all a great night out.
Push_BirthDay_Ret
@flarn2006
Copy link

Great work! I always prefer DRM methods that are practically invisible to the end-user (though as always, no DRM at all is preferable) but Valve seemed to have forgotten that even this can negatively impact legitimate customers. I enjoy hacking games (single-player ones; don't worry!) and CEG can really get in the way of that.

Thanks for sharing!

@sontono
Copy link

sontono commented Nov 24, 2015

Good work! Thanks for sharing!

@Bigtalljosh
Copy link

Definitely an interesting read - Thanks for sharing.

@T3rm1
Copy link

T3rm1 commented Mar 13, 2022

Interesting read. Thanks for sharing. I wonder if the protection - 10 years later - is still the same.

@illnyang
Copy link

Interesting read. Thanks for sharing. I wonder if the protection - 10 years later - is still the same.

this document is far from exhaustive. you can find killswitches by searching for x-refs to GetTickCount; it always accompanied by return address override (which is why you can't see the callstack when placing a breakpoint at TerminateProcess). x-refs to these killswitches share common code - it is possible to completely bypass CEG by patching a single function. If you REALLY want to get rid of CEG for good, take a look at how PLAZA removed CEG from iw5sp (compare their crack with original exe). Also, use LumaCEG.

@relative
Copy link

Interesting read. Thanks for sharing. I wonder if the protection - 10 years later - is still the same.

this document is far from exhaustive. you can find killswitches by searching for x-refs to GetTickCount; it always accompanied by return address override (which is why you can't see the callstack when placing a breakpoint at TerminateProcess). x-refs to these killswitches share common code - it is possible to completely bypass CEG by patching a single function. If you REALLY want to get rid of CEG for good, take a look at how PLAZA removed CEG from iw5sp (compare their crack with original exe). Also, use LumaCEG.

Maybe you weren't viewing the gist in Notepad++.

@tkm129
Copy link

tkm129 commented Jul 20, 2022

@illnyang I tried LumaCEG but it could'nt generate a working executable. It hangs on creating certificate. Nevermind
I found this but their protection is a lot weaker than on my exe (civ v).

it is possible to completely bypass CEG by patching a single function

Please could you provide a disassembly / screenshot / description of that function ?
Many thanks

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment