Garry's Mod Wiki

Detouring Functions with Binary Modules

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:

image.png

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.

image.png

Select everything between the last dot and the next dot, and then we got our signature.

image.png

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:

image.png

Now open the search box by pressing alt + t or going onto Search->Search.
Enter CServerGameDLL::ShouldHideServer and search.

image.png

Now the function should be selected in the left list, and you need to double-click it.

image.png

Now it should show us the function and the signature like this.

image.png

And now we got the signature for CServerGameDLL::ShouldHideServer. In this case, it is _ZN14CServerGameDLL16ShouldHideServerEv

image.png

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"), // Our signature for CServerGameDLL::ShouldHideServer };

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; } // If we don't want to force the server hidden, we can fallback to the original function. 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"), // Our signature for CServerGameDLL::ShouldHideServer }; bool hide_server = true; bool hook_ShouldHideServer() { if (hide_server) { return true; } // If we don't want to force the server hidden, we can fallback to the original function. return detour_ShouldHideServer.GetTrampoline<ShouldHideServer>()(); } // A Lua function to hide the server. game.HideServer() 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(); // We remove our detour. return 0; } [...]

Now you can test everything and it should work as expected.