diff --git a/AMBuildScript b/AMBuildScript index 5df6da6..1c63a29 100644 --- a/AMBuildScript +++ b/AMBuildScript @@ -280,7 +280,7 @@ class MMSPluginConfig(object): cxx.cxxincludes += [ os.path.join(context.currentSourcePath), os.path.join(mms_core_path), - os.path.join(mms_core_path, 'sourcehook'), + os.path.join(self.mms_root, 'third_party', 'khook', 'include'), ] defines = [] diff --git a/AMBuilder b/AMBuilder index 0706972..fb54c2a 100644 --- a/AMBuilder +++ b/AMBuilder @@ -28,16 +28,10 @@ for sdk_target in MMSPlugin.sdk_targets: target_folder = 'Debug' if builder.options.debug else 'Release' if binary.compiler.target.platform == 'linux': - binary.compiler.postlink += [ - os.path.join(builder.sourcePath, 'vendor', 'funchook', 'lib', target_folder, 'libfunchook.a'), - os.path.join(builder.sourcePath, 'vendor', 'funchook', 'lib', target_folder, 'libdistorm.a'), - ] binary.sources += ['src/utils/plat_unix.cpp'] elif binary.compiler.target.platform == 'windows': binary.compiler.postlink += [ os.path.join('psapi.lib'), - os.path.join(builder.sourcePath, 'vendor', 'funchook', 'lib', target_folder, 'funchook.lib'), - os.path.join(builder.sourcePath, 'vendor', 'funchook', 'lib', target_folder, 'distorm.lib'), os.path.join(sdk['path'], 'lib', 'public', 'win64', 'steam_api64.lib') ] binary.sources += ['src/utils/plat_win.cpp'] @@ -50,7 +44,6 @@ for sdk_target in MMSPlugin.sdk_targets: os.path.join(builder.sourcePath, 'src', 'cs2_sdk'), os.path.join(builder.sourcePath, 'src', 'utils'), os.path.join(builder.sourcePath, 'public'), - os.path.join(builder.sourcePath, 'vendor', 'funchook', 'include'), ] protoc_builder = builder.tools.Protoc(protoc = sdk_target.protoc, sources = [ diff --git a/hl2sdk-manifests b/hl2sdk-manifests index 20b3a01..25562f7 160000 --- a/hl2sdk-manifests +++ b/hl2sdk-manifests @@ -1 +1 @@ -Subproject commit 20b3a014264b38908c4a5d4eb263ba2c488f3dc1 +Subproject commit 25562f7019dbe9534a61a5e8b1959ea4e36a6e9e diff --git a/src/multiaddonmanager.cpp b/src/multiaddonmanager.cpp index d58d0ee..beaf3f4 100644 --- a/src/multiaddonmanager.cpp +++ b/src/multiaddonmanager.cpp @@ -24,13 +24,11 @@ #include "multiaddonmanager.h" #include "module.h" #include "utils/plat.h" -#include "networksystem/inetworkserializer.h" #include "networksystem/inetworkmessages.h" #include "convar.h" #include "hoststate.h" #include "igameeventsystem.h" #include "serversideclient.h" -#include "funchook.h" #include "filesystem.h" #include "steam/steam_gameserver.h" #include @@ -114,57 +112,26 @@ ISteamUGC *GetSteamUGC() return SteamUGC(); } -typedef bool (FASTCALL *SendNetMessage_t)(CServerSideClientBase *, CNetMessage*, NetChannelBufType_t); +typedef bool (FASTCALL *SendNetMessage_t)(CServerSideClientBase *, const CNetMessage*, NetChannelBufType_t); typedef void (FASTCALL *HostStateRequest_t)(CHostStateMgr*, CHostStateRequest*); typedef void (FASTCALL *ReplyConnection_t)(INetworkGameServer *, CServerSideClient *); typedef uint64 (FASTCALL *ScriptGetAddon_t)(); -bool FASTCALL Hook_SendNetMessage_ServerSideClient(CServerSideClientBase *pClient, CNetMessage *pData, NetChannelBufType_t bufType); -bool FASTCALL Hook_SendNetMessage_HLTVClient(CServerSideClientBase *pClient, CNetMessage *pData, NetChannelBufType_t bufType); -void FASTCALL Hook_SetPendingHostStateRequest(CHostStateMgr*, CHostStateRequest*); -void FASTCALL Hook_ReplyConnection(INetworkGameServer *, CServerSideClient *); -uint64 FASTCALL Hook_ScriptGetAddon(); - -SendNetMessage_t g_pfnSendNetMessage_ServerSideClient = nullptr; -SendNetMessage_t g_pfnSendNetMessage_HLTVClient = nullptr; -HostStateRequest_t g_pfnSetPendingHostStateRequest = nullptr; -ReplyConnection_t g_pfnReplyConnection = nullptr; -ScriptGetAddon_t g_pfnScriptGetAddon = nullptr; - -funchook_t *g_pSendNetMessageHook_ServerSideClient = nullptr; -funchook_t *g_pSendNetMessageHook_HLTVClient = nullptr; -funchook_t *g_pSetPendingHostStateRequest = nullptr; -funchook_t *g_pReplyConnectionHook = nullptr; -funchook_t *g_pScriptGetAddonHook = nullptr; - -int g_iLoadEventsFromFileHookId = -1; - class GameSessionConfiguration_t { }; -SH_DECL_HOOK0_void(IServerGameDLL, GameServerSteamAPIActivated, SH_NOATTRIB, 0); -SH_DECL_HOOK3_void(INetworkServerService, StartupServer, SH_NOATTRIB, 0, const GameSessionConfiguration_t &, ISource2WorldSession *, const char *); -SH_DECL_HOOK6(IServerGameClients, ClientConnect, SH_NOATTRIB, 0, bool, CPlayerSlot, const char*, uint64, const char *, bool, CBufferString *); -SH_DECL_HOOK5_void(IServerGameClients, ClientDisconnect, SH_NOATTRIB, false, CPlayerSlot, ENetworkDisconnectionReason, const char *, uint64, const char *); -SH_DECL_HOOK4_void(IServerGameClients, ClientActive, SH_NOATTRIB, false, CPlayerSlot, bool, const char *, uint64); -SH_DECL_HOOK3_void(IServerGameDLL, GameFrame, SH_NOATTRIB, 0, bool, bool, bool); -SH_DECL_HOOK8_void(IGameEventSystem, PostEventAbstract, SH_NOATTRIB, 0, CSplitScreenSlot, bool, int, const uint64 *, - INetworkMessageInternal *, const CNetMessage *, unsigned long, NetChannelBufType_t); -SH_DECL_HOOK2(IGameEventManager2, LoadEventsFromFile, SH_NOATTRIB, 0, int, const char *, bool); -SH_DECL_HOOK3(IServerGameClients, CanHLTVClientConnect, SH_NOATTRIB, 0, bool, int, const CSteamID &, int *); - // Signatures // "Discarding pending request '%s, %u'\n" // "Sending S2C_CONNECTION to %s [addons:'%s']\n" // First call without args in func with "Saving existing workshop save file from %s\n" #ifdef PLATFORM_WINDOWS -constexpr const byte g_HostStateRequest_Sig[] = "\x48\x89\x74\x24\x2A\x57\x48\x83\xEC\x2A\x33\xF6\x48\x8B\xFA\x48\x39\x35"; -constexpr const byte g_ReplyConnection_Sig[] = "\x48\x8B\xC4\x55\x41\x55\x41\x56"; -constexpr const byte g_ScriptGetAddon_Sig[] = "\x40\x56\x48\x83\xEC\x2A\x48\x8B\x0D\x2A\x2A\x2A\x2A\x48\x8D\x54\x24"; +constexpr const char *g_HostStateRequest_Sig = "48 89 74 24 ? 57 48 83 EC ? 33 F6 48 8B FA 48 39 35"; +constexpr const char *g_ReplyConnection_Sig = "48 8B C4 55 41 55 41 56"; +constexpr const char *g_ScriptGetAddon_Sig = "40 56 48 83 EC ? 48 8B 0D ? ? ? ? 48 8D 54 24"; #else -constexpr const byte g_HostStateRequest_Sig[] = "\x55\x48\x89\xE5\x41\x56\x41\x55\x41\x54\x49\x89\xF4\x53\x48\x83\x7F"; -constexpr const byte g_ReplyConnection_Sig[] = "\x55\xB9\x2A\x2A\x2A\x2A\x41\xB8"; -constexpr const byte g_ScriptGetAddon_Sig[] = "\x55\x48\x89\xE5\x41\x55\x41\x54\x48\x8D\x75\x2A\x53\x48\x83\xEC\x2A\x48\x8D\x05\x2A\x2A\x2A\x2A\x48\xC7\x45\x2A\x2A\x2A\x2A\x2A\x48\xC7\x45\x2A\x2A\x2A\x2A\x2A\x48\x8B\x38\x48\x8B\x07\xFF\x90\x2A\x2A\x2A\x2A\x8B\x55"; +constexpr const char *g_HostStateRequest_Sig = "55 48 89 E5 41 56 41 55 41 54 49 89 F4 53 48 83 7F"; +constexpr const char *g_ReplyConnection_Sig = "55 B9 ? ? ? ? 41 B8"; +constexpr const char *g_ScriptGetAddon_Sig = "55 48 89 E5 41 55 41 54 48 8D 75 ? 53 48 83 EC ? 48 8D 05 ? ? ? ? 48 C7 45 ? ? ? ? ? 48 C7 45 ? ? ? ? ? 48 8B 38 48 8B 07 FF 90 ? ? ? ? 8B 55"; #endif @@ -256,13 +223,35 @@ CConVar mm_client_extra_addons("mm_client_extra_addons", FCVAR_NONE, StringToVector(new_val->Get(), g_MultiAddonManager.m_GlobalClientAddons); }); -MultiAddonManager g_MultiAddonManager; INetworkGameServer *g_pNetworkGameServer = nullptr; CGlobalVars *gpGlobals = nullptr; IGameEventSystem *g_pGameEventSystem = nullptr; IGameEventManager2 *g_pGameEventManager = nullptr; +IGameEventManager2 *g_pGameEventManagerVTable = nullptr; +CServerSideClientBase *g_pServerSideClientVTable = nullptr; +CServerSideClientBase *g_pHLTVClientVTable = nullptr; +MultiAddonManager g_MultiAddonManager; PLUGIN_EXPOSE(MultiAddonManager, g_MultiAddonManager); + +MultiAddonManager::MultiAddonManager() : + m_hookGameFrame(&IServerGameDLL::GameFrame, this, nullptr, &MultiAddonManager::Hook_GameFrame), + m_hookGameServerSteamAPIActivated(&IServerGameDLL::GameServerSteamAPIActivated, this, &MultiAddonManager::Hook_GameServerSteamAPIActivated, nullptr), + m_hookStartupServer(&INetworkServerService::StartupServer, this, nullptr, &MultiAddonManager::Hook_StartupServer), + m_hookClientConnect(&IServerGameClients::ClientConnect, this, &MultiAddonManager::Hook_ClientConnect, nullptr), + m_hookCanHLTVClientConnect(&IServerGameClients::CanHLTVClientConnect, this, &MultiAddonManager::Hook_CanHLTVClientConnect, nullptr), + m_hookClientDisconnect(&IServerGameClients::ClientDisconnect, this, nullptr, &MultiAddonManager::Hook_ClientDisconnect), + m_hookClientActive(&IServerGameClients::ClientActive, this, nullptr, &MultiAddonManager::Hook_ClientActive), + m_hookPostEventAbstract(&IGameEventSystem::PostEventAbstract, this, &MultiAddonManager::Hook_PostEvent, nullptr), + m_hookLoadEventsFromFile(&IGameEventManager2::LoadEventsFromFile, this, &MultiAddonManager::Hook_LoadEventsFromFile, nullptr), + m_hookSendNetMessage_ServerSideClient(&CServerSideClientBase::SendNetMessage, this, &MultiAddonManager::Hook_SendNetMessage_ServerSideClient, nullptr), + m_hookSendNetMessage_HLTVClient(&CServerSideClientBase::SendNetMessage, this, &MultiAddonManager::Hook_SendNetMessage_HLTVClient, nullptr), + m_hookSetPendingHostStateRequest(this, &MultiAddonManager::Hook_SetPendingHostStateRequest, nullptr), + m_hookReplyConnection(this, &MultiAddonManager::Hook_ReplyConnection, nullptr), + m_hookScriptGetAddon(this, &MultiAddonManager::Hook_ScriptGetAddon, nullptr) +{ +} + bool MultiAddonManager::Load(PluginId id, ISmmAPI *ismm, char *error, size_t maxlen, bool late) { PLUGIN_SAVEVARS(); @@ -282,89 +271,73 @@ bool MultiAddonManager::Load(PluginId id, ISmmAPI *ismm, char *error, size_t max CModule engineModule(ROOTBIN, "engine2"); CModule serverModule(GAMEBIN, "server"); - int sig_error; + bool g_bRequiredInitLoaded = true; - g_pfnSetPendingHostStateRequest = (HostStateRequest_t)engineModule.FindSignature(g_HostStateRequest_Sig, sizeof(g_HostStateRequest_Sig) - 1, sig_error); + auto pfnSetPendingHostStateRequest = (HostStateRequest_t)engineModule.LookupSignature(g_HostStateRequest_Sig); - if (!g_pfnSetPendingHostStateRequest) - { - V_snprintf(error, maxlen, "Could not find the signature for HostStateRequest\n"); - Panic("%s", error); - return false; - } - else if (sig_error == SIG_FOUND_MULTIPLE) + if (!pfnSetPendingHostStateRequest) { - Panic("Signature for HostStateRequest occurs multiple times! Using first match but this might end up crashing!\n"); + Panic("Failed to lookup the signature for HostStateRequest\n"); + g_bRequiredInitLoaded = false; } - g_pSetPendingHostStateRequest = funchook_create(); - funchook_prepare(g_pSetPendingHostStateRequest, (void**)&g_pfnSetPendingHostStateRequest, (void*)Hook_SetPendingHostStateRequest); - funchook_install(g_pSetPendingHostStateRequest, 0); + m_hookSetPendingHostStateRequest.Configure(pfnSetPendingHostStateRequest); - // We're using funchook even though it's a virtual function because it can be called on a different thread and SourceHook isn't thread-safe - void **pServerSideClientVTable = (void **)engineModule.FindVirtualTable("CServerSideClient"); - g_pfnSendNetMessage_ServerSideClient = (SendNetMessage_t)pServerSideClientVTable[g_iSendNetMessageOffset]; + auto pfnReplyConnection = (ReplyConnection_t)engineModule.LookupSignature(g_ReplyConnection_Sig); - g_pSendNetMessageHook_ServerSideClient = funchook_create(); - funchook_prepare(g_pSendNetMessageHook_ServerSideClient, (void**)&g_pfnSendNetMessage_ServerSideClient, (void*)Hook_SendNetMessage_ServerSideClient); - funchook_install(g_pSendNetMessageHook_ServerSideClient, 0); - - void **pHLTVClientVTable = (void **)engineModule.FindVirtualTable("CHLTVClient"); - g_pfnSendNetMessage_HLTVClient = (SendNetMessage_t)pHLTVClientVTable[g_iSendNetMessageOffset]; - - g_pSendNetMessageHook_HLTVClient = funchook_create(); - funchook_prepare(g_pSendNetMessageHook_HLTVClient, (void **)&g_pfnSendNetMessage_HLTVClient, (void *)Hook_SendNetMessage_HLTVClient); - funchook_install(g_pSendNetMessageHook_HLTVClient, 0); + if (!pfnReplyConnection) + { + Panic("Failed to lookup the signature for ReplyConnection\n"); + g_bRequiredInitLoaded = false; + } - g_pfnReplyConnection = (ReplyConnection_t)engineModule.FindSignature(g_ReplyConnection_Sig, sizeof(g_ReplyConnection_Sig) - 1, sig_error); + m_hookReplyConnection.Configure(pfnReplyConnection); + + auto pfnScriptGetAddon = (ScriptGetAddon_t)serverModule.LookupSignature(g_ScriptGetAddon_Sig); - if (!g_pfnReplyConnection) + if (!pfnScriptGetAddon) { - V_snprintf(error, maxlen, "Could not find the signature for ReplyConnection\n"); - Panic("%s", error); - return false; + Panic("Failed to lookup the signature for ScriptGetAddon\n"); + g_bRequiredInitLoaded = false; } - else if (sig_error == SIG_FOUND_MULTIPLE) + + m_hookScriptGetAddon.Configure(pfnScriptGetAddon); + + if (!(g_pGameEventManagerVTable = (IGameEventManager2 *)serverModule.FindVirtualTable("CGameEventManager"))) { - Panic("Signature for ReplyConnection occurs multiple times! Using first match but this might end up crashing!\n"); + Panic("Failed to lookup the vtable for CGameEventManager\n"); + g_bRequiredInitLoaded = false; } - g_pReplyConnectionHook = funchook_create(); - funchook_prepare(g_pReplyConnectionHook, (void**)&g_pfnReplyConnection, (void*)Hook_ReplyConnection); - funchook_install(g_pReplyConnectionHook, 0); - - g_pfnScriptGetAddon = (ScriptGetAddon_t)serverModule.FindSignature(g_ScriptGetAddon_Sig, sizeof(g_ScriptGetAddon_Sig) - 1, sig_error); - - if (!g_pfnScriptGetAddon) + if (!(g_pServerSideClientVTable = (CServerSideClientBase *)engineModule.FindVirtualTable("CServerSideClient"))) { - V_snprintf(error, maxlen, "Could not find the signature for ScriptGetAddon\n"); - Panic("%s", error); - return false; + Panic("Failed to lookup the vtable for CServerSideClient\n"); + g_bRequiredInitLoaded = false; } - else if (sig_error == SIG_FOUND_MULTIPLE) + + if (!(g_pHLTVClientVTable = (CServerSideClientBase *)engineModule.FindVirtualTable("CHLTVClient"))) { - Panic("Signature for ScriptGetAddon occurs multiple times! Using first match but this might end up crashing!\n"); + Panic("Failed to lookup the vtable for CHLTVClient\n"); + g_bRequiredInitLoaded = false; } - g_pScriptGetAddonHook = funchook_create(); - funchook_prepare(g_pScriptGetAddonHook, (void**)&g_pfnScriptGetAddon, (void*)Hook_ScriptGetAddon); - funchook_install(g_pScriptGetAddonHook, 0); - - SH_ADD_HOOK(IServerGameDLL, GameServerSteamAPIActivated, g_pSource2Server, SH_MEMBER(this, &MultiAddonManager::Hook_GameServerSteamAPIActivated), false); - SH_ADD_HOOK(INetworkServerService, StartupServer, g_pNetworkServerService, SH_MEMBER(this, &MultiAddonManager::Hook_StartupServer), true); - SH_ADD_HOOK(IServerGameClients, ClientConnect, g_pSource2GameClients, SH_MEMBER(this, &MultiAddonManager::Hook_ClientConnect), false); - SH_ADD_HOOK(IServerGameClients, ClientDisconnect, g_pSource2GameClients, SH_MEMBER(this, &MultiAddonManager::Hook_ClientDisconnect), true); - SH_ADD_HOOK(IServerGameClients, ClientActive, g_pSource2GameClients, SH_MEMBER(this, &MultiAddonManager::Hook_ClientActive), true); - SH_ADD_HOOK(IServerGameClients, CanHLTVClientConnect, g_pSource2GameClients, SH_MEMBER(this, &MultiAddonManager::Hook_CanHLTVClientConnect), false); - SH_ADD_HOOK(IServerGameDLL, GameFrame, g_pSource2Server, SH_MEMBER(this, &MultiAddonManager::Hook_GameFrame), true); - SH_ADD_HOOK(IGameEventSystem, PostEventAbstract, g_pGameEventSystem, SH_MEMBER(this, &MultiAddonManager::Hook_PostEvent), false); - - auto pCGameEventManagerVTable = (IGameEventManager2*)serverModule.FindVirtualTable("CGameEventManager"); - - if (!pCGameEventManagerVTable) + if (!g_bRequiredInitLoaded) + { + V_snprintf(error, maxlen, "One or more address lookups failed, please refer to startup logs for more information"); return false; + } - g_iLoadEventsFromFileHookId = SH_ADD_DVPHOOK(IGameEventManager2, LoadEventsFromFile, pCGameEventManagerVTable, SH_MEMBER(this, &MultiAddonManager::Hook_LoadEventsFromFile), false); + m_hookClientConnect.Add(g_pSource2GameClients); + m_hookCanHLTVClientConnect.Add(g_pSource2GameClients); + m_hookClientDisconnect.Add(g_pSource2GameClients); + m_hookClientActive.Add(g_pSource2GameClients); + m_hookGameServerSteamAPIActivated.Add(g_pSource2Server); + m_hookGameFrame.Add(g_pSource2Server); + m_hookStartupServer.Add(g_pNetworkServerService); + m_hookPostEventAbstract.Add(g_pGameEventSystem); + m_hookLoadEventsFromFile.AddGlobal((IGameEventManager2*)&g_pGameEventManagerVTable); + m_hookSendNetMessage_ServerSideClient.AddGlobal((CServerSideClientBase*)&g_pServerSideClientVTable); + m_hookSendNetMessage_HLTVClient.AddGlobal((CServerSideClientBase*)&g_pHLTVClientVTable); if (late) { @@ -389,45 +362,17 @@ bool MultiAddonManager::Unload(char *error, size_t maxlen) { ClearAddons(); - SH_REMOVE_HOOK(IServerGameDLL, GameServerSteamAPIActivated, g_pSource2Server, SH_MEMBER(this, &MultiAddonManager::Hook_GameServerSteamAPIActivated), false); - SH_REMOVE_HOOK(INetworkServerService, StartupServer, g_pNetworkServerService, SH_MEMBER(this, &MultiAddonManager::Hook_StartupServer), true); - SH_REMOVE_HOOK(IServerGameClients, ClientConnect, g_pSource2GameClients, SH_MEMBER(this, &MultiAddonManager::Hook_ClientConnect), false); - SH_REMOVE_HOOK(IServerGameClients, ClientDisconnect, g_pSource2GameClients, SH_MEMBER(this, &MultiAddonManager::Hook_ClientDisconnect), true); - SH_REMOVE_HOOK(IServerGameClients, ClientActive, g_pSource2GameClients, SH_MEMBER(this, &MultiAddonManager::Hook_ClientActive), true); - SH_REMOVE_HOOK(IServerGameClients, CanHLTVClientConnect, g_pSource2GameClients, SH_MEMBER(this, &MultiAddonManager::Hook_CanHLTVClientConnect), false); - SH_REMOVE_HOOK(IServerGameDLL, GameFrame, g_pSource2Server, SH_MEMBER(this, &MultiAddonManager::Hook_GameFrame), true); - SH_REMOVE_HOOK(IGameEventSystem, PostEventAbstract, g_pGameEventSystem, SH_MEMBER(this, &MultiAddonManager::Hook_PostEvent), false); - SH_REMOVE_HOOK_ID(g_iLoadEventsFromFileHookId); - - if (g_pSetPendingHostStateRequest) - { - funchook_uninstall(g_pSetPendingHostStateRequest, 0); - funchook_destroy(g_pSetPendingHostStateRequest); - } - - if (g_pSendNetMessageHook_ServerSideClient) - { - funchook_uninstall(g_pSendNetMessageHook_ServerSideClient, 0); - funchook_destroy(g_pSendNetMessageHook_ServerSideClient); - } - - if (g_pSendNetMessageHook_HLTVClient) - { - funchook_uninstall(g_pSendNetMessageHook_HLTVClient, 0); - funchook_destroy(g_pSendNetMessageHook_HLTVClient); - } - - if (g_pReplyConnectionHook) - { - funchook_uninstall(g_pReplyConnectionHook, 0); - funchook_destroy(g_pReplyConnectionHook); - } - - if (g_pScriptGetAddonHook) - { - funchook_uninstall(g_pScriptGetAddonHook, 0); - funchook_destroy(g_pScriptGetAddonHook); - } + m_hookClientConnect.Remove(g_pSource2GameClients); + m_hookCanHLTVClientConnect.Remove(g_pSource2GameClients); + m_hookClientDisconnect.Remove(g_pSource2GameClients); + m_hookClientActive.Remove(g_pSource2GameClients); + m_hookGameServerSteamAPIActivated.Remove(g_pSource2Server); + m_hookGameFrame.Remove(g_pSource2Server); + m_hookStartupServer.Remove(g_pNetworkServerService); + m_hookPostEventAbstract.Remove(g_pGameEventSystem); + m_hookLoadEventsFromFile.RemoveGlobal((IGameEventManager2*)&g_pGameEventManagerVTable); + m_hookSendNetMessage_ServerSideClient.RemoveGlobal((CServerSideClientBase *)&g_pServerSideClientVTable); + m_hookSendNetMessage_HLTVClient.RemoveGlobal((CServerSideClientBase *)&g_pHLTVClientVTable); return true; } @@ -672,11 +617,11 @@ void MultiAddonManager::ClearAddons() UnmountAddon(m_MountedAddons[i].c_str()); } -void MultiAddonManager::Hook_GameServerSteamAPIActivated() +KHook::Return MultiAddonManager::Hook_GameServerSteamAPIActivated(IServerGameDLL *pThis) { // This is only intended for dedicated servers if (!g_pEngineServer->IsDedicatedServer()) - RETURN_META(MRES_IGNORED); + return {KHook::Action::Ignore}; Message("Steam API Activated\n"); @@ -684,7 +629,7 @@ void MultiAddonManager::Hook_GameServerSteamAPIActivated() RefreshAddons(true); - RETURN_META(MRES_IGNORED); + return {KHook::Action::Ignore}; } void MultiAddonManager::ReloadMap() @@ -847,7 +792,7 @@ void MultiAddonManager::AddClientAddon(const char *pszAddon, uint64 steamID64, b ClientAddonInfo_t &clientInfo = g_ClientAddons[steamID64]; CUtlVector addons; - g_MultiAddonManager.GetClientAddons(addons, steamID64); + GetClientAddons(addons, steamID64); FOR_EACH_VEC(clientInfo.downloadedAddons, j) { @@ -988,7 +933,7 @@ CON_COMMAND_F(mm_print_searchpaths_client, "Print search paths client-side, only g_pFullFileSystem->PrintSearchPaths(); } -void MultiAddonManager::Hook_StartupServer(const GameSessionConfiguration_t &config, ISource2WorldSession *session, const char *mapname) +KHook::Return MultiAddonManager::Hook_StartupServer(INetworkServerService *pThis, const GameSessionConfiguration_t &config, ISource2WorldSession *session, const char *mapname) { gpGlobals = g_pEngineServer->GetServerGlobals(); g_pNetworkGameServer = g_pNetworkServerService->GetIGameServer(); @@ -1003,9 +948,11 @@ void MultiAddonManager::Hook_StartupServer(const GameSessionConfiguration_t &con // So if the current map is ID 1 and extra addons are IDs 2 and 3, they would be mounted in that order with ID 3 at the top // Note that the actual map VPK(s) and any sub-maps like team_select will be even higher, but those usually don't contain any assets that concern us RefreshAddons(); + + return {KHook::Action::Ignore}; } -bool FASTCALL Hook_SendNetMessage(CServerSideClientBase *pClient, CNetMessage *pData, NetChannelBufType_t bufType, SendNetMessage_t pOriginalFunc) +bool Hook_SendNetMessage(CServerSideClientBase *pClient, const CNetMessage *pData, NetChannelBufType_t bufType, SendNetMessage_t pOriginalFunc) { NetMessageInfo_t *info = pData->GetNetMessage()->GetNetMessageInfo(); @@ -1018,12 +965,11 @@ bool FASTCALL Hook_SendNetMessage(CServerSideClientBase *pClient, CNetMessage *p if (info->m_MessageId != net_SignonState || !g_pEngineServer->IsDedicatedServer()) return pOriginalFunc(pClient, pData, bufType); - auto pMsg = pData->ToPB(); + auto pMsg = const_cast(pData)->ToPB(); CUtlVector addons; g_MultiAddonManager.GetClientAddons(addons, steamID64); - if (pMsg->signon_state() == SIGNONSTATE_CHANGELEVEL) { // When switching to another map, the signon message might contain more than 1 addon. @@ -1067,19 +1013,19 @@ bool FASTCALL Hook_SendNetMessage(CServerSideClientBase *pClient, CNetMessage *p return pOriginalFunc(pClient, pData, bufType); } -bool FASTCALL Hook_SendNetMessage_ServerSideClient(CServerSideClientBase *pClient, CNetMessage *pData, NetChannelBufType_t bufType) +KHook::Return MultiAddonManager::Hook_SendNetMessage_ServerSideClient(CServerSideClientBase *pClient, const CNetMessage *pData, NetChannelBufType_t bufType) { - return Hook_SendNetMessage(pClient, pData, bufType, g_pfnSendNetMessage_ServerSideClient); + return {KHook::Action::Supersede, Hook_SendNetMessage(pClient, pData, bufType, (SendNetMessage_t)KHook::GetOriginalFunction())}; } -bool FASTCALL Hook_SendNetMessage_HLTVClient(CServerSideClientBase *pClient, CNetMessage *pData, NetChannelBufType_t bufType) +KHook::Return MultiAddonManager::Hook_SendNetMessage_HLTVClient(CServerSideClientBase *pClient, const CNetMessage *pData, NetChannelBufType_t bufType) { - return Hook_SendNetMessage(pClient, pData, bufType, g_pfnSendNetMessage_HLTVClient); + return {KHook::Action::Supersede, Hook_SendNetMessage(pClient, pData, bufType, (SendNetMessage_t)KHook::GetOriginalFunction())}; } // pMgrDoNotUse is named as such because the variable is optimized out in Windows builds and will not be passed to the function. // The original Windows function just uses the global singleton instead. -void FASTCALL Hook_SetPendingHostStateRequest(CHostStateMgr* pMgrDoNotUse, CHostStateRequest *pRequest) +KHook::Return MultiAddonManager::Hook_SetPendingHostStateRequest(CHostStateMgr* pMgrDoNotUse, CHostStateRequest *pRequest) { // When IVEngineServer::ChangeLevel is called by the plugin or the server code, // (which happens at the end of a map), the server-defined addon does not change. @@ -1096,16 +1042,16 @@ void FASTCALL Hook_SetPendingHostStateRequest(CHostStateMgr* pMgrDoNotUse, CHost // Workshop map changes from end of match votes have null keyvalues // ...and when such votes lead to reloading the CURRENT map, m_Addons will also be null, in which case we want to keep the workshop map unchanged if (!pRequest->m_Addons.IsEmpty()) - g_MultiAddonManager.SetCurrentWorkshopMap(pRequest->m_Addons); + SetCurrentWorkshopMap(pRequest->m_Addons); else if (bValveMap) // Sadly this will include any workshop maps that share names with shipped Valve maps, but at this point there's no way to tell - g_MultiAddonManager.ClearCurrentWorkshopMap(); + ClearCurrentWorkshopMap(); } else if (V_stricmp(pRequest->m_pKV->GetName(), "ChangeLevel")) { if (!V_stricmp(pRequest->m_pKV->GetName(), "map_workshop")) - g_MultiAddonManager.SetCurrentWorkshopMap(pRequest->m_pKV->GetString("customgamemode", "")); + SetCurrentWorkshopMap(pRequest->m_pKV->GetString("customgamemode", "")); else - g_MultiAddonManager.ClearCurrentWorkshopMap(); + ClearCurrentWorkshopMap(); } // Valve changed the way community maps (like de_dogtown) are loaded @@ -1113,27 +1059,27 @@ void FASTCALL Hook_SetPendingHostStateRequest(CHostStateMgr* pMgrDoNotUse, CHost // So check if the addon is indeed one of the community maps and keep it, otherwise clients would error out due to missing assets // Each map has its own folder under game/csgo_community_addons which is mounted as "OFFICIAL_ADDONS" if (!pRequest->m_Addons.IsEmpty() && g_pFullFileSystem->IsDirectory(pRequest->m_Addons.String(), "OFFICIAL_ADDONS")) - g_MultiAddonManager.SetCurrentWorkshopMap(pRequest->m_Addons); + SetCurrentWorkshopMap(pRequest->m_Addons); - if (g_MultiAddonManager.m_ExtraAddons.Count() == 0) - return g_pfnSetPendingHostStateRequest(pMgrDoNotUse, pRequest); + if (m_ExtraAddons.Count() == 0) + return {KHook::Action::Ignore}; // Rebuild the addon list. We always start with the original addon. - if (g_MultiAddonManager.GetCurrentWorkshopMap().empty()) + if (GetCurrentWorkshopMap().empty()) { - pRequest->m_Addons = VectorToString(g_MultiAddonManager.m_ExtraAddons).c_str(); + pRequest->m_Addons = VectorToString(m_ExtraAddons).c_str(); } else { // Don't add the same addon twice. Hopefully no server owner is diabolical enough to do things like `map de_dust2 customgamemode=1234,5678`. CUtlVector newAddons; - newAddons.CopyArray(g_MultiAddonManager.m_ExtraAddons.Base(), g_MultiAddonManager.m_ExtraAddons.Count()); - newAddons.FindAndRemove(g_MultiAddonManager.GetCurrentWorkshopMap().c_str()); - newAddons.AddToHead(g_MultiAddonManager.GetCurrentWorkshopMap().c_str()); + newAddons.CopyArray(m_ExtraAddons.Base(), m_ExtraAddons.Count()); + newAddons.FindAndRemove(GetCurrentWorkshopMap().c_str()); + newAddons.AddToHead(GetCurrentWorkshopMap().c_str()); pRequest->m_Addons = VectorToString(newAddons).c_str(); } - g_pfnSetPendingHostStateRequest(pMgrDoNotUse, pRequest); + return {KHook::Action::Ignore}; } void MultiAddonManager::CheckClientAddons(uint64 steamID64) @@ -1170,33 +1116,37 @@ void MultiAddonManager::CheckClientAddons(uint64 steamID64) return; } -bool MultiAddonManager::Hook_ClientConnect( CPlayerSlot slot, const char *pszName, uint64 steamID64, const char *pszNetworkID, bool unk1, CBufferString *pRejectReason ) +KHook::Return MultiAddonManager::Hook_ClientConnect(IServerGameClients *pThis, CPlayerSlot slot, const char *pszName, uint64 steamID64, const char *pszNetworkID, bool unk1, CBufferString *pRejectReason ) { CheckClientAddons(steamID64); - RETURN_META_VALUE(MRES_IGNORED, true); + return {KHook::Action::Ignore}; } -bool MultiAddonManager::Hook_CanHLTVClientConnect(int index, const CSteamID &steamID, int *pRejectReason) +KHook::Return MultiAddonManager::Hook_CanHLTVClientConnect(IServerGameClients *pThis, int index, const CSteamID &steamID, int *pRejectReason) { CheckClientAddons(steamID.ConvertToUint64()); - RETURN_META_VALUE(MRES_IGNORED, true); + return {KHook::Action::Ignore}; } -void MultiAddonManager::Hook_ClientDisconnect( CPlayerSlot slot, ENetworkDisconnectionReason reason, const char *pszName, uint64 steamID64, const char *pszNetworkID ) +KHook::Return MultiAddonManager::Hook_ClientDisconnect(IServerGameClients *pThis, CPlayerSlot slot, ENetworkDisconnectionReason reason, const char *pszName, uint64 steamID64, const char *pszNetworkID ) { // Mark the disconnection time for caching purposes. g_ClientAddons[steamID64].lastActiveTime = Plat_FloatTime(); g_ClientAddons[steamID64].connectedState = CLIENTCONN_NONE; + + return {KHook::Action::Ignore}; } -void MultiAddonManager::Hook_ClientActive(CPlayerSlot slot, bool bLoadGame, const char * pszName, uint64 steamID64) +KHook::Return MultiAddonManager::Hook_ClientActive(IServerGameClients *pThis, CPlayerSlot slot, bool bLoadGame, const char * pszName, uint64 steamID64) { // When the client reaches this stage, they should already have all the necessary addons downloaded, so we can safely remove the downloaded addons list here. if (!mm_cache_clients_with_addons.Get()) g_ClientAddons[steamID64].downloadedAddons.RemoveAll(); + + return {KHook::Action::Ignore}; } -void MultiAddonManager::Hook_GameFrame(bool simulating, bool bFirstTick, bool bLastTick) +KHook::Return MultiAddonManager::Hook_GameFrame(IServerGameDLL *pThis, bool simulating, bool bFirstTick, bool bLastTick) { static double s_flTime = 0.0f; @@ -1208,7 +1158,7 @@ void MultiAddonManager::Hook_GameFrame(bool simulating, bool bFirstTick, bool bL } if (!m_TimedOutClients.size()) - return; + return {KHook::Action::Ignore}; auto pClients = GetClientList(); @@ -1224,9 +1174,11 @@ void MultiAddonManager::Hook_GameFrame(bool simulating, bool bFirstTick, bool bL g_ClientAddons[steamID64].connectedState = CLIENTCONN_NONE; } } + + return {KHook::Action::Ignore}; } -void MultiAddonManager::Hook_PostEvent(CSplitScreenSlot nSlot, bool bLocalOnly, int nClientCount, const uint64 *clients, +KHook::Return MultiAddonManager::Hook_PostEvent(IGameEventSystem *pThis, CSplitScreenSlot nSlot, bool bLocalOnly, int nClientCount, const uint64 *clients, INetworkMessageInternal *pEvent, const CNetMessage *pData, unsigned long nSize, NetChannelBufType_t bufType) { NetMessageInfo_t *info = pEvent->GetNetMessageInfo(); @@ -1248,20 +1200,20 @@ void MultiAddonManager::Hook_PostEvent(CSplitScreenSlot nSlot, bool bLocalOnly, } } - RETURN_META(MRES_IGNORED); + return {KHook::Action::Ignore}; } -int MultiAddonManager::Hook_LoadEventsFromFile(const char *filename, bool bSearchAll) +KHook::Return MultiAddonManager::Hook_LoadEventsFromFile(IGameEventManager2 *pThis, const char *filename, bool bSearchAll) { if (!g_pGameEventManager) - g_pGameEventManager = META_IFACEPTR(IGameEventManager2); + g_pGameEventManager = pThis; - RETURN_META_VALUE(MRES_IGNORED, 0); + return {KHook::Action::Ignore}; } -void FASTCALL Hook_ReplyConnection(INetworkGameServer *server, CServerSideClient *client) +KHook::Return MultiAddonManager::Hook_ReplyConnection(INetworkGameServer *pThis, CServerSideClient *pClient) { - uint64 steamID64 = client->GetClientSteamID().ConvertToUint64(); + uint64 steamID64 = pClient->GetClientSteamID().ConvertToUint64(); // Clear cache if necessary. ClientAddonInfo_t &clientInfo = g_ClientAddons[steamID64]; if (mm_cache_clients_with_addons.Get() && mm_cache_clients_duration.Get() != 0 && Plat_FloatTime() - clientInfo.lastActiveTime > mm_cache_clients_duration.Get()) @@ -1275,19 +1227,18 @@ void FASTCALL Hook_ReplyConnection(INetworkGameServer *server, CServerSideClient clientInfo.lastActiveTime = Plat_FloatTime(); // Server copies the CUtlString from CNetworkGameServer to this client. - CUtlString *addons = (CUtlString *)((uintptr_t)server + g_iServerAddonsOffset); + CUtlString *addons = (CUtlString *)((uintptr_t)pThis + g_iServerAddonsOffset); CUtlString originalAddons = *addons; // Figure out which addons the client should be loading. CUtlVector clientAddons; - g_MultiAddonManager.GetClientAddons(clientAddons, steamID64); + GetClientAddons(clientAddons, steamID64); if (clientAddons.Count() == 0) { // No addons to send. This means the list of original addons is empty as well. assert(originalAddons.IsEmpty()); clientInfo.currentPendingAddon.clear(); - g_pfnReplyConnection(server, client); - return; + return {KHook::Action::Ignore}; } if (clientInfo.connectedState != CLIENTCONN_CONNECTING) @@ -1300,8 +1251,8 @@ void FASTCALL Hook_ReplyConnection(INetworkGameServer *server, CServerSideClient Plat_FloatTime() - clientInfo.connectionStartTime > mm_addon_connection_timeout.Get()) { // Can't kick right now as this will crash on windows, so defer to the next frame - g_MultiAddonManager.AddTimedOutClient(steamID64); - return; + AddTimedOutClient(steamID64); + return {KHook::Action::Supersede}; } // Handle the first addon here. The rest should be handled in the SendNetMessage hook. @@ -1323,20 +1274,22 @@ void FASTCALL Hook_ReplyConnection(INetworkGameServer *server, CServerSideClient if (mm_addon_debug.Get()) Message("%s: Sending addons %s to steamID64 %lli\n", __func__, addons->Get(), steamID64); - g_pfnReplyConnection(server, client); + m_hookReplyConnection.CallOriginal(pThis, pClient); *addons = originalAddons; + + return {KHook::Action::Supersede}; } -uint64 FASTCALL Hook_ScriptGetAddon() +KHook::Return MultiAddonManager::Hook_ScriptGetAddon() { - if (!g_MultiAddonManager.m_ExtraAddons.Count()) - return g_pfnScriptGetAddon(); + if (!m_ExtraAddons.Count()) + return {KHook::Action::Ignore}; - uint64 iAddon = V_StringToUint64(g_MultiAddonManager.GetCurrentWorkshopMap().c_str(), 0); + uint64 iAddon = V_StringToUint64(GetCurrentWorkshopMap().c_str(), 0); if (!iAddon) - return g_pfnScriptGetAddon(); + return {KHook::Action::Ignore}; - return iAddon; + return {KHook::Action::Supersede, iAddon}; } diff --git a/src/multiaddonmanager.h b/src/multiaddonmanager.h index cfcab9d..0f63402 100644 --- a/src/multiaddonmanager.h +++ b/src/multiaddonmanager.h @@ -21,7 +21,7 @@ #include #include -#include +#include "khook.hpp" #include "utlqueue.h" #include "utlvector.h" #include "networksystem/inetworkserializer.h" @@ -37,23 +37,38 @@ #define GAMEBIN "/csgo/bin/linuxsteamrt64/" #endif +class IGameEventSystem; +class INetworkGameServer; +class CNetMessage; +class CHostStateMgr; +class CServerSideClientBase; +class CServerSideClient; +struct CHostStateRequest; + class MultiAddonManager : public ISmmPlugin, public IMetamodListener, public IMultiAddonManager { public: + MultiAddonManager(); + bool Load(PluginId id, ISmmAPI *ismm, char *error, size_t maxlen, bool late); bool Unload(char *error, size_t maxlen); void *OnMetamodQuery(const char *iface, int *ret); public: //hooks - void Hook_GameServerSteamAPIActivated(); - void Hook_StartupServer(const GameSessionConfiguration_t &config, ISource2WorldSession *, const char *); - bool Hook_ClientConnect(CPlayerSlot slot, const char *pszName, uint64 steamID64, const char *pszNetworkID, bool unk1, CBufferString *pRejectReason); - void Hook_ClientDisconnect(CPlayerSlot slot, ENetworkDisconnectionReason reason, const char *pszName, uint64 steamID64, const char *pszNetworkID); - void Hook_ClientActive(CPlayerSlot slot, bool bLoadGame, const char *pszName, uint64 steamID64); - void Hook_GameFrame(bool simulating, bool bFirstTick, bool bLastTick); - void Hook_PostEvent(CSplitScreenSlot nSlot, bool bLocalOnly, int nClientCount, const uint64 *clients, + KHook::Return Hook_GameServerSteamAPIActivated(IServerGameDLL *pThis); + KHook::Return Hook_StartupServer(INetworkServerService *pThis, const GameSessionConfiguration_t &config, ISource2WorldSession *, const char *); + KHook::Return Hook_ClientConnect(IServerGameClients *pThis, CPlayerSlot slot, const char *pszName, uint64 steamID64, const char *pszNetworkID, bool unk1, CBufferString *pRejectReason); + KHook::Return Hook_ClientDisconnect(IServerGameClients *pThis, CPlayerSlot slot, ENetworkDisconnectionReason reason, const char *pszName, uint64 steamID64, const char *pszNetworkID); + KHook::Return Hook_ClientActive(IServerGameClients *pThis, CPlayerSlot slot, bool bLoadGame, const char *pszName, uint64 steamID64); + KHook::Return Hook_GameFrame(IServerGameDLL *pThis, bool simulating, bool bFirstTick, bool bLastTick); + KHook::Return Hook_PostEvent(IGameEventSystem *pThis, CSplitScreenSlot nSlot, bool bLocalOnly, int nClientCount, const uint64 *clients, INetworkMessageInternal *pEvent, const CNetMessage *pData, unsigned long nSize, NetChannelBufType_t bufType); - int Hook_LoadEventsFromFile(const char *filename, bool bSearchAll); - bool Hook_CanHLTVClientConnect(int index, const CSteamID &steamID, int *pRejectReason); + KHook::Return Hook_LoadEventsFromFile(IGameEventManager2 *pThis, const char *filename, bool bSearchAll); + KHook::Return Hook_CanHLTVClientConnect(IServerGameClients *pThis, int index, const CSteamID &steamID, int *pRejectReason); + KHook::Return Hook_SendNetMessage_ServerSideClient(CServerSideClientBase *pClient, const CNetMessage *pData, NetChannelBufType_t bufType); + KHook::Return Hook_SendNetMessage_HLTVClient(CServerSideClientBase *pClient, const CNetMessage *pData, NetChannelBufType_t bufType); + KHook::Return Hook_SetPendingHostStateRequest(CHostStateMgr *pMgrDoNotUse, CHostStateRequest *pRequest); + KHook::Return Hook_ReplyConnection(INetworkGameServer *pThis, CServerSideClient *pClient); + KHook::Return Hook_ScriptGetAddon(); void ParseCfg(); void BuildAddonPath(const char *pszAddon, char *buf, size_t len, bool bLegacy); @@ -98,6 +113,21 @@ class MultiAddonManager : public ISmmPlugin, public IMetamodListener, public IMu CUtlVector m_GlobalClientAddons; private: + KHook::Virtual m_hookGameFrame; + KHook::Virtual m_hookGameServerSteamAPIActivated; + KHook::Virtual m_hookStartupServer; + KHook::Virtual m_hookClientConnect; + KHook::Virtual m_hookCanHLTVClientConnect; + KHook::Virtual m_hookClientDisconnect; + KHook::Virtual m_hookClientActive; + KHook::Virtual m_hookPostEventAbstract; + KHook::Virtual m_hookLoadEventsFromFile; + KHook::Virtual m_hookSendNetMessage_ServerSideClient; + KHook::Virtual m_hookSendNetMessage_HLTVClient; + KHook::Function m_hookSetPendingHostStateRequest; + KHook::Function m_hookReplyConnection; + KHook::Function m_hookScriptGetAddon; + CUtlVector m_ImportantDownloads; // Important addon downloads that will trigger a map reload when finished CUtlQueue m_DownloadQueue; // Queue of all addon downloads to print progress diff --git a/src/utils/module.h b/src/utils/module.h index e8f3da4..2ded500 100644 --- a/src/utils/module.h +++ b/src/utils/module.h @@ -21,6 +21,7 @@ #include "dbg.h" #include "interface.h" #include "strtools.h" +#include "khook.hpp" #include "plat.h" #include @@ -31,13 +32,6 @@ #include #endif -enum SigError -{ - SIG_OK, - SIG_NOT_FOUND, - SIG_FOUND_MULTIPLE, -}; - // equivalent to FindSignature, but allows for multiple signatures to be found and iterated over class SignatureIterator { @@ -102,38 +96,9 @@ class CModule #endif } - void *FindSignature(const byte *pData, size_t iSigLength, int &error) + void *LookupSignature(const char *pSignature) { - unsigned char *pMemory; - void *return_addr = nullptr; - error = 0; - - pMemory = (byte *)m_base; - - for (size_t i = 0; i < m_size; i++) - { - size_t Matches = 0; - while (*(pMemory + i + Matches) == pData[Matches] || pData[Matches] == '\x2A') - { - Matches++; - if (Matches == iSigLength) - { - if (return_addr) - { - error = SIG_FOUND_MULTIPLE; - return return_addr; - } - - return_addr = (void *)(pMemory + i); - break; - } - } - } - - if (!return_addr) - error = SIG_NOT_FOUND; - - return return_addr; + return KHook::LookupSignature(m_base, m_size, pSignature); } void *FindInterface(const char *name) diff --git a/vendor/funchook/LICENSE b/vendor/funchook/LICENSE deleted file mode 100644 index 2da840d..0000000 --- a/vendor/funchook/LICENSE +++ /dev/null @@ -1,360 +0,0 @@ -Funchook is distributed under the terms of the GNU General Public -License version 2 or later with the following clarification and -special exception. - -Linking this library statically or dynamically with other modules is -making a combined work based on this library. Thus, the terms and -conditions of the GNU General Public License cover the whole -combination. - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent -modules, and to copy and distribute the resulting executable under -terms of your choice, provided that you also meet, for each linked -independent module, the terms and conditions of the license of that -module. An independent module is a module which is not derived from or -based on this library. If you modify this library, you must extend this -exception to your version of the library. - -===================================================================== - - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 1989, 1991 Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. This -General Public License applies to most of the Free Software -Foundation's software and to any other program whose authors commit to -using it. (Some other Free Software Foundation software is covered by -the GNU Lesser General Public License instead.) You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must show them these terms so they know their -rights. - - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at all. - - The precise terms and conditions for copying, distribution and -modification follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License applies to any program or other work which contains -a notice placed by the copyright holder saying it may be distributed -under the terms of this General Public License. The "Program", below, -refers to any such program or work, and a "work based on the Program" -means either the Program or any derivative work under copyright law: -that is to say, a work containing the Program or a portion of it, -either verbatim or with modifications and/or translated into another -language. (Hereinafter, translation is included without limitation in -the term "modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the -Program (independent of having been made by running the Program). -Whether that is true depends on what the Program does. - - 1. You may copy and distribute verbatim copies of the Program's -source code as you receive it, in any medium, provided that you -conspicuously and appropriately publish on each copy an appropriate -copyright notice and disclaimer of warranty; keep intact all the -notices that refer to this License and to the absence of any warranty; -and give any other recipients of the Program a copy of this License -along with the Program. - -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. - - 2. You may modify your copy or copies of the Program or any portion -of it, thus forming a work based on the Program, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Program, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source -code means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to -control compilation and installation of the executable. However, as a -special exception, the source code distributed need not include -anything that is normally distributed (in either source or binary -form) with the major components (compiler, kernel, and so on) of the -operating system on which the executable runs, unless that component -itself accompanies the executable. - -If distribution of executable or object code is made by offering -access to copy from a designated place, then offering equivalent -access to copy the source code from the same place counts as -distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. - - 4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense or distribute the Program is -void, and will automatically terminate your rights under this License. -However, parties who have received copies, or rights, from you under -this License will not have their licenses terminated so long as such -parties remain in full compliance. - - 5. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Program or works based on it. - - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to -this License. - - 7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Program at all. For example, if a patent -license would not permit royalty-free redistribution of the Program by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License -may add an explicit geographical distribution limitation excluding -those countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 9. The Free Software Foundation may publish revised and/or new versions -of the General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -this License, you may choose any version ever published by the Free Software -Foundation. - - 10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. - - NO WARRANTY - - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along - with this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: - - Gnomovision version 69, Copyright (C) year name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, the commands you use may -be called something other than `show w' and `show c'; they could even be -mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the program - `Gnomovision' (which makes passes at compilers) written by James Hacker. - - , 1 April 1989 - Ty Coon, President of Vice - -This General Public License does not permit incorporating your program into -proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. diff --git a/vendor/funchook/README.md b/vendor/funchook/README.md deleted file mode 100644 index 419021f..0000000 --- a/vendor/funchook/README.md +++ /dev/null @@ -1,273 +0,0 @@ -Funchook - an API hook library -============================== - -[![tests](https://github.com/kubo/funchook/actions/workflows/run-tests.yml/badge.svg?branch=master)](https://github.com/kubo/funchook/actions/workflows/run-tests.yml) - -This library depends on one of the following disassemblers. - -On x86_64 and x86 -* [diStorm3][] (default) -* [zydis][] (when `-DFUNCHOOK_DISASM=zydis` is passed to the `cmake` command) -* [capstone][] (when `-DFUNCHOOK_DISASM=capstone` is passed to the `cmake` command) - -On arm64 -* [capstone][] - -TODO ----- - -* write documents. - -News ----- - -### 2.0.0 (20XX-XX-XX) - -* Add `funchook_prepare_with_params()` to support prehook. -* Add `funchook_get_arg()` to get arguments in prehook. - -### 1.1.1 (2022-10-02) - -* More permissive check for page allocation mmap ([#25][]) -* Flush instruction cache for arm64. It does nothing for intel CPU. -* Disassember engine - * Upgrade capstone to 4.0.2 - * Upgrade distorm to 3.5.2 -* CMake - * Allow user to specify FUNCHOOK_CPU explicitly ([#19][]) - * Avoid polluting global include and link dirs ([#20][]) - * Use target based compile options for gcc's -Wall ([#21][]) - * Use ExternalProject_add to download captone only ([#30][]) - * Add option FUNCHOOK_INSTALL ([#31][]) - * Use "FUNCHOOK_CPU MATCHES " ([#32][]) -* Documentation - * added example usage from python ([#22][]) -* Fix tests on Android ([#29][]) - -### 1.1.0 (2020-03-22) - -* Arm64 Linux support. [capstone][] is used as the disassembler library on arm64. -* Options to use [zydis][] and [capstone][] as a disassembler library on x86_64 and x86. -* `extern "C"` was added in funchook.h for C++. ([#15][]) -* Libc-compatible functions were removed to simplify code. - -### 1.0.0 (2020-01-19) - -* [diStorm3][] is used as the disassembler library. -* Libc-compatible functions were implemented on Linux in order not to hook function calls issued by funchook itself. - -Supported Platforms -------------------- - -* Linux x86_64 -* Linux x86 -* Linux arm64 (since 1.1.0) -* macOS x86_64 (Functions in executables cannot be hooked when Xcode version >= 11.0. (*1)) -* Windows x64 (except C-runtime functions under [Wine][]) -* Windows 32-bit - -*1 [`mprotect`] fails with EACCES. - -Unsupported Platforms ---------------------- - -* macOS arm64 (*1) - -*1 I received a mail that [`mprotect`] failed with `EINVAL`. Apple seems to prevent executable memory regions from being writable. - -Compilation and installation ------------ - -### Unix - -```shell -$ git clone --recursive https://github.com/kubo/funchook.git -$ mkdir build -$ cd build -$ cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/path/to/install/directory ../funchook -$ make -$ make install -``` - -* Available [`CMAKE_BUILD_TYPE`][] values are empty(default), `Debug`, `Release`, `RelWithDebInfo`(release build with debug information) and `MinSizeRel`. -* When [`CMAKE_INSTALL_PREFIX`][] isn't set, funchook is installed at `/usr/local`. - - installed files: - * `${CMAKE_INSTALL_PREFIX}/include/funchook.h` (header file) - * `${CMAKE_INSTALL_PREFIX}/lib/libfunchook.so` (symbolic link to `libfunchook.so.1`) - * `${CMAKE_INSTALL_PREFIX}/lib/libfunchook.so.1` ([soname][]; symbolic link to `libfunchook.so.1.1.0`) - * `${CMAKE_INSTALL_PREFIX}/lib/libfunchook.so.1.1.0` (shared library) - * `${CMAKE_INSTALL_PREFIX}/lib/libfunchook.a` (static library) - -### Windows - -Here is an example to compile funchook with Visual Studio 2017 Win64. -Change the argument of `-G` to use other compilers. - -```shell -$ git clone --recursive https://github.com/kubo/funchook.git -$ mkdir build -$ cd build -$ cmake -G "Visual Studio 15 2017 Win64" -DCMAKE_INSTALL_PREFIX=c:\path\to\install\directory ..\funchook -$ cmake --build . --config Release --target INSTALL -``` - -* Available `-G` arguments (generators) are listed in the output of `cmake --help`. -* Available `--config` arguments are `Debug`(default), `Release`, `RelWithDebInfo` and `MinSizeRel`. -* When [`CMAKE_INSTALL_PREFIX`][] isn't set, funchook is installed at `c:\Program Files\funchook`. - - installed files: - * `${CMAKE_INSTALL_PREFIX}\include\funchook.h` (header file) - * `${CMAKE_INSTALL_PREFIX}\bin\funchook.dll` (shared library) - * `${CMAKE_INSTALL_PREFIX}\bin\funchook.pdb` (debug file for `funchook.dll` when `--config` is `Debug` or `RelWithDebInfo`) - * `${CMAKE_INSTALL_PREFIX}\lib\funchook.lib` (static library) - * `${CMAKE_INSTALL_PREFIX}\lib\funchook_dll.lib` (import library for `funchook.dll`) - -Example -------- - -```c -static ssize_t (*send_func)(int sockfd, const void *buf, size_t len, int flags); -static ssize_t (*recv_func)(int sockfd, void *buf, size_t len, int flags); - -static ssize_t send_hook(int sockfd, const void *buf, size_t len, int flags); -{ - ssize_t rv; - - ... do your task: logging, etc. ... - rv = send_func(sockfd, buf, len, flags); /* call the original send(). */ - ... do your task: logging, checking the return value, etc. ... - return rv; -} - -static ssize_t recv_hook(int sockfd, void *buf, size_t len, int flags); -{ - ssize_t rv; - - ... do your task: logging, etc. ... - rv = recv_func(sockfd, buf, len, flags); /* call the original recv(). */ - ... do your task: logging, checking received data, etc. ... - return rv; -} - -int install_hooks() -{ - funchook_t *funchook = funchook_create(); - int rv; - - /* Prepare hooking. - * The return value is used to call the original send function - * in send_hook. - */ - send_func = send; - rv = funchook_prepare(funchook, (void**)&send_func, send_hook); - if (rv != 0) { - /* error */ - ... - } - - /* ditto */ - recv_func = recv; - rv = funchook_prepare(funchook, (void**)&recv_func, recv_hook); - if (rv != 0) { - /* error */ - ... - } - - /* Install hooks. - * The first 5-byte code of send() and recv() are changed respectively. - */ - rv = funchook_install(funchook, 0); - if (rv != 0) { - /* error */ - ... - } -} - -``` - -Example - Using Python ctypes ------------------------------ -```python -# should work on python 2.7/3 windows/linux - -# load funchook -import ctypes -fh_lib = ctypes.cdll.LoadLibrary('/path/to/funchook/dll/or/so') - -# define signatures -funchook_create = fh_lib.funchook_create -funchook_create.restype = ctypes.c_void_p -funchook_create.argtypes = [] - -funchook_prepare = fh_lib.funchook_prepare -funchook_prepare.restype = ctypes.c_ssize_t -funchook_prepare.argtypes = [ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p] - -funchook_install = fh_lib.funchook_install -funchook_install.restype = ctypes.c_ssize_t -funchook_install.argtypes = [ctypes.c_void_p, ctypes.c_int] - -PySys_WriteStdout = ctypes.pythonapi.PySys_WriteStdout -PySys_WriteStdout.restype = None -PySys_WriteStdout.argtypes=[ctypes.c_char_p] - -# must keep those references alive, or stuff will be GC'd and weird errors will occur -global orig_write, hook, orig_write_ptr - -# create hook (this function will replace the original function) -hook_type = ctypes.PYFUNCTYPE(None, ctypes.c_char_p) -orig_write = None -def hook_impl(msg): - print('about to write: ' + str(msg)) # do what we want - orig_write(msg) # call the original function - -hook = hook_type(hook_impl) - -fh = funchook_create() -# create a pointer object with the function address -orig_write_ptr = ctypes.c_void_p(ctypes.c_void_p.from_address(ctypes.addressof(PySys_WriteStdout)).value) -# orig_write_ptr.value will get a ptr to the original PySys_WriteStdout and PySys_WriteStdout will now point to the hook -ret = funchook_prepare(fh, ctypes.addressof(orig_write_ptr), hook) -assert not ret, 'ret is ' + str(ret) -ret = funchook_install(fh, 0) -assert not ret, 'ret is ' + str(ret) -orig_write = hook_type.from_address(ctypes.addressof(orig_write_ptr)) -PySys_WriteStdout(b'hi there\n') -``` - -License -------- - -GPLv2 or later with a [GPL linking exception][]. - -You can use funchook in any software. Though funchook is licensed under -the GPL, it doesn't affect outside of funchook due to the linking exception. -You have no need to open your souce code under the GPL except funchook itself. - -If you modify funchook itself and release it, the modifed part must be -open under the GPL with or without the linking exception because funchook -itself is under the GPL. - -[diStorm3][] and [capstone][] are released under the 3-clause BSD license. -[zydis][] is released under the MIT license. They are compatible with the GPL. - -[GPL linking exception]: https://en.wikipedia.org/wiki/GPL_linking_exception -[diStorm3]: https://github.com/gdabah/distorm/ -[zydis]: https://github.com/zyantific/zydis -[capstone]: https://github.com/aquynh/capstone -[Wine]: https://www.winehq.org/ -[`CMAKE_BUILD_TYPE`]: https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html -[`CMAKE_INSTALL_PREFIX`]: https://cmake.org/cmake/help/latest/variable/CMAKE_INSTALL_PREFIX.html -[soname]: https://en.wikipedia.org/wiki/Soname -[#15]: https://github.com/kubo/funchook/issues/15 -[#19]: https://github.com/kubo/funchook/pull/19 -[#20]: https://github.com/kubo/funchook/pull/20 -[#21]: https://github.com/kubo/funchook/pull/21 -[#22]: https://github.com/kubo/funchook/pull/22 -[#25]: https://github.com/kubo/funchook/pull/25 -[#29]: https://github.com/kubo/funchook/pull/29 -[#30]: https://github.com/kubo/funchook/pull/30 -[#31]: https://github.com/kubo/funchook/pull/31 -[#32]: https://github.com/kubo/funchook/pull/32 -[`mprotect`]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/mprotect.2.html diff --git a/vendor/funchook/include/funchook.h b/vendor/funchook/include/funchook.h deleted file mode 100644 index 5c6ed34..0000000 --- a/vendor/funchook/include/funchook.h +++ /dev/null @@ -1,167 +0,0 @@ -/* - * This file is part of Funchook. - * https://github.com/kubo/funchook - * - * Funchook is free software: you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 2 of the License, or (at your - * option) any later version. - * - * As a special exception, the copyright holders of this library give you - * permission to link this library with independent modules to produce an - * executable, regardless of the license terms of these independent - * modules, and to copy and distribute the resulting executable under - * terms of your choice, provided that you also meet, for each linked - * independent module, the terms and conditions of the license of that - * module. An independent module is a module which is not derived from or - * based on this library. If you modify this library, you may extend this - * exception to your version of the library, but you are not obliged to - * do so. If you do not wish to do so, delete this exception statement - * from your version. - * - * Funchook is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License - * along with Funchook. If not, see . - */ -#ifndef FUNCHOOK_H -#define FUNCHOOK_H 1 - -#ifdef __cplusplus -extern "C" { -#endif - -/* - * Only functions with FUNCHOOK_EXPORT are visible from outside of funchook.dll - * or libfunchook.so. Others are invisible. - */ -#ifdef FUNCHOOK_EXPORTS -#if defined(_WIN32) -#define FUNCHOOK_EXPORT __declspec(dllexport) -#elif defined(__GNUC__) -#define FUNCHOOK_EXPORT __attribute__((visibility("default"))) -#endif -#endif /* FUNCHOOK_EXPORTS */ -#ifndef FUNCHOOK_EXPORT -#define FUNCHOOK_EXPORT -#endif - -typedef struct funchook funchook_t; - -#define FUNCHOOK_ERROR_INTERNAL_ERROR -1 -#define FUNCHOOK_ERROR_SUCCESS 0 -#define FUNCHOOK_ERROR_OUT_OF_MEMORY 1 -#define FUNCHOOK_ERROR_ALREADY_INSTALLED 2 -#define FUNCHOOK_ERROR_DISASSEMBLY 3 -#define FUNCHOOK_ERROR_IP_RELATIVE_OFFSET 4 -#define FUNCHOOK_ERROR_CANNOT_FIX_IP_RELATIVE 5 -#define FUNCHOOK_ERROR_FOUND_BACK_JUMP 6 -#define FUNCHOOK_ERROR_TOO_SHORT_INSTRUCTIONS 7 -#define FUNCHOOK_ERROR_MEMORY_ALLOCATION 8 /* memory allocation error */ -#define FUNCHOOK_ERROR_MEMORY_FUNCTION 9 /* other memory function errors */ -#define FUNCHOOK_ERROR_NOT_INSTALLED 10 -#define FUNCHOOK_ERROR_NO_AVAILABLE_REGISTERS 11 -#define FUNCHOOK_ERROR_NO_SPACE_NEAR_TARGET_ADDR 12 - -#define FUNCHOOK_FLAG_THISCALL (1u << 0) -#define FUNCHOOK_FLAG_FASTCALL (1u << 1) - -typedef struct funchook_arg_handle funchook_arg_handle_t; - -typedef struct funchook_info { - void *original_target_func; - void *target_func; - void *trampoline_func; - void *hook_func; - void *user_data; - funchook_arg_handle_t *arg_handle; -} funchook_info_t; - -typedef void (*funchook_hook_t)(funchook_info_t *fi); - -typedef struct { - void *hook_func; - funchook_hook_t prehook; - void *user_data; - unsigned int flags; -} funchook_params_t; - -/** - * Create a funchook handle - * - * @return allocated funchook handle. NULL when out-of-memory. - */ -FUNCHOOK_EXPORT funchook_t *funchook_create(void); - -/** - * Prepare hooking - * - * @param funchook a funchook handle created by funchook_create() - * @param target_func function pointer to be intercepted. The pointer to trampoline function is set on success. - * @param hook_func function pointer which is called istead of target_func - * @return error code. one of FUNCHOOK_ERROR_*. - */ -FUNCHOOK_EXPORT int funchook_prepare(funchook_t *funchook, void **target_func, void *hook_func); - -FUNCHOOK_EXPORT int funchook_prepare_with_params(funchook_t *funchook, - void **target_func, const funchook_params_t *params); - -/** - * Install hooks prepared by funchook_prepare(). - * - * @param funchook a funchook handle created by funchook_create() - * @param flags reserved. Set zero. - * @return error code. one of FUNCHOOK_ERROR_*. - */ -FUNCHOOK_EXPORT int funchook_install(funchook_t *funchook, int flags); - -/** - * Uninstall hooks installed by funchook_install(). - * - * @param funchook a funchook handle created by funchook_create() - * @param flags reserved. Set zero. - * @return error code. one of FUNCHOOK_ERROR_*. - */ -FUNCHOOK_EXPORT int funchook_uninstall(funchook_t *funchook, int flags); - -/** - * Destroy a funchook handle - * - * @param funchook a funchook handle created by funchook_create() - * @return error code. one of FUNCHOOK_ERROR_*. - */ -FUNCHOOK_EXPORT int funchook_destroy(funchook_t *funchook); - -/** - * Get error message - * - * @param funchook a funchook handle created by funchook_create() - * @return pointer to buffer containing error message - */ -FUNCHOOK_EXPORT const char *funchook_error_message(const funchook_t *funchook); - -/** - * Set log file name to debug funchook itself. - * - * @param name log file name - * @return error code. one of FUNCHOOK_ERROR_*. - */ -FUNCHOOK_EXPORT int funchook_set_debug_file(const char *name); - -/* This function is under developemnt. It will be used by C++ template functions later. */ -FUNCHOOK_EXPORT void *funchook_arg_get_int_reg_addr(const funchook_arg_handle_t *arg_handle, int pos); - -/* This function is under developemnt. It will be used by C++ template functions later. */ -FUNCHOOK_EXPORT void *funchook_arg_get_flt_reg_addr(const funchook_arg_handle_t *arg_handle, int pos); - -/* This function is under developemnt. It will be used by C++ template functions later. */ -FUNCHOOK_EXPORT void *funchook_arg_get_stack_addr(const funchook_arg_handle_t *arg_handle, int pos); - -#ifdef __cplusplus -} // extern "C" -#endif - -#endif diff --git a/vendor/funchook/lib/Debug/distorm.lib b/vendor/funchook/lib/Debug/distorm.lib deleted file mode 100644 index c6fb398..0000000 Binary files a/vendor/funchook/lib/Debug/distorm.lib and /dev/null differ diff --git a/vendor/funchook/lib/Debug/distorm.pdb b/vendor/funchook/lib/Debug/distorm.pdb deleted file mode 100644 index c15ddfe..0000000 Binary files a/vendor/funchook/lib/Debug/distorm.pdb and /dev/null differ diff --git a/vendor/funchook/lib/Debug/funchook.lib b/vendor/funchook/lib/Debug/funchook.lib deleted file mode 100644 index 319115e..0000000 Binary files a/vendor/funchook/lib/Debug/funchook.lib and /dev/null differ diff --git a/vendor/funchook/lib/Debug/funchook.pdb b/vendor/funchook/lib/Debug/funchook.pdb deleted file mode 100644 index 4f5c4a8..0000000 Binary files a/vendor/funchook/lib/Debug/funchook.pdb and /dev/null differ diff --git a/vendor/funchook/lib/Debug/libdistorm.a b/vendor/funchook/lib/Debug/libdistorm.a deleted file mode 100644 index d449bda..0000000 Binary files a/vendor/funchook/lib/Debug/libdistorm.a and /dev/null differ diff --git a/vendor/funchook/lib/Debug/libfunchook.a b/vendor/funchook/lib/Debug/libfunchook.a deleted file mode 100644 index 572919f..0000000 Binary files a/vendor/funchook/lib/Debug/libfunchook.a and /dev/null differ diff --git a/vendor/funchook/lib/Release/distorm.lib b/vendor/funchook/lib/Release/distorm.lib deleted file mode 100644 index 31aa0b3..0000000 Binary files a/vendor/funchook/lib/Release/distorm.lib and /dev/null differ diff --git a/vendor/funchook/lib/Release/funchook.lib b/vendor/funchook/lib/Release/funchook.lib deleted file mode 100644 index 7ce8959..0000000 Binary files a/vendor/funchook/lib/Release/funchook.lib and /dev/null differ diff --git a/vendor/funchook/lib/Release/libdistorm.a b/vendor/funchook/lib/Release/libdistorm.a deleted file mode 100644 index 7094a7b..0000000 Binary files a/vendor/funchook/lib/Release/libdistorm.a and /dev/null differ diff --git a/vendor/funchook/lib/Release/libfunchook.a b/vendor/funchook/lib/Release/libfunchook.a deleted file mode 100644 index 1b25984..0000000 Binary files a/vendor/funchook/lib/Release/libfunchook.a and /dev/null differ