Created
August 19, 2012 14:04
-
-
Save hardware/3395025 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ | |
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ | |
@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@ | |
@@@@@@@@@@@@@@@ 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 | |
@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
Maybe you weren't viewing the gist in Notepad++.