Garry's Mod Wiki

Revision Difference

Binary_Modules_Detouring_Functions#561096

<cat>Dev</cat>⤶ <cat>Dev.Modules</cat>⤶ <title>Detouring Functions with Binary Modules</title> # Navigation - [Some Information](https://wiki.facepunch.com/gmod/Binary_Modules_Detouring_Functions#someinformation) - [Getting started](https://wiki.facepunch.com/gmod/Binary_Modules_Detouring_Functions#gettingstarted) - [Getting the Signature](https://wiki.facepunch.com/gmod/Binary_Modules_Detouring_Functions#gettingthesignature) - [Linux](https://wiki.facepunch.com/gmod/Binary_Modules_Detouring_Functions#linux) - [HxD](https://wiki.facepunch.com/gmod/Binary_Modules_Detouring_Functions#hxdlinux) - [IDA](https://wiki.facepunch.com/gmod/Binary_Modules_Detouring_Functions#idalinux) - [Windows](https://wiki.facepunch.com/gmod/Binary_Modules_Detouring_Functions#windows) - [Detouring functions](https://wiki.facepunch.com/gmod/Binary_Modules_Detouring_Functions#detouringfunctions) # Some Information This will explain everything for [garrysmod_common](https://github.com/danielga/garrysmod_common). This will also explain how to find the signatures with [HxD](https://mh-nexus.de/de/hxd/) and [IDA](https://hex-rays.com/ida-free/). 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](https://wiki.facepunch.com/gmod/Creating_Binary_Modules:_Premake), or you can use a template like [this one](https://github.com/RaphaelIT7/gmod-common-module-base)   Open your `premake5.lua` file and call these functions after `CreateProject`.   ```lua 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: ```lua 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 <key>Ctrl + O</key> or by going onto File->Open. Now it should look something like this: <upload src="b04e5/8db94f64eefc60e.png" size="201996" name="image.png" /> Now we only need to search for the function we want. Open the search box by pressing <key>Ctrl + F</key> or by going onto Search->Search. Now enter `ShouldHideServer` and search for it. Now, the section containing `ShouldHideServer` is selected. <upload src="b04e5/8db94f8454baac0.png" size="20592" name="image.png" /> Select everything between the last dot and the next dot, and then we got our signature. <upload src="b04e5/8db94f82350bed5.png" size="20534" name="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: <upload src="b04e5/8db94f971ecd9db.png" size="183968" name="image.png" /> Now open the search box by pressing <key>Alt + T</key> or going onto Search->Search. Enter `CServerGameDLL::ShouldHideServer` and search. <upload src="b04e5/8db94fa412a26e7.png" size="5370" name="image.png" /> Now the function should be selected in the left list, and you need to double-click it. <upload src="b04e5/8db94fa64b5834d.png" size="49073" name="image.png" /> Now it should show us the function and the signature like this. <upload src="b04e5/8db94fa77834303.png" size="65429" name="image.png" /> And now we got the signature for `CServerGameDLL::ShouldHideServer`. In this case, it is `_ZN14CServerGameDLL16ShouldHideServerEv` <upload src="b04e5/8db94fa98d2669b.png" size="15979" name="image.png" /> ## Windows ToDo: Learn and Document how to get the signature for windows. # Detouring functions. First, we include everything needed. ```cpp #include <GarrysMod/FactoryLoader.hpp> #include <scanning/symbolfinder.hpp> #include <GarrysMod/Symbol.hpp> #include <detouring/hook.hpp> ``` After that, we declare our `Symbol` like this: ```cpp 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. ```cpp 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. ```cpp 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: ```cpp #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.