Steam proxy

This commit is contained in:
momo5502 2016-07-12 18:33:25 +02:00
parent 2ea490382b
commit 245cd533d1
19 changed files with 1544 additions and 1442 deletions

2
deps/fmt vendored

@ -1 +1 @@
Subproject commit 4133e501f3277aeef530b75de2e7bfceca93e5d2
Subproject commit 0d5ef5c2a66026409b0cfbafa1d2f46cdc5aa4d0

2
deps/mongoose vendored

@ -1 +1 @@
Subproject commit 6f7f774080f0c2ec291bfa0a908bc31a923051a1
Subproject commit 36a1927915f966f20486a80070f0428f2606a53a

2
deps/protobuf vendored

@ -1 +1 @@
Subproject commit 790e6afb72ed4ad952d9c74e73ae53a01443fe97
Subproject commit 70c1ac756d3cd8fa04725f82f0ad1a30404c3bb3

View File

@ -1,254 +1,254 @@
#include "STDInclude.hpp"
namespace Components
{
Dvar::Var Colors::NewColors;
std::vector<DWORD> Colors::ColorTable;
DWORD Colors::HsvToRgb(Colors::HsvColor hsv)
{
DWORD rgb;
unsigned char region, p, q, t;
unsigned int h, s, v, remainder;
if (hsv.s == 0)
{
rgb = RGB(hsv.v, hsv.v, hsv.v);
return rgb;
}
// converting to 16 bit to prevent overflow
h = hsv.h;
s = hsv.s;
v = hsv.v;
region = static_cast<uint8_t>(h / 43);
remainder = (h - (region * 43)) * 6;
p = static_cast<uint8_t>((v * (255 - s)) >> 8);
q = static_cast<uint8_t>((v * (255 - ((s * remainder) >> 8))) >> 8);
t = static_cast<uint8_t>((v * (255 - ((s * (255 - remainder)) >> 8))) >> 8);
switch (region)
{
case 0:
rgb = RGB(v, t, p);
break;
case 1:
rgb = RGB(q, v, p);
break;
case 2:
rgb = RGB(p, v, t);
break;
case 3:
rgb = RGB(p, q, v);
break;
case 4:
rgb = RGB(t, p, v);
break;
default:
rgb = RGB(v, p, q);
break;
}
return rgb;
}
void Colors::Strip(const char* in, char* out, int max)
{
if (!in || !out) return;
max--;
int current = 0;
while (*in != 0 && current < max)
{
char index = *(in + 1);
if (*in == '^' && (Colors::ColorIndex(index) != 7 || index == '7'))
{
++in;
}
else
{
*out = *in;
++out;
++current;
}
++in;
}
*out = '\0';
}
std::string Colors::Strip(std::string in)
{
char buffer[1000] = { 0 }; // Should be more than enough
Colors::Strip(in.data(), buffer, sizeof(buffer));
return std::string(buffer);
}
void __declspec(naked) Colors::ClientUserinfoChanged()
{
__asm
{
mov eax, [esp + 4h] // length
sub eax, 1
push eax
push ecx // name
push edx // buffer
call strncpy
add esp, 0Ch
retn
}
}
char* Colors::GetClientName(int localClientNum, int index, char *buf, size_t size)
{
Game::CL_GetClientName(localClientNum, index, buf, size);
// Remove the colors
strncpy(buf, Colors::Strip(buf).data(), size);
return buf;
}
void Colors::PatchColorLimit(char limit)
{
Utils::Hook::Set<char>(0x535629, limit); // DrawText2d
Utils::Hook::Set<char>(0x4C1BE4, limit); // No idea :P
Utils::Hook::Set<char>(0x4863DD, limit); // No idea :P
Utils::Hook::Set<char>(0x486429, limit); // No idea :P
Utils::Hook::Set<char>(0x49A5A8, limit); // No idea :P
Utils::Hook::Set<char>(0x505721, limit); // R_TextWidth
Utils::Hook::Set<char>(0x505801, limit); // No idea :P
Utils::Hook::Set<char>(0x50597F, limit); // No idea :P
Utils::Hook::Set<char>(0x5815DB, limit); // No idea :P
Utils::Hook::Set<char>(0x592ED0, limit); // No idea :P
Utils::Hook::Set<char>(0x5A2E2E, limit); // No idea :P
Utils::Hook::Set<char>(0x5A2733, limit - '0'); // No idea :P
}
char Colors::Add(uint8_t r, uint8_t g, uint8_t b)
{
char index = '0' + static_cast<char>(Colors::ColorTable.size());
Colors::ColorTable.push_back(RGB(r, g, b));
Colors::PatchColorLimit(index);
return index;
}
unsigned int Colors::ColorIndex(unsigned char index)
{
unsigned int result = index - '0';
if (result >= Colors::ColorTable.size() || result < 0) result = 7;
return result;
}
void Colors::LookupColor(DWORD* color, char index)
{
*color = RGB(255, 255, 255);
if (index == '8') // Color 8
{
*color = *reinterpret_cast<DWORD*>(0x66E5F70);
}
else if (index == '9') // Color 9
{
*color = *reinterpret_cast<DWORD*>(0x66E5F74);
}
else if (index == ':')
{
*color = Colors::HsvToRgb({ static_cast<uint8_t>((Game::Sys_Milliseconds() / 200) % 256), 255,255 });
}
else if (index == ';')
{
float fltColor[4];
Game::Dvar_GetUnpackedColorByName("sv_customTextColor", fltColor);
*color = RGB(fltColor[0] * 255, fltColor[1] * 255, fltColor[2] * 255);
}
else
{
int clrIndex = Colors::ColorIndex(index);
// Use native colors
if (clrIndex <= 7 && !Colors::NewColors.Get<bool>())
{
*color = reinterpret_cast<DWORD*>(0x78DC70)[index - 48];
}
else
{
*color = Colors::ColorTable[clrIndex];
}
}
}
char* Colors::CleanStrStub(char* string)
{
Colors::Strip(string, string, strlen(string) + 1);
return string;
}
void __declspec(naked) Colors::LookupColorStub()
{
__asm
{
push ebx
push [esp + 8h] // Index
push esi // Color ref
call Colors::LookupColor
add esp, 8h
pop ebx
retn
}
}
Colors::Colors()
{
// Disable SV_UpdateUserinfo_f, to block changing the name ingame
Utils::Hook::Set<BYTE>(0x6258D0, 0xC3);
// Allow colored names ingame
Utils::Hook(0x5D8B40, Colors::ClientUserinfoChanged, HOOK_JUMP).Install()->Quick();
// Though, don't apply that to overhead names.
Utils::Hook(0x581932, Colors::GetClientName, HOOK_CALL).Install()->Quick();
// Patch RB_LookupColor
Utils::Hook(0x534CD0, Colors::LookupColorStub, HOOK_JUMP).Install()->Quick();
// Patch ColorIndex
Utils::Hook(0x417770, Colors::ColorIndex, HOOK_JUMP).Install()->Quick();
// Patch I_CleanStr
Utils::Hook(0x4AD470, Colors::CleanStrStub, HOOK_JUMP).Install()->Quick();
// Register dvar
Colors::NewColors = Dvar::Register<bool>("cg_newColors", true, Game::dvar_flag::DVAR_FLAG_SAVED, "Use Warfare² color code style.");
Game::Dvar_RegisterColor("sv_customTextColor", 1, 0.7f, 0, 1, Game::dvar_flag::DVAR_FLAG_REPLICATED, "Color for the extended color code.");
// Add our colors
Colors::Add(0, 0, 0); // 0 - Black
Colors::Add(255, 49, 49); // 1 - Red
Colors::Add(134, 192, 0); // 2 - Green
Colors::Add(255, 173, 34); // 3 - Yellow
Colors::Add(0, 135, 193); // 4 - Blue
Colors::Add(32, 197, 255); // 5 - Light Blue
Colors::Add(151, 80, 221); // 6 - Pink
Colors::Add(255, 255, 255); // 7 - White
Colors::Add(0, 0, 0); // 8 - Team color (axis?)
Colors::Add(0, 0, 0); // 9 - Team color (allies?)
// Custom colors
Colors::Add(0, 0, 0); // 10 - Rainbow (:)
Colors::Add(0, 0, 0); // 11 - Server color (;) - using that color in infostrings (e.g. your name) fails, ';' is an illegal character!
}
Colors::~Colors()
{
Colors::ColorTable.clear();
}
}
#include "STDInclude.hpp"
namespace Components
{
Dvar::Var Colors::NewColors;
std::vector<DWORD> Colors::ColorTable;
DWORD Colors::HsvToRgb(Colors::HsvColor hsv)
{
DWORD rgb;
unsigned char region, p, q, t;
unsigned int h, s, v, remainder;
if (hsv.s == 0)
{
rgb = RGB(hsv.v, hsv.v, hsv.v);
return rgb;
}
// converting to 16 bit to prevent overflow
h = hsv.h;
s = hsv.s;
v = hsv.v;
region = static_cast<uint8_t>(h / 43);
remainder = (h - (region * 43)) * 6;
p = static_cast<uint8_t>((v * (255 - s)) >> 8);
q = static_cast<uint8_t>((v * (255 - ((s * remainder) >> 8))) >> 8);
t = static_cast<uint8_t>((v * (255 - ((s * (255 - remainder)) >> 8))) >> 8);
switch (region)
{
case 0:
rgb = RGB(v, t, p);
break;
case 1:
rgb = RGB(q, v, p);
break;
case 2:
rgb = RGB(p, v, t);
break;
case 3:
rgb = RGB(p, q, v);
break;
case 4:
rgb = RGB(t, p, v);
break;
default:
rgb = RGB(v, p, q);
break;
}
return rgb;
}
void Colors::Strip(const char* in, char* out, int max)
{
if (!in || !out) return;
max--;
int current = 0;
while (*in != 0 && current < max)
{
char index = *(in + 1);
if (*in == '^' && (Colors::ColorIndex(index) != 7 || index == '7'))
{
++in;
}
else
{
*out = *in;
++out;
++current;
}
++in;
}
*out = '\0';
}
std::string Colors::Strip(std::string in)
{
char buffer[1000] = { 0 }; // Should be more than enough
Colors::Strip(in.data(), buffer, sizeof(buffer));
return std::string(buffer);
}
void __declspec(naked) Colors::ClientUserinfoChanged()
{
__asm
{
mov eax, [esp + 4h] // length
sub eax, 1
push eax
push ecx // name
push edx // buffer
call strncpy
add esp, 0Ch
retn
}
}
char* Colors::GetClientName(int localClientNum, int index, char *buf, size_t size)
{
Game::CL_GetClientName(localClientNum, index, buf, size);
// Remove the colors
strncpy_s(buf, size, Colors::Strip(buf).data(), size);
return buf;
}
void Colors::PatchColorLimit(char limit)
{
Utils::Hook::Set<char>(0x535629, limit); // DrawText2d
Utils::Hook::Set<char>(0x4C1BE4, limit); // No idea :P
Utils::Hook::Set<char>(0x4863DD, limit); // No idea :P
Utils::Hook::Set<char>(0x486429, limit); // No idea :P
Utils::Hook::Set<char>(0x49A5A8, limit); // No idea :P
Utils::Hook::Set<char>(0x505721, limit); // R_TextWidth
Utils::Hook::Set<char>(0x505801, limit); // No idea :P
Utils::Hook::Set<char>(0x50597F, limit); // No idea :P
Utils::Hook::Set<char>(0x5815DB, limit); // No idea :P
Utils::Hook::Set<char>(0x592ED0, limit); // No idea :P
Utils::Hook::Set<char>(0x5A2E2E, limit); // No idea :P
Utils::Hook::Set<char>(0x5A2733, limit - '0'); // No idea :P
}
char Colors::Add(uint8_t r, uint8_t g, uint8_t b)
{
char index = '0' + static_cast<char>(Colors::ColorTable.size());
Colors::ColorTable.push_back(RGB(r, g, b));
Colors::PatchColorLimit(index);
return index;
}
unsigned int Colors::ColorIndex(unsigned char index)
{
unsigned int result = index - '0';
if (result >= Colors::ColorTable.size() || result < 0) result = 7;
return result;
}
void Colors::LookupColor(DWORD* color, char index)
{
*color = RGB(255, 255, 255);
if (index == '8') // Color 8
{
*color = *reinterpret_cast<DWORD*>(0x66E5F70);
}
else if (index == '9') // Color 9
{
*color = *reinterpret_cast<DWORD*>(0x66E5F74);
}
else if (index == ':')
{
*color = Colors::HsvToRgb({ static_cast<uint8_t>((Game::Sys_Milliseconds() / 200) % 256), 255,255 });
}
else if (index == ';')
{
float fltColor[4];
Game::Dvar_GetUnpackedColorByName("sv_customTextColor", fltColor);
*color = RGB(fltColor[0] * 255, fltColor[1] * 255, fltColor[2] * 255);
}
else
{
int clrIndex = Colors::ColorIndex(index);
// Use native colors
if (clrIndex <= 7 && !Colors::NewColors.Get<bool>())
{
*color = reinterpret_cast<DWORD*>(0x78DC70)[index - 48];
}
else
{
*color = Colors::ColorTable[clrIndex];
}
}
}
char* Colors::CleanStrStub(char* string)
{
Colors::Strip(string, string, strlen(string) + 1);
return string;
}
void __declspec(naked) Colors::LookupColorStub()
{
__asm
{
push ebx
push [esp + 8h] // Index
push esi // Color ref
call Colors::LookupColor
add esp, 8h
pop ebx
retn
}
}
Colors::Colors()
{
// Disable SV_UpdateUserinfo_f, to block changing the name ingame
Utils::Hook::Set<BYTE>(0x6258D0, 0xC3);
// Allow colored names ingame
Utils::Hook(0x5D8B40, Colors::ClientUserinfoChanged, HOOK_JUMP).Install()->Quick();
// Though, don't apply that to overhead names.
Utils::Hook(0x581932, Colors::GetClientName, HOOK_CALL).Install()->Quick();
// Patch RB_LookupColor
Utils::Hook(0x534CD0, Colors::LookupColorStub, HOOK_JUMP).Install()->Quick();
// Patch ColorIndex
Utils::Hook(0x417770, Colors::ColorIndex, HOOK_JUMP).Install()->Quick();
// Patch I_CleanStr
Utils::Hook(0x4AD470, Colors::CleanStrStub, HOOK_JUMP).Install()->Quick();
// Register dvar
Colors::NewColors = Dvar::Register<bool>("cg_newColors", true, Game::dvar_flag::DVAR_FLAG_SAVED, "Use Warfare² color code style.");
Game::Dvar_RegisterColor("sv_customTextColor", 1, 0.7f, 0, 1, Game::dvar_flag::DVAR_FLAG_REPLICATED, "Color for the extended color code.");
// Add our colors
Colors::Add(0, 0, 0); // 0 - Black
Colors::Add(255, 49, 49); // 1 - Red
Colors::Add(134, 192, 0); // 2 - Green
Colors::Add(255, 173, 34); // 3 - Yellow
Colors::Add(0, 135, 193); // 4 - Blue
Colors::Add(32, 197, 255); // 5 - Light Blue
Colors::Add(151, 80, 221); // 6 - Pink
Colors::Add(255, 255, 255); // 7 - White
Colors::Add(0, 0, 0); // 8 - Team color (axis?)
Colors::Add(0, 0, 0); // 9 - Team color (allies?)
// Custom colors
Colors::Add(0, 0, 0); // 10 - Rainbow (:)
Colors::Add(0, 0, 0); // 11 - Server color (;) - using that color in infostrings (e.g. your name) fails, ';' is an illegal character!
}
Colors::~Colors()
{
Colors::ColorTable.clear();
}
}

File diff suppressed because it is too large Load Diff

View File

@ -13,11 +13,11 @@ namespace Components
{
char filename[MAX_PATH];
__time64_t time;
tm* ltime;
tm ltime;
_time64(&time);
ltime = _localtime64(&time);
strftime(filename, sizeof(filename) - 1, "iw4x-" VERSION_STR "-%Y%m%d%H%M%S.dmp", ltime);
_localtime64_s(&ltime, &time);
strftime(filename, sizeof(filename) - 1, "iw4x-" VERSION_STR "-%Y%m%d%H%M%S.dmp", &ltime);
HANDLE hFile = CreateFileA(filename, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);

View File

@ -1,155 +1,155 @@
#include "STDInclude.hpp"
namespace Components
{
std::mutex Logger::MessageMutex;
std::vector<std::string> Logger::MessageQueue;
void(*Logger::PipeCallback)(std::string) = nullptr;
bool Logger::IsConsoleReady()
{
return (IsWindow(*reinterpret_cast<HWND*>(0x64A3288)) != FALSE || (Dedicated::IsDedicated() && !Flags::HasFlag("console")));
}
void Logger::Print(const char* message, ...)
{
return Logger::MessagePrint(0, Logger::Format(&message));
}
void Logger::Print(int channel, const char* message, ...)
{
return Logger::MessagePrint(channel, Logger::Format(&message));
}
void Logger::MessagePrint(int channel, std::string message)
{
if (Flags::HasFlag("stdout") || Loader::PerformingUnitTests())
{
printf("%s", message.data());
fflush(stdout);
return;
}
if (!Logger::IsConsoleReady())
{
OutputDebugStringA(message.data());
}
if (!Game::Sys_IsMainThread())
{
Logger::EnqueueMessage(message);
}
else
{
Game::Com_PrintMessage(0, message.data(), 0);
}
}
void Logger::ErrorPrint(int error, std::string message)
{
return Game::Com_Error(error, "%s", message.data());
}
void Logger::Error(int error, const char* message, ...)
{
return Logger::ErrorPrint(error, Logger::Format(&message));
}
void Logger::Error(const char* message, ...)
{
return Logger::ErrorPrint(0, Logger::Format(&message));
}
void Logger::SoftError(const char* message, ...)
{
return Logger::ErrorPrint(2, Logger::Format(&message));
}
std::string Logger::Format(const char** message)
{
char buffer[0x1000] = { 0 };
va_list ap = reinterpret_cast<char*>(const_cast<char**>(&message[1]));
//va_start(ap, *message);
_vsnprintf(buffer, sizeof(buffer), *message, ap);
va_end(ap);
return buffer;
}
void Logger::Frame()
{
Logger::MessageMutex.lock();
for (unsigned int i = 0; i < Logger::MessageQueue.size(); ++i)
{
Game::Com_PrintMessage(0, Logger::MessageQueue[i].data(), 0);
if (!Logger::IsConsoleReady())
{
OutputDebugStringA(Logger::MessageQueue[i].data());
}
}
Logger::MessageQueue.clear();
Logger::MessageMutex.unlock();
}
void Logger::PipeOutput(void(*callback)(std::string))
{
Logger::PipeCallback = callback;
}
void Logger::PrintMessagePipe(const char* data)
{
if (Logger::PipeCallback)
{
Logger::PipeCallback(data);
}
}
void __declspec(naked) Logger::PrintMessageStub()
{
__asm
{
mov eax, Logger::PipeCallback
test eax, eax
jz returnPrint
push [esp + 8h]
call Logger::PrintMessagePipe
add esp, 4h
retn
returnPrint:
push esi
mov esi, [esp + 0Ch]
mov eax, 4AA835h
jmp eax
}
}
void Logger::EnqueueMessage(std::string message)
{
Logger::MessageMutex.lock();
Logger::MessageQueue.push_back(message);
Logger::MessageMutex.unlock();
}
Logger::Logger()
{
Logger::PipeOutput(nullptr);
QuickPatch::OnFrame(Logger::Frame);
Utils::Hook(Game::Com_PrintMessage, Logger::PrintMessageStub, HOOK_JUMP).Install()->Quick();
}
Logger::~Logger()
{
Logger::MessageMutex.lock();
Logger::MessageQueue.clear();
Logger::MessageMutex.unlock();
}
}
#include "STDInclude.hpp"
namespace Components
{
std::mutex Logger::MessageMutex;
std::vector<std::string> Logger::MessageQueue;
void(*Logger::PipeCallback)(std::string) = nullptr;
bool Logger::IsConsoleReady()
{
return (IsWindow(*reinterpret_cast<HWND*>(0x64A3288)) != FALSE || (Dedicated::IsDedicated() && !Flags::HasFlag("console")));
}
void Logger::Print(const char* message, ...)
{
return Logger::MessagePrint(0, Logger::Format(&message));
}
void Logger::Print(int channel, const char* message, ...)
{
return Logger::MessagePrint(channel, Logger::Format(&message));
}
void Logger::MessagePrint(int channel, std::string message)
{
if (Flags::HasFlag("stdout") || Loader::PerformingUnitTests())
{
printf("%s", message.data());
fflush(stdout);
return;
}
if (!Logger::IsConsoleReady())
{
OutputDebugStringA(message.data());
}
if (!Game::Sys_IsMainThread())
{
Logger::EnqueueMessage(message);
}
else
{
Game::Com_PrintMessage(0, message.data(), 0);
}
}
void Logger::ErrorPrint(int error, std::string message)
{
return Game::Com_Error(error, "%s", message.data());
}
void Logger::Error(int error, const char* message, ...)
{
return Logger::ErrorPrint(error, Logger::Format(&message));
}
void Logger::Error(const char* message, ...)
{
return Logger::ErrorPrint(0, Logger::Format(&message));
}
void Logger::SoftError(const char* message, ...)
{
return Logger::ErrorPrint(2, Logger::Format(&message));
}
std::string Logger::Format(const char** message)
{
char buffer[0x1000] = { 0 };
va_list ap = reinterpret_cast<char*>(const_cast<char**>(&message[1]));
//va_start(ap, *message);
_vsnprintf_s(buffer, sizeof(buffer), *message, ap);
va_end(ap);
return buffer;
}
void Logger::Frame()
{
Logger::MessageMutex.lock();
for (unsigned int i = 0; i < Logger::MessageQueue.size(); ++i)
{
Game::Com_PrintMessage(0, Logger::MessageQueue[i].data(), 0);
if (!Logger::IsConsoleReady())
{
OutputDebugStringA(Logger::MessageQueue[i].data());
}
}
Logger::MessageQueue.clear();
Logger::MessageMutex.unlock();
}
void Logger::PipeOutput(void(*callback)(std::string))
{
Logger::PipeCallback = callback;
}
void Logger::PrintMessagePipe(const char* data)
{
if (Logger::PipeCallback)
{
Logger::PipeCallback(data);
}
}
void __declspec(naked) Logger::PrintMessageStub()
{
__asm
{
mov eax, Logger::PipeCallback
test eax, eax
jz returnPrint
push [esp + 8h]
call Logger::PrintMessagePipe
add esp, 4h
retn
returnPrint:
push esi
mov esi, [esp + 0Ch]
mov eax, 4AA835h
jmp eax
}
}
void Logger::EnqueueMessage(std::string message)
{
Logger::MessageMutex.lock();
Logger::MessageQueue.push_back(message);
Logger::MessageMutex.unlock();
}
Logger::Logger()
{
Logger::PipeOutput(nullptr);
QuickPatch::OnFrame(Logger::Frame);
Utils::Hook(Game::Com_PrintMessage, Logger::PrintMessageStub, HOOK_JUMP).Install()->Quick();
}
Logger::~Logger()
{
Logger::MessageMutex.lock();
Logger::MessageQueue.clear();
Logger::MessageMutex.unlock();
}
}

View File

@ -118,7 +118,7 @@ namespace Components
AntiCheat::EmptyHash();
_snprintf(buffer, size, format, mapname);
_snprintf_s(buffer, size, size, format, mapname);
}
void Maps::AddDependency(std::string expression, std::string zone)

View File

@ -45,7 +45,7 @@ namespace Components
Game::Script_SetupTokens(script, reinterpret_cast<char*>(0x797F80));
script->punctuations = reinterpret_cast<Game::punctuation_t*>(0x797F80);
strcpy(script->buffer, buffer.data());
memcpy(script->buffer, buffer.data(), script->length + 1);
script->length = Game::Script_CleanString(script->buffer);
@ -75,7 +75,7 @@ namespace Components
return 0;
}
strncpy(source->filename, "string", 64);
strncpy_s(source->filename, 64, "string", 64);
source->scriptstack = script;
source->tokens = NULL;
source->defines = NULL;

View File

@ -305,6 +305,7 @@ namespace Components
Utils::Hook::Nop(0x6830B1, 20);
Utils::Hook(0x682EBF, QuickPatch::GetStatsID, HOOK_CALL).Install()->Quick();
Utils::Hook(0x6830B1, QuickPatch::GetStatsID, HOOK_CALL).Install()->Quick();
//Utils::Hook::Set<BYTE>(0x68323A, 0xEB);
// Exploit fixes
Utils::Hook(0x414D92, QuickPatch::MsgReadBitsCompressCheckSV, HOOK_CALL).Install()->Quick();

View File

@ -144,7 +144,7 @@ namespace Components
char msgbuf[1024] = { 0 };
va_list v;
va_start(v, message);
_vsnprintf(msgbuf, sizeof(msgbuf), message, v);
_vsnprintf_s(msgbuf, sizeof(msgbuf), message, v);
va_end(v);
Game::Scr_ShutdownAllocNode();

View File

@ -271,12 +271,17 @@ namespace Components
Theatre::DemoContainer.CurrentSelection = index;
Theatre::Container::DemoInfo info = Theatre::DemoContainer.Demos[index];
tm time;
char buffer[1000] = { 0 };
localtime_s(&time, &info.TimeStamp);
asctime_s(buffer, sizeof buffer, &time);
Dvar::Var("ui_demo_mapname").Set(info.Mapname);
Dvar::Var("ui_demo_mapname_localized").Set(Game::UI_LocalizeMapName(info.Mapname.data()));
Dvar::Var("ui_demo_gametype").Set(Game::UI_LocalizeGameType(info.Gametype.data()));
Dvar::Var("ui_demo_length").Set(Utils::String::FormatTimeSpan(info.Length));
Dvar::Var("ui_demo_author").Set(info.Author);
Dvar::Var("ui_demo_date").Set(std::asctime(std::localtime(&info.TimeStamp)));
Dvar::Var("ui_demo_date").Set(buffer);
}
}

View File

@ -8,7 +8,7 @@
// Disable irrelevant warnings
#pragma warning(disable: 4100) // Unreferenced parameter (steam has to have them and other stubs as well, due to their calling convention)
#define _CRT_SECURE_NO_WARNINGS
#define VC_EXTRALEAN
#define WIN32_LEAN_AND_MEAN
#include <windows.h>

View File

@ -1,105 +1,97 @@
#include "STDInclude.hpp"
namespace Steam
{
unsigned int Utils::GetSecondsSinceAppActive()
{
return 0;
}
unsigned int Utils::GetSecondsSinceComputerActive()
{
return 0;
}
int Utils::GetConnectedUniverse()
{
return 1;
}
unsigned int Utils::GetServerRealTime()
{
return 0;
}
const char* Utils::GetIPCountry()
{
return "US";
}
bool Utils::GetImageSize(int iImage, unsigned int *pnWidth, unsigned int *pnHeight)
{
return false;
}
bool Utils::GetImageRGBA(int iImage, unsigned char *pubDest, int nDestBufferSize)
{
return false;
}
bool Utils::GetCSERIPPort(unsigned int *unIP, unsigned short *usPort)
{
return false;
}
unsigned char Utils::GetCurrentBatteryPower()
{
return 255;
}
unsigned int Utils::GetAppID()
{
return 10190;
}
void Utils::SetOverlayNotificationPosition(int eNotificationPosition)
{
if (Steam::Overlay)
{
FARPROC setPosition = GetProcAddress(Steam::Overlay, "SetNotificationPosition");
if (setPosition)
{
::Utils::Hook::Call<void(int)>(setPosition)(eNotificationPosition);
}
}
}
bool Utils::IsAPICallCompleted(unsigned __int64 hSteamAPICall, bool *pbFailed)
{
return false;
}
int Utils::GetAPICallFailureReason(unsigned __int64 hSteamAPICall)
{
return -1;
}
bool Utils::GetAPICallResult(unsigned __int64 hSteamAPICall, void *pCallback, int cubCallback, int iCallbackExpected, bool *pbFailed)
{
return false;
}
void Utils::RunFrame()
{
}
unsigned int Utils::GetIPCCallCount()
{
return 0;
}
void Utils::SetWarningMessageHook(void(*pFunction)(int hpipe, const char *message))
{
}
bool Utils::IsOverlayEnabled()
{
return false;
}
bool Utils::BOverlayNeedsPresent()
{
return false;
}
}
#include "STDInclude.hpp"
namespace Steam
{
unsigned int Utils::GetSecondsSinceAppActive()
{
return 0;
}
unsigned int Utils::GetSecondsSinceComputerActive()
{
return 0;
}
int Utils::GetConnectedUniverse()
{
return 1;
}
unsigned int Utils::GetServerRealTime()
{
return 0;
}
const char* Utils::GetIPCountry()
{
return "US";
}
bool Utils::GetImageSize(int iImage, unsigned int *pnWidth, unsigned int *pnHeight)
{
return false;
}
bool Utils::GetImageRGBA(int iImage, unsigned char *pubDest, int nDestBufferSize)
{
return false;
}
bool Utils::GetCSERIPPort(unsigned int *unIP, unsigned short *usPort)
{
return false;
}
unsigned char Utils::GetCurrentBatteryPower()
{
return 255;
}
unsigned int Utils::GetAppID()
{
return 10190;
}
void Utils::SetOverlayNotificationPosition(int eNotificationPosition)
{
Proxy::SetOverlayNotificationPosition(eNotificationPosition);
}
bool Utils::IsAPICallCompleted(unsigned __int64 hSteamAPICall, bool *pbFailed)
{
return false;
}
int Utils::GetAPICallFailureReason(unsigned __int64 hSteamAPICall)
{
return -1;
}
bool Utils::GetAPICallResult(unsigned __int64 hSteamAPICall, void *pCallback, int cubCallback, int iCallbackExpected, bool *pbFailed)
{
return false;
}
void Utils::RunFrame()
{
}
unsigned int Utils::GetIPCCallCount()
{
return 0;
}
void Utils::SetWarningMessageHook(void(*pFunction)(int hpipe, const char *message))
{
}
bool Utils::IsOverlayEnabled()
{
return false;
}
bool Utils::BOverlayNeedsPresent()
{
return false;
}
}

88
src/Steam/Proxy.cpp Normal file
View File

@ -0,0 +1,88 @@
#include "STDInclude.hpp"
namespace Steam
{
HMODULE Proxy::Client = nullptr;
HMODULE Proxy::Overlay = nullptr;
bool Proxy::Inititalize()
{
std::string directoy = Proxy::GetSteamDirectory();
if (directoy.empty()) return false;
SetDllDirectoryA(Proxy::GetSteamDirectory().data());
Proxy::Client = LoadLibraryA(STEAMCLIENT_LIB);
Proxy::Overlay = LoadLibraryA(GAMEOVERLAY_LIB);
return (Proxy::Client && Proxy::Overlay);
}
void Proxy::Uninititalize()
{
if (Proxy::Client) FreeLibrary(Proxy::Client);
Proxy::Client = nullptr;
if (Proxy::Overlay) FreeLibrary(Proxy::Overlay);
Proxy::Overlay = nullptr;
}
std::string Proxy::GetSteamDirectory()
{
HKEY hRegKey;
char SteamPath[MAX_PATH];
if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, STEAM_REGISTRY_PATH, 0, KEY_QUERY_VALUE, &hRegKey) == ERROR_SUCCESS)
{
DWORD dwLength = sizeof(SteamPath);
RegQueryValueExA(hRegKey, "InstallPath", NULL, NULL, reinterpret_cast<BYTE*>(SteamPath), &dwLength);
RegCloseKey(hRegKey);
return SteamPath;
}
return "";
}
void Proxy::SetOverlayNotificationPosition(uint32_t eNotificationPosition)
{
if (Proxy::Overlay)
{
FARPROC SetNotificationPositionFn = GetProcAddress(Proxy::Overlay, "SetNotificationPosition");
if (SetNotificationPositionFn)
{
::Utils::Hook::Call<void(uint32_t)>(SetNotificationPositionFn)(eNotificationPosition);
}
}
}
bool Proxy::IsOverlayEnabled()
{
if (Proxy::Overlay)
{
FARPROC IsOverlayEnabledFn = GetProcAddress(Proxy::Overlay, "IsOverlayEnabled");
if (IsOverlayEnabledFn)
{
return ::Utils::Hook::Call<bool()>(IsOverlayEnabledFn)();
}
}
return false;
}
bool Proxy::BOverlayNeedsPresent()
{
if (Proxy::Overlay)
{
FARPROC BOverlayNeedsPresentFn = GetProcAddress(Proxy::Overlay, "BOverlayNeedsPresent");
if (BOverlayNeedsPresentFn)
{
return ::Utils::Hook::Call<bool()>(BOverlayNeedsPresentFn)();
}
}
return false;
}
}

30
src/Steam/Proxy.hpp Normal file
View File

@ -0,0 +1,30 @@
#ifdef _WIN64
#define GAMEOVERLAY_LIB "gameoverlayrenderer64.dll"
#define STEAMCLIENT_LIB "steamclient64.dll"
#define STEAM_REGISTRY_PATH "Software\\Wow6432Node\\Valve\\Steam"
#else
#define GAMEOVERLAY_LIB "gameoverlayrenderer.dll"
#define STEAMCLIENT_LIB "steamclient.dll"
#define STEAM_REGISTRY_PATH "Software\\Valve\\Steam"
#endif
namespace Steam
{
class Proxy
{
public:
static bool Inititalize();
static void Uninititalize();
//Overlay related proxies
static void SetOverlayNotificationPosition(uint32_t eNotificationPosition);
static bool IsOverlayEnabled();
static bool BOverlayNeedsPresent();
private:
static HMODULE Client;
static HMODULE Overlay;
static std::string GetSteamDirectory();
};
}

View File

@ -2,8 +2,6 @@
namespace Steam
{
HMODULE Overlay = 0;
uint64_t Callbacks::CallID = 0;
std::map<uint64_t, bool> Callbacks::Calls;
std::map<uint64_t, Callbacks::Base*> Callbacks::ResultHandlers;
@ -71,22 +69,9 @@ namespace Steam
{
bool SteamAPI_Init()
{
Overlay = GetModuleHandleA("gameoverlayrenderer.dll");
if (!Overlay)
if (!Proxy::Inititalize())
{
HKEY hRegKey;
if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, "Software\\Valve\\Steam", 0, KEY_QUERY_VALUE, &hRegKey) == ERROR_SUCCESS)
{
char steamPath[MAX_PATH] = { 0 };
DWORD dwLength = sizeof(steamPath);
RegQueryValueExA(hRegKey, "InstallPath", NULL, NULL, reinterpret_cast<BYTE*>(steamPath), &dwLength);
RegCloseKey(hRegKey);
SetDllDirectoryA(steamPath);
Overlay = LoadLibraryA(::Utils::String::VA("%s\\%s", steamPath, "gameoverlayrenderer.dll"));
}
OutputDebugStringA("Steamproxy not initialized properly");
}
return true;
@ -109,6 +94,7 @@ namespace Steam
void SteamAPI_Shutdown()
{
Proxy::Uninititalize();
}
void SteamAPI_UnregisterCallResult()

View File

@ -1,93 +1,93 @@
#pragma once
#define STEAM_EXPORT extern "C" __declspec(dllexport)
typedef union
{
struct
{
unsigned int AccountID : 32;
unsigned int AccountInstance : 20;
unsigned int AccountType : 4;
int Universe : 8;
};
unsigned long long Bits;
} SteamID;
#include "Interfaces\SteamUser.hpp"
#include "Interfaces\SteamUtils.hpp"
#include "Interfaces\SteamFriends.hpp"
#include "Interfaces\SteamGameServer.hpp"
#include "Interfaces\SteamNetworking.hpp"
#include "Interfaces\SteamMatchmaking.hpp"
#include "Interfaces\SteamRemoteStorage.hpp"
#include "Interfaces\SteamMasterServerUpdater.hpp"
namespace Steam
{
class Callbacks
{
public:
class Base
{
public:
Base() : Flags(0), Callback(0) {};
virtual void Run(void *pvParam) = 0;
virtual void Run(void *pvParam, bool bIOFailure, uint64_t hSteamAPICall) = 0;
virtual int GetCallbackSizeBytes() = 0;
int GetICallback() { return Callback; }
void SetICallback(int iCallback) { Callback = iCallback; }
protected:
unsigned char Flags;
int Callback;
};
struct Result
{
void* data;
int size;
int type;
uint64_t call;
};
static uint64_t RegisterCall();
static void RegisterCallback(Base* handler, int callback);
static void RegisterCallResult(uint64_t call, Base* result);
static void ReturnCall(void* data, int size, int type, uint64_t call);
static void RunCallbacks();
private:
static uint64_t CallID;
static std::map<uint64_t, bool> Calls;
static std::map<uint64_t, Base*> ResultHandlers;
static std::vector<Result> Results;
static std::vector<Base*> CallbackList;
};
STEAM_EXPORT bool SteamAPI_Init();
STEAM_EXPORT void SteamAPI_RegisterCallResult(Callbacks::Base* result, uint64_t call);
STEAM_EXPORT void SteamAPI_RegisterCallback(Callbacks::Base* handler, int callback);
STEAM_EXPORT void SteamAPI_RunCallbacks();
STEAM_EXPORT void SteamAPI_Shutdown();
STEAM_EXPORT void SteamAPI_UnregisterCallResult();
STEAM_EXPORT void SteamAPI_UnregisterCallback();
STEAM_EXPORT bool SteamGameServer_Init();
STEAM_EXPORT void SteamGameServer_RunCallbacks();
STEAM_EXPORT void SteamGameServer_Shutdown();
STEAM_EXPORT Steam::Friends* SteamFriends();
STEAM_EXPORT Steam::Matchmaking* SteamMatchmaking();
STEAM_EXPORT Steam::GameServer* SteamGameServer();
STEAM_EXPORT Steam::MasterServerUpdater* SteamMasterServerUpdater();
STEAM_EXPORT Steam::Networking* SteamNetworking();
STEAM_EXPORT Steam::RemoteStorage* SteamRemoteStorage();
STEAM_EXPORT Steam::User* SteamUser();
STEAM_EXPORT Steam::Utils* SteamUtils();
extern HMODULE Overlay;
}
#pragma once
#define STEAM_EXPORT extern "C" __declspec(dllexport)
typedef union
{
struct
{
unsigned int AccountID : 32;
unsigned int AccountInstance : 20;
unsigned int AccountType : 4;
int Universe : 8;
};
unsigned long long Bits;
} SteamID;
#include "Interfaces\SteamUser.hpp"
#include "Interfaces\SteamUtils.hpp"
#include "Interfaces\SteamFriends.hpp"
#include "Interfaces\SteamGameServer.hpp"
#include "Interfaces\SteamNetworking.hpp"
#include "Interfaces\SteamMatchmaking.hpp"
#include "Interfaces\SteamRemoteStorage.hpp"
#include "Interfaces\SteamMasterServerUpdater.hpp"
#include "Proxy.hpp"
namespace Steam
{
class Callbacks
{
public:
class Base
{
public:
Base() : Flags(0), Callback(0) {};
virtual void Run(void *pvParam) = 0;
virtual void Run(void *pvParam, bool bIOFailure, uint64_t hSteamAPICall) = 0;
virtual int GetCallbackSizeBytes() = 0;
int GetICallback() { return Callback; }
void SetICallback(int iCallback) { Callback = iCallback; }
protected:
unsigned char Flags;
int Callback;
};
struct Result
{
void* data;
int size;
int type;
uint64_t call;
};
static uint64_t RegisterCall();
static void RegisterCallback(Base* handler, int callback);
static void RegisterCallResult(uint64_t call, Base* result);
static void ReturnCall(void* data, int size, int type, uint64_t call);
static void RunCallbacks();
private:
static uint64_t CallID;
static std::map<uint64_t, bool> Calls;
static std::map<uint64_t, Base*> ResultHandlers;
static std::vector<Result> Results;
static std::vector<Base*> CallbackList;
};
STEAM_EXPORT bool SteamAPI_Init();
STEAM_EXPORT void SteamAPI_RegisterCallResult(Callbacks::Base* result, uint64_t call);
STEAM_EXPORT void SteamAPI_RegisterCallback(Callbacks::Base* handler, int callback);
STEAM_EXPORT void SteamAPI_RunCallbacks();
STEAM_EXPORT void SteamAPI_Shutdown();
STEAM_EXPORT void SteamAPI_UnregisterCallResult();
STEAM_EXPORT void SteamAPI_UnregisterCallback();
STEAM_EXPORT bool SteamGameServer_Init();
STEAM_EXPORT void SteamGameServer_RunCallbacks();
STEAM_EXPORT void SteamGameServer_Shutdown();
STEAM_EXPORT Steam::Friends* SteamFriends();
STEAM_EXPORT Steam::Matchmaking* SteamMatchmaking();
STEAM_EXPORT Steam::GameServer* SteamGameServer();
STEAM_EXPORT Steam::MasterServerUpdater* SteamMasterServerUpdater();
STEAM_EXPORT Steam::Networking* SteamNetworking();
STEAM_EXPORT Steam::RemoteStorage* SteamRemoteStorage();
STEAM_EXPORT Steam::User* SteamUser();
STEAM_EXPORT Steam::Utils* SteamUtils();
}

View File

@ -1,257 +1,257 @@
#include "STDInclude.hpp"
namespace Utils
{
std::map<void*, void*> Hook::Interceptor::IReturn;
std::map<void*, void(*)()> Hook::Interceptor::ICallbacks;
void Hook::Signature::Process()
{
if (Hook::Signature::Signatures.empty()) return;
char* start = reinterpret_cast<char*>(Hook::Signature::Start);
unsigned int sigCount = Hook::Signature::Signatures.size();
Hook::Signature::Container* containers = Hook::Signature::Signatures.data();
for (size_t i = 0; i < Hook::Signature::Length; ++i)
{
char* address = start + i;
for (unsigned int k = 0; k < sigCount; ++k)
{
Hook::Signature::Container* container = &containers[k];
unsigned int j = 0;
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(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;
}
void __declspec(naked) 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 RunCallback // Run the callback based on the given stack pointer
call 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 (Hook::Initialized)
{
Hook::Uninstall();
}
}
Hook* Hook::Initialize(DWORD place, void(*stub)(), bool useJump)
{
return Hook::Initialize(place, reinterpret_cast<void*>(stub), useJump);
}
Hook* Hook::Initialize(DWORD place, void* stub, bool useJump)
{
return Hook::Initialize(reinterpret_cast<void*>(place), stub, useJump);
}
Hook* Hook::Initialize(void* place, void* stub, bool useJump)
{
if (Hook::Initialized) return this;
Hook::Initialized = true;
Hook::UseJump = useJump;
Hook::Place = place;
Hook::Stub = stub;
Hook::Original = static_cast<char*>(Hook::Place) + 5 + *reinterpret_cast<DWORD*>((static_cast<char*>(Hook::Place) + 1));
return this;
}
Hook* Hook::Install(bool unprotect, bool keepUnportected)
{
Hook::StateMutex.lock();
if (!Hook::Initialized || Hook::Installed)
{
Hook::StateMutex.unlock();
return this;
}
Hook::Installed = true;
if (unprotect) VirtualProtect(Hook::Place, sizeof(Hook::Buffer), PAGE_EXECUTE_READWRITE, &this->Protection);
std::memcpy(Hook::Buffer, Hook::Place, sizeof(Hook::Buffer));
char* code = static_cast<char*>(Hook::Place);
*code = static_cast<char>(Hook::UseJump ? 0xE9 : 0xE8);
*reinterpret_cast<size_t*>(code + 1) = reinterpret_cast<size_t>(Hook::Stub) - (reinterpret_cast<size_t>(Hook::Place) + 5);
if (unprotect && !keepUnportected) VirtualProtect(Hook::Place, sizeof(Hook::Buffer), Hook::Protection, &this->Protection);
FlushInstructionCache(GetCurrentProcess(), Hook::Place, sizeof(Hook::Buffer));
Hook::StateMutex.unlock();
return this;
}
void Hook::Quick()
{
if (Hook::Installed)
{
Hook::Installed = false;
}
}
Hook* Hook::Uninstall(bool unprotect)
{
Hook::StateMutex.lock();
if (!Hook::Initialized || !Hook::Installed)
{
Hook::StateMutex.unlock();
return this;
}
Hook::Installed = false;
if(unprotect) VirtualProtect(Hook::Place, sizeof(Hook::Buffer), PAGE_EXECUTE_READWRITE, &this->Protection);
std::memcpy(Hook::Place, Hook::Buffer, sizeof(Hook::Buffer));
if (unprotect) VirtualProtect(Hook::Place, sizeof(Hook::Buffer), Hook::Protection, &this->Protection);
FlushInstructionCache(GetCurrentProcess(), Hook::Place, sizeof(Hook::Buffer));
Hook::StateMutex.unlock();
return this;
}
void* Hook::GetAddress()
{
return Hook::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(static_cast<char*>(place), 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);
}
}
#include "STDInclude.hpp"
namespace Utils
{
std::map<void*, void*> Hook::Interceptor::IReturn;
std::map<void*, void(*)()> Hook::Interceptor::ICallbacks;
void Hook::Signature::Process()
{
if (Hook::Signature::Signatures.empty()) return;
char* start = reinterpret_cast<char*>(Hook::Signature::Start);
unsigned int sigCount = Hook::Signature::Signatures.size();
Hook::Signature::Container* containers = Hook::Signature::Signatures.data();
for (size_t i = 0; i < Hook::Signature::Length; ++i)
{
char* address = start + i;
for (unsigned int k = 0; k < sigCount; ++k)
{
Hook::Signature::Container* container = &containers[k];
unsigned int j = 0;
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(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;
}
void __declspec(naked) 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 RunCallback // Run the callback based on the given stack pointer
call 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 (Hook::Initialized)
{
Hook::Uninstall();
}
}
Hook* Hook::Initialize(DWORD place, void(*stub)(), bool useJump)
{
return Hook::Initialize(place, reinterpret_cast<void*>(stub), useJump);
}
Hook* Hook::Initialize(DWORD place, void* stub, bool useJump)
{
return Hook::Initialize(reinterpret_cast<void*>(place), stub, useJump);
}
Hook* Hook::Initialize(void* place, void* stub, bool useJump)
{
if (Hook::Initialized) return this;
Hook::Initialized = true;
Hook::UseJump = useJump;
Hook::Place = place;
Hook::Stub = stub;
Hook::Original = static_cast<char*>(Hook::Place) + 5 + *reinterpret_cast<DWORD*>((static_cast<char*>(Hook::Place) + 1));
return this;
}
Hook* Hook::Install(bool unprotect, bool keepUnportected)
{
Hook::StateMutex.lock();
if (!Hook::Initialized || Hook::Installed)
{
Hook::StateMutex.unlock();
return this;
}
Hook::Installed = true;
if (unprotect) VirtualProtect(Hook::Place, sizeof(Hook::Buffer), PAGE_EXECUTE_READWRITE, &this->Protection);
std::memcpy(Hook::Buffer, Hook::Place, sizeof(Hook::Buffer));
char* code = static_cast<char*>(Hook::Place);
*code = static_cast<char>(Hook::UseJump ? 0xE9 : 0xE8);
*reinterpret_cast<size_t*>(code + 1) = reinterpret_cast<size_t>(Hook::Stub) - (reinterpret_cast<size_t>(Hook::Place) + 5);
if (unprotect && !keepUnportected) VirtualProtect(Hook::Place, sizeof(Hook::Buffer), Hook::Protection, &this->Protection);
FlushInstructionCache(GetCurrentProcess(), Hook::Place, sizeof(Hook::Buffer));
Hook::StateMutex.unlock();
return this;
}
void Hook::Quick()
{
if (Hook::Installed)
{
Hook::Installed = false;
}
}
Hook* Hook::Uninstall(bool unprotect)
{
Hook::StateMutex.lock();
if (!Hook::Initialized || !Hook::Installed)
{
Hook::StateMutex.unlock();
return this;
}
Hook::Installed = false;
if(unprotect) VirtualProtect(Hook::Place, sizeof(Hook::Buffer), PAGE_EXECUTE_READWRITE, &this->Protection);
std::memcpy(Hook::Place, Hook::Buffer, sizeof(Hook::Buffer));
if (unprotect) VirtualProtect(Hook::Place, sizeof(Hook::Buffer), Hook::Protection, &this->Protection);
FlushInstructionCache(GetCurrentProcess(), Hook::Place, sizeof(Hook::Buffer));
Hook::StateMutex.unlock();
return this;
}
void* Hook::GetAddress()
{
return Hook::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);
}
}