Skip to content

Commit

Permalink
Warn if Metamod is detected. Auto disable it for cstrike. (#508)
Browse files Browse the repository at this point in the history
* Warn if Metamod is detected. Auto disable it for cstrike.

* fix windows build

* actual fix

* stdafx.hpp: included regex library

* LoadThisDll declaration has been fixed, code has been rewritten for more flexibility, helper functions are now declared in a separate file

* LoadThisDll: debug messages for old and new path

* Add library extension at compile time instead of runtime

* Fixed the message about detecting a third-party plugin and removed the message about disabling AmxModX

* swap_lib: return the original path if we did not find the desired folder in the path

* crash_if_failed: use exit(1) instead of clearing pointers to engine interfaces for cause an intentional crash

* com_fixslashes: replaced regex with std::replace

* Throw an error if metamod is detected, but swap_lib returned us the original path in the end

* Catch the case where the previous character from the start is not a slash

* stdafx.hpp: removed regex library

* helper_functions.hpp: moved defines at the top of header

* swap_lib: changed return type from const char* to std::string

* Declare a variable at the beginning to be in scope of original function and .c_str() wouldn't be a dangling pointer at that point

I didn't immediately release that the result was a dangling pointer, the life of which ended at the end of the condition

Of course, since we didn't allocate memory to it, after the original function is called it will still be freed, but it seems that the engine no longer uses this pointer too, and therefore we don't seem to need to store it.... So even if then it will be dangling, then specifically with this function it should not cause some issues after its call

---------

Co-authored-by: SmileyAG <[email protected]>
  • Loading branch information
khanghugo and SmileyAG authored Mar 16, 2024
1 parent 7ad2ec1 commit 76aefb2
Show file tree
Hide file tree
Showing 5 changed files with 137 additions and 14 deletions.
43 changes: 43 additions & 0 deletions BunnymodXT/helper_functions.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
#include "stdafx.hpp"
#include "modules.hpp"
#include "helper_functions.hpp"

namespace helper_functions
{
void com_fixslashes(std::string &str)
{
// https://github.com/ValveSoftware/halflife/blob/c7240b965743a53a29491dd49320c88eecf6257b/game_shared/bot/nav_file.cpp#L680
#ifdef _WIN32
std::replace(str.begin(), str.end(), '/', '\\');
#else
std::replace(str.begin(), str.end(), '\\', '/');
#endif
}

std::string swap_lib(const char* current_lib_path, std::string new_lib_path, const char *start)
{
const std::string filename = current_lib_path;
const auto index = filename.find(start);

if ((index == std::string::npos) || // String not found in current path.
((index > 0) && (filename[index - 1] != PATH_SLASH))) // Previous character from the specified start is not a slash.
return current_lib_path;

com_fixslashes(new_lib_path);

std::string new_path = filename.substr(0, index) + new_lib_path + DLL_EXTENSION;

return new_path;
}

void crash_if_failed(std::string str)
{
EngineWarning("%s", str.c_str());

#ifdef _WIN32
MessageBox(NULL, str.c_str(), "Fatal Error", MB_OK | MB_ICONERROR);
#endif

std::exit(1);
}
};
16 changes: 16 additions & 0 deletions BunnymodXT/helper_functions.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#pragma once

#ifdef _WIN32
#define DLL_EXTENSION ".dll"
#define PATH_SLASH '\\'
#else
#define DLL_EXTENSION ".so"
#define PATH_SLASH '/'
#endif

namespace helper_functions
{
void com_fixslashes(std::string &str);
std::string swap_lib(const char* current_lib_path, std::string new_lib_path, const char *start);
void crash_if_failed(std::string str);
}
89 changes: 75 additions & 14 deletions BunnymodXT/modules/HwDLL.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include "../stdafx.hpp"

#include <boost/algorithm/string/replace.hpp>
#include <boost/algorithm/string/predicate.hpp>
#include <cerrno>
#include <GL/gl.h>
#include "../sptlib-wrapper.hpp"
Expand All @@ -22,6 +23,7 @@
#include "../custom_triggers.hpp"
#include "../simulation_ipc.hpp"
#include "../splits.hpp"
#include "../helper_functions.hpp"

using namespace std::literals;

Expand Down Expand Up @@ -346,6 +348,11 @@ extern "C" qboolean __cdecl CL_ReadDemoMessage_OLD()
{
return HwDLL::HOOKED_CL_ReadDemoMessage_OLD();
}

extern "C" void __cdecl LoadThisDll(const char *szDllFilename)
{
return HwDLL::HOOKED_LoadThisDll(szDllFilename);
}
#endif

void HwDLL::Hook(const std::wstring& moduleName, void* moduleHandle, void* moduleBase, size_t moduleLength, bool needToIntercept)
Expand Down Expand Up @@ -472,6 +479,7 @@ void HwDLL::Hook(const std::wstring& moduleName, void* moduleHandle, void* modul
MemUtils::MarkAsExecutable(ORIG_ValidStuffText);
MemUtils::MarkAsExecutable(ORIG_CL_ReadDemoMessage_OLD);
MemUtils::MarkAsExecutable(ORIG_NLoadBlobFileClient);
MemUtils::MarkAsExecutable(ORIG_LoadThisDll);
}

MemUtils::Intercept(moduleName,
Expand Down Expand Up @@ -536,7 +544,8 @@ void HwDLL::Hook(const std::wstring& moduleName, void* moduleHandle, void* modul
ORIG_ReleaseEntityDlls, HOOKED_ReleaseEntityDlls,
ORIG_ValidStuffText, HOOKED_ValidStuffText,
ORIG_CL_ReadDemoMessage_OLD, HOOKED_CL_ReadDemoMessage_OLD,
ORIG_Host_Shutdown, HOOKED_Host_Shutdown);
ORIG_Host_Shutdown, HOOKED_Host_Shutdown,
ORIG_LoadThisDll, HOOKED_LoadThisDll);
}

#ifdef _WIN32
Expand Down Expand Up @@ -630,7 +639,8 @@ void HwDLL::Unhook()
ORIG_ReleaseEntityDlls,
ORIG_ValidStuffText,
ORIG_CL_ReadDemoMessage_OLD,
ORIG_Host_Shutdown);
ORIG_Host_Shutdown,
ORIG_LoadThisDll);
}

for (auto cvar : CVars::allCVars)
Expand Down Expand Up @@ -733,6 +743,7 @@ void HwDLL::Clear()
ORIG_ReleaseEntityDlls = nullptr;
ORIG_ValidStuffText = nullptr;
ORIG_CL_ReadDemoMessage_OLD = nullptr;
ORIG_LoadThisDll = nullptr;

ClientDLL::GetInstance().pEngfuncs = nullptr;
ServerDLL::GetInstance().pEngfuncs = nullptr;
Expand Down Expand Up @@ -1324,6 +1335,14 @@ void HwDLL::FindStuff()
EngineDevMsg("[hw dll] Found g_sv_delta at %p.\n", g_sv_delta);
else
EngineDevWarning("[hw dll] Could not find g_sv_delta.\n");

ORIG_LoadThisDll = reinterpret_cast<_LoadThisDll>(MemUtils::GetSymbolAddress(m_Handle, "LoadThisDll"));
if (ORIG_LoadThisDll) {
EngineDevMsg("[hw dll] Found LoadThisDll at %p.\n", ORIG_LoadThisDll);
} else {
EngineDevWarning("[hw dll] Could not find LoadThisDll.\n");
EngineWarning("[hw dll] AmxModX might crash with BunnymodXT.\n");
}
}
else
{
Expand Down Expand Up @@ -1471,29 +1490,28 @@ void HwDLL::FindStuff()
}
});

void* LoadThisDll;
auto fLoadThisDll = FindAsync(
LoadThisDll,
ORIG_LoadThisDll,
patterns::engine::LoadThisDll,
[&](auto pattern) {
switch (pattern - patterns::engine::LoadThisDll.cbegin())
{
default:
case 0: // HL-Steampipe
ServerDLL::GetInstance().pEngfuncs = *reinterpret_cast<enginefuncs_t**>(reinterpret_cast<uintptr_t>(LoadThisDll) + 95);
ppGlobals = *reinterpret_cast<globalvars_t**>(reinterpret_cast<uintptr_t>(LoadThisDll) + 90);
ServerDLL::GetInstance().pEngfuncs = *reinterpret_cast<enginefuncs_t**>(reinterpret_cast<uintptr_t>(ORIG_LoadThisDll) + 95);
ppGlobals = *reinterpret_cast<globalvars_t**>(reinterpret_cast<uintptr_t>(ORIG_LoadThisDll) + 90);
break;
case 1: // HL-4554
ServerDLL::GetInstance().pEngfuncs = *reinterpret_cast<enginefuncs_t**>(reinterpret_cast<uintptr_t>(LoadThisDll) + 91);
ppGlobals = *reinterpret_cast<globalvars_t**>(reinterpret_cast<uintptr_t>(LoadThisDll) + 86);
ServerDLL::GetInstance().pEngfuncs = *reinterpret_cast<enginefuncs_t**>(reinterpret_cast<uintptr_t>(ORIG_LoadThisDll) + 91);
ppGlobals = *reinterpret_cast<globalvars_t**>(reinterpret_cast<uintptr_t>(ORIG_LoadThisDll) + 86);
break;
case 2: // HL-WON-1712
ServerDLL::GetInstance().pEngfuncs = *reinterpret_cast<enginefuncs_t**>(reinterpret_cast<uintptr_t>(LoadThisDll) + 89);
ppGlobals = *reinterpret_cast<globalvars_t**>(reinterpret_cast<uintptr_t>(LoadThisDll) + 84);
ServerDLL::GetInstance().pEngfuncs = *reinterpret_cast<enginefuncs_t**>(reinterpret_cast<uintptr_t>(ORIG_LoadThisDll) + 89);
ppGlobals = *reinterpret_cast<globalvars_t**>(reinterpret_cast<uintptr_t>(ORIG_LoadThisDll) + 84);
break;
case 3: // CoF-5936
ServerDLL::GetInstance().pEngfuncs = *reinterpret_cast<enginefuncs_t**>(reinterpret_cast<uintptr_t>(LoadThisDll) + 118);
ppGlobals = *reinterpret_cast<globalvars_t**>(reinterpret_cast<uintptr_t>(LoadThisDll) + 113);
ServerDLL::GetInstance().pEngfuncs = *reinterpret_cast<enginefuncs_t**>(reinterpret_cast<uintptr_t>(ORIG_LoadThisDll) + 118);
ppGlobals = *reinterpret_cast<globalvars_t**>(reinterpret_cast<uintptr_t>(ORIG_LoadThisDll) + 113);
break;
}
});
Expand Down Expand Up @@ -2058,8 +2076,8 @@ void HwDLL::FindStuff()

{
auto pattern = fLoadThisDll.get();
if (LoadThisDll) {
EngineDevMsg("[hw dll] Found LoadThisDll at %p (using the %s pattern).\n", LoadThisDll, pattern->name());
if (ORIG_LoadThisDll) {
EngineDevMsg("[hw dll] Found LoadThisDll at %p (using the %s pattern).\n", ORIG_LoadThisDll, pattern->name());
EngineDevMsg("[hw dll] Found g_engfuncsExportedToDlls at %p.\n", ServerDLL::GetInstance().pEngfuncs);
EngineDevMsg("[hw dll] Found gGlobalVariables at %p.\n", ppGlobals);
}
Expand Down Expand Up @@ -8247,3 +8265,46 @@ HOOK_DEF_0(HwDLL, qboolean, __cdecl, CL_ReadDemoMessage_OLD)

return rv;
}

HOOK_DEF_1(HwDLL, void, __cdecl, LoadThisDll, const char*, szDllFilename)
{
auto oldszDllFilename = szDllFilename;
std::string newszDllFilename;

if (boost::ends_with(szDllFilename, "metamod" DLL_EXTENSION))
{
EngineDevMsg("[hw dll] Metamod detected.\n");

bool is_failed = false;

static bool is_cstrike = ClientDLL::GetInstance().DoesGameDirMatch("cstrike");
if (is_cstrike)
{
#ifdef _WIN32
const std::string cs_lib = "dlls\\mp";
#else
const std::string cs_lib = "dlls/cs";
#endif

EngineDevMsg("[hw dll] Old path to game library: %s\n", szDllFilename);
newszDllFilename = helper_functions::swap_lib(szDllFilename, cs_lib, "addons");
szDllFilename = newszDllFilename.c_str();
EngineDevMsg("[hw dll] New path to game library: %s\n", szDllFilename);

if (!strcmp(szDllFilename, oldszDllFilename))
is_failed = true;
}
else
{
is_failed = true;
}

if (is_failed)
{
const std::string error_msg = "[hw dll] Cannot disable AmxModX for current mod. Edit <mod>/liblist.gam to continue.\n";
helper_functions::crash_if_failed(error_msg);
}
}

ORIG_LoadThisDll(szDllFilename);
}
1 change: 1 addition & 0 deletions BunnymodXT/modules/HwDLL.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ class HwDLL : public IHookableNameFilterOrdered
HOOK_DECL(void, __cdecl, ReleaseEntityDlls)
HOOK_DECL(qboolean, __cdecl, ValidStuffText, char* buf)
HOOK_DECL(qboolean, __cdecl, CL_ReadDemoMessage_OLD)
HOOK_DECL(void, __cdecl, LoadThisDll, const char* szDllFilename)

struct cmdbuf_t
{
Expand Down
2 changes: 2 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,7 @@ set (HEADER_FILES
BunnymodXT/input_editor.hpp
BunnymodXT/simulation_ipc.hpp
BunnymodXT/splits.hpp
BunnymodXT/helper_functions.hpp
BunnymodXT/git_revision.hpp)

set (SOURCE_FILES
Expand All @@ -206,6 +207,7 @@ set (SOURCE_FILES
BunnymodXT/input_editor.cpp
BunnymodXT/simulation_ipc.cpp
BunnymodXT/splits.cpp
BunnymodXT/helper_functions.cpp
${CMAKE_CURRENT_BINARY_DIR}/BunnymodXT/git_revision.cpp)

if (MSVC)
Expand Down

0 comments on commit 76aefb2

Please sign in to comment.