Blizzhackers

Return of the Jedi

* Login   * Register    * FAQ    * Search

Join us on IRC: #bh@irc.synirc.net (or Mibbit Web IRC)


MuleFactory


It is currently Fri May 24, 2013 2:28 pm


All times are UTC [ DST ]





Post new topic Reply to topic  [ 9 posts ] 
Author Message
 Post subject: D2res (Wall of Text)
PostPosted: Sat Apr 07, 2012 10:03 pm 
 
User
User

Joined: Sat Mar 17, 2012 5:39 pm
This is my own little (shitty) resolution hack, similar to all the previous resolution hacks, but by no means completed. There is still much work to be done, and yet, so little time...

REV 04/08/12 @ 3:10 PM EST

This is assuming you are developing for Closed Battle.net. A lot of things can be simplified if you only plan to use this for Single Player/Open Battle.net.

The first order of business is something you will need to do on your own: develop a system to auto-inject your DLL before SetDisplayMode is called. After you solve this little dilemma, it's all smooth sailing. You might also consider developing a system for auto-injecting when the Diablo II window gains the focus, in case you Alt+Tab.

Below is a simple DLL injector, but does not include either of the systems I mentioned above. I don't feel like I need to explain this, because I am lazy, and there are tons of explanations out there already. Plus, I'm just no good at commenting my code.

D2LoadDll.cpp

#pragma warning(disable:4996)

#include <Windows.h>


Before the WinMain function, there is the user-defined function, SetDebugPrivilege, which enables/disables the Debug privilege. This will allow D2LoadDll to open the Diablo II (Game.exe) process handle. For a more detailed explanation, take a look at this article, on MSDN. This step is skipped a lot because most processes don't require the Debug privilege to open the process handle. You can avoid this by creating your own launcher.

void SetDebugPrivilege(HANDLE TokenHandle, BOOL bPrivilegeEnabled)
{
   LUID Luid;
   TOKEN_PRIVILEGES NewState;

   LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &Luid);

   NewState.PrivilegeCount = 1;
   NewState.Privileges[0].Luid = Luid;
   if(bPrivilegeEnabled)
   {
      NewState.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
   }
   else
   {
      NewState.Privileges[0].Attributes = 0;
   }

   AdjustTokenPrivileges(TokenHandle, FALSE, &NewState, 0, NULL, NULL);
}


Again, for a more detailed explanation, take a look at this thread, by Darawk, or type "Dll Injection" into Google. You need only change the second strcat parameter to that of your DLL name for this to function. Unfortunately, without the systems I mentioned earlier, you will be required to inject after every game, which is a very tedious task.

int CALLBACK WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
   HANDLE TokenHandle;
   HWND hWnd;
   DWORD dwProcessId;
   HANDLE hProcess;
   char lpBuffer[MAX_PATH];
   size_t nSize;
   LPVOID lpFileName;
   HANDLE hThread;

   OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &TokenHandle);
   SetDebugPrivilege(TokenHandle, TRUE);

   hWnd = FindWindow("Diablo II", "Diablo II");
   GetWindowThreadProcessId(hWnd, &dwProcessId);
   hProcess = OpenProcess(PROCESS_CREATE_THREAD|PROCESS_VM_OPERATION|PROCESS_VM_WRITE, FALSE, dwProcessId);

   SetDebugPrivilege(TokenHandle, FALSE);
   CloseHandle(TokenHandle);

   GetCurrentDirectory(sizeof(lpBuffer), lpBuffer);
   strcat(lpBuffer, "\\D2res.dll");
   nSize = strlen(lpBuffer) + 1;

   lpFileName = VirtualAllocEx(hProcess, NULL, nSize, MEM_COMMIT|MEM_RESERVE, PAGE_READWRITE);
   WriteProcessMemory(hProcess, lpFileName, lpBuffer, nSize, NULL);
   hThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)LoadLibrary, lpFileName, 0, NULL);

   WaitForSingleObject(hThread, INFINITE);
   VirtualFreeEx(hProcess, lpFileName, nSize, MEM_RELEASE);

   CloseHandle(hProcess);
   CloseHandle(hThread);

   return 0;
}


I'd like to mention some (less than) valuable tips for making your own resolution hack before throwing unexplained code at you. If you want to make a fully functional resolution hack (DD/D3D/Glide/Win), you will need to find the functions and pointers on your own. To do this is relatively simple. First, set the mode you want by running the Video Test or setting -w as a command line parameter. Next, go into a game, search for your current resolution width, change it, refine your search using the new resolution width, and repeat; Game Hacking 101. Finally, break on Write and viola. Some of what you will find might be in D2DDraw.dll/D2Direct3D.dll/D2Glide.dll/D2Gdi.dll, but the main components are located in D2gfx.dll/D2Win.dll/D2Client.dll. For example, display mode for D3D is in D2Direct3D.dll, but the resolution is in D2Client.dll.

D2Direct3D.dll

6F88BE5E  |.  8935 6C318B6F           mov dword ptr ds:[6F8B316C], esi
6F88BE64  |.  75 16                   jnz short 6F88BE7C
6F88BE66  |.  C705 6C298B6F 80020000  mov dword ptr ds:[6F8B296C], 280
6F88BE70  |.  C705 FC2D8B6F E0010000  mov dword ptr ds:[6F8B2DFC], 1E0
6F88BE7A  |.  EB 14                   jmp short 6F88BE90
6F88BE7C  |>  C705 6C298B6F 20030000  mov dword ptr ds:[6F8B296C], 320
6F88BE86  |.  C705 FC2D8B6F 58020000  mov dword ptr ds:[6F8B2DFC], 258
...
6F88BEDE  |> \8B0D FC2D8B6F           mov ecx, dword ptr ds:[6F8B2DFC]
6F88BEE4  |.  A1 44318B6F             mov eax, dword ptr ds:[6F8B3144]
6F88BEE9  |.  8B10                    mov edx, dword ptr ds:[eax]
6F88BEEB  |.  53                      push ebx
6F88BEEC  |.  53                      push ebx
6F88BEED  |.  6A 10                   push 10
6F88BEEF  |.  51                      push ecx
6F88BEF0  |.  8B0D 6C298B6F           mov ecx, dword ptr ds:[6F8B296C]
6F88BEF6  |.  51                      push ecx
6F88BEF7  |.  50                      push eax
6F88BEF8  |.  FF52 54                 call dword ptr ds:[edx+54]


D2Client.dll

6FADC220   $  E8 BB0DFEFF             call <jmp.&D2gfx.#10012>
6FADC225   .  3BF0                    cmp esi, eax
6FADC227   .  0F84 89000000           je 6FADC2B6
6FADC22D   .  8BC6                    mov eax, esi
6FADC22F   .  83E8 00                 sub eax, 0                               ;  Switch (cases 0..2)
6FADC232   .  74 25                   je short 6FADC259
6FADC234   .  83E8 02                 sub eax, 2
6FADC237   .  75 40                   jnz short 6FADC279
6FADC239   .  B8 20030000             mov eax, 320                             ;  Case 2 of switch 6FADC22F
6FADC23E   .  A3 3470BA6F             mov dword ptr ds:[6FBA7034], eax
6FADC243   .  C705 3870BA6F 58020000  mov dword ptr ds:[6FBA7038], 258
6FADC24D   .  C705 B4D2BC6F 01000000  mov dword ptr ds:[6FBCD2B4], 1
6FADC257   .  EB 25                   jmp short 6FADC27E
6FADC259   >  B8 80020000             mov eax, 280                             ;  Case 0 of switch 6FADC22F
6FADC25E   .  A3 3470BA6F             mov dword ptr ds:[6FBA7034], eax
6FADC263   .  C705 3870BA6F E0010000  mov dword ptr ds:[6FBA7038], 1E0
6FADC26D   .  C705 B4D2BC6F 00000000  mov dword ptr ds:[6FBCD2B4], 0
6FADC277   .  EB 05                   jmp short 6FADC27E
6FADC279   >  A1 3470BA6F             mov eax, dword ptr ds:[6FBA7034]         ;  Default case of switch 6FADC22F
6FADC27E   >  8B0D 3870BA6F           mov ecx, dword ptr ds:[6FBA7038]
6FADC284   .  83C1 D8                 add ecx, -28
6FADC287   .  56                      push esi
6FADC288   .  A3 643DBD6F             mov dword ptr ds:[6FBD3D64], eax
6FADC28D   .  890D 603DBD6F           mov dword ptr ds:[6FBD3D60], ecx
6FADC293   .  A3 3C70BA6F             mov dword ptr ds:[6FBA703C], eax
6FADC298   .  E8 A910FEFF             call <jmp.&D2Win.#10037>
6FADC29D   .  A1 70D0BC6F             mov eax, dword ptr ds:[6FBCD070]
6FADC2A2   .  E8 49020300             call 6FB0C4F0
6FADC2A7   .  B9 01000000             mov ecx, 1
6FADC2AC   .  E8 0F5D0400             call 6FB21FC0
6FADC2B1   .^ E9 DA07FFFF             jmp 6FACCA90
6FADC2B6   >  C3                      retn


A little helper function I developed to get the correct base for the specified module: GetModuleBase will attempt to get the base using GetModuleHandle; however, if the module isn't loaded (D2Client.dll, for example), it's loaded into the process with LoadLibrary. This is assuming the specified module is in the Diablo II directory. The great thing about this is that you don't have to worry about when you can access certain functions or pointers.

D2res.cpp

DWORD GetModuleBase(LPCSTR lpModuleName)
{
   DWORD dwModuleBase;

   dwModuleBase = (DWORD)GetModuleHandle(lpModuleName);

   if(dwModuleBase == NULL)
   {
      dwModuleBase = (DWORD)LoadLibrary(lpModuleName);
   }

   return dwModuleBase;
}


Changing the display mode without using "detours" (Microsoft or otherwise) requires a vtable hook; do the hooking inside the DLL_PROCESS_ATTACH routine (or a thread therein). You must remember to unhook the vtable after SetDisplayMode is called, and before you return from the hook. Also, clean up any other changes to the client in the DLL_PROCESS_DETACH routine. The code in its current state will not work. You must develop a system to unload the DLL after the hook is executed. An incomplete exampled is embedded in the code.

D2res.cpp

void OnDllProcessAttach(HMODULE hModule)
{
   /*
   6F88BEE4  |.  A1 44318B6F   mov eax, dword ptr ds:[6F8B3144]
   6F88BEE9  |.  8B10          mov edx, dword ptr ds:[eax]
   ...
   6F88BEF8  |.  FF52 54       call dword ptr ds:[edx+54]
   */

   LPDIRECTDRAW4 lpDD;

   // IDirectDraw4 *
   lpDD = (LPDIRECTDRAW4)*(LPDWORD)(D2Direct3D_dll + 0x33144); // [6F8B3144]
   g_lpDDVTable = (LPDWORD)*(LPDWORD)lpDD;
   // SetDisplayMode
   *(LPDWORD)&SetDisplayMode = g_lpDDVTable[21];
   *(LPDWORD)&g_lpDDVTable[21] = (DWORD)SetDisplayModeHook;

//   while(!bExitThread)
//   {
//      Sleep(1);
//   }

   FreeLibraryAndExitThread(hModule, EXIT_SUCCESS);
}


The SetDisplayMode hook is where the display mode and resolution are changed. Don't forget to declare the D2Client_dll global somewhere (D2Client.h, perhaps). You will probably want to find a different time to change the resolution, and is probably the source of a small bug I'll mention later.

D2Direct3D.h

#include <ddraw.h>

const DWORD D2Direct3D_dll = GetModuleBase("D2Direct3D.dll");

LPDWORD g_lpDDVTable;

DWORD g_dwWidth = GetSystemMetrics(SM_CXSCREEN);
DWORD g_dwHeight = GetSystemMetrics(SM_CYSCREEN);

typedef HRESULT (WINAPI *SETDISPLAYMODE)(LPDIRECTDRAW4 lpDD, DWORD dwWidth, DWORD dwHeight, DWORD dwBPP, DWORD dwRefreshRate, DWORD dwFlags);
SETDISPLAYMODE SetDisplayMode;

HRESULT WINAPI SetDisplayModeHook(LPDIRECTDRAW4 lpDD, DWORD dwWidth, DWORD dwHeight, DWORD dwBPP, DWORD dwRefreshRate, DWORD dwFlags)
{
   HRESULT hResult;

   *(LPDWORD)(D2Direct3D_dll + 0x3296C) = g_dwWidth; // dwWidth [6F8B296C]
   *(LPDWORD)(D2Direct3D_dll + 0x32DFC) = g_dwHeight; // dwHeight [6F8B2DFC]

   dwWidth = g_dwWidth;
   dwHeight = g_dwHeight;

   hResult = SetDisplayMode(lpDD, dwWidth, dwHeight, dwBPP, dwRefreshRate, dwFlags);

   *(LPDWORD)(D2Client_dll + 0xF7034) = g_dwWidth; // [6FBA7034]
   *(LPDWORD)(D2Client_dll + 0xF7038) = g_dwHeight; // [6FBA7038]
   *(LPDWORD)(D2Client_dll + 0x11D2B4) = 0x1; // [6FBCD2B4]
   *(LPDWORD)(D2Client_dll + 0x123D64) = g_dwWidth; // [6FBD3D64]
   *(LPDWORD)(D2Client_dll + 0x123D60) = (g_dwHeight - 0x28); // [6FBD3D60] (y-0x28)
   *(LPDWORD)(D2Client_dll + 0xF703C) = g_dwWidth; // [6FBA703C]

   // SetDisplayMode
   *(LPDWORD)&g_lpDDVTable[21] = (DWORD)SetDisplayMode; // Retour

   return hResult;
}


Unfortunately, the screen is glitched until you bring up an inventory (inventory/stash/cube/etc.; press I, twice, and problem solved). If you can fix this, good for you. Everything should be self-explanatory at this point. I probably forgot to mention some things, so when/if I remember, I'll append them to this post.

Source: http://www.fileswap.com/dl/ZdvDml00fL/D2res.zip.html
Example: viewtopic.php?f=166&t=488658


Last edited by FireFromTheSky on Mon Apr 09, 2012 11:53 pm, edited 6 times in total.
Top
 Profile  
 Post subject: Re: D2res (Wall of Text)
PostPosted: Mon Apr 09, 2012 8:31 pm 
 
User
User
User avatar

Joined: Mon Apr 05, 2010 12:29 am
good work m8

Top
 Profile  
 Post subject: Re: D2res (Wall of Text)
PostPosted: Tue Apr 10, 2012 9:29 am 
 
User
User
User avatar

Joined: Sun Jun 22, 2008 7:00 pm
inv x, y offsets are in d2client.dll somewhere :/

_________________
d2bot# with kolbot
For live support: irc://irc.synirc.net/d2bs

Top
 Profile  
 Post subject: Re: D2res (Wall of Text)
PostPosted: Tue Apr 10, 2012 12:22 pm 
 
Moderator
Moderator
User avatar

Joined: Thu Apr 30, 2009 12:31 pm
Location: %scrdir%
inv x, y offsets are in d2client.dll somewhere :/
to be more precise, the lines for the current resolution mode get copied into a global cache (which doesn't get refreshed, you'll need to edit it directly) which then gets used, so modifying the compiled txt at runtime will have no effect

_________________
Learn C++, not Crap++ http://tinyurl.com/so-cxxbooks
Hackito Ergo Sum
Cthulhon: No, I am a dancer. I am in charge of popping and locking.

Top
 Profile  
 Post subject: Re: D2res (Wall of Text)
PostPosted: Wed Apr 11, 2012 11:04 am 
 
User
User
User avatar

Joined: Sun Jun 22, 2008 7:00 pm
inv x, y offsets are in d2client.dll somewhere :/
to be more precise, the lines for the current resolution mode get copied into a global cache (which doesn't get refreshed, you'll need to edit it directly) which then gets used, so modifying the compiled txt at runtime will have no effect


yup, you have to change it then change resolution mode

finding the resolution offsets are pretty easy you can just search for hex 800/600 in w/e decompiler you are using but you have to actually try to interpret the code to figure out where the inventory drawing code is and so on

a more "lame" solution would be to edit the dc6 file and make it so it aligns up with whereever your inventory is spawning now

_________________
d2bot# with kolbot
For live support: irc://irc.synirc.net/d2bs

Top
 Profile  
 Post subject: Re: D2res (Wall of Text)
PostPosted: Wed Apr 11, 2012 5:29 pm 
 
User
User

Joined: Sat Mar 17, 2012 5:39 pm
Don't just talk about it; be about it.

Top
 Profile  
 Post subject: Re: D2res (Wall of Text)
PostPosted: Wed Apr 11, 2012 9:44 pm 
 
User
User
User avatar

Joined: Sun Sep 04, 2011 10:07 pm
I personally made my resolution mode by porting from v1.10f edits, posted by Dav92 from the Phrozenkeep.
The only annoying things is that he shows edited code, so to see the original code, you have to use something like D2SE, run a clean v1.10f copy, and then port the edits to your version (v1.13c in my case)

You can find the offsets sheet there: http://snej.d2maniacs.org/forum/index.php?topic=34744.0
It has pretty much everything needed for a high-resolution mod.

Good luck.

Top
 Profile  
 Post subject: Re: D2res (Wall of Text)
PostPosted: Thu Apr 12, 2012 2:14 am 
 
User
User
User avatar

Joined: Sun Jun 22, 2008 7:00 pm
thats pretty nice

that guy spent super amounts of time doing that it seems like

he organized it really well

_________________
d2bot# with kolbot
For live support: irc://irc.synirc.net/d2bs

Top
 Profile  
 Post subject: Re: D2res (Wall of Text)
PostPosted: Thu Apr 12, 2012 3:12 am 
 
User
User
User avatar

Joined: Sun Sep 04, 2011 10:07 pm
thats pretty nice

that guy spent super amounts of time doing that it seems like

he organized it really well


Yes, it,s pretty useful. But like I said, the only inconvenient is that it shows some modified data, so you have to run a 1.10 copy to see the original code, then find it on your version. But it's very useful yes.

Top
 Profile  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 9 posts ] 

All times are UTC [ DST ]


Who is online

Users browsing this forum: No registered users and 8 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
Jump to:  
cron