Target
Our target for this lesson will be Urban Terror 4.3.4.
Identify
Our goal in this lesson is to create a chams hack, which is a type of hack that colors all players a bright color. We can accomplish this by hooking the game’s graphics library and modifying its code to make all player models render with a bright color instead of a texture.
Understand
When entities are rendered to the screen, they are just filled polygons. To make these entities have visuals (such as eyes, camouflage, or hair), textures have to be applied to the polygons. These textures are specially formatted images, which wrap around the entity when applied to it. For example, the oil barrel texture from Urban Terror looks like:
When this is applied to the circular barrel model, it wraps around it. This is how 2D textures are applied to 3D models.
To create a chams hack, we will modify this rendering flow. After the polygons have been rendered, we will disable textures in OpenGL. When textures are disabled, OpenGL will fall back to using the lighting (or color) array specified by the game. If we disable that as well, OpenGL will fall back to using whatever color was last specified by a call to glColor. If we set our own color and then render the entity, we can make the entity appear as a bright solid color, such as red.
Texture Function Pointers
To make our development easier, we will build off the OpenGL wallhack we created in the previous lesson. For that, we created function pointers for two functions related to depth testing: glDepthFunc and glDepthRange. To disable and enable textures, we will need to create function pointers to four additional functions:
- glEnable
- glDisable
- glEnableClientState
- glDisableClientState
We plan to use glEnable and glDisable to enable and disable GL_COLOR_MATERIAL. In addition, we will need to call glEnableClientState and glDisableClientState to enable and disable GL_COLOR_ARRAY and GL_TEXTURE_COORD_ARRAY. We will enable and disable all these elements to ensure that OpenGL falls back to a mode where we can set the color.
To set the color after we have done those steps, we will also need to create a function pointer to glColor. glColor has many forms that allow you to pass in different type of parameters. Any of these functions will work, but for our hack, we will use glColor4f, the version of glColor that takes 4 floats (values that allow decimals): one for red, green, blue, and alpha. The alpha float is responsible for controlling the opacity of the color.
We can declare these function pointers right below the pointers for glDepthFunc and glDepthRange:
void(__stdcall* glColor4f)(float, float, float, float) = NULL;
void(__stdcall* glEnable)(unsigned int) = NULL;
void(__stdcall* glDisable)(unsigned int) = NULL;
void(__stdcall* glEnableClientState)(unsigned int) = NULL;
void(__stdcall* glDisableClientState)(unsigned int) = NULL;
...
...
glColor4f = (void(__stdcall*)(float, float, float, float))GetProcAddress(openGLHandle, "glColor4f");
glEnable = (void(__stdcall*)(unsigned int))GetProcAddress(openGLHandle, "glEnable");
glDisable = (void(__stdcall*)(unsigned int))GetProcAddress(openGLHandle, "glDisable");
glEnableClientState = (void(__stdcall*)(unsigned int))GetProcAddress(openGLHandle, "glEnableClientState");
glDisableClientState = (void(__stdcall*)(unsigned int))GetProcAddress(openGLHandle, "glDisableClientState");
glDrawElements Code Cave
In our code cave, we already have the logic built out to display models through walls if they have a count greater than 500. We will expand on this code to also color them. First, we will disable GL_COLOR_ARRAY and GL_TEXTURE_COORD_ARRAY. The game uses these client states to let OpenGL know that the game wants to map textures and color arrays (for lighting) to polygons. To apply a static color to a model, we need to tell OpenGL that we are not using these features. Since these are considered client states, we will use glDisableClientState to disable them. We can get their values from gl.h:
if (count > 500) {
...
(*glDisableClientState)(0x8078);
(*glDisableClientState)(0x8076);
Next, we will enable GL_COLOR_MATERIAL and set our color to red. glColor4f takes a value between 0 and 1 for all values. If we want a red color, we will set the red value to 1 and the alpha to 1. However, if we leave green and blue at 0, our ending red color will be dark and muted. To make it vibrant, we will set these values to 0.6. Adding an f on the end of a number in C++ will cause the number to be interpreted as a float:
(*glEnable)(0x0B57);
(*glColor4f)(1.0f, 0.6f, 0.6f, 1.0f);
Finally, just like with our wallhack, we will disable this coloring when the model’s count is less than 500. To do this, we will enable GL_COLOR_ARRAY and GL_TEXTURE_COORD_ARRAY and then disable GL_COLOR_MATERIAL. Finally, we will make another call to glColor, this time setting the color to a pure white. This is not strictly necessary for Urban Terror, but for some games, this will prevent the colors of effects from getting corrupted if they use the previously set color:
(*glEnableClientState)(0x8078);
(*glEnableClientState)(0x8076);
(*glDisable)(0x0B57);
(*glColor4f)(1.0f, 1.0f, 1.0f, 1.0f);
With this done, you can inject the DLL into the game, and you will see all the models appearing through walls with a bright red color:
The full source code for this hack is available on github.