D2Template

Threads that no longer serve a purpose. Read-only.
User avatar
evil_potato
Mangler
458 | 51
Great Popularity Badge
Has a thread with over 50.000 views
Common Love Badge
Earned over 20 cookies
Common Guide Badge
Created a complete character guide
if you ever want to do anything cool with programming, learn asm.
Food
Core Lord
360 | 32
Great Popularity Badge
Has a thread with over 50.000 views
Common Love Badge
Earned over 20 cookies
Great Patron Badge
Patreon Contributor
Common Contribution Badge
Has collaborated to our forums, realms or mod
I'm still looking into ASM hoping I'll be able to grasp enough of the thing to be useful here. Anyway I noticed a probable bug in the template.

In DLLmain.cpp D2TEMPLATE_ApplyPatch returns TRUE for success and FALSE for failure, but when the function is called inside D2TEMPLATE_DllAttach the return value is not checked.

Code: Select all

int __stdcall DllAttach()
{
   D2TEMPLATE_GetDebugPrivilege();

   void* hGame = OpenProcess(PROCESS_ALL_ACCESS, 0, GetCurrentProcessId());
   if (!hGame) return 0;

   if (!D2TEMPLATE_LoadModules())
   {
      CloseHandle(hGame);
      return 0;
   }

   D2TEMPLATE_ApplyPatch(hGame, gptTemplatePatches); // right here

   CloseHandle(hGame);

   return 1;
}


I suppose the code should be

Code: Select all

if (!D2TEMPLATE_ApplyPatch(hGame, gptTemplatePatches))
{
   CloseHandle(hGame);
   return 0;
};


Of course an or in the previous if would suffice, but long lines are less readable and split lines aren't as nice to look at.

I also have a question. How do I find stuff in the debugger? I mean, let's say I want to change the number of items generated in the gamble screen (first random thing I thought), how can I find where that code is executed? And more importantly, how would I recognize the relative code once I see it?

I'm not asking for a full course / tutorial, but a few pointers would be nice. And yes, I read another tutorial that explained how to make the game check for every item gamble cost in the .txt (as opposed to only rings and amulets) but it started with "let's go to this address of this specific dll because here is where the code is". That's cool, but supposing I didn't know where the code was, how would I find it?

Cheers.

EDIT: I realized that when a block patch is specified (so when size > 0) only the least significant byte of the DWORD (or whatever the patch size is) will be applied. Thus if I have this patch

Code: Select all

{D2DLL_D2CLIENT, 0x9A6F0, 0x05, (DWORD)0x8B4424CC, FALSE}


The resulting patch will NOT be

Code: Select all

6FB4A6F0    8B4424 CC              MOV EAX,DWORD PTR SS:[ESP-34]
6FB4A6F4    8B4424 CC              MOV EAX,DWORD PTR SS:[ESP-34]
6FB4A6F8    8B4424 CC              MOV EAX,DWORD PTR SS:[ESP-34]
6FB4A6FC    8B4424 CC              MOV EAX,DWORD PTR SS:[ESP-34]
6FB4A700    8B4424 CC              MOV EAX,DWORD PTR SS:[ESP-34]


but rather:

Code: Select all

6FB4A6F0    CC              INT3
6FB4A6F1    CC              INT3
6FB4A6F2    CC              INT3
6FB4A6F3    CC              INT3
6FB4A6F4    CC              INT3


I guess this makes sense since I don't foresee the need to replicate the same exact WORD-sized command over and over, so I believe this is by design? Well, anyway it's documented now.

As an aside, this means that block patches would IMHO be more readable if they were written like

Code: Select all

{D2DLL_D2CLIENT, 0x9A6F1, 0x34, (BYTE)PATCH_NOPBLOCK, FALSE}

so the fact they can only be byte-sized would be rather obvious.
User avatar
evil_potato
Mangler
458 | 51
Great Popularity Badge
Has a thread with over 50.000 views
Common Love Badge
Earned over 20 cookies
Common Guide Badge
Created a complete character guide
never done much reversing/cracking with games, but i'd imagine you'd want to figure out which windows APIs were being used to draw the items, set breakpoints on all instances of them, root around in the functions using those apis a bit to find out which one was being called when you generate items to gamble, and work from there.
thaison
Skeleton
3 | 0
Food wrote:I'm still looking into ASM hoping I'll be able to grasp enough of the thing to be useful here. Anyway I noticed a probable bug in the template.

In DLLmain.cpp D2TEMPLATE_ApplyPatch returns TRUE for success and FALSE for failure, but when the function is called inside D2TEMPLATE_DllAttach the return value is not checked.

Code: Select all

int __stdcall DllAttach()
{
   D2TEMPLATE_GetDebugPrivilege();

   void* hGame = OpenProcess(PROCESS_ALL_ACCESS, 0, GetCurrentProcessId());
   if (!hGame) return 0;

   if (!D2TEMPLATE_LoadModules())
   {
      CloseHandle(hGame);
      return 0;
   }

   D2TEMPLATE_ApplyPatch(hGame, gptTemplatePatches); // right here

   CloseHandle(hGame);

   return 1;
}


I suppose the code should be

Code: Select all

if (!D2TEMPLATE_ApplyPatch(hGame, gptTemplatePatches))
{
   CloseHandle(hGame);
   return 0;
};


Of course an or in the previous if would suffice, but long lines are less readable and split lines aren't as nice to look at.

I also have a question. How do I find stuff in the debugger? I mean, let's say I want to change the number of items generated in the gamble screen (first random thing I thought), how can I find where that code is executed? And more importantly, how would I recognize the relative code once I see it?

I'm not asking for a full course / tutorial, but a few pointers would be nice. And yes, I read another tutorial that explained how to make the game check for every item gamble cost in the .txt (as opposed to only rings and amulets) but it started with "let's go to this address of this specific dll because here is where the code is". That's cool, but supposing I didn't know where the code was, how would I find it?

Cheers.

EDIT: I realized that when a block patch is specified (so when size > 0) only the least significant byte of the DWORD (or whatever the patch size is) will be applied. Thus if I have this patch

Code: Select all

{D2DLL_D2CLIENT, 0x9A6F0, 0x05, (DWORD)0x8B4424CC, FALSE}


The resulting patch will NOT be

Code: Select all

6FB4A6F0    8B4424 CC              MOV EAX,DWORD PTR SS:[ESP-34]
6FB4A6F4    8B4424 CC              MOV EAX,DWORD PTR SS:[ESP-34]
6FB4A6F8    8B4424 CC              MOV EAX,DWORD PTR SS:[ESP-34]
6FB4A6FC    8B4424 CC              MOV EAX,DWORD PTR SS:[ESP-34]
6FB4A700    8B4424 CC              MOV EAX,DWORD PTR SS:[ESP-34]


but rather:

Code: Select all

6FB4A6F0    CC              INT3
6FB4A6F1    CC              INT3
6FB4A6F2    CC              INT3
6FB4A6F3    CC              INT3
6FB4A6F4    CC              INT3


I guess this makes sense since I don't foresee the need to replicate the same exact WORD-sized command over and over, so I believe this is by design? Well, anyway it's documented now.

As an aside, this means that block patches would IMHO be more readable if they were written like

Code: Select all

{D2DLL_D2CLIENT, 0x9A6F1, 0x34, (BYTE)PATCH_NOPBLOCK, FALSE}

so the fact they can only be byte-sized would be rather obvious.

Here

Code: Select all

#define name           0xCC24448B


And

Code: Select all

{D2DLL_D2CLIENT, 0x9A6F0, 0x05, (DWORD)name, FALSE}
User avatar
whist
Team Member
641 | 562
Legendary Popularity Badge
Has a thread with over 250.000 views
Legendary Love Badge
Earned over 500 cookies
Great Supporter Badge
Donated 5 times
Legendary Contribution Badge
Median XL Team Member
Sorry, somehow missed the replies on this post.
Food wrote:I'm still looking into ASM hoping I'll be able to grasp enough of the thing to be useful here. Anyway I noticed a probable bug in the template.
In DLLmain.cpp D2TEMPLATE_ApplyPatch returns TRUE for success and FALSE for failure, but when the function is called inside D2TEMPLATE_DllAttach the return value is not checked.


Well, I used to check the return value a long time ago, but the template was made from the base project I use for Sigma. And before I released this template, I had splitted patches in multiple arrays (one for every dll), for various reasons. Didn't feel like checking the return value for every call, and besides it's not necessary, the function will likely never fail. The important one to check is D2TEMPLATE_LoadModules.

Code: Select all

int __stdcall DllAttach()
{
   D2TEMPLATE_GetDebugPrivilege();

   void* hGame = OpenProcess(PROCESS_ALL_ACCESS, 0, GetCurrentProcessId());
   if (!hGame) return 0;

   if (!D2TEMPLATE_LoadModules())
   {
      CloseHandle(hGame);
      return 0;
   }
   
   #define __SERVER_BUILD__
   
   D2TEMPLATE_ApplyPatch(hGame, gptD2ServerPatches);
   
   #endif

   D2TEMPLATE_ApplyPatch(hGame, gptD2GamePatches);
   D2TEMPLATE_ApplyPatch(hGame, gptD2ClientPatches);
   D2TEMPLATE_ApplyPatch(hGame, gptD2CommonPatches);
   D2TEMPLATE_ApplyPatch(hGame, gptD2GfxPatches);
   D2TEMPLATE_ApplyPatch(hGame, gptD2WinPatches);
   D2TEMPLATE_ApplyPatch(hGame, gptD2LangPatches);
   D2TEMPLATE_ApplyPatch(hGame, gptD2FogPatches);
   D2TEMPLATE_ApplyPatch(hGame, gptD2NetPatches);

   #ifdef __CLIENT_BUILD__

   if (!CONFIG_AllocConfigData()) return 0;

   D2TEMPLATE_ApplyPatch(hGame, gptD2LaunchPatches);
   D2TEMPLATE_ApplyPatch(hGame, gptD2GdiPatches);
   D2TEMPLATE_ApplyPatch(hGame, gptD2GlidePatches);
   D2TEMPLATE_ApplyPatch(hGame, gptD2Direct3DPatches);
   D2TEMPLATE_ApplyPatch(hGame, gptD2SmackW32Patches);
   D2TEMPLATE_ApplyPatch(hGame, gptD2BnClientPatches);

   #endif

   THREADS_Create();
   CloseHandle(hGame);

   return 1;
}


Food wrote:I also have a question. How do I find stuff in the debugger? I mean, let's say I want to change the number of items generated in the gamble screen (first random thing I thought), how can I find where that code is executed? And more importantly, how would I recognize the relative code once I see it?

I'm not asking for a full course / tutorial, but a few pointers would be nice. And yes, I read another tutorial that explained how to make the game check for every item gamble cost in the .txt (as opposed to only rings and amulets) but it started with "let's go to this address of this specific dll because here is where the code is". That's cool, but supposing I didn't know where the code was, how would I find it?


This question gets asked quite often, and the answer will always be the same, there is no precise way to find stuff. There are many different tricks you can use to find stuff, it varies a lot from one change to another. If you wanted to find the function that draws the inventory for example, you would search for the string corresponding to the dc6's file name, see where it gets loaded up, then see where the cached cellfile pointer gets used from. That's just one example out of many others, and listing them all would be way too long. Basically you just learn tricks as you progress. One good thing to do as well, is labeling everything you find. Functions, variables, label them all. Eventually you get to a point where you have a good overview of the codebase. At some point you get to recognize some structures in the memory, unit pointers for example, and so analyzing functions without knowing them becomes possible. And finally, remember you're not starting from scratch. The Phrozenkeep has an almost infinite amount of resources to get you started on finding something. In worse case you can always ask a question if you don't find any topic that helps you finding what you're looking for, chances are someone knows where to look. Some few subjects are prohibited, mainly stuff related to client<->server communication, but if you ever need some information in this subject you can take a chance and throw me a pm, might be able to help you out.

Food wrote:EDIT: I realized that when a block patch is specified (so when size > 0) only the least significant byte of the DWORD (or whatever the patch size is) will be applied. Thus if I have this patch


Yes that is indeed intended. This feature is mainly meant for quick fix patches, usually nop blocks. I remember I had implemented this in the base project used for sigma because it was annoying to create mutiple patches for nop blocks. Like this one for example, would require 9 patch lines to achieve without this small feature.

Code: Select all

{D2DLL_D2COMMON,   0x602B6,   0x26,   (DWORD)PATCH_NOPBLOCK,                     FALSE},   //states records limit


The code for this is here, in D2TEMPLATE_ApplyPatch

Code: Select all

if (hPatch->nPatchSize > 0)
      {
         BYTE Buffer[8192];
         for (size_t i = 0; i < hPatch->nPatchSize; i++)
         {
            Buffer[i] = (BYTE)dwData;
         }

         VirtualProtect(hAddress, hPatch->nPatchSize, PAGE_EXECUTE_READWRITE, &dwOldPage);
         nReturn = WriteProcessMemory(hGame, hAddress, &Buffer, hPatch->nPatchSize, 0);
         VirtualProtect(hAddress, hPatch->nPatchSize, dwOldPage, 0);
      }