Declaring code patches
Declaring code patches is the basic of the template. After all, we need to inject our code into the game code flow at some point if we want it to be executed, right? This is done by patching the executable's memory to change it's flow. The template does this for you, all you have to do is setup an array of patches declarations, which is done in
D2Patch.h
Structure of the patch array
The structure of patch definitions should look like this:
Code: Select all
{ DLL, OFFSET, PATCH DATA, RELATIVE (bool), SIZE }
Now let's take a closer look at what every part of the array defines.
DLL: This defines in which of the game's library this patch should be applied. This is needed so that the template's patcher can retrieve the said library's base address (as the patcher uses relative addresses patch definitions, to keep compatibility in case of reallocation). The dll name definitions are found in DLLmain.h. It is also possible to extend this in order to have it patch custom libraries that are not defined in the original template but you shouldn't attempt this unless you know what you're doing.
Code: Select all
enum D2TEMPLATE_DLL_FILES
{
D2DLL_BINKW32,
D2DLL_BNCLIENT,
D2DLL_D2CLIENT,
D2DLL_D2CMP,
D2DLL_D2COMMON,
D2DLL_D2DDRAW,
D2DLL_D2DIRECT3D,
D2DLL_D2GAME,
D2DLL_D2GDI,
D2DLL_D2GFX,
D2DLL_D2GLIDE,
D2DLL_D2LANG,
D2DLL_D2LAUNCH,
D2DLL_D2MCPCLIENT,
D2DLL_D2MULTI,
D2DLL_D2NET,
D2DLL_D2SOUND,
D2DLL_D2WIN,
D2DLL_FOG,
D2DLL_GLIDE3X,
D2DLL_IJL11,
D2DLL_SMACKW32,
D2DLL_STORM,
D2DLL_PLUGY,
D2DLL_D2SERVER,
D2DLL_INVALID
};
OFFSET: This is the relative address at which the patch should be applied. Example, you want to patch something at D2Game.0x6FC25000, assuming the base address is 0x6FC20000, you would then set this part of the array as 0x5000.
SIZE: This here defines the number of bytes to patch. Setting this to 0 will make it patch a DWORD. You should use non-zero values only when you want to make big repetitive patches, such as nop blocks. Example:
Code: Select all
{D2DLL_D2CLIENT, 0x9A6F1, (DWORD)PATCH_NOPBLOCK, FALSE, 0x34},
This patch would look like this once applied:
Code: Select all
6FB4A6F1 90 NOP
6FB4A6F2 90 NOP
6FB4A6F3 90 NOP
6FB4A6F4 90 NOP
6FB4A6F5 90 NOP
6FB4A6F6 90 NOP
6FB4A6F7 90 NOP
6FB4A6F8 90 NOP
6FB4A6F9 90 NOP
6FB4A6FA 90 NOP
6FB4A6FB 90 NOP
6FB4A6FC 90 NOP
6FB4A6FD 90 NOP
6FB4A6FE 90 NOP
6FB4A6FF 90 NOP
6FB4A700 90 NOP
6FB4A701 90 NOP
6FB4A702 90 NOP
6FB4A703 90 NOP
6FB4A704 90 NOP
6FB4A705 90 NOP
6FB4A706 90 NOP
6FB4A707 90 NOP
6FB4A708 90 NOP
6FB4A709 90 NOP
6FB4A70A 90 NOP
6FB4A70B 90 NOP
6FB4A70C 90 NOP
6FB4A70D 90 NOP
6FB4A70E 90 NOP
6FB4A70F 90 NOP
6FB4A710 90 NOP
6FB4A711 90 NOP
6FB4A712 90 NOP
6FB4A713 90 NOP
6FB4A714 90 NOP
6FB4A715 90 NOP
6FB4A716 90 NOP
6FB4A717 90 NOP
6FB4A718 90 NOP
6FB4A719 90 NOP
6FB4A71A 90 NOP
6FB4A71B 90 NOP
6FB4A71C 90 NOP
6FB4A71D 90 NOP
6FB4A71E 90 NOP
6FB4A71F 90 NOP
6FB4A720 90 NOP
6FB4A721 90 NOP
6FB4A722 90 NOP
6FB4A723 90 NOP
6FB4A724 90 NOP
PATCH DATA: This is the data you want to patch. This can be a function, some bytes, whatever you want. This is explained further later in this tutorial.
RELATIVE: This tells the patcher whether it should consider this patch as a relative address. If you look at how calls or jumps work in ASM, you will notice it doesn't point directly to an address
Code: Select all
6FB4A6CE E8 DD28FFFF CALL D2Client.6FB3CFB0
Setting this to true will make the patcher handle this stuff on it's own so that we don't need to worry about it. So when patching function adresses basically, you set this to true. (in most cases)
--------------------------------------------------------------------------------------------------
Patch Defintions Examples
There's plenty of different stuff you can patch using the patcher, but here goes the main ones you will be using.
You will likely find out what other types of patches there is to make by yourself as you get better at code injection with the template.
Patching a NOP block
The following patch would patch a block of 52 NOP's at D2Client.0x9A6F1
Code: Select all
{D2DLL_D2CLIENT, 0x9A6F1, (DWORD)PATCH_NOPBLOCK, FALSE, 0x34},
This patch would look like this once applied:
Code: Select all
6FB4A6F1 90 NOP
6FB4A6F2 90 NOP
6FB4A6F3 90 NOP
6FB4A6F4 90 NOP
6FB4A6F5 90 NOP
6FB4A6F6 90 NOP
6FB4A6F7 90 NOP
6FB4A6F8 90 NOP
6FB4A6F9 90 NOP
6FB4A6FA 90 NOP
6FB4A6FB 90 NOP
6FB4A6FC 90 NOP
6FB4A6FD 90 NOP
6FB4A6FE 90 NOP
6FB4A6FF 90 NOP
6FB4A700 90 NOP
6FB4A701 90 NOP
6FB4A702 90 NOP
6FB4A703 90 NOP
6FB4A704 90 NOP
6FB4A705 90 NOP
6FB4A706 90 NOP
6FB4A707 90 NOP
6FB4A708 90 NOP
6FB4A709 90 NOP
6FB4A70A 90 NOP
6FB4A70B 90 NOP
6FB4A70C 90 NOP
6FB4A70D 90 NOP
6FB4A70E 90 NOP
6FB4A70F 90 NOP
6FB4A710 90 NOP
6FB4A711 90 NOP
6FB4A712 90 NOP
6FB4A713 90 NOP
6FB4A714 90 NOP
6FB4A715 90 NOP
6FB4A716 90 NOP
6FB4A717 90 NOP
6FB4A718 90 NOP
6FB4A719 90 NOP
6FB4A71A 90 NOP
6FB4A71B 90 NOP
6FB4A71C 90 NOP
6FB4A71D 90 NOP
6FB4A71E 90 NOP
6FB4A71F 90 NOP
6FB4A720 90 NOP
6FB4A721 90 NOP
6FB4A722 90 NOP
6FB4A723 90 NOP
6FB4A724 90 NOP
Patching a function call (to call our own function instead)
The following patch would replace the call to D2Client.0xC39E0 with our own function. Notice we don't patch D2Client.0x4437B here, but rather one byte later as we do not want to overwrite the CALL instruction. An ASM CALL instruction looks like this
0xE8 ########. The 0xE8 is the CALL instruction, the ######## is the part we want to patch.
Code: Select all
{D2DLL_D2CLIENT, 0x4437C, (DWORD)D2UI_Main, TRUE, 0x00},
The patch would look like this once applied:
Code: Select all
6FAF437B E8 ######## CALL D2Template.########
Patching a function call (where there is no call instruction originally)
Similar to the previous patch, except that we're patching a location where there is no call instruction originally, so we need to patch it ourself.
Code: Select all
{D2DLL_D2CLIENT, 0x8B1DE, (DWORD)PATCH_CALL, FALSE, 0x00}, // needs to be declared first
{D2DLL_D2CLIENT, 0x8B1DF, (DWORD)DRLGUI_LevelBackground, TRUE, 0x00},
The patch would look like this once applied:
Code: Select all
6FB3B1DE E8 ######## CALL D2Template.########
You can do the same thing with a jump if you want:
Code: Select all
{D2DLL_FOG, 0x17F60, (DWORD)PATCH_JMP, FALSE, 0x00},
{D2DLL_FOG, 0x17F61, (DWORD)SAVEFILE_GetSavePath, TRUE, 0x00},