// Copyright © 2008-, Valve LLC, All rigStahts reserved. // // cegclient.h // // This file is to be imported by client applications that wish to link with our DRM library ! // // Performance Note : // // There are several points within cegclient.h where we'll place a 'Performance Note' to indicate // the potential performance consequences of particular CEG functions. // // // // // CEG Initialization - // // The first and last functions within the CEG SDK that must be called are : // Steamworks_InitCEGLibrary() // Steamworks_TermCEGLibrary() // // There are alternate versions of these functions, for people who restrict their usage of the // CEG SDK to a subset of the available API's (more on the subset later). These functions are : // // Steamworks_MinimumInitCEGLibrary() // Steamworks_MinimumTermCEGLibrary(). // // In the event that the CEG library is initialized through Steamworks_InitCEGLibrary(), then the // following functions must also be called, on each thread on which CEG code may execute, before any // other CEG code code executes on the thread (these functions are not necessary if Steamworks_MinimumInitCEGLibrary() is called). // // Steamworks_RegisterThread() // Steamworks_UnRegisterThread(). // // The only function which can be called before Steamworks_RegisterThread() is Steamworks_InitCEGLibrary(). // Steamworks_RegisterThread() must be called on the thread that calls Steamworks_InitCEGLibrary(), if it calls any // other CEG functions. // For example, your main() will probably look like : // // int main( int argc, char* argv[] ) // { // Steamworks_InitCEGLibrary(); // Steamworks_RegisterThread(); // // /* Real work here */ // // Steamworks_UnRegisterThread(); // Steamworks_TermCEGLibrary(); // return 0; // } // // // // CEG Minimum API : // // Steamworks_SimpleCheck() // // This API is provided for people who are trying to combine CEG with other DRM technology. // This function does a very basic check that the machine is executing on the machine it was produced for. // This function doesn't conceal any of the data it is using to evaluate the machine, and therefore should not be // used with the full CEG SDK. It it not necessary to call Steamworks_RegisterThread()/Steamworks_UnRegisterThread() // if CEG API usage is restricted to this function. // // CEG Full API's : // // The full set of CEG API's takes the form of direct function calls, who's performance impacts may be easily analyzed // versus macros, which cause sophisticated manipulations of your .obj files before the final executable is linked. // // // Direct Functions Calls - // Steamworks_TestSecret() // Steamworks_TestSecretAlways(), // Steamorks_SelfCheck(). // // Steamworks_TestSecret() and Steamworks_TestSecretAlways() are focused on evaluating the current // computer to determine whether it is the machine the binary was produced for. // Because a hacker may be 'tracing' all windows API calls with a tool such as sysinternal's Process Monitor // ( http://technet.microsoft.com/en-us/sysinternals/bb896645 ), Steamworks_TestSecret() will not always // evaluate it's secret. The intention is to make it harder to record CEG activity. // Steamworks_TestSecretAlways() will always evaluate it's portion of secret data. // // Steamworks_SelfCheck() - this function is focused on determining whether the executable has been modified. // // // Macro Mechanisms: // // CEG's macro mechanisms attempt to entwine machine specific information into the correct operation of the game // product. As a result, unlike CEG function calls (which a hacker can simply stub out), a hacker must // take the time to determine how the CEG code is entwined within the product, and make a more significant effort // to modify the game. // // Specific Macro Mechanisms: // // CEG_EncryptFunction() // // The function which contains this macro will be modified, so that the opcodes comprising the function // are encrypted within the executable file. The decryption key is derived from machine specific data. // If decryption of the code fails, the function will not be executed, and the game will to continue to run. // Whether the executable immediately terminates or not depends on what the encrypted function does for the game, // as well as calling convention and architecture issues, as the CEG code may not clean up the stack correctly // when the function fails to execute. // (Please note : Many CEG functions are themselves encrypted using this mechanism). // // This mechanism can be used an unlimited number of times - the following macros have restrictions on // the number of times they can be used within your executable. // // Performance Note : // Every time a function containing CEG_EncryptFunction() macro is invoked, CEG code must execute to // produce the function in a ready to run form in temporarily allocated memory. // CEG will keep a cached version of the function for up to 10 seconds, so that the full cost of decryption // is not paid on every invocation. However, every invocation does incur some CEG overhead to // either decrypt or locate the cached form and to properly martial the call to the decrypted form of the function. // //----------------------------------------- // CEG_ProtectFunction() // // The function which contains this macro will be modified, so that it's address must be computed // by every caller of the function. The address computation will involve machine specific data, // as well as checksum computations which verify that the executable has not been modified. // // This mechanism cannot be used (in conjunction with CEG_Define_Constant_Function) more then 130 times. // // Performance Note: // // The full cost of the CEG_ProtectFunction() will be paid on every call of the target function. // Because this mechanism involves computing checksums of the executable image, this will be more // expensive then CEG_EncryptFunction(). However, this mechanism is much more likely to cause problems // for somebody who is attacking the executable with a debugger, as the checksums are likely to find // the breakpoints being used by the debugger. // //---------------------------------------- // CEG_Define_Constant_Function( name, value ) // CEG_Declare_Constant_Function( name ) // CEG_GetConstantValue( name ) // // These macros create and declare a functions that the game can use to get interesting constants // for game play. (i.e. Field Of View angle, maximum player velocity etc...) // // Computation of CEG_GetConstantValue() involves machine specific information as well as checksums // of the executing binary (same as CEG_ProtectFunction). // If the machine is different, or the executable has been modified, then the results returned // by CEG_GetConstantValue() will be different. The results in the game will depend on how // the constant is used. // // The same Performance Note as for CEG_ProtectFunction() apply to this mechanism. // // // Some General Notes on CEG's macro mechanisms: // // The Compiler can eliminate CEG_ProtectFunction() and CEG_EncryptFunction() if it chooses to // inline your function !!! In general, it's better to use these macros only in function which appear in // .cpp files (not in inline functions which appear in header files). It's also better if the function // in which CEG_ProtectFunction() or CEG_EncryptFunction() is placed is not called from within the same file! // // C++ Constructors and Destructors : // // You can use CEG_ProtectFunction() and CEG_EncryptFunction() within your C++ constructors. // HOWEVER - if there is a global variable that invokes the constructor, you will be invoking // the CEG mechanisms before you have executed Steamworks_InitCEGLibrary() - and this will probably crash your game. // // // #ifndef _CEGCLIENT_H_ #define _CEGCLIENT_H_ #pragma once // // Many of the CEG functions implement below compute CRC's over the executing image // of the game when invoked. This results in their performance impact varying with // the size of the game executable file. // A typical result for Steamworks_SelfCheck() and CEG_Protect_Member_Function() is // 3ms of overhead in a 6MB executable. (Measured in L4D2). // // In order to allow more fine grain control of which part of the executable is covered // by CEG CRC's this macro is provided. // // Executable code that is placed in this section WILL NOT have any CRC's covering the code. // To place code in this section on an entire source file basis use '#pragma code_seg( NO_CEG_SECTION )' // This places all of the code following the pragma into the NO_CEG_SECTION of the executable. // // Care should be taken that the marked code cannot be modified to prevent execution of CEG checks. // Do not put direct CEG call sites into this section, or most of the call stack leading to a CEG call site. // This can be used to improve the performance of the Steamwork_SelfCheck() and CEG_Protect_Member_Function() mechanisms // as they will operate on a smaller portion of the game image. // Do not overuse, as placing all code into such sections would mean that the hackers could easily // identify CEG library code - which would be the code not in NO_CEG_SECTION. // #define NO_CEG_SECTION ".textnc" // // This is the result code the DRM library passes to ExitProcess() when it terminates // a process that requires DRM processing. // #define STEAM_PROCESS_TERMINATE_DRM_REQUIRED 0x8000DEAD // // This function should be called exactly once by a client application. // The Steamworks_InitCEGLibrary() and Steamworks_TermCEGLibrary() will let steam know that a game was // running no matter what mechanism the user used to start the game. // extern bool __cdecl Steamworks_InitCEGLibrary() ; // // This function should be called exactly once by a client application - // A client application should call only one of Steamworks_InitCEGLibrary or Steamworks_MinimumInitCEGLibrary() - NOT BOTH! // // This function is provided for those applications incorporating additional DRM mechanisms into their application. // In those cases it may be appropriate to use Steamworks_MinimumInitCEGLibrary(). // Otherwise, Steamworks_InitCEGLibrary() is the interface that should be used. // extern bool __cdecl Steamworks_MinimumInitCEGLibrary(); // // This function should be called exactly once by a client application, immediately // before it is going to exit the game. // extern bool __cdecl Steamworks_TermCEGLibrary() ; // // This function pairs with Steamworks_MinimumInitCEGLibrary(). // extern bool __cdecl Steamworks_MinimumTermCEGLibrary(); // // This pair of functions must be called on each thread that uses any CEG mechanism. // Steamworks_RegisterThread() must be called before any CEG mechanism executes on // the thread, including all of the CEG_Protect_Member* macros. // Steamworks_UnRegisterThread() must be called AFTER all CEG mechanisms have been // executed on a particular thread. // // IMPORTANT NOTE REGARDING CEG IN MULTIPLE COMPONENTS - // This Comment ONLY applies if you are using CEG in multiple DLL's (or a .DLL and .EXE) // which are loaded in the same process. // If Steamworks_RegisterThread() is called in DLL A, which invokes DLL B which also // contains CEG code, then DLL B must call Steamworks_RegisterThread() before any CEG // function within DLL B is executed, and must call Steamworks_UnRegisterThread() before // it returns to DLL A. // // If a thread executes exclusively in DLL A without calling DLL B, then Steamworks_RegisterThread() // only needs to be called in DLL A. // extern bool __cdecl Steamworks_RegisterThread() ; extern bool __cdecl Steamworks_UnRegisterThread() ; // // This function performs the most basic CEG checks for ownership, and makes no attempt // to conceal it's inner workings, unlike the remaining API's // // If bTerminateIfUnowned is non zero then the CEG will crash the process // and attempt to return STEAM_PROCESS_TERMINATE_DRM_REQUIRED to the steam client. // The caller may pass zero (false) to the function, and take responsibility for terminating the game. // This allows the caller to separate the legitimacy test from the enforcement. // It is very important that the process have an exit code of STEAM_PROCESS_TERMINATE_DRM_REQUIRED // if this is done - the Steam Client will use that to report CEG errors to Steam // and to repair a customer installation. This may arise if the customer // has upgraded their Operating System, in which case the first time the game // is launched after the upgrade, CEG may fail to identify the system and cause the game to exit. // In this situation, the steam client will repair the customer's installation before // the game is launched again. // // The variable argument list to the function is ignored by the steam client, // but may be used to mask the signature of the function. // extern bool __cdecl Steamworks_SimpleCheck( DWORD bTerminateIfUnowned, ... ); // // This function checks to see whether an application has been 'stolen' - it does // so by examining properties of the system on which we are running and checking if // those properties match those expected through the encoding we've done into the binary ! // // IMPORTANT NOTE : This function has internal metering, it does not always perform its // full check. The goal is to make it more difficult to discover for hackers to locate // all of these checks. // extern bool __cdecl Steamworks_TestSecret() ; // // This function performs the same type of checks as Steamworks_TestSecret(), however // it has no internal metering - it will always perform a check. // extern bool __cdecl Steamworks_TestSecretAlways() ; // // This function checks to see whether an application has been 'stolen' - it does // so by examining the PE file (.dll or .exe) in which the DRM library has been linked // and determines whether the PE file has been modified. // extern bool __cdecl Steamworks_SelfCheck() ; // // This function takes an interface pointer returned from a steam dll, and verifies // that it actually references a legitimate steam client. // extern bool __cdecl Steamworks_ValidateComponentInterface(void** lpv) ; // // By default - we use WinCrypt API's to do signature validation - // if somebody desires, they can provide their own implementation. // class ISignatureImplementation { public : virtual bool VerifyHash( // // First - we specify the data structure which has been 'signed' - // We sign our signature using Wincrypt's PROV_RSA_FULL provider // with the CALG_SHA1 algorithm. // LPBYTE lpbSignedData, DWORD cbSignedData, // // The signature block is generated using // CryptCreateHash( RSA FULL PROVIDER, CALG_SHA1 ) and CryptHashData(). // The Hash is then signed using CryptSignHash( Hash(), AT_SIGNATURE, .... ) // generating the specified SignatureBlock ! // LPBYTE lpbSignatureBlock, DWORD cbSignatureBlock, // // The public key associated with the private key that signed the Hash data ! // LPBYTE lpbPublicKey, DWORD cbPublicKey ) = 0 ; } ; // // This function checks a signature of all the read-only portions of the executing image. // Unlike other CEG mechanisms, this uses cryptographic mechanisms that are not easily concealed from reverse engineering. // Additionally, this is a higher cost mechanism as it involves the entire executing image. // This check can be used at game launch, (before any user interface is displayed) where it will serve as a stalking horse, // and occasionally throughout execution. // // Additionally, neither of Steamworks_ValidateComponentInterface() or Steamworks_SelfValidate() provide multiple implementations. // Steamworks_TestSecret(), Steamworks_TestSecretAlways(), Steamworks_SelfCheck() will all be multi-plexed across many distinct // implementations (this is done by mingle.exe). Additional call sites for Steamworks_SelfValidate() are not as valuable as // additional call sites for the previously mentioned CEG functions. // extern bool __cdecl Steamworks_SelfValidate(ISignatureImplementation* pISignatureImplementation) ; //////////////////////////////////////////////////// // // DO NOT CALL THIS FUNCTION ! // This is referenced only through the CEG_Define_Constant_Function // typedef DWORD (*PFNSteamworks_ComputeDwordValue)(); extern DWORD __cdecl Steamworks_ComputeDwordValue() ; // // DO NOT DO NOT CALL THIS FUNCTION ! // // This is only referenced indirectly through the CEG_Protect_Virtual_Function macro ! // extern void* __cdecl Steamworks_ProtectFunction( void*, void* ) ; // // DO NOT CALL THIS FUNCTION ! // // This declaration is used within CEG Concealed function mechanisms to incorporate // machine specific data into the function concealment mechanism. It's not to be // directly called. // extern void __cdecl Steamworks_GetSecretData( unsigned __int32 /* 32bit unsigned int - all platforms.*/, union _16BYTES_U& ); // // DO NOT DO NOT CALL THIS FUNCTION ! // // This function should only be referenced through the CEG_EncryptFunction macro ! // extern bool __cdecl Steamworks_EncryptedFunctionLoad(); // // DO NOT DO NOT CALL THIS FUNCTION ! // // This symbol exists for the benefit of mingle.exe when it processes your .obj files // and should only appear in the initializers of a CEGProtectedFunction structure ! // extern void __cdecl Steamworks_InvalidReference() ; // // DO NOT CALL THIS FUNCTION - Exists solely for use in macros defined below ! // // This function exists so we can force optimizing compilers to emit all the CEG // relevant data, as otherwise the compiler would discard them as unreferenced. // extern void __cdecl CEG_ForceReference(const struct CEG_Protection_Thunk&, const char* ) ; // // This class is defined purely so we can create derived classes in the CEG_Protect_Member_Function() macro. // Because that macro must be used within a function, defining a class allows us to generate the necessary // compiler references to ensure that the compiler does not optimize out CEG functions and symbols. // class I_CEG_ForceReference_Interface { virtual const CEG_Protection_Thunk* ReferencingFunction(unsigned index) = 0 ; } ; //////////////////////////////////////////////////////////////////////////////// // DO NOT CALL THIS FUNCTION - Exists solely for use in macros defined below ! // // Together with the I_CEG_ForceReference_Interface allows us to force compilation // of some of our fancy CEG symbols ! // extern int __cdecl CEG_ForceReference( class I_CEG_ForceReference_Interface* p ) ; // // /////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// // // CEG Internal Macros - // // The following are not intended for direct use, but will be instantiated // by CEG_EncryptFunction()/CEG_ProtectFunction()/CEG_GetConstantValue(). // // // These handy macros help to generate unique variable names, as well as messages // through __pragma( message() ) ! // #define CEG_UNIQNAME2(x,y) x##y #define CEG_UNIQNAME1(x,y) CEG_UNIQNAME2(x,y) #define CEG_UNIQNAME(x) CEG_UNIQNAME1(x,__COUNTER__) #define CEG_STRING(z) #z #define CEG_LINE_NUMBER(x) CEG_STRING(x) #if defined( _M_X64 ) #define CEG_UNIQNAME3(x, y) CEG_STRING( x##y ) #else #define CEG_UNIQNAME3(x, y) CEG_STRING( _##x##y ) #endif // // Too bad there's no hexadecimal 'G', F+1 will do // #define CEG_PROTECT_SIGNATURE 0xCEF1CEF1 #define CEG_PROTECT_VIRTUAL_SIGNATURE 0xCEF10000 // // Define various strings used by CEG as section names through __pragma() directives. // #if !defined(CEG_PUBLIC_SECTION_STRINGS) #define CEG_PUBLIC_SECTION_STRINGS // // These macros correspond to section names used by CEG. // // The following macros will use C++ pragma's to allocate objects into these // various sections. No direct reference to these macros should be necessary. // #define CEG_META_GRAPH_START ".cegm$ga" #define CEG_META_GRAPH_END ".cegm$gz" // // This section will contain the signature tested by the Steamworks_ValidateSelf() interface // #define CEG_SIGNATURE_SECTION ".crsig" // // This section will contain the data CEG uses to generate the Constant Function mechanisms ! // #define CEG_EXTERNAL_VALUE ".cegi$d" #endif extern DWORD __cdecl Steamworks_RevealFunction( DWORD_PTR, DWORD_PTR ); extern void __cdecl Steamworks_ForceRef( struct CEG_SwapStruct* ); // // We use this macro to generate identifiers that Mingle may modify. // In some .obj manipulations, Mingle will change identifiers in the .obj file - // And will expect the identifiers to be produced by this macro! // // NOTE that the __XXXXXXXX will be turned into digits (essentially a counter) // by mingle ! // #define Steamworks_CEG_MingleModifiableName_Prefix Steamworks_CEGIdentifier_ #define Steamworks_CEG_MingleModifiableName_Suffix __XXXXXXXX #define Steamworks_CEG_MingleModifiableName(name) Steamworks_CEGIdentifier_ ## name ## __XXXXXXXX #define CEG_TEMPLATE_USE_START_SECTION ".cegtu$a" #define CEG_TEMPLATE_USE_SECTION ".cegtu$m" #define CEG_TEMPLATE_USE_END_SECTION ".cegtu$z" // // Reserve scratch space for the CEG Implementation to cache results! // // struct Steamworks_ThunkFunction_Scratch { DWORD m_rgdw[16] ; }; // // Identify the version number of the CEG_SwapStruct structure. // #define Steamworks_CEG_SwapVersion 1 // // This mask specifies that the function specified by CEG_SwapStruct should be prepped by mingle // to have runtime encryption operations applied to it. // #define Steamworks_CEG_EncryptSectionMask 1 // // This mask specifies that the function specified by CEG_SwapStruct should be marked as COMDAT Select // Associative to the specification section. The select associative option is only used if // the original section was already COMDAT Select Any (common for templates and inline functions). // This flag is used by code within the CEG library implementing various secrets - where we want to // ensure that the target executable file links the absolute minimum amount of stuff, and does not // pull in any un-necessary objects. // #define Steamworks_CEG_SelectAssocMask 2 // // This is the macro we use to cause the 'consumption' of a template ! // #define Steamworks_CEG_InvokeTemplate( arg, flags ) \ static char CEG_SwapName_Local[] = __FUNCDNAME__ ; \ __pragma( section(CEG_TEMPLATE_USE_SECTION, read, write) ) \ static CEG_SwapStruct __declspec(align(1)) __declspec(allocate(CEG_TEMPLATE_USE_SECTION)) \ LocalSwap = { \ Steamworks_CEG_SwapVersion, \ CEG_SwapName_Local, \ Steamworks_CEG_MingleModifiableName( arg ), \ flags, NULL, 0, 0 \ } ; \ Steamworks_ForceRef(&LocalSwap) #define Steamworks_DeclareCEGTemplate( arg ) \ extern DWORD_PTR __cdecl Steamworks_CEG_MingleModifiableName( arg )( DWORD_PTR ) Steamworks_DeclareCEGTemplate( CacheConcealThunk ); Steamworks_DeclareCEGTemplate( ProtectFunction ); #pragma pack(push, 1) #if !defined(CEG_LINKOBJECT_DEFINED) #define CEG_LINKOBJECT_DEFINED // // The 'ID' of an object identified by mingle - this // is large enough to be a GUID or an MD5 computation ! // struct LinkObjectId { BYTE m_rgb[16]; }; #endif struct CEG_SwapStruct { // // Tell Mingle what version of this structure the file was compiled with ! // DWORD_PTR m_Version; // // This field is the decorated name of the function that is being manipulated. // This is generated through the __FUNCDNAME__ preprocessor directive of Visual Studio. // char* m_szDecoratedName; // // This points to the function that will 'replace' the specified function. // void* m_pfnOriginal; // // Reserve space in the structure for communication with mingle.exe and // cegdll.dll regarding the details of what happens to the swapped code ! // DWORD_PTR m_SectionOptions; // // Based on the Section Options, these fields will be interpreted by Mingle and the CEG runtime. // void* m_Reserved1; DWORD_PTR m_Reserved2; // // Mingle will give us the size of the Swap Target function, in bytes ! // DWORD_PTR m_cbTarget; // // This is a mingle generated identifier, that will be used by cegdll.dll and drmpe.exe // to identify the template used and it's associated metadata ! // LinkObjectId m_LinkObjectId; }; // // This structure must have the exact same size as CEG_SwapStruct, and will be the runtime interpretation // of the structure ! Mingle will modify relocation records so that the final linked form stores 'distances' // to the actual referenced items instead of pointers. We do this to reduce relocation records in the final // target executable, which we believe give data structure feedback to hackers. // struct CEG_Runtime_SwapStruct { // // This field carries the version of the structure. // DWORD_PTR m_Version; // // This is the 'distance' to the function that Mingle placed into the .obj file. // This function is called directly instead of the original 'TargetFunction' // // Note that 'distances' are stored by mingle.exe using a relocation type that is appropriate for code. // That means that distances on both 32 and 64bit platforms are 32 bit signed integers - // However, this field is 64bits on a 64bit platform. The linker will have stored a 32 bit signed // integer into the field, so we must do appropriate casting, because we don't have a genuine 64 bit signed integer in here. // When manipulating the structures, we will at a time turn this field into a full 'pointer like' value // (i.e. during the CEG process) - so it is convenient for us that it can hold that. // INT_PTR m_OffsetSubstitute; // // NOTE : All the same comments that apply to m_OffsetSubstitute apply to this field ! // // This is the distance to the 'Target' function - the function containing the Steamworks_CEG_InvokeTemplate macro // This TargetFunction may be in an encrypted form, depending on the flags specified in m_SectionOptions! // INT_PTR m_OffsetOriginal; // // These options specify manipulations that mingle will perform on the 'Original' function // before it is linked. In particular, it may be turned into a 'Concealed' function - which // is a self-contained data structure containing the functions op-codes and metadata that can // be encrypted during the CEG process. // DWORD_PTR m_SectionOptions; // // We allow the macro to request what Encryption thunk is used in the event that the // Section Options specify // DWORD_PTR m_SectionThunk; // // For future use .... // DWORD_PTR m_Reserved2; // // Mingle will give us the size of the Substitute function, in bytes ! // It is usefull to know the Substitute function size - as during runtime we may // need to 'search' for it. // DWORD_PTR m_cbTarget; // // This is a mingle generated identifier, that will be used by cegdll.dll and drmpe.exe // to identify the template used and it's associated metadata ! // LinkObjectId m_LinkObjectId; void* GetOriginalFunction() const { return reinterpret_cast(reinterpret_cast(&m_OffsetOriginal)+static_cast(m_OffsetOriginal)+sizeof(INT32)); } void* GetSubstituteFunction() const { return reinterpret_cast(reinterpret_cast(&m_OffsetSubstitute)+static_cast(m_OffsetSubstitute)+sizeof(INT32)); } }; #pragma pack(pop) // // End of CEG Internal Macros - // //////////////////////////////////////////////////////////////////////////////// // // The flowing three macros : // CEG_Define_Constant_Function( name, value ), // CEG_Declare_Constant_Function( name ), // CEG_GetConstantValue( name ) // // Operate together to provide another CEG mechanism for protecting your binary. // // Example usage : // // header.h : // /* macro is at File Scope !*/ // CEG_Declare_Constant_Function( ZombiesPerSecond ) ; // // main.cpp : // /* macro is at File Scope !*/ // CEG_Define_Constant_Function( ZombiesPerSecond, 17 ) ; // // zombies.cpp : // /* CEG_GetConstantValue( ZombiesPerSecond ) must be used within a function !*/ // // void // ClockTick() // { // if( ElapsedTime > 1 ) /* Has 1 second passed ? */ // { // DWORD cZombies = CEG_GetConstantValue( ZombiesPerSecond ) ; // for( DWORD i=0; i( Steamworks_ComputeDwordValue ) , \ } ; \ __pragma( comment( linker, "/INCLUDE:" CEG_UNIQNAME3( Steamworks_CEG_ValueBinding_, name ) ) ) \ }; \ extern DWORD CEG_UNIQNAME1( CEG_ConstantValue_, name )( void ); \ DWORD CEG_UNIQNAME1( CEG_ConstantValue_, name )( void ) \ { \ INT32* pOffset = reinterpret_cast( & CEG_UNIQNAME1( Steamworks_CEG_ValueBinding_, name ).m_ImplementationFunction ) ; \ PFNSteamworks_ComputeDwordValue pfn = reinterpret_cast( reinterpret_cast(pOffset+1) + *pOffset ); \ return (*pfn)(); \ } #define CEG_Declare_Constant_Function( name ) \ extern DWORD CEG_UNIQNAME1( CEG_ConstantValue_, name )() // // These forms of CEG_Define_Constant_Function() appeared in older CEG SDK's, but are no longer available ! // // #define CEG_Define_Constant_Function2( name, value ) \ __pragma( message( __FILE__ "(" CEG_LINE_NUMBER(__LINE__) ") : CEG_Defined_Constant_Function2 has been retired and can no longer be used! - use CEG_Define_Constant_Function!") ) #define CEG_Define_ConstantFloat_Function( name, value ) \ __pragma( message( __FILE__ "(" CEG_LINE_NUMBER(__LINE__) ") : CEG_Defined_ConstantFloat_Function has been retired and can no longer be used! - use CEG_Define_Constant_Function!") ) #define CEG_Define_ConstantFloat_Function2( name, value ) \ __pragma( message( __FILE__ "(" CEG_LINE_NUMBER(__LINE__) ") : CEG_Defined_ConstantFloat_Function2 has been retired and can no longer be used! - use CEG_Define_Constant_Function!") ) /*************************************************** **************************************************** CEG_ProtectFunction and CEG_EncryptFunction These macros must be placed within the body of a function. Here is a small example, which describes how CEG_ProtectFunction() operates : class CMyClass { virtual void MyVirtualFunction( int SomeArg ) ; } ; __declspec(noinline) // This is necessary to prevent compiler optimizations from eliminating CEG check. void CMyClass::MyVirtualFunction( int SomeArg ) { CEG_ProtectFunction(); // // Now do the real work ! // } Void ExampleCall(CMyClass * p ) { p->MyVirtualFunction( EXAMPLE_CONSTANT ) ; } } Now what happens to your binary is the following : The vtable for CMyClass has been changed to reference a CEG function. When ExampleCall() is executed, It will actually end up calling CEG code through the vtable. This CEG code preserves the state of the stack and arguments in a fashion similar to the CRT setjmp() function. The CEG code will then compute a checksum that incorporates machine identifying information into the checksum. If nobody has modified the executable (by setting breakpoints, or by changing the executable file) and the executable is running on the machine it was produced for, then the checksum results in the address of CMyClass::MyVirtualFunction(). In this case, CEG will patch the CONTEXT it got from it's setjmp() operation and longjmp() to CMyClass::MyVirtualFunction(). The setjmp()/longjmp() manipulations allow CEG to do it's work, without having to understand the calling convention between ExampleCall() and CMyClass::MyVirtualFunction(). Before the CEG code invokes longjmp(), it checks that the address it computed is correct, by computing an MD5 of the address, and comparing this to a stored MD5. If this comparison fail, CEG terminates the process directly. You can use CEG_ProtectFunction()/CEG_EncryptFunction() in any kind of function - C++ member functions, C++ static member functions etc.... ******************************************************* ******************************************************/ #define CEG_ProtectFunction( ) \ Steamworks_CEG_InvokeTemplate( ProtectFunction, 0 ) #define CEG_EncryptFunction( ) \ Steamworks_CEG_InvokeTemplate( CacheConcealThunk, Steamworks_CEG_EncryptSectionMask ) // // These are previus forms of CEG_ProtectFunction() that appeared in older SDK's - and should be replaced by either CEG_ProtectFunction() // or CEG_EncryptFunction(). // #define CEG_Protect_Function(x) \ __pragma( message( __FILE__ "(" CEG_LINE_NUMBER(__LINE__) ") : CEG_Protect_Function has been retired and can no longer be used! - use CEG_ProtectFunction!") ) #define CEG_Protect_StaticMemberFunction(x, y) \ __pragma( message( __FILE__ "(" CEG_LINE_NUMBER(__LINE__) ") : CEG_Protect_StaticMemberFunction has been retired and can no longer be used! - use CEG_ProtectFunction!") ) #define CEG_Protect_Virtual_Function3( name ) \ __pragma( message( __FILE__ "(" CEG_LINE_NUMBER(__LINE__) ") : CEG_Protect_Virtual_Function3 has been retired and can no longer be used! - use CEG_ProtectFunction!") ) #define CEG_Protect_Member_Function( name ) \ __pragma( message( __FILE__ "(" CEG_LINE_NUMBER(__LINE__) ") : CEG_Protect_Member_Function has been retired and can no longer be used! - use CEG_ProtectFunction!") ) #define CEG_Protect_Member_Function2( name ) \ __pragma( message( __FILE__ "(" CEG_LINE_NUMBER(__LINE__) ") : CEG_Protect_Member_Function2 has been retired and can no longer be used! - use CEG_ProtectFunction!") ) // // This structure is declared to be a platform invariant size ! // struct Steamworks_CEG_ValueBinding { DWORD32 m_Signature; DWORD32 m_BindingUse; DWORD64 m_DesiredResult; DWORD64 m_ImplementationFunction; }; ////////////////////////////////////////////////////////////// // // Reference Macros ! // // These macro's instantiate several CEG data structures as the CEG tools // (mingle.exe and drmpe.exe) will see them in .obj and .exe files. // // #define CEG_PROTECT_START_SIGNATURE 0xCCEEFF11 #define CEG_PROTECT_END_SIGNATURE 0x11ffeeCC // // DO NOT REFERENCE // // We specify these symbols here so that the linker will properly // concatenate the CEG sections together in the final image. // // These symbols are only for use by internal code of the CEG library ! // // // ////////////////////////////////////////////////////////////// #endif // _CEGCLIENT_H_