Navigation
Some Information
This will explain everything for garrysmod_common.
This will also explain how to find the signatures with HxD and IDA. Feel free to decide which one you want to use.
Getting started
If you don't have already a project, you can create one following this page, or you can use a template like this one
Open your premake5.lua
file and call these functions after CreateProject
.
IncludeHelpersExtended()
IncludeDetouring()
IncludeScanning()
This will add the extended helpers, the detouring and scanning submodule, which we'll need for detouring functions.
Your file should look something like this:
CreateWorkspace({name = "[Your Project]", abi_compatible = false})
CreateProject({serverside = [true or false], manual_files = false})
[Your includes ...]
IncludeHelpersExtended()
IncludeDetouring()
IncludeScanning()
Getting the Signature
This part will explain how to get a signature for the given platform.
Linux
First, open one of the .so files you want to search in.
There may be a _srv.so version of the file you want to search in. If so, use that file.
For this example, we will get the signature for CServerGameDLL::ShouldHideServer
from the garrysmod/bin/server_srv.so
.
HxD (Linux)
First, open the server_srv.so
file.
You can open a file by pressing ctrl + o or by going onto File->Open.
Now it should look something like this:
Now we only need to search for the function we want.
Open the search box by pressing ctrl + f or by going onto Search->Search.
Now enter ShouldHideServer
and search for it.
Now, the section containing ShouldHideServer
is selected.
Select everything between the last dot and the next dot, and then we got our signature.
And now we got the signature for CServerGameDLL::ShouldHideServer
. In this case, it is _ZN14CServerGameDLL16ShouldHideServerEv
IDA (Linux)
First, open the server_srv.so
file.
If it's the first time you opened the file, it can take a while for the entire file to be loaded and analyzed.
After it finished loading, it should look something like this:
Now open the search box by pressing alt + t or going onto Search->Search.
Enter CServerGameDLL::ShouldHideServer
and search.
Now the function should be selected in the left list, and you need to double-click it.
Now it should show us the function and the signature like this.
And now we got the signature for CServerGameDLL::ShouldHideServer
. In this case, it is _ZN14CServerGameDLL16ShouldHideServerEv
Windows
ToDo: Learn and Document how to get the signature for windows.
Detouring functions.
First, we include everything needed.
#include <GarrysMod/FactoryLoader.hpp>
#include <scanning/symbolfinder.hpp>
#include <GarrysMod/Symbol.hpp>
#include <detouring/hook.hpp>
After that, we declare our Symbol
like this:
typedef bool (*ShouldHideServer)();
Detouring::Hook detour_ShouldHideServer;
const std::vector<Symbol> ShouldHideServerSyms = {
Symbol::FromName("_ZN14CServerGameDLL16ShouldHideServerEv"),
};
Now we only need to declare a function that we want to replace it with.
bool hide_server = true;
bool hook_ShouldHideServer()
{
if (hide_server) {
return true;
}
return detour_ShouldHideServer.GetTrampoline<ShouldHideServer>()();
}
We return true to hide the server from the server list.
This is useful if you would want no players to find your server.
The only thing left is to detour the actual function now.
SourceSDK::ModuleLoader server_loader("server_srv");
SymbolFinder symfinder;
void* sv_shserver = nullptr;
for (const auto& sym : ShouldHideServerSyms) {
sv_shserver = symfinder.Resolve(server_loader.GetModule(), sym.name.c_str(), sym.length);
if (sv_shserver)
break;
}
if (sv_shserver == nullptr) {
Msg("Could not locate CServerGameDLL::ShouldHideServer symbol!\n");
} else {
Msg("Located CServerGameDLL::ShouldHideServer\n");
}
detour_ShouldHideServer.Create(reinterpret_cast<void*>(sv_shserver), reinterpret_cast<void*>(&hook_ShouldHideServer));
detour_ShouldHideServer.Enable();
if (detour_ShouldHideServer.IsValid()) {
Msg("Valid detour for CServerGameDLL::ShouldHideServer\n");
} else {
Msg("Invalid detour for CServerGameDLL::ShouldHideServer\n");
}
We could also add a Lua function to hide the Server.
At the end, your file could look something like this:
#include <GarrysMod/FactoryLoader.hpp>
#include <scanning/symbolfinder.hpp>
#include <GarrysMod/Symbol.hpp>
#include <detouring/hook.hpp>
typedef bool (*ShouldHideServer)();
Detouring::Hook detour_ShouldHideServer;
const std::vector<Symbol> ShouldHideServerSyms = {
Symbol::FromName("_ZN14CServerGameDLL16ShouldHideServerEv"),
};
bool hide_server = true;
bool hook_ShouldHideServer()
{
if (hide_server) {
return true;
}
return detour_ShouldHideServer.GetTrampoline<ShouldHideServer>()();
}
LUA_FUNCTION(HideServer)
{
LUA->CheckType(1, Type::Bool);
hide_server = LUA->GetBool(1);
return 0;
}
GMOD_MODULE_OPEN()
{
LUA->PushSpecial(GarrysMod::Lua::SPECIAL_GLOB);
LUA->GetField(-1, "game");
LUA->PushCFunction(HideServer);
LUA->SetField(-2, "HideServer");
LUA->Pop(2);
SourceSDK::ModuleLoader server_loader("server_srv");
SymbolFinder symfinder;
void* sv_shserver = nullptr;
for (const auto& sym : ShouldHideServerSyms) {
sv_shserver = symfinder.Resolve(server_loader.GetModule(), sym.name.c_str(), sym.length);
if (sv_shserver)
break;
}
if (sv_shserver == nullptr) {
Msg("Could not locate CServerGameDLL::ShouldHideServer symbol!\n");
}
else {
Msg("Located CServerGameDLL::ShouldHideServer\n");
}
detour_ShouldHideServer.Create(reinterpret_cast<void*>(sv_shserver), reinterpret_cast<void*>(&hook_ShouldHideServer));
detour_ShouldHideServer.Enable();
if (detour_ShouldHideServer.IsValid()) {
Msg("Valid detour for CServerGameDLL::ShouldHideServer\n");
}
else {
Msg("Invalid detour for CServerGameDLL::ShouldHideServer\n");
}
return 0;
}
GMOD_MODULE_CLOSE()
{
detour_ShouldHideServer.Destroy();
return 0;
}
[...]
Now you can test everything and it should work as expected.