Antal1987
Warlord
Any serious game patch requires changing of asm instructions and adding new code. The problem is that there are only about 0x200 (512) bytes of available (unused) space in exe-file, where patch code can be placed. It is inside PE-header allocation space)
After some experiments with dll injecting and investigating C3C I concluded that it's possible to design all patches in a separate DLL, which can be loaded and unloaded during runtime without code violations.
There is a DLL in Civ3 installation package, it's called jgl.dll
Not everyone knows, that this is the most valuable library for the game, because it controls game windows (1 window actually), system events and game graphics.
That dll is loading inside the following function
address: 0x006306E0
JGL provides many useful methods but the game imports only 1 of them: "get_graphsy_object_ptr". The other methods are getting accesed "somehow".
Here is how it works.
JGL in get_graphsy_object_ptr creates and returns pointer to an object of class:
General functionality provided by JGL is exporting in vtable (virtual functions table) of that class object.
The game after receiving the object pointer saves it along with library's module handle.
JGL_Lib_Module is actually a pointer to a place where the JGL is located. That value is used when the game finalizes:
address: 0x006306A0
Patch framework can be made similarly.
Few worlds about virtual tables. When a simple class creates new instance, it's 1-st field has offset = 0. But if a real class inherits from an abstract virtual class (interface) it's objects have the virtual table pointer at offset = 0.
Virtual table consist of pointers to virtual methods with predefined signatures.
The compiler places virtual methods into vitrual table in the order corresponding to order of those methods in the class. For example, the table for class:
would be:
0x00 - destructor (~iOpenable)
0x04 - open
0x08 - close.
So, lets make a special class for storing patch functions:
IC3CPatchCollection is just an interface, it cannot have instances. But C3CPatchCollection is a real class. It may have instances.
Functions patch_1, patch_2, ... patch_N may have various signatures. It's order would be fixed. Therefore C3CPatchCollection class object would have a virtual table (offset: 0) with the following structure:
0x00 - patch_1;
0x04 - patch_2;
...
4 * (N-1) - patch_N;
Now lets define an export function which creates an instance of C3CPatchCollection and returns it.
Now we have to make some initial patch inside C3C exe.
1) allocate 2 int values in free space for storing:
- HModule for out patch library
- pointer to C3CPatchCollection object
2) write inside free space an asm function which would load the library and call it's export function (Init_Function)
3) write inside free space an asm function to call C3CPatchCollection object's destructor and free library (Dispose_Function)
4) make somewhere in f_Load_JGL_Graphics an injection to calling Init_Function
5) make somewhere in JGL_Lib_Free an injection to call Free_Function
Now, how to use patch methods.
Lets assume we already define a pointer to C3CPatchCollection object:
C3CPatchCollection * Patch_Framework
the call in C++ would be this:
That call in asm would be like this:
In summary: that approach provides a lot of possibilities:
1) It can be overwritten any difficult function or even function group which represents an entire behaviour.
2) There is no need writting complicated code in asm. C++ can be used instead. Asm is required only for calls injection.
After some experiments with dll injecting and investigating C3C I concluded that it's possible to design all patches in a separate DLL, which can be loaded and unloaded during runtime without code violations.
There is a DLL in Civ3 installation package, it's called jgl.dll
Not everyone knows, that this is the most valuable library for the game, because it controls game windows (1 window actually), system events and game graphics.
That dll is loading inside the following function
address: 0x006306E0
Code:
HMODULE __cdecl f_Load_JGL_Graphics(LPCSTR lpLibFileName)
{
HMODULE result; // eax@1
class_JGL_Graphics *(*p_Get_Graphics)(void); // eax@3
class_JGL_Graphics *_Graphics; // esi@5
result = lpLibFileName;
if ( lpLibFileName )
{
result = LoadLibraryA(lpLibFileName);
JGL_Lib_Module = result;
if ( result )
{
p_Get_Graphics = GetProcAddress(result, "get_graphsy_object_ptr");
if ( p_Get_Graphics )
{
_Graphics = p_Get_Graphics();
if ( !_Graphics )
JGL_Lib_Free();
JGL_Graphics = _Graphics;
result = _Graphics;
}
else
{
JGL_Lib_Free();
result = 0;
}
}
}
return result;
}
JGL provides many useful methods but the game imports only 1 of them: "get_graphsy_object_ptr". The other methods are getting accesed "somehow".
Here is how it works.
JGL in get_graphsy_object_ptr creates and returns pointer to an object of class:
Code:
#pragma pack(push, 1)
struct class_JGL_Graphics
{
struct_JGL_Graphics_vtable *vtable;
int field_4[74];
int Screen_Width;
int Screen_Height;
int field_134;
HDC DC;
int field_13C;
HMODULE Main_Module;
int hWnd;
class_PCX_Image *PCX;
};
#pragma pack(pop)
General functionality provided by JGL is exporting in vtable (virtual functions table) of that class object.
The game after receiving the object pointer saves it along with library's module handle.
JGL_Lib_Module is actually a pointer to a place where the JGL is located. That value is used when the game finalizes:
address: 0x006306A0
Code:
void __cdecl JGL_Lib_Free()
{
if ( JGL_Graphics )
(JGL_Graphics->vtable->m03)();
if ( JGL_Lib_Module )
{
FreeLibrary(JGL_Lib_Module);
JGL_Lib_Module = 0;
}
JGL_Graphics = 0;
}
Patch framework can be made similarly.
Few worlds about virtual tables. When a simple class creates new instance, it's 1-st field has offset = 0. But if a real class inherits from an abstract virtual class (interface) it's objects have the virtual table pointer at offset = 0.
Virtual table consist of pointers to virtual methods with predefined signatures.
The compiler places virtual methods into vitrual table in the order corresponding to order of those methods in the class. For example, the table for class:
Code:
class iOpenable
{
public:
virtual ~iOpenable(){}
virtual void open()=0;
virtual void close()=0;
};
0x00 - destructor (~iOpenable)
0x04 - open
0x08 - close.
So, lets make a special class for storing patch functions:
Code:
class IC3CPatchCollection
{
public:
virtual ~IC3CPatchCollection(){}
virtual void patch_1()=0;
virtual void patch_2()=0;
...
virtual void patch_N()=0;
};
class C3CPatchCollection: public IC3CPatchCollection
{
public:
C3CPatchCollection(){}
virtual ~C3CPatchCollection(){}
virtual void patch_1(){}
virtual void patch_2(){}
...
virtual void patch_N(){};
};
IC3CPatchCollection is just an interface, it cannot have instances. But C3CPatchCollection is a real class. It may have instances.
Functions patch_1, patch_2, ... patch_N may have various signatures. It's order would be fixed. Therefore C3CPatchCollection class object would have a virtual table (offset: 0) with the following structure:
0x00 - patch_1;
0x04 - patch_2;
...
4 * (N-1) - patch_N;
Now lets define an export function which creates an instance of C3CPatchCollection and returns it.
Code:
#define PATCH_FRAMEWORK_API __declspec(dllexport)
PATCH_FRAMEWORK_API C3CPatchCollection * init_patch_collection(void)
{
return new C3CPatchCollection();
}
Now we have to make some initial patch inside C3C exe.
1) allocate 2 int values in free space for storing:
- HModule for out patch library
- pointer to C3CPatchCollection object
2) write inside free space an asm function which would load the library and call it's export function (Init_Function)
3) write inside free space an asm function to call C3CPatchCollection object's destructor and free library (Dispose_Function)
4) make somewhere in f_Load_JGL_Graphics an injection to calling Init_Function
5) make somewhere in JGL_Lib_Free an injection to call Free_Function
Now, how to use patch methods.
Lets assume we already define a pointer to C3CPatchCollection object:
C3CPatchCollection * Patch_Framework
the call in C++ would be this:
Code:
Patch_Framework->patch_1()
That call in asm would be like this:
Code:
mov ecx, DS:Patch_Framework
mov ecx, [ecx]
call [ecx+patch_1_offset]
In summary: that approach provides a lot of possibilities:
1) It can be overwritten any difficult function or even function group which represents an entire behaviour.
2) There is no need writting complicated code in asm. C++ can be used instead. Asm is required only for calls injection.