mirror of
https://github.com/ineedbots/cod2m.git
synced 2025-07-11 12:51:48 +00:00
Init iw4x base
This commit is contained in:
9
src/Game/MP.cpp
Normal file
9
src/Game/MP.cpp
Normal file
@ -0,0 +1,9 @@
|
||||
#include "STDInclude.hpp"
|
||||
|
||||
namespace MP
|
||||
{
|
||||
void PatchT4()
|
||||
{
|
||||
MessageBoxA(nullptr, "MP", "DEBUG", 0);
|
||||
}
|
||||
}
|
6
src/Game/MP.hpp
Normal file
6
src/Game/MP.hpp
Normal file
@ -0,0 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
namespace MP
|
||||
{
|
||||
void PatchT4();
|
||||
}
|
0
src/Game/MP/Functions.hpp
Normal file
0
src/Game/MP/Functions.hpp
Normal file
0
src/Game/MP/Structs.hpp
Normal file
0
src/Game/MP/Structs.hpp
Normal file
9
src/Game/SP.cpp
Normal file
9
src/Game/SP.cpp
Normal file
@ -0,0 +1,9 @@
|
||||
#include "STDInclude.hpp"
|
||||
|
||||
namespace SP
|
||||
{
|
||||
void PatchT4()
|
||||
{
|
||||
MessageBoxA(nullptr, "SP", "DEBUG", 0);
|
||||
}
|
||||
}
|
6
src/Game/SP.hpp
Normal file
6
src/Game/SP.hpp
Normal file
@ -0,0 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
namespace SP
|
||||
{
|
||||
void PatchT4();
|
||||
}
|
0
src/Game/SP/Functions.hpp
Normal file
0
src/Game/SP/Functions.hpp
Normal file
0
src/Game/SP/Structs.hpp
Normal file
0
src/Game/SP/Structs.hpp
Normal file
89
src/Main.cpp
Normal file
89
src/Main.cpp
Normal file
@ -0,0 +1,89 @@
|
||||
#include "STDInclude.hpp"
|
||||
|
||||
namespace Main
|
||||
{
|
||||
static BYTE originalCode[5];
|
||||
static PBYTE originalEP = 0;
|
||||
|
||||
void UnprotectModule(HMODULE hModule)
|
||||
{
|
||||
PIMAGE_DOS_HEADER header = (PIMAGE_DOS_HEADER)hModule;
|
||||
PIMAGE_NT_HEADERS ntHeader = (PIMAGE_NT_HEADERS)((DWORD)hModule + header->e_lfanew);
|
||||
|
||||
// unprotect the entire PE image
|
||||
SIZE_T size = ntHeader->OptionalHeader.SizeOfImage;
|
||||
DWORD oldProtect;
|
||||
VirtualProtect((LPVOID)hModule, size, PAGE_EXECUTE_READWRITE, &oldProtect);
|
||||
}
|
||||
|
||||
void DoInit()
|
||||
{
|
||||
// return to the original EP
|
||||
memcpy(originalEP, &originalCode, sizeof(originalCode));
|
||||
|
||||
// unprotect our entire PE image
|
||||
HMODULE hModule;
|
||||
if (SUCCEEDED(GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (LPCWSTR)DoInit, &hModule)))
|
||||
{
|
||||
UnprotectModule(hModule);
|
||||
}
|
||||
|
||||
// detect which executable's patches to apply
|
||||
DWORD dataStrData = Utils::Hook::Get<DWORD>(0x881CAC);
|
||||
if (dataStrData == 0x62616E55)
|
||||
MP::PatchT4();
|
||||
else
|
||||
SP::PatchT4();
|
||||
|
||||
hModule = GetModuleHandle(NULL);
|
||||
PIMAGE_DOS_HEADER header = (PIMAGE_DOS_HEADER)hModule;
|
||||
PIMAGE_NT_HEADERS ntHeader = (PIMAGE_NT_HEADERS)((DWORD)hModule + header->e_lfanew);
|
||||
|
||||
// back up original code
|
||||
originalEP = (PBYTE)((DWORD)hModule + ntHeader->OptionalHeader.AddressOfEntryPoint);
|
||||
|
||||
__asm
|
||||
{
|
||||
jmp originalEP
|
||||
}
|
||||
}
|
||||
|
||||
void SetSafeInit()
|
||||
{
|
||||
// find the entry point for the executable process, set page access, and replace the EP
|
||||
HMODULE hModule = GetModuleHandle(NULL); // passing NULL should be safe even with the loader lock being held (according to ReactOS ldr.c)
|
||||
|
||||
if (hModule)
|
||||
{
|
||||
PIMAGE_DOS_HEADER header = (PIMAGE_DOS_HEADER)hModule;
|
||||
PIMAGE_NT_HEADERS ntHeader = (PIMAGE_NT_HEADERS)((DWORD)hModule + header->e_lfanew);
|
||||
|
||||
UnprotectModule(hModule);
|
||||
|
||||
// back up original code
|
||||
PBYTE ep = (PBYTE)((DWORD)hModule + ntHeader->OptionalHeader.AddressOfEntryPoint);
|
||||
memcpy(originalCode, ep, sizeof(originalCode));
|
||||
|
||||
// patch to call our EP
|
||||
int newEP = (int)DoInit - ((int)ep + 5);
|
||||
ep[0] = 0xE9; // for some reason this doesn't work properly when run under the debugger
|
||||
memcpy(&ep[1], &newEP, 4);
|
||||
|
||||
originalEP = ep;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool APIENTRY DllMain(HMODULE, DWORD dwReason, LPVOID)
|
||||
{
|
||||
if (dwReason == DLL_PROCESS_ATTACH)
|
||||
{
|
||||
DWORD textSegData = Utils::Hook::Get<DWORD>(0x401000);
|
||||
|
||||
// detect for all executables to hook into
|
||||
//if (textSegData == 0x9EF490B8 || textSegData == 0x83EC8B55)
|
||||
Main::SetSafeInit();
|
||||
}
|
||||
return true;
|
||||
}
|
97
src/Resource.rc
Normal file
97
src/Resource.rc
Normal file
@ -0,0 +1,97 @@
|
||||
// Microsoft Visual C++ generated resource script.
|
||||
//
|
||||
#pragma code_page(65001)
|
||||
|
||||
#include "STDInclude.hpp"
|
||||
|
||||
#define APSTUDIO_READONLY_SYMBOLS
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Generated from the TEXTINCLUDE 2 resource.
|
||||
//
|
||||
#include "windows.h"
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
#undef APSTUDIO_READONLY_SYMBOLS
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// English (United States) resources
|
||||
|
||||
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
|
||||
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
|
||||
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// TEXTINCLUDE
|
||||
//
|
||||
|
||||
1 TEXTINCLUDE
|
||||
BEGIN
|
||||
"#include ""windows.h""\r\n"
|
||||
"\0"
|
||||
END
|
||||
|
||||
2 TEXTINCLUDE
|
||||
BEGIN
|
||||
"\r\n"
|
||||
"\0"
|
||||
END
|
||||
|
||||
#endif // APSTUDIO_INVOKED
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Version
|
||||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEFLAGSMASK 0x3fL
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS 0x1L
|
||||
#else
|
||||
FILEFLAGS 0x0L
|
||||
#endif
|
||||
FILEOS 0x40004L
|
||||
FILETYPE VFT_DLL
|
||||
FILESUBTYPE 0x0L
|
||||
BEGIN
|
||||
BLOCK "StringFileInfo"
|
||||
BEGIN
|
||||
BLOCK "040904b0"
|
||||
BEGIN
|
||||
VALUE "CompanyName", "CoD2m"
|
||||
#ifdef _DEBUG
|
||||
VALUE "FileDescription", "CoD2 client/server modification (DEBUG)"
|
||||
#else
|
||||
VALUE "FileDescription", "CoD2 client/server modification"
|
||||
#endif
|
||||
VALUE "FileVersion", SHORTVERSION
|
||||
VALUE "InternalName", "cod2m"
|
||||
VALUE "LegalCopyright", "All rights reserved."
|
||||
VALUE "OriginalFilename", "d3d9.dll"
|
||||
VALUE "ProductName", "CoD2m"
|
||||
VALUE "ProductVersion", SHORTVERSION
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
BEGIN
|
||||
VALUE "Translation", 0x409, 1200
|
||||
END
|
||||
END
|
||||
|
||||
#endif // English (United States) resources
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
|
||||
#ifndef APSTUDIO_INVOKED
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Generated from the TEXTINCLUDE 3 resource.
|
||||
//
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
#endif // not APSTUDIO_INVOKED
|
||||
|
90
src/SDLLP.cpp
Normal file
90
src/SDLLP.cpp
Normal file
@ -0,0 +1,90 @@
|
||||
// --------------------------------------+
|
||||
// System Dynamic Link Library Proxy
|
||||
// by momo5502
|
||||
// --------------------------------------+
|
||||
|
||||
#include "STDInclude.hpp"
|
||||
|
||||
// Macro to declare an export
|
||||
// --------------------------------------+
|
||||
#define EXPORT(_export) extern "C" __declspec(naked) __declspec(dllexport) void _export() { static FARPROC function = 0; if(!function) function = SDLLP::GetExport(__FUNCTION__, LIBRARY); __asm { jmp function } }
|
||||
|
||||
// Static class
|
||||
// --------------------------------------+
|
||||
class SDLLP
|
||||
{
|
||||
private:
|
||||
static std::map<std::string, HINSTANCE> mLibraries;
|
||||
|
||||
static void Log(const char* message, ...);
|
||||
static void LoadLibrary(const char* library);
|
||||
static bool IsLibraryLoaded(const char* library);
|
||||
|
||||
public:
|
||||
static FARPROC GetExport(const char* function, const char* library);
|
||||
};
|
||||
|
||||
// Class variable declarations
|
||||
// --------------------------------------+
|
||||
std::map<std::string, HINSTANCE> SDLLP::mLibraries;
|
||||
|
||||
// Load necessary library
|
||||
// --------------------------------------+
|
||||
void SDLLP::LoadLibrary(const char* library)
|
||||
{
|
||||
Log("[SDLLP] Loading library '%s'.", library);
|
||||
|
||||
CHAR mPath[MAX_PATH];
|
||||
|
||||
GetSystemDirectoryA(mPath, MAX_PATH);
|
||||
strcat_s(mPath, "\\");
|
||||
strcat_s(mPath, library);
|
||||
|
||||
mLibraries[library] = ::LoadLibraryA(mPath);
|
||||
|
||||
if (!IsLibraryLoaded(library)) Log("[SDLLP] Unable to load library '%s'.", library);
|
||||
}
|
||||
|
||||
// Check if export already loaded
|
||||
// --------------------------------------+
|
||||
bool SDLLP::IsLibraryLoaded(const char* library)
|
||||
{
|
||||
return (mLibraries.find(library) != mLibraries.end() && mLibraries[library]);
|
||||
}
|
||||
|
||||
// Get export address
|
||||
// --------------------------------------+
|
||||
FARPROC SDLLP::GetExport(const char* function, const char* library)
|
||||
{
|
||||
Log("[SDLLP] Export '%s' requested from %s.", function, library);
|
||||
|
||||
if (!IsLibraryLoaded(library)) LoadLibrary(library);
|
||||
|
||||
FARPROC address = GetProcAddress(mLibraries[library], function);
|
||||
|
||||
if (!address) Log("[SDLLP] Unable to load export '%s' from library '%s'.", function, library);
|
||||
return address;
|
||||
}
|
||||
|
||||
// Write debug string
|
||||
// --------------------------------------+
|
||||
void SDLLP::Log(const char* message, ...)
|
||||
{
|
||||
CHAR buffer[1024];
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, message);
|
||||
vsprintf(buffer, message, ap);
|
||||
va_end(ap);
|
||||
|
||||
OutputDebugStringA(buffer);
|
||||
}
|
||||
|
||||
// --------------------------------------+
|
||||
// Adapt export functions and library
|
||||
// --------------------------------------+
|
||||
|
||||
#define LIBRARY "d3d9.dll"
|
||||
EXPORT(D3DPERF_BeginEvent)
|
||||
EXPORT(D3DPERF_EndEvent)
|
||||
EXPORT(Direct3DCreate9)
|
115
src/STDInclude.cpp
Normal file
115
src/STDInclude.cpp
Normal file
@ -0,0 +1,115 @@
|
||||
#include "STDInclude.hpp"
|
||||
|
||||
// Rename sections
|
||||
#ifndef DEBUG
|
||||
#pragma comment(linker, "/merge:.text=.UPX0")
|
||||
#pragma comment(linker, "/merge:.data=.UPX1")
|
||||
#pragma comment(linker, "/merge:.rdata=.UPX2")
|
||||
#pragma comment(linker, "/merge:.tls=.UPX3")
|
||||
#pragma comment(linker, "/merge:.gfids=.UPX4")
|
||||
#endif
|
||||
|
||||
#pragma comment(linker,"\"/manifestdependency:type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")
|
||||
|
||||
// Do necessary assertions here
|
||||
// Some compilers treat them differently which causes a size mismatch
|
||||
|
||||
// WinAPI types
|
||||
AssertSize(DWORD, 4);
|
||||
AssertSize(WORD, 2);
|
||||
AssertSize(BYTE, 1);
|
||||
|
||||
// 128 bit integers (only x64)
|
||||
//AssertSize(__int128, 16);
|
||||
//AssertSize(unsigned __int128, 16);
|
||||
|
||||
// 64 bit integers
|
||||
AssertSize(__int64, 8);
|
||||
AssertSize(unsigned __int64, 8);
|
||||
AssertSize(long long, 8);
|
||||
AssertSize(unsigned long long, 8);
|
||||
AssertSize(int64_t, 8);
|
||||
AssertSize(uint64_t, 8);
|
||||
AssertSize(std::int64_t, 8);
|
||||
AssertSize(std::uint64_t, 8);
|
||||
|
||||
// 64 bit double precision floating point numbers
|
||||
AssertSize(double, 8);
|
||||
|
||||
// 32 bit integers
|
||||
AssertSize(__int32, 4);
|
||||
AssertSize(unsigned __int32, 4);
|
||||
AssertSize(int, 4);
|
||||
AssertSize(unsigned int, 4);
|
||||
AssertSize(long, 4);
|
||||
AssertSize(unsigned long, 4);
|
||||
AssertSize(int32_t, 4);
|
||||
AssertSize(uint32_t, 4);
|
||||
AssertSize(std::int32_t, 4);
|
||||
AssertSize(std::uint32_t, 4);
|
||||
|
||||
// 32 bit single precision floating point numbers
|
||||
AssertSize(float, 4);
|
||||
|
||||
// 16 bit integers
|
||||
AssertSize(__int16, 2);
|
||||
AssertSize(unsigned __int16, 2);
|
||||
AssertSize(short, 2);
|
||||
AssertSize(unsigned short, 2);
|
||||
AssertSize(int16_t, 2);
|
||||
AssertSize(uint16_t, 2);
|
||||
AssertSize(std::int16_t, 2);
|
||||
AssertSize(std::uint16_t, 2);
|
||||
|
||||
// 8 bit integers
|
||||
AssertSize(bool, 1);
|
||||
AssertSize(__int8, 1);
|
||||
AssertSize(unsigned __int8, 1);
|
||||
AssertSize(char, 1);
|
||||
AssertSize(unsigned char, 1);
|
||||
AssertSize(int8_t, 1);
|
||||
AssertSize(uint8_t, 1);
|
||||
AssertSize(std::int8_t, 1);
|
||||
AssertSize(std::uint8_t, 1);
|
||||
|
||||
// Ensure pointers are 4 bytes in size (32-bit)
|
||||
// ReSharper disable CppRedundantBooleanExpressionArgument
|
||||
static_assert(sizeof(intptr_t) == 4 && sizeof(void*) == 4 && sizeof(size_t) == 4, "This doesn't seem to be a 32-bit environment!");
|
||||
// ReSharper restore CppRedundantBooleanExpressionArgument
|
||||
|
||||
#if !defined(_M_IX86)
|
||||
#error "Invalid processor achritecture!"
|
||||
#endif
|
||||
|
||||
extern "C"
|
||||
{
|
||||
// Disable telemetry data logging
|
||||
void __cdecl __vcrt_initialize_telemetry_provider() {}
|
||||
void __cdecl __telemetry_main_invoke_trigger() {}
|
||||
void __cdecl __telemetry_main_return_trigger() {}
|
||||
void __cdecl __vcrt_uninitialize_telemetry_provider() {}
|
||||
|
||||
// Enable 'High Performance Graphics'
|
||||
__declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001;
|
||||
|
||||
// Tommath fixes
|
||||
int s_read_arc4random(void*, size_t)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
int s_read_getrandom(void*, size_t)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
int s_read_urandom(void*, size_t)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
int s_read_ltm_rng(void*, size_t)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
};
|
120
src/STDInclude.hpp
Normal file
120
src/STDInclude.hpp
Normal file
@ -0,0 +1,120 @@
|
||||
#pragma once
|
||||
|
||||
// Version number
|
||||
#include "version.h"
|
||||
|
||||
#ifndef RC_INVOKED
|
||||
|
||||
#define _HAS_CXX17 1
|
||||
#define _HAS_CXX20 1
|
||||
#define VC_EXTRALEAN
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#define _CRT_SECURE_NO_WARNINGS
|
||||
|
||||
// Requires Visual Leak Detector plugin: http://vld.codeplex.com/
|
||||
#define VLD_FORCE_ENABLE
|
||||
//#include <vld.h>
|
||||
#pragma warning(disable: 4740)
|
||||
|
||||
#include <windows.h>
|
||||
#include <timeapi.h>
|
||||
#include <shellapi.h>
|
||||
#include <Wininet.h>
|
||||
#include <Aclapi.h>
|
||||
#include <Psapi.h>
|
||||
#include <tlhelp32.h>
|
||||
#include <Shlwapi.h>
|
||||
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable: 4091)
|
||||
#pragma warning(disable: 4244)
|
||||
#include <dbghelp.h>
|
||||
|
||||
#include <sstream>
|
||||
#include <fstream>
|
||||
#include <cctype>
|
||||
#include <regex>
|
||||
#include <thread>
|
||||
#include <future>
|
||||
#include <map>
|
||||
#include <queue>
|
||||
|
||||
// Experimental C++17 features
|
||||
#include <filesystem>
|
||||
#include <optional>
|
||||
|
||||
#pragma warning(pop)
|
||||
|
||||
// Usefull for debugging
|
||||
template <size_t S> class Sizer { };
|
||||
#define BindNum(x, y) Sizer<x> y;
|
||||
#define Size_Of(x, y) BindNum(sizeof(x), y)
|
||||
#define Offset_Of(x, y, z) BindNum(offsetof(x, y), z)
|
||||
|
||||
// Submodules
|
||||
// Ignore the warnings, it's not our code!
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable: 4005)
|
||||
#pragma warning(disable: 4091)
|
||||
#pragma warning(disable: 4100)
|
||||
#pragma warning(disable: 4244)
|
||||
#pragma warning(disable: 4389)
|
||||
#pragma warning(disable: 4702)
|
||||
#pragma warning(disable: 4800)
|
||||
#pragma warning(disable: 4996) // _CRT_SECURE_NO_WARNINGS
|
||||
#pragma warning(disable: 5054)
|
||||
#pragma warning(disable: 6001)
|
||||
#pragma warning(disable: 6011)
|
||||
#pragma warning(disable: 6031)
|
||||
#pragma warning(disable: 6255)
|
||||
#pragma warning(disable: 6258)
|
||||
#pragma warning(disable: 6386)
|
||||
#pragma warning(disable: 6387)
|
||||
|
||||
#ifdef max
|
||||
#undef max
|
||||
#endif
|
||||
|
||||
#ifdef min
|
||||
#undef min
|
||||
#endif
|
||||
|
||||
#pragma warning(pop)
|
||||
|
||||
#include "Utils/Hooking.hpp"
|
||||
|
||||
#include "Game/MP.hpp"
|
||||
#include "Game/SP.hpp"
|
||||
|
||||
// Libraries
|
||||
#pragma comment(lib, "Winmm.lib")
|
||||
#pragma comment(lib, "Crypt32.lib")
|
||||
#pragma comment(lib, "Ws2_32.lib")
|
||||
#pragma comment(lib, "Wininet.lib")
|
||||
#pragma comment(lib, "shlwapi.lib")
|
||||
#pragma comment(lib, "Urlmon.lib")
|
||||
#pragma comment(lib, "Advapi32.lib")
|
||||
#pragma comment(lib, "rpcrt4.lib")
|
||||
#pragma comment(lib, "dbghelp.lib")
|
||||
|
||||
// Enable additional literals
|
||||
using namespace std::literals;
|
||||
|
||||
#endif
|
||||
|
||||
#define STRINGIZE_(x) #x
|
||||
#define STRINGIZE(x) STRINGIZE_(x)
|
||||
|
||||
#define AssertSize(x, size) static_assert(sizeof(x) == size, STRINGIZE(x) " structure has an invalid size.")
|
||||
#define AssertOffset(x, y, offset) static_assert(offsetof(x, y) == offset, STRINGIZE(x) "::" STRINGIZE(y) " is not at the right offset.")
|
||||
|
||||
// Resource stuff
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
#ifndef APSTUDIO_READONLY_SYMBOLS
|
||||
// Defines below make accessing the resources from the code easier.
|
||||
#define _APS_NEXT_RESOURCE_VALUE 102
|
||||
#define _APS_NEXT_COMMAND_VALUE 40001
|
||||
#define _APS_NEXT_CONTROL_VALUE 1001
|
||||
#define _APS_NEXT_SYMED_VALUE 101
|
||||
#endif
|
||||
#endif
|
256
src/Utils/Hooking.cpp
Normal file
256
src/Utils/Hooking.cpp
Normal file
@ -0,0 +1,256 @@
|
||||
#include "STDInclude.hpp"
|
||||
|
||||
namespace Utils
|
||||
{
|
||||
std::map<void*, void*> Hook::Interceptor::IReturn;
|
||||
std::map<void*, void(*)()> Hook::Interceptor::ICallbacks;
|
||||
|
||||
void Hook::Signature::process()
|
||||
{
|
||||
if (this->signatures.empty()) return;
|
||||
|
||||
char* _start = reinterpret_cast<char*>(this->start);
|
||||
|
||||
unsigned int sigCount = this->signatures.size();
|
||||
Hook::Signature::Container* containers = this->signatures.data();
|
||||
|
||||
for (size_t i = 0; i < this->length; ++i)
|
||||
{
|
||||
char* address = _start + i;
|
||||
|
||||
for (unsigned int k = 0; k < sigCount; ++k)
|
||||
{
|
||||
Hook::Signature::Container* container = &containers[k];
|
||||
|
||||
unsigned int j;
|
||||
for (j = 0; j < strlen(container->mask); ++j)
|
||||
{
|
||||
if (container->mask[j] != '?' &&container->signature[j] != address[j])
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (j == strlen(container->mask))
|
||||
{
|
||||
container->callback(address);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Hook::Signature::add(Hook::Signature::Container& container)
|
||||
{
|
||||
Hook::Signature::signatures.push_back(container);
|
||||
}
|
||||
|
||||
void Hook::Interceptor::Install(void* place, void* stub)
|
||||
{
|
||||
return Hook::Interceptor::Install(place, static_cast<void(*)()>(stub));
|
||||
}
|
||||
|
||||
void Hook::Interceptor::Install(void* place, void(*stub)())
|
||||
{
|
||||
return Hook::Interceptor::Install(reinterpret_cast<void**>(place), stub);
|
||||
}
|
||||
|
||||
void Hook::Interceptor::Install(void** place, void(*stub)())
|
||||
{
|
||||
Hook::Interceptor::IReturn[place] = *place;
|
||||
Hook::Interceptor::ICallbacks[place] = stub;
|
||||
*place = Hook::Interceptor::InterceptionStub;
|
||||
}
|
||||
|
||||
__declspec(naked) void Hook::Interceptor::InterceptionStub()
|
||||
{
|
||||
__asm
|
||||
{
|
||||
sub esp, 4h // Reserve space on the stack for the return address
|
||||
pushad // Store registers
|
||||
|
||||
lea eax, [esp + 20h] // Load initial stack pointer
|
||||
push eax // Push it onto the stack
|
||||
|
||||
call Hook::Interceptor::RunCallback // Run the callback based on the given stack pointer
|
||||
call Hook::Interceptor::PopReturn // Get the initial return address according to the stack pointer
|
||||
|
||||
add esp, 4h // Clear the stack
|
||||
|
||||
mov [esp + 20h], eax // Store the return address at the reserved space
|
||||
popad // Restore the registers
|
||||
|
||||
retn // Return (jump to our return address)
|
||||
}
|
||||
}
|
||||
|
||||
void Hook::Interceptor::RunCallback(void* place)
|
||||
{
|
||||
auto iCallback = Hook::Interceptor::ICallbacks.find(place);
|
||||
if (iCallback != Hook::Interceptor::ICallbacks.end())
|
||||
{
|
||||
iCallback->second();
|
||||
Hook::Interceptor::ICallbacks.erase(iCallback);
|
||||
}
|
||||
}
|
||||
|
||||
void* Hook::Interceptor::PopReturn(void* _place)
|
||||
{
|
||||
void* retVal = nullptr;
|
||||
|
||||
auto iReturn = Hook::Interceptor::IReturn.find(_place);
|
||||
if (iReturn != Hook::Interceptor::IReturn.end())
|
||||
{
|
||||
retVal = iReturn->second;
|
||||
Hook::Interceptor::IReturn.erase(iReturn);
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
Hook::~Hook()
|
||||
{
|
||||
if (this->initialized)
|
||||
{
|
||||
this->uninstall();
|
||||
}
|
||||
}
|
||||
|
||||
Hook* Hook::initialize(DWORD _place, void(*_stub)(), bool _useJump)
|
||||
{
|
||||
return this->initialize(_place, reinterpret_cast<void*>(_stub), _useJump);
|
||||
}
|
||||
|
||||
Hook* Hook::initialize(DWORD _place, void* _stub, bool _useJump)
|
||||
{
|
||||
return this->initialize(reinterpret_cast<void*>(_place), _stub, _useJump);
|
||||
}
|
||||
|
||||
Hook* Hook::initialize(void* _place, void* _stub, bool _useJump)
|
||||
{
|
||||
if (this->initialized) return this;
|
||||
this->initialized = true;
|
||||
|
||||
this->useJump = _useJump;
|
||||
this->place = _place;
|
||||
this->stub = _stub;
|
||||
|
||||
this->original = static_cast<char*>(this->place) + 5 + *reinterpret_cast<DWORD*>((static_cast<char*>(this->place) + 1));
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
Hook* Hook::install(bool unprotect, bool keepUnprotected)
|
||||
{
|
||||
std::lock_guard<std::mutex> _(this->stateMutex);
|
||||
|
||||
if (!this->initialized || this->installed)
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
this->installed = true;
|
||||
|
||||
if (unprotect) VirtualProtect(this->place, sizeof(this->buffer), PAGE_EXECUTE_READWRITE, &this->protection);
|
||||
std::memcpy(this->buffer, this->place, sizeof(this->buffer));
|
||||
|
||||
char* code = static_cast<char*>(this->place);
|
||||
|
||||
*code = static_cast<char>(this->useJump ? 0xE9 : 0xE8);
|
||||
|
||||
*reinterpret_cast<size_t*>(code + 1) = reinterpret_cast<size_t>(this->stub) - (reinterpret_cast<size_t>(this->place) + 5);
|
||||
|
||||
if (unprotect && !keepUnprotected) VirtualProtect(this->place, sizeof(this->buffer), this->protection, &this->protection);
|
||||
|
||||
FlushInstructionCache(GetCurrentProcess(), this->place, sizeof(this->buffer));
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
void Hook::quick()
|
||||
{
|
||||
if (Hook::installed)
|
||||
{
|
||||
Hook::installed = false;
|
||||
}
|
||||
}
|
||||
|
||||
Hook* Hook::uninstall(bool unprotect)
|
||||
{
|
||||
std::lock_guard<std::mutex> _(this->stateMutex);
|
||||
|
||||
if (!this->initialized || !this->installed)
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
this->installed = false;
|
||||
|
||||
if (unprotect) VirtualProtect(this->place, sizeof(this->buffer), PAGE_EXECUTE_READWRITE, &this->protection);
|
||||
|
||||
std::memcpy(this->place, this->buffer, sizeof(this->buffer));
|
||||
|
||||
if (unprotect) VirtualProtect(this->place, sizeof(this->buffer), this->protection, &this->protection);
|
||||
|
||||
FlushInstructionCache(GetCurrentProcess(), this->place, sizeof(this->buffer));
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
void* Hook::getAddress()
|
||||
{
|
||||
return this->place;
|
||||
}
|
||||
|
||||
void Hook::Nop(void* place, size_t length)
|
||||
{
|
||||
DWORD oldProtect;
|
||||
VirtualProtect(place, length, PAGE_EXECUTE_READWRITE, &oldProtect);
|
||||
|
||||
memset(place, 0x90, length);
|
||||
|
||||
VirtualProtect(place, length, oldProtect, &oldProtect);
|
||||
FlushInstructionCache(GetCurrentProcess(), place, length);
|
||||
}
|
||||
|
||||
void Hook::Nop(DWORD place, size_t length)
|
||||
{
|
||||
Nop(reinterpret_cast<void*>(place), length);
|
||||
}
|
||||
|
||||
void Hook::SetString(void* place, const char* string, size_t length)
|
||||
{
|
||||
DWORD oldProtect;
|
||||
VirtualProtect(place, length + 1, PAGE_EXECUTE_READWRITE, &oldProtect);
|
||||
|
||||
strncpy_s(static_cast<char*>(place), length, string, length);
|
||||
|
||||
VirtualProtect(place, length + 1, oldProtect, &oldProtect);
|
||||
}
|
||||
|
||||
void Hook::SetString(DWORD place, const char* string, size_t length)
|
||||
{
|
||||
Hook::SetString(reinterpret_cast<void*>(place), string, length);
|
||||
}
|
||||
|
||||
void Hook::SetString(void* place, const char* string)
|
||||
{
|
||||
Hook::SetString(place, string, strlen(static_cast<char*>(place)));
|
||||
}
|
||||
|
||||
void Hook::SetString(DWORD place, const char* string)
|
||||
{
|
||||
Hook::SetString(reinterpret_cast<void*>(place), string);
|
||||
}
|
||||
|
||||
void Hook::RedirectJump(void* place, void* stub)
|
||||
{
|
||||
char* operandPtr = static_cast<char*>(place) + 2;
|
||||
int newOperand = reinterpret_cast<int>(stub) - (reinterpret_cast<int>(place) + 6);
|
||||
Utils::Hook::Set<int>(operandPtr, newOperand);
|
||||
}
|
||||
|
||||
void Hook::RedirectJump(DWORD place, void* stub)
|
||||
{
|
||||
Hook::RedirectJump(reinterpret_cast<void*>(place), stub);
|
||||
}
|
||||
}
|
185
src/Utils/Hooking.hpp
Normal file
185
src/Utils/Hooking.hpp
Normal file
@ -0,0 +1,185 @@
|
||||
#pragma once
|
||||
|
||||
#define HOOK_JUMP true
|
||||
#define HOOK_CALL false
|
||||
|
||||
namespace Utils
|
||||
{
|
||||
class Hook
|
||||
{
|
||||
public:
|
||||
class Signature
|
||||
{
|
||||
public:
|
||||
struct Container
|
||||
{
|
||||
const char* signature;
|
||||
const char* mask;
|
||||
std::function<void(char*)> callback;
|
||||
};
|
||||
|
||||
Signature(void* _start, size_t _length) : start(_start), length(_length) {}
|
||||
Signature(DWORD _start, size_t _length) : Signature(reinterpret_cast<void*>(_start), _length) {}
|
||||
Signature() : Signature(0x400000, 0x800000) {}
|
||||
|
||||
void process();
|
||||
void add(Container& container);
|
||||
|
||||
private:
|
||||
void* start;
|
||||
size_t length;
|
||||
std::vector<Container> signatures;
|
||||
};
|
||||
|
||||
class Interceptor
|
||||
{
|
||||
public:
|
||||
static void Install(void* place, void* stub);
|
||||
static void Install(void* place, void(*stub)());
|
||||
static void Install(void** place, void(*stub)());
|
||||
|
||||
private:
|
||||
static std::map<void*, void*> IReturn;
|
||||
static std::map<void*, void(*)()> ICallbacks;
|
||||
|
||||
static void InterceptionStub();
|
||||
static void RunCallback(void* place);
|
||||
static void* PopReturn(void* place);
|
||||
};
|
||||
|
||||
Hook() : initialized(false), installed(false), place(nullptr), stub(nullptr), original(nullptr), useJump(false), protection(0) { ZeroMemory(this->buffer, sizeof(this->buffer)); }
|
||||
|
||||
Hook(void* place, void* stub, bool useJump = true) : Hook() { this->initialize(place, stub, useJump); }
|
||||
Hook(void* place, void(*stub)(), bool useJump = true) : Hook(place, reinterpret_cast<void*>(stub), useJump) {}
|
||||
|
||||
Hook(DWORD place, void* stub, bool useJump = true) : Hook(reinterpret_cast<void*>(place), stub, useJump) {}
|
||||
Hook(DWORD place, DWORD stub, bool useJump = true) : Hook(reinterpret_cast<void*>(place), reinterpret_cast<void*>(stub), useJump) {}
|
||||
Hook(DWORD place, void(*stub)(), bool useJump = true) : Hook(reinterpret_cast<void*>(place), reinterpret_cast<void*>(stub), useJump) {}
|
||||
|
||||
~Hook();
|
||||
|
||||
Hook* initialize(void* place, void* stub, bool useJump = true);
|
||||
Hook* initialize(DWORD place, void* stub, bool useJump = true);
|
||||
Hook* initialize(DWORD place, void(*stub)(), bool useJump = true); // For lambdas
|
||||
Hook* install(bool unprotect = true, bool keepUnprotected = false);
|
||||
Hook* uninstall(bool unprotect = true);
|
||||
|
||||
void* getAddress();
|
||||
void quick();
|
||||
|
||||
template <typename T> static std::function<T> Call(DWORD function)
|
||||
{
|
||||
return std::function<T>(reinterpret_cast<T*>(function));
|
||||
}
|
||||
|
||||
template <typename T> static std::function<T> Call(FARPROC function)
|
||||
{
|
||||
return Call<T>(reinterpret_cast<DWORD>(function));
|
||||
}
|
||||
|
||||
template <typename T> static std::function<T> Call(void* function)
|
||||
{
|
||||
return Call<T>(reinterpret_cast<DWORD>(function));
|
||||
}
|
||||
|
||||
static void SetString(void* place, const char* string, size_t length);
|
||||
static void SetString(DWORD place, const char* string, size_t length);
|
||||
|
||||
static void SetString(void* place, const char* string);
|
||||
static void SetString(DWORD place, const char* string);
|
||||
|
||||
static void Nop(void* place, size_t length);
|
||||
static void Nop(DWORD place, size_t length);
|
||||
|
||||
static void RedirectJump(void* place, void* stub);
|
||||
static void RedirectJump(DWORD place, void* stub);
|
||||
|
||||
template <typename T> static void Set(void* place, T value)
|
||||
{
|
||||
DWORD oldProtect;
|
||||
VirtualProtect(place, sizeof(T), PAGE_EXECUTE_READWRITE, &oldProtect);
|
||||
|
||||
*static_cast<T*>(place) = value;
|
||||
|
||||
VirtualProtect(place, sizeof(T), oldProtect, &oldProtect);
|
||||
FlushInstructionCache(GetCurrentProcess(), place, sizeof(T));
|
||||
}
|
||||
|
||||
template <typename T> static void Set(DWORD place, T value)
|
||||
{
|
||||
return Set<T>(reinterpret_cast<void*>(place), value);
|
||||
}
|
||||
|
||||
template <typename T> static void Xor(void* place, T value)
|
||||
{
|
||||
DWORD oldProtect;
|
||||
VirtualProtect(place, sizeof(T), PAGE_EXECUTE_READWRITE, &oldProtect);
|
||||
|
||||
*static_cast<T*>(place) ^= value;
|
||||
|
||||
VirtualProtect(place, sizeof(T), oldProtect, &oldProtect);
|
||||
FlushInstructionCache(GetCurrentProcess(), place, sizeof(T));
|
||||
}
|
||||
|
||||
template <typename T> static void Xor(DWORD place, T value)
|
||||
{
|
||||
return Xor<T>(reinterpret_cast<void*>(place), value);
|
||||
}
|
||||
|
||||
template <typename T> static void Or(void* place, T value)
|
||||
{
|
||||
DWORD oldProtect;
|
||||
VirtualProtect(place, sizeof(T), PAGE_EXECUTE_READWRITE, &oldProtect);
|
||||
|
||||
*static_cast<T*>(place) |= value;
|
||||
|
||||
VirtualProtect(place, sizeof(T), oldProtect, &oldProtect);
|
||||
FlushInstructionCache(GetCurrentProcess(), place, sizeof(T));
|
||||
}
|
||||
|
||||
template <typename T> static void Or(DWORD place, T value)
|
||||
{
|
||||
return Or<T>(reinterpret_cast<void*>(place), value);
|
||||
}
|
||||
|
||||
template <typename T> static void And(void* place, T value)
|
||||
{
|
||||
DWORD oldProtect;
|
||||
VirtualProtect(place, sizeof(T), PAGE_EXECUTE_READWRITE, &oldProtect);
|
||||
|
||||
*static_cast<T*>(place) &= value;
|
||||
|
||||
VirtualProtect(place, sizeof(T), oldProtect, &oldProtect);
|
||||
FlushInstructionCache(GetCurrentProcess(), place, sizeof(T));
|
||||
}
|
||||
|
||||
template <typename T> static void And(DWORD place, T value)
|
||||
{
|
||||
return And<T>(reinterpret_cast<void*>(place), value);
|
||||
}
|
||||
|
||||
template <typename T> static T Get(void* place)
|
||||
{
|
||||
return *static_cast<T*>(place);
|
||||
}
|
||||
|
||||
template <typename T> static T Get(DWORD place)
|
||||
{
|
||||
return Get<T>(reinterpret_cast<void*>(place));
|
||||
}
|
||||
|
||||
private:
|
||||
bool initialized;
|
||||
bool installed;
|
||||
|
||||
void* place;
|
||||
void* stub;
|
||||
void* original;
|
||||
char buffer[5];
|
||||
bool useJump;
|
||||
|
||||
DWORD protection;
|
||||
|
||||
std::mutex stateMutex;
|
||||
};
|
||||
}
|
Reference in New Issue
Block a user