
Looking at a series of posts about thirty lower case javascript programming, I also wanted to write something, though not in 30 lines, but after spending a minimum of time, just for fun. The installer of the classic Grand Theft Auto for Windows was downloaded. This GTA only works in standard resolutions with a 4: 3 aspect ratio, I decided to write a plugin that would run it in the native resolution of my monitor (1920x1080).
Before you start directly writing a plugin, you need to somehow load it into the game. For this, I use the universal
ASI Loader . GTA 1 - the game is quite old, so the best option would be to use
ddraw.dll . You can make sure that
Grand Theft Auto.exe really uses this library through the hex editor:

I copy the contents of the archive into the
Grand Theft Auto \ WINO folder (folder with the executable file), rename
dinput8.dll (ASI Loader) to
ddraw.dll . Knowing that the game will start in low resolution, I create an empty
wndmode.ini file in the same folder. Since ASI Loader includes
wndmode.dll , which was already
mentioned in Habré, if you have a wndmode.ini file, GTA should appear in the window.
')
When you first start the test plugin reports that everything works, and you can write your own:

The game menu has opened, in this form:

And it turned out that the game crashes when minimized, and had to abandon the window mode,
wndmode.ini was removed. Also the scripts folder has been deleted, as unnecessary. I start the game again, now when folding / unfolding it does not crash, it looks like this:

Naturally, 1024x768 in 2013 does not suit me, so in
Visual Studio I create a new Win32 project, the type is a DLL, and in the properties I set it up:
- Configuration - Release
- Character Set - Use Multibyte Encoding
- Runtime Library - Multi-threaded (/ MT)
- The final extension is .asi
- The output directory is E: \ Games \ Rockstar Games \ Grand Theft Auto Classics \ Grand Theft Auto \ WINO \
The basis of the plugin:
#include "stdafx.h" #include "CPatch.h" DWORD WINAPI Thread(LPVOID param) { return 0; } BOOL APIENTRY DllMain(HMODULE hModule, DWORD reason, LPVOID lpReserved) { if (reason == DLL_PROCESS_ATTACH) { HANDLE HndThread = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)&Thread, NULL, 0, NULL); } return TRUE; }
Now you need to know what memory addresses store the current value of the screen resolution. With their help, it will be possible to find the functions in which this value is recorded and replace this record with its own. I start the game, press the
F11 key, it allows you to change the screen resolution:

By default,
1024x768 was set, I open the
Cheat Engine , select the
Grand Theft Auto.exe process in it, in the search parameters I set the following settings:

After clicking the First Scan button, about twenty thousand addresses were found to weed out the extra ones, I changed the resolution several times in the game and searched for new values ​​through the Next Scan button. The same was done for the height, in the end I received about two dozen addresses:

Simply changing these addresses does not work, as they are overwritten with the current value immediately after the game is deployed.
Not at all certain that it would work, I decided that it was worth trying to replace the commands for recording the original permission with my own.
Having disassembled
Grand Theft Auto.exe in
IDA , the first thing I began to look at was the call parameters for the standard
CreateWindowExA ,
SetWindowPos ,
ShowWindow functions , until I came across this:

Before calling the
CreateWindowExA function, the game places on the stack the values ​​of
nWidth and
nHeight , which are located at
0x787310 and
0x787314 . These addresses are in the
Cheat Engine table, so I decided to start the substitution with them. To do this, in
IDA I press “X” on
nWidth , I look where the recording takes place (Type - w):

In the same place is written in
nHeight :

Returning to the studio, creating the function
patch_res () and making a jump to it at 0x491E4C:
CPatch::RedirectJump(0x491E4C, patch_res); ~~~ void __declspec(naked)patch_res() { _asm { mov eax, 1920 MOV DWORD PTR DS : [0x787310], EAX MOV DWORD PTR DS : [0x787370], EAX MOV EAX, DWORD PTR DS : [EBX + 1B4h] INC EAX TEST ECX, ECX mov eax, 1080 MOV DWORD PTR DS : [0x787314], EAX MOV DWORD PTR DS : [0x787388], EAX mov jmpAddress, 0x491E69 jmp jmpAddress } }
The original asm code was copied from OllyDbg, because the code from Cheat Engine or IDA studio does not always interpret correctly, you have to correct. I compile, run the game and see a familiar picture:

In the game itself is the same:

From the table
Cheat Engine rewrote some of the addresses, eliminating unnecessary:
CPatch::RedirectJump(0x491E4C, patch_res); CPatch::RedirectJump(0x414FF7, patch_res_x1); CPatch::RedirectJump(0x43B7CF, patch_res_x2); CPatch::RedirectJump(0x46453B, patch_res_x3); CPatch::RedirectJump(0x46452C, patch_res_x4); CPatch::RedirectJump(0x486848, patch_res_x5); CPatch::RedirectJump(0x486852, patch_res_x6); CPatch::RedirectJump(0x48C137, patch_res_x7); CPatch::RedirectJump(0x48C276, patch_res_x8); CPatch::RedirectJump(0x48C159, patch_res_x9); CPatch::RedirectJump(0x49168B, patch_res_x10); CPatch::RedirectJump(0x415008, patch_res_y1); CPatch::RedirectJump(0x43B7D8, patch_res_y2); CPatch::RedirectJump(0x464532, patch_res_y3); CPatch::RedirectJump(0x48683A, patch_res_y4); CPatch::RedirectJump(0x48C13D, patch_res_y5); CPatch::RedirectJump(0x48C2B0, patch_res_y6);
Created relevant functions:
void __declspec(naked)patch_res_x1() { _asm { mov eax, res_x MOV DWORD PTR DS : [0x504CC0], EAX mov jmpAddress, 0x414FFC jmp jmpAddress } } void __declspec(naked)patch_res_x2() { _asm { mov edx, res_x MOV DWORD PTR DS : [0x5C0C00], EDX mov jmpAddress, 0x43B7D5 jmp jmpAddress } } ~~~~~~~ void __declspec(naked)patch_res_y6() { _asm { mov eax, res_y MOV DWORD PTR DS : [0x787AF0], EAX mov jmpAddress, 0x48C2B5 jmp jmpAddress } } void __declspec(naked)patch_res_y7() { _asm { mov edx, res_y MOV DWORD PTR DS : [0x4B48C0], EDX mov jmpAddress, 0x48AE8B jmp jmpAddress } }
res_x and
res_y installed in
1920 and
1080 , but the result was not very pleased:

Although half the battle is done, the game works in
1920x1080 . At first, I decided that the render was incorrect due to the fact that not all values ​​in the Cheat Engine table were changed to 1920 and 1080. But it’s not realistic to catch them all, so I tried to remove redirects to some of my functions. By the method of scientific
typing , it was discovered that
patch_res_x4 ,
5 and
6 cause similar behavior, and without them everything works fine, except for the menu. Disabling the
x7-x10 puts in order and menu.
In the end, the result I expected, I achieved:


Of course, there were no side effects, the 2d sprites are a bit stretched, the menu is not displayed correctly at all resolutions, but this wasn’t my plan, so I leave it as it is.
The source code is available on
GitHub , ready fix
in the same place . The installer with the game was found on the Internet, because The official on Windows 8 does not start, and it is not currently
available for download. The exe size is 774,144 bytes, the plugin may not work with others.