2014-09-22 23:35:43 +02:00
|
|
|
#define WIN32_LEAN_AND_MEAN
|
2015-04-22 01:00:36 +02:00
|
|
|
#define WINVER 0x0501
|
|
|
|
#define _WIN32_WINNT 0x0501
|
2014-09-22 23:35:43 +02:00
|
|
|
|
|
|
|
#include <windows.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <Shlwapi.h>
|
2015-04-22 01:00:36 +02:00
|
|
|
#include <ShlObj.h>
|
2014-09-22 23:35:43 +02:00
|
|
|
#include "MemoryMgr.h"
|
2017-09-18 17:19:56 +02:00
|
|
|
#include "Patterns.h"
|
2014-09-22 23:35:43 +02:00
|
|
|
|
2017-09-18 13:46:14 +02:00
|
|
|
#pragma comment(lib, "shlwapi.lib")
|
|
|
|
|
2014-09-22 23:35:43 +02:00
|
|
|
extern "C" HRESULT WINAPI DirectDrawCreateEx(GUID FAR *lpGUID, LPVOID *lplpDD, REFIID iid, IUnknown FAR *pUnkOuter)
|
|
|
|
{
|
|
|
|
static HRESULT (WINAPI *pDirectDrawCreateEx)(GUID FAR*, LPVOID*, REFIID, IUnknown FAR*);
|
2015-05-02 00:46:46 +02:00
|
|
|
if ( pDirectDrawCreateEx == nullptr )
|
2014-09-22 23:35:43 +02:00
|
|
|
{
|
|
|
|
wchar_t wcSystemPath[MAX_PATH];
|
|
|
|
GetSystemDirectoryW(wcSystemPath, MAX_PATH);
|
|
|
|
PathAppendW(wcSystemPath, L"ddraw.dll");
|
|
|
|
|
|
|
|
HMODULE hLib = LoadLibraryW(wcSystemPath);
|
|
|
|
pDirectDrawCreateEx = (HRESULT(WINAPI*)(GUID FAR*, LPVOID*, REFIID, IUnknown FAR*))GetProcAddress(hLib, "DirectDrawCreateEx");
|
|
|
|
}
|
2014-10-12 02:55:16 +02:00
|
|
|
return pDirectDrawCreateEx(lpGUID, lplpDD, iid, pUnkOuter);
|
|
|
|
}
|
|
|
|
|
2015-04-22 01:00:36 +02:00
|
|
|
char** ppUserFilesDir;
|
|
|
|
|
|
|
|
char* GetMyDocumentsPath()
|
|
|
|
{
|
|
|
|
static char cUserFilesPath[MAX_PATH];
|
|
|
|
|
|
|
|
if ( cUserFilesPath[0] == '\0' )
|
|
|
|
{
|
2017-04-09 18:21:07 +02:00
|
|
|
SHGetFolderPathA(nullptr, CSIDL_MYDOCUMENTS, nullptr, SHGFP_TYPE_CURRENT, cUserFilesPath);
|
|
|
|
PathAppendA(cUserFilesPath, *ppUserFilesDir);
|
2015-06-25 01:19:46 +02:00
|
|
|
|
2017-04-09 18:21:07 +02:00
|
|
|
CreateDirectoryA(cUserFilesPath, nullptr);
|
2015-04-22 01:00:36 +02:00
|
|
|
}
|
|
|
|
return cUserFilesPath;
|
|
|
|
}
|
|
|
|
|
2015-06-25 01:19:46 +02:00
|
|
|
|
|
|
|
void InjectHooks()
|
2014-10-12 02:55:16 +02:00
|
|
|
{
|
2016-08-10 22:27:58 +02:00
|
|
|
using namespace Memory::VP;
|
2014-10-12 02:55:16 +02:00
|
|
|
|
2015-06-25 01:19:46 +02:00
|
|
|
static char aNoDesktopMode[64];
|
|
|
|
|
|
|
|
RECT desktop;
|
|
|
|
GetWindowRect(GetDesktopWindow(), &desktop);
|
2016-03-31 19:51:14 +02:00
|
|
|
sprintf_s(aNoDesktopMode, "Cannot find %dx%dx32 video mode", desktop.right, desktop.bottom);
|
2015-06-25 01:19:46 +02:00
|
|
|
|
|
|
|
if (*(DWORD*)0x5C1E75 == 0xB85548EC)
|
|
|
|
{
|
|
|
|
// III 1.0
|
|
|
|
ppUserFilesDir = (char**)0x580C16;
|
|
|
|
InjectHook(0x580BB0, GetMyDocumentsPath, PATCH_JUMP);
|
|
|
|
|
|
|
|
Patch<DWORD>(0x581E5E, desktop.right);
|
|
|
|
Patch<DWORD>(0x581E68, desktop.bottom);
|
|
|
|
Patch<BYTE>(0x581E72, 32);
|
|
|
|
Patch<const char*>(0x581EA8, aNoDesktopMode);
|
|
|
|
|
|
|
|
// No 12mb vram check
|
|
|
|
Patch<BYTE>(0x581411, 0xEB);
|
|
|
|
|
|
|
|
// No DirectPlay dependency
|
|
|
|
Patch<BYTE>(0x5812D6, 0xB8);
|
|
|
|
Patch<DWORD>(0x5812D7, 0x900);
|
|
|
|
}
|
|
|
|
else if (*(DWORD*)0x5C2135 == 0xB85548EC)
|
|
|
|
{
|
|
|
|
// III 1.1
|
|
|
|
ppUserFilesDir = (char**)0x580F66;
|
|
|
|
InjectHook(0x580F00, GetMyDocumentsPath, PATCH_JUMP);
|
|
|
|
|
|
|
|
Patch<DWORD>(0x58219E, desktop.right);
|
|
|
|
Patch<DWORD>(0x5821A8, desktop.bottom);
|
|
|
|
Patch<BYTE>(0x5821B2, 32);
|
|
|
|
Patch<const char*>(0x5821E8, aNoDesktopMode);
|
|
|
|
|
|
|
|
// No 12mb vram check
|
|
|
|
Patch<BYTE>(0x581753, 0xEB);
|
|
|
|
|
|
|
|
// No DirectPlay dependency
|
|
|
|
Patch<BYTE>(0x581620, 0xB8);
|
|
|
|
Patch<DWORD>(0x581621, 0x900);
|
|
|
|
}
|
|
|
|
else if (*(DWORD*)0x5C6FD5 == 0xB85548EC)
|
|
|
|
{
|
|
|
|
// III Steam
|
|
|
|
ppUserFilesDir = (char**)0x580E66;
|
|
|
|
InjectHook(0x580E00, GetMyDocumentsPath, PATCH_JUMP);
|
|
|
|
|
|
|
|
Patch<DWORD>(0x58208E, desktop.right);
|
|
|
|
Patch<DWORD>(0x582098, desktop.bottom);
|
|
|
|
Patch<BYTE>(0x5820A2, 32);
|
|
|
|
Patch<const char*>(0x5820D8, aNoDesktopMode);
|
|
|
|
|
|
|
|
// No 12mb vram check
|
|
|
|
Patch<BYTE>(0x581653, 0xEB);
|
|
|
|
|
|
|
|
// No DirectPlay dependency
|
|
|
|
Patch<BYTE>(0x581520, 0xB8);
|
|
|
|
Patch<DWORD>(0x581521, 0x900);
|
|
|
|
}
|
|
|
|
|
|
|
|
else if (*(DWORD*)0x667BF5 == 0xB85548EC)
|
|
|
|
{
|
|
|
|
// VC 1.0
|
|
|
|
ppUserFilesDir = (char**)0x6022AA;
|
|
|
|
InjectHook(0x602240, GetMyDocumentsPath, PATCH_JUMP);
|
|
|
|
|
|
|
|
InjectHook(0x601A40, GetMyDocumentsPath, PATCH_CALL);
|
|
|
|
InjectHook(0x601A45, 0x601B2F, PATCH_JUMP);
|
|
|
|
|
|
|
|
Patch<DWORD>(0x600E7E, desktop.right);
|
|
|
|
Patch<DWORD>(0x600E88, desktop.bottom);
|
|
|
|
Patch<BYTE>(0x600E92, 32);
|
|
|
|
Patch<const char*>(0x600EC8, aNoDesktopMode);
|
|
|
|
|
|
|
|
// No 12mb vram check
|
|
|
|
Patch<BYTE>(0x601E26, 0xEB);
|
|
|
|
|
|
|
|
// No DirectPlay dependency
|
|
|
|
Patch<BYTE>(0x601CA0, 0xB8);
|
|
|
|
Patch<DWORD>(0x601CA1, 0x900);
|
|
|
|
}
|
|
|
|
else if (*(DWORD*)0x667C45 == 0xB85548EC)
|
|
|
|
{
|
|
|
|
// VC 1.1
|
|
|
|
ppUserFilesDir = (char**)0x60228A;
|
|
|
|
InjectHook(0x602220, GetMyDocumentsPath, PATCH_JUMP);
|
|
|
|
|
|
|
|
InjectHook(0x601A70, GetMyDocumentsPath, PATCH_CALL);
|
|
|
|
InjectHook(0x601A75, 0x601B5F, PATCH_JUMP);
|
|
|
|
|
|
|
|
Patch<DWORD>(0x600E9E, desktop.right);
|
|
|
|
Patch<DWORD>(0x600EA8, desktop.bottom);
|
|
|
|
Patch<BYTE>(0x600EB2, 32);
|
|
|
|
Patch<const char*>(0x600EE8, aNoDesktopMode);
|
|
|
|
|
|
|
|
// No 12mb vram check
|
|
|
|
Patch<BYTE>(0x601E56, 0xEB);
|
|
|
|
|
|
|
|
// No DirectPlay dependency
|
|
|
|
Patch<BYTE>(0x601CD0, 0xB8);
|
|
|
|
Patch<DWORD>(0x601CD1, 0x900);
|
|
|
|
}
|
|
|
|
else if (*(DWORD*)0x666BA5 == 0xB85548EC)
|
|
|
|
{
|
|
|
|
// VC Steam
|
|
|
|
ppUserFilesDir = (char**)0x601ECA;
|
|
|
|
InjectHook(0x601E60, GetMyDocumentsPath, PATCH_JUMP);
|
|
|
|
|
|
|
|
InjectHook(0x6016B0, GetMyDocumentsPath, PATCH_CALL);
|
|
|
|
InjectHook(0x6016B5, 0x60179F, PATCH_JUMP);
|
|
|
|
|
|
|
|
Patch<DWORD>(0x600ADE, desktop.right);
|
|
|
|
Patch<DWORD>(0x600AE8, desktop.bottom);
|
|
|
|
Patch<BYTE>(0x600AF2, 32);
|
|
|
|
Patch<const char*>(0x600B28, aNoDesktopMode);
|
|
|
|
|
|
|
|
// No 12mb vram check
|
|
|
|
Patch<BYTE>(0x601A96, 0xEB);
|
|
|
|
|
|
|
|
// No DirectPlay dependency
|
|
|
|
Patch<BYTE>(0x601910, 0xB8);
|
|
|
|
Patch<DWORD>(0x601911, 0x900);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-09-18 17:19:56 +02:00
|
|
|
static bool FixRwcseg_Patterns();
|
|
|
|
static bool rwcsegUnprotected = false;
|
|
|
|
|
|
|
|
static void ProcHook()
|
2015-06-25 01:19:46 +02:00
|
|
|
{
|
|
|
|
static bool bPatched = false;
|
|
|
|
if ( !bPatched )
|
2015-04-22 01:00:36 +02:00
|
|
|
{
|
2015-06-25 01:19:46 +02:00
|
|
|
bPatched = true;
|
2015-05-02 00:27:56 +02:00
|
|
|
|
2015-06-25 01:19:46 +02:00
|
|
|
InjectHooks();
|
2017-09-18 17:19:56 +02:00
|
|
|
|
|
|
|
if ( !rwcsegUnprotected )
|
|
|
|
{
|
|
|
|
rwcsegUnprotected = FixRwcseg_Patterns();
|
|
|
|
}
|
2015-06-25 01:19:46 +02:00
|
|
|
}
|
2017-09-18 17:19:56 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static VOID (WINAPI* pOrgGetStartupInfoA)(LPSTARTUPINFOA);
|
|
|
|
VOID WINAPI GetStartupInfoA_Hook(LPSTARTUPINFOA lpStartupInfo)
|
|
|
|
{
|
|
|
|
ProcHook();
|
2015-06-25 01:19:46 +02:00
|
|
|
pOrgGetStartupInfoA(lpStartupInfo);
|
|
|
|
}
|
2015-05-02 00:27:56 +02:00
|
|
|
|
2017-09-18 17:19:56 +02:00
|
|
|
static uint8_t orgCode[5];
|
|
|
|
static decltype(SystemParametersInfoA)* pOrgSystemParametersInfoA;
|
|
|
|
BOOL WINAPI SystemParametersInfoA_OverwritingHook( UINT uiAction, UINT uiParam, PVOID pvParam, UINT fWinIni )
|
|
|
|
{
|
|
|
|
ProcHook();
|
|
|
|
Memory::VP::Patch( pOrgSystemParametersInfoA, { orgCode[0], orgCode[1], orgCode[2], orgCode[3], orgCode[4] } );
|
|
|
|
return pOrgSystemParametersInfoA( uiAction, uiParam, pvParam, fWinIni );
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool FixRwcseg_Header()
|
2015-06-25 01:19:46 +02:00
|
|
|
{
|
2017-04-27 22:15:40 +02:00
|
|
|
HINSTANCE hInstance = GetModuleHandle(nullptr);
|
2017-09-18 17:19:56 +02:00
|
|
|
PIMAGE_NT_HEADERS ntHeader = (PIMAGE_NT_HEADERS)((DWORD_PTR)hInstance + ((PIMAGE_DOS_HEADER)hInstance)->e_lfanew);
|
2015-05-02 00:27:56 +02:00
|
|
|
|
2015-06-25 01:19:46 +02:00
|
|
|
// Give _rwcseg proper access rights
|
2017-09-18 17:19:56 +02:00
|
|
|
PIMAGE_SECTION_HEADER pSection = IMAGE_FIRST_SECTION(ntHeader);
|
2015-04-22 01:00:36 +02:00
|
|
|
|
2016-09-12 00:11:17 +02:00
|
|
|
for ( SIZE_T i = 0, j = ntHeader->FileHeader.NumberOfSections; i < j; i++, pSection++ )
|
2015-06-25 01:19:46 +02:00
|
|
|
{
|
|
|
|
if ( *(uint64_t*)(pSection->Name) == 0x006765736377725F ) // _rwcseg
|
2015-04-22 01:00:36 +02:00
|
|
|
{
|
2015-06-25 01:19:46 +02:00
|
|
|
DWORD dwProtect;
|
2017-09-18 17:19:56 +02:00
|
|
|
VirtualProtect((LPVOID)((DWORD_PTR)hInstance + pSection->VirtualAddress), pSection->Misc.VirtualSize, PAGE_EXECUTE_READ, &dwProtect);
|
2017-04-27 22:12:48 +02:00
|
|
|
|
2017-05-17 00:36:09 +02:00
|
|
|
DWORD Characteristics = pSection->Characteristics;
|
|
|
|
if ( (Characteristics & IMAGE_SCN_CNT_CODE) == 0 )
|
2017-04-27 22:12:48 +02:00
|
|
|
{
|
2017-05-17 00:36:09 +02:00
|
|
|
Characteristics |= IMAGE_SCN_CNT_CODE;
|
|
|
|
Memory::VP::Patch( &ntHeader->OptionalHeader.SizeOfCode, ntHeader->OptionalHeader.SizeOfCode + pSection->Misc.VirtualSize );
|
2017-04-27 22:12:48 +02:00
|
|
|
}
|
2017-05-17 00:36:09 +02:00
|
|
|
if ( (Characteristics & IMAGE_SCN_CNT_INITIALIZED_DATA) != 0 )
|
2017-04-27 22:12:48 +02:00
|
|
|
{
|
2017-05-17 00:36:09 +02:00
|
|
|
Characteristics &= ~(IMAGE_SCN_CNT_INITIALIZED_DATA);
|
|
|
|
Memory::VP::Patch( &ntHeader->OptionalHeader.SizeOfInitializedData, ntHeader->OptionalHeader.SizeOfInitializedData - pSection->Misc.VirtualSize );
|
2017-04-27 22:12:48 +02:00
|
|
|
}
|
2017-05-17 00:36:09 +02:00
|
|
|
if ( (Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA) != 0 )
|
2017-04-27 22:12:48 +02:00
|
|
|
{
|
2017-05-17 00:36:09 +02:00
|
|
|
Characteristics &= ~(IMAGE_SCN_CNT_UNINITIALIZED_DATA);
|
|
|
|
Memory::VP::Patch( &ntHeader->OptionalHeader.SizeOfUninitializedData, ntHeader->OptionalHeader.SizeOfUninitializedData - pSection->Misc.VirtualSize );
|
2017-04-27 22:12:48 +02:00
|
|
|
}
|
2017-05-17 00:36:09 +02:00
|
|
|
Memory::VP::Patch( &pSection->Characteristics, Characteristics );
|
2017-09-18 17:19:56 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool FixRwcseg_Patterns()
|
|
|
|
{
|
|
|
|
using namespace hook;
|
|
|
|
|
|
|
|
auto begin = pattern( "55 8B EC 50 53 51 52 8B 5D 14 8B 4D 10 8B 45 0C 8B 55 08" ).count_hint(1000);
|
|
|
|
auto end = pattern( "9B D9 3D ? ? ? ? 81 25 ? ? ? ? FF FC FF FF 83 0D ? ? ? ? 3F" ).count_hint(1000);
|
|
|
|
|
|
|
|
if ( begin.count_hint(1).size() == 1 && end.count_hint(1).size() == 1 )
|
|
|
|
{
|
|
|
|
const ptrdiff_t size = (intptr_t)end.get_first( 24 ) - (intptr_t)begin.get_first();
|
|
|
|
if ( size > 0 )
|
|
|
|
{
|
|
|
|
DWORD dwProtect;
|
|
|
|
VirtualProtect( begin.get_first(), size, PAGE_EXECUTE_READ, &dwProtect );
|
|
|
|
return true;
|
2015-06-25 01:19:46 +02:00
|
|
|
}
|
|
|
|
}
|
2017-09-18 17:19:56 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool PatchIAT()
|
|
|
|
{
|
|
|
|
HINSTANCE hInstance = GetModuleHandle(nullptr);
|
|
|
|
PIMAGE_NT_HEADERS ntHeader = (PIMAGE_NT_HEADERS)((DWORD_PTR)hInstance + ((PIMAGE_DOS_HEADER)hInstance)->e_lfanew);
|
2015-04-22 01:00:36 +02:00
|
|
|
|
2015-06-25 01:19:46 +02:00
|
|
|
// Find IAT
|
2017-09-18 17:19:56 +02:00
|
|
|
PIMAGE_IMPORT_DESCRIPTOR pImports = (PIMAGE_IMPORT_DESCRIPTOR)((DWORD_PTR)hInstance + ntHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);
|
2015-05-02 00:27:56 +02:00
|
|
|
|
2015-06-25 01:19:46 +02:00
|
|
|
// Find kernel32.dll
|
|
|
|
for ( ; pImports->Name != 0; pImports++ )
|
|
|
|
{
|
2017-09-18 17:19:56 +02:00
|
|
|
if ( !_stricmp((const char*)((DWORD_PTR)hInstance + pImports->Name), "KERNEL32.DLL") )
|
2015-04-22 01:00:36 +02:00
|
|
|
{
|
2017-09-18 17:19:56 +02:00
|
|
|
if ( pImports->OriginalFirstThunk == 0 ) return false;
|
|
|
|
|
|
|
|
PIMAGE_IMPORT_BY_NAME* pFunctions = (PIMAGE_IMPORT_BY_NAME*)((DWORD_PTR)hInstance + pImports->OriginalFirstThunk);
|
2015-04-22 01:00:36 +02:00
|
|
|
|
2015-06-25 01:19:46 +02:00
|
|
|
// kernel32.dll found, find GetStartupInfoA
|
|
|
|
for ( ptrdiff_t j = 0; pFunctions[j] != nullptr; j++ )
|
|
|
|
{
|
2017-09-18 17:19:56 +02:00
|
|
|
if ( !strcmp((const char*)((DWORD_PTR)hInstance + pFunctions[j]->Name), "GetStartupInfoA") )
|
2015-06-25 01:19:46 +02:00
|
|
|
{
|
|
|
|
// Overwrite the address with the address to a custom GetStartupInfoA
|
|
|
|
DWORD dwProtect[2];
|
2017-09-18 17:19:56 +02:00
|
|
|
DWORD_PTR* pAddress = &((DWORD_PTR*)((DWORD_PTR)hInstance + pImports->FirstThunk))[j];
|
2015-06-25 01:19:46 +02:00
|
|
|
|
2017-09-18 17:19:56 +02:00
|
|
|
VirtualProtect(pAddress, sizeof(DWORD_PTR), PAGE_EXECUTE_READWRITE, &dwProtect[0]);
|
2015-06-25 01:19:46 +02:00
|
|
|
pOrgGetStartupInfoA = **(VOID(WINAPI**)(LPSTARTUPINFOA))pAddress;
|
2017-09-18 17:19:56 +02:00
|
|
|
*pAddress = (DWORD_PTR)GetStartupInfoA_Hook;
|
|
|
|
VirtualProtect(pAddress, sizeof(DWORD_PTR), dwProtect[0], &dwProtect[1]);
|
2015-06-25 01:19:46 +02:00
|
|
|
|
2017-09-18 17:19:56 +02:00
|
|
|
return true;
|
2015-06-25 01:19:46 +02:00
|
|
|
}
|
|
|
|
}
|
2015-04-22 01:00:36 +02:00
|
|
|
}
|
2015-06-25 01:19:46 +02:00
|
|
|
}
|
2017-09-18 17:19:56 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool PatchIAT_ByPointers()
|
|
|
|
{
|
|
|
|
pOrgSystemParametersInfoA = SystemParametersInfoA;
|
|
|
|
memcpy( orgCode, pOrgSystemParametersInfoA, sizeof(orgCode) );
|
|
|
|
Memory::VP::InjectHook( pOrgSystemParametersInfoA, SystemParametersInfoA_OverwritingHook, PATCH_JUMP );
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void ApplyDDrawHooks()
|
|
|
|
{
|
|
|
|
rwcsegUnprotected = FixRwcseg_Header();
|
|
|
|
|
|
|
|
bool getStartupInfoHooked = PatchIAT();
|
|
|
|
if ( !getStartupInfoHooked )
|
|
|
|
{
|
|
|
|
PatchIAT_ByPointers();
|
|
|
|
}
|
2015-06-25 01:19:46 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
|
|
|
|
{
|
|
|
|
UNREFERENCED_PARAMETER(hinstDLL);
|
|
|
|
UNREFERENCED_PARAMETER(lpvReserved);
|
2015-04-22 01:00:36 +02:00
|
|
|
|
2015-06-25 01:19:46 +02:00
|
|
|
if ( fdwReason == DLL_PROCESS_ATTACH )
|
|
|
|
{
|
2017-09-18 17:19:56 +02:00
|
|
|
ApplyDDrawHooks();
|
2015-04-22 01:00:36 +02:00
|
|
|
}
|
|
|
|
|
2014-09-22 23:35:43 +02:00
|
|
|
return TRUE;
|
|
|
|
}
|