diff --git a/l4dtoolz.cpp b/l4dtoolz.cpp index fb9d187..97aa0b2 100644 --- a/l4dtoolz.cpp +++ b/l4dtoolz.cpp @@ -9,16 +9,16 @@ #define CHKPTR(P, V) ((P) && !((uintptr_t)(P) & (V))) #define CMPPTR(P, V, C) (CHKPTR(P, V) && abs((int)(P) - (int)(C)) < BINMSIZE) #define READCALL(P) (((P) + 5 - 1) + *(int *)(P)) -#define CHKVAL \ - int new_value = ((ConVar *)var)->GetInt(); \ - int old_value = atoi(pOldValue); \ - if (new_value == old_value) return; #pragma pack(push, 1) +class CSteamID { +public: + uint64_t m_steamid; +}; typedef struct { - uint64_t id; + CSteamID id; int32_t code; - uint64_t owner; + CSteamID owner; } ValidateAuthTicketResponse_t; #pragma pack(pop) @@ -33,43 +33,58 @@ static edict_t **edict_ptr; static int *slots_ptr; static uint64 *cookie_ptr; static int *maxcl_ptr; -static uintptr_t *gamerules_ptr; +static uintptr_t ***gamerules_ptr; static uintptr_t rules_max_ptr; -static mem_sig_t *rules_max_org; -static uintptr_t dsp_max_ptr; -static mem_sig_t *dsp_max_org; -static uintptr_t lobby_req_ptr; -static mem_sig_t *lobby_req_org; +static uintptr_t rules_max_org; +static uintptr_t match_max_ptr; +static uintptr_t match_max_org; +static uintptr_t lobbyreq_ptr; +static uintptr_t lobbyreq_org; static uintptr_t *steam3_ptr; static uintptr_t authreq_ptr; -static mem_sig_t *authreq_org; +static uintptr_t authreq_org; static uintptr_t *authrsp_ptr; static uintptr_t authrsp_org; static uintptr_t tickint_ptr; -static mem_sig_t *tickint_org; +static uintptr_t tickint_org; -void l4dtoolz::OnChangeMax(IConVar *var, const char *pOldValue, float flOldValue) { - CHKVAL +static void write_dword(uintptr_t addr, uintptr_t val) { + static uint8_t dword[6] = {0x04, 0x00}; + static auto patch = (mem_sig_t *)dword; + if (!addr) return; + *(uintptr_t *)patch->sig = val; + write_sig(addr, patch); +} + +// Linux: static int FUNC_T GetTotalNumPlayersSupported(void *); +static int FUNC_T GetTotalNumPlayersSupported() { + return 32; // max +} + +// Linux: static int FUNC_T GetMaxHumanPlayers(void *); +static int FUNC_T GetMaxHumanPlayers() { + return g_cvar->FindVar("sv_maxplayers")->GetInt(); +} + +void OnChangeMax(IConVar *var, const char *, float) { + int new_value = ((ConVar *)var)->GetInt(); if (!slots_ptr) { var->SetValue(-1); Msg("[L4DToolZ] sv_maxplayers init error\n"); return; } if (new_value < 0) { - write_sig(rules_max_ptr, rules_max_org); - write_sig(dsp_max_ptr, dsp_max_org); + write_dword(rules_max_ptr, rules_max_org); return; } *slots_ptr = new_value; - max_player_new->sig[1] = (uint8_t)new_value; - write_sig(rules_max_ptr, max_player_new); - if (!dsp_max_ptr) Msg("[L4DToolZ] sv_maxplayers(dsp) init error\n"); - else write_sig(dsp_max_ptr, max_player_new); + write_dword(match_max_ptr, (uintptr_t)&GetTotalNumPlayersSupported); + write_dword(rules_max_ptr, (uintptr_t)&GetMaxHumanPlayers); } -ConVar sv_maxplayers("sv_maxplayers", "-1", 0, "Max human players", true, -1, true, 31, l4dtoolz::OnChangeMax); +ConVar sv_maxplayers("sv_maxplayers", "-1", 0, "Max human players", true, -1, true, 31, OnChangeMax); ConVar sv_lobby_cookie("sv_lobby_cookie", "0", 0); -void l4dtoolz::Cookie_f(const CCommand &args) { +void Cookie_f(const CCommand &args) { if (!cookie_ptr) { Msg("[L4DToolZ] sv_cookie init error\n"); return; @@ -88,10 +103,10 @@ void l4dtoolz::Cookie_f(const CCommand &args) { g_cvar->FindVar("sv_allow_lobby_connect_only")->SetValue(val != 0); *cookie_ptr = val; } -ConCommand cookie("sv_cookie", l4dtoolz::Cookie_f, "Lobby reservation cookie"); +ConCommand cookie("sv_cookie", Cookie_f, "Lobby reservation cookie"); -void l4dtoolz::OnSetMaxCl(IConVar *var, const char *pOldValue, float flOldValue) { - CHKVAL +void OnSetMaxCl(IConVar *var, const char *, float) { + int new_value = ((ConVar *)var)->GetInt(); if (!maxcl_ptr) { Msg("[L4DToolZ] sv_setmax init error\n"); return; @@ -99,7 +114,7 @@ void l4dtoolz::OnSetMaxCl(IConVar *var, const char *pOldValue, float flOldValue) *maxcl_ptr = new_value; Msg("[L4DToolZ] maxplayers set to %d\n", new_value); } -ConVar sv_setmax("sv_setmax", "18", 0, "Max clients", true, 18, true, 32, l4dtoolz::OnSetMaxCl); +ConVar sv_setmax("sv_setmax", "18", 0, "Max clients", true, 18, true, 32, OnSetMaxCl); void l4dtoolz::ServerActivate(edict_t *, int, int) { int slots = sv_maxplayers.GetInt(); @@ -109,23 +124,12 @@ void l4dtoolz::ServerActivate(edict_t *, int, int) { Msg("[L4DToolZ] sv_maxplayers(rules) init error\n"); return; } - rules_max_ptr = ((uintptr_t **)*gamerules_ptr)[0][info_idx]; - read_sig(rules_max_ptr, max_player_new, rules_max_org); - if (slots >= 0) write_sig(rules_max_ptr, max_player_new); + rules_max_ptr = (uintptr_t)&(*gamerules_ptr)[0][info_idx]; + rules_max_org = (*gamerules_ptr)[0][info_idx]; + if (slots >= 0) write_dword(rules_max_ptr, (uintptr_t)&GetMaxHumanPlayers); } -// Linux: static float GetTickInterval(void *); -static float GetTickInterval() { - static float tickinv = 1.0f / g_tickrate; - return tickinv; -} - -#ifdef WIN32 -static int PreAuth(const void *, int, uint64 steamID) -#else -static int PreAuth(void *, const void *, int, uint64 steamID) -#endif -{ +HOOK_DEF(int, BeginAuthSession, const void *, int, uint64 steamID) { if (!steamID) { Msg("[L4DToolZ] invalid steamID.\n"); return 1; @@ -134,28 +138,27 @@ static int PreAuth(void *, const void *, int, uint64 steamID) return 0; } -void l4dtoolz::OnBypassAuth(IConVar *var, const char *pOldValue, float flOldValue) { - CHKVAL +#define authreq_idx 0x1A // rodata? +void OnBypassAuth(IConVar *var, const char *, float) { + int new_value = ((ConVar *)var)->GetInt(); if (!steam3_ptr) { err: var->SetValue(0); Msg("[L4DToolZ] sv_steam_bypass init error\n"); return; } - uint8_t authreq[6] = {0x04, 0x00}; - auto authreq_new = (mem_sig_t *)authreq; if (!authreq_ptr) { auto gsv = (uintptr_t **)steam3_ptr[1]; if (!CHKPTR(gsv, 0xFU)) goto err; authreq_ptr = (uintptr_t)&gsv[0][authreq_idx]; - read_sig(authreq_ptr, authreq_new, authreq_org); + authreq_org = gsv[0][authreq_idx]; } - *(uintptr_t *)authreq_new->sig = (uintptr_t)&PreAuth; - if (new_value) write_sig(authreq_ptr, authreq_new); - else write_sig(authreq_ptr, authreq_org); + if (new_value) write_dword(authreq_ptr, (uintptr_t)&BeginAuthSession); + else write_dword(authreq_ptr, authreq_org); } -ConVar sv_steam_bypass("sv_steam_bypass", "0", 0, "Bypass steam validation", true, 0, true, 1, l4dtoolz::OnBypassAuth); +ConVar sv_steam_bypass("sv_steam_bypass", "0", 0, "Bypass steam validation", true, 0, true, 1, OnBypassAuth); +#define rate_idx 0x2C void l4dtoolz::ClientSettingsChanged(edict_t *pEdict) // rate { if (g_tickrate == 30) return; @@ -169,12 +172,8 @@ void l4dtoolz::ClientSettingsChanged(edict_t *pEdict) // rate PLUGIN_RESULT l4dtoolz::ClientConnect(bool *bAllowConnect, edict_t *pEntity, const char *, const char *, char *, int) { if (sv_steam_bypass.GetInt() != 1) return PLUGIN_CONTINUE; - ValidateAuthTicketResponse_t rsp = {(uint64)g_engine->GetClientXUID(pEntity)}; -#ifdef WIN32 - ((void(__thiscall *)(uintptr_t *, void *))authrsp_org)(steam3_ptr, &rsp); -#else - ((void (*)(uintptr_t *, void *))authrsp_org)(steam3_ptr, &rsp); -#endif + ValidateAuthTicketResponse_t rsp = {g_engine->GetClientXUID(pEntity)}; + CALL(void, authrsp_org, uintptr_t *, void *)(steam3_ptr, &rsp); if (g_engine->GetPlayerUserId(pEntity) == -1) { *bAllowConnect = false; return PLUGIN_STOP; @@ -183,58 +182,56 @@ PLUGIN_RESULT l4dtoolz::ClientConnect(bool *bAllowConnect, edict_t *pEntity, con return PLUGIN_CONTINUE; } -#ifdef WIN32 -static void PostAuth(ValidateAuthTicketResponse_t *rsp) -#else -static void PostAuth(void *, ValidateAuthTicketResponse_t *rsp) -#endif -{ - if (!rsp->code && (rsp->id != rsp->owner)) { +HOOK_DEF(void, OnValidateAuthTicketResponse, ValidateAuthTicketResponse_t *rsp) { + if (!rsp->code && (rsp->id.m_steamid != rsp->owner.m_steamid)) { rsp->code = 2; - Msg("[L4DToolZ] %llu using family sharing, owner: %llu.\n", rsp->id, rsp->owner); - } -#ifdef WIN32 - __asm { - leave - mov ecx, steam3_ptr - jmp authrsp_org + Msg("[L4DToolZ] %llu using family sharing, owner: %llu.\n", rsp->id.m_steamid, rsp->owner.m_steamid); } -#else - ((void (*)(uintptr_t *, void *))authrsp_org)(steam3_ptr, rsp); -#endif + CALL(void, authrsp_org, uintptr_t *, void *)(steam3_ptr, rsp); } -void l4dtoolz::OnAntiSharing(IConVar *var, const char *pOldValue, float flOldValue) { - CHKVAL +void OnAntiSharing(IConVar *var, const char *, float) { + int new_value = ((ConVar *)var)->GetInt(); if (!authrsp_ptr) { var->SetValue(0); Msg("[L4DToolZ] sv_anti_sharing init error\n"); return; } - if (new_value) *authrsp_ptr = (uintptr_t)&PostAuth; + if (new_value) *authrsp_ptr = (uintptr_t)&OnValidateAuthTicketResponse; else *authrsp_ptr = authrsp_org; } -ConVar sv_anti_sharing("sv_anti_sharing", "0", 0, "No family sharing", true, 0, true, 1, l4dtoolz::OnAntiSharing); +ConVar sv_anti_sharing("sv_anti_sharing", "0", 0, "No family sharing", true, 0, true, 1, OnAntiSharing); -// Linux: static void ReplyReservationRequest(void *, void *, void *); -static void ReplyReservationRequest(void *, void *) { } +HOOK_DEF(void, ReplyReservationRequest, void *, void *) { } -void l4dtoolz::OnForceUnreserved(IConVar *var, const char *pOldValue, float flOldValue) { - CHKVAL - if (!lobby_req_ptr) { +void OnForceUnreserved(IConVar *var, const char *, float) { + int new_value = ((ConVar *)var)->GetInt(); + if (!lobbyreq_ptr) { var->SetValue(0); Msg("[L4DToolZ] sv_force_unreserved init error\n"); return; } if (new_value) { - write_sig(lobby_req_ptr, lobby_req_new); + write_dword(lobbyreq_ptr, (uintptr_t)&ReplyReservationRequest); g_cvar->FindVar("sv_allow_lobby_connect_only")->SetValue(0); return; } - write_sig(lobby_req_ptr, lobby_req_org); + write_dword(lobbyreq_ptr, lobbyreq_org); +} +ConVar sv_force_unreserved("sv_force_unreserved", "0", 0, "Disallow lobby reservation", true, 0, true, 1, OnForceUnreserved); + +// Linux: static float FUNC_T GetTickInterval(void *); +static float FUNC_T GetTickInterval() { + static float tickinv = 1.0f / g_tickrate; + return tickinv; } -ConVar sv_force_unreserved("sv_force_unreserved", "0", 0, "Disallow lobby reservation", true, 0, true, 1, l4dtoolz::OnForceUnreserved); +#define maxcl_idx 0x41 +#define rules_idx 0x12 // rodata +#define title_idx 0x8 // rodata +#define mat_max_idx 0x4 // rodata +#define sv_idx 0x80 // rodata +#define tickint_idx 0x09 // rodata bool l4dtoolz::Load(CreateInterfaceFn interfaceFactory, CreateInterfaceFn gameServerFactory) { g_engine = (IVEngineServer *)interfaceFactory(INTERFACEVERSION_VENGINESERVER, NULL); g_cvar = (ICvar *)interfaceFactory(CVAR_INTERFACE_VERSION, NULL); @@ -245,11 +242,11 @@ bool l4dtoolz::Load(CreateInterfaceFn interfaceFactory, CreateInterfaceFn gameSe if (!gamerules_ptr) { auto client = (uintptr_t **)gameServerFactory("ServerGameClients003", NULL); - auto gamerules = *(uintptr_t **)(client[0][18] + info_off); // mov + auto gamerules = *(uintptr_t ****)(client[0][rules_idx] + rules_off); // mov if (CMPPTR(gamerules, 0x3U, gameServerFactory)) gamerules_ptr = gamerules; } if (!edict_ptr) { - auto sv = *(uintptr_t ***)(((uint **)g_engine)[0][0x80] + sv_off); + auto sv = *(uintptr_t ***)(((uint **)g_engine)[0][sv_idx] + sv_off); if (!CMPPTR(sv, 0x7U, interfaceFactory)) return false; edict_ptr = (edict_t **)&sv[edict_idx]; slots_ptr = (int *)&sv[slots_idx]; @@ -261,25 +258,21 @@ bool l4dtoolz::Load(CreateInterfaceFn interfaceFactory, CreateInterfaceFn gameSe authrsp_ptr = &steam3_ptr[authrsp_idx]; authrsp_org = *authrsp_ptr; } - lobby_req_ptr = (uintptr_t)&sv[0][lobbyreq_idx]; - read_sig(lobby_req_ptr, lobby_req_new, lobby_req_org); - *(uintptr_t *)lobby_req_new->sig = (uintptr_t)&ReplyReservationRequest; + lobbyreq_ptr = (uintptr_t)&sv[0][lobbyreq_idx]; + lobbyreq_org = sv[0][lobbyreq_idx]; } - if (!dsp_max_ptr) { + if (!match_max_ptr) { auto match = (uintptr_t **)interfaceFactory("MATCHFRAMEWORK_001", NULL); - auto title = ((uintptr_t * *(*)(void)) match[0][8])(); - dsp_max_ptr = title[0][4]; - read_sig(dsp_max_ptr, max_player_new, dsp_max_org); + auto title = ((uintptr_t * *(*)(void)) match[0][title_idx])(); + match_max_ptr = (uintptr_t)&title[0][mat_max_idx]; + match_max_org = title[0][mat_max_idx]; } if ((g_tickrate != 30) && !tickint_ptr) { auto game = (uintptr_t **)gameServerFactory(INTERFACEVERSION_SERVERGAMEDLL, NULL); tickint_ptr = (uintptr_t)&game[0][tickint_idx]; - uint8_t tickint[6] = {0x04, 0x00}; - auto tickint_new = (mem_sig_t *)tickint; - read_sig(tickint_ptr, tickint_new, tickint_org); - *(uintptr_t *)tickint_new->sig = (uintptr_t)&GetTickInterval; - write_sig(tickint_ptr, tickint_new); + tickint_org = game[0][tickint_idx]; + write_dword(tickint_ptr, (uintptr_t)&GetTickInterval); ((uint *)g_cvar->FindVar("net_splitpacket_maxrate"))[15] = 0; // m_bHasMax Msg("[L4DToolZ] tickrate: %d\n", g_tickrate); } @@ -290,10 +283,10 @@ void l4dtoolz::Unload() { ConVar_Unregister(); DisconnectTier1Libraries(); + write_dword(authreq_ptr, authreq_org); if (authrsp_ptr) *authrsp_ptr = authrsp_org; - free_sig(authreq_ptr, authreq_org); - free_sig(rules_max_ptr, rules_max_org); - free_sig(dsp_max_ptr, dsp_max_org); - free_sig(lobby_req_ptr, lobby_req_org); - free_sig(tickint_ptr, tickint_org); + write_dword(rules_max_ptr, rules_max_org); + write_dword(match_max_ptr, match_max_org); + write_dword(lobbyreq_ptr, lobbyreq_org); + write_dword(tickint_ptr, tickint_org); } diff --git a/l4dtoolz.h b/l4dtoolz.h index 1388be3..aa92deb 100644 --- a/l4dtoolz.h +++ b/l4dtoolz.h @@ -11,7 +11,7 @@ class l4dtoolz : public IServerPluginCallbacks { virtual void Unload(); virtual void Pause() { } virtual void UnPause() { } - virtual const char *GetPluginDescription() { return "L4DToolZ v2.3.3, https://github.com/lakwsh/l4dtoolz"; } + virtual const char *GetPluginDescription() { return "L4DToolZ v2.3.4, https://github.com/lakwsh/l4dtoolz"; } virtual void LevelInit(char const *pMapName) { } virtual void ServerActivate(edict_t *pEdictList, int edictCount, int clientMax); virtual void GameFrame(bool simulating) { } @@ -25,13 +25,6 @@ class l4dtoolz : public IServerPluginCallbacks { virtual PLUGIN_RESULT ClientCommand(edict_t *pEntity, const CCommand &args) { return PLUGIN_CONTINUE; } virtual PLUGIN_RESULT NetworkIDValidated(const char *pszUserName, const char *pszNetworkID) { return PLUGIN_CONTINUE; } virtual void OnQueryCvarValueFinished(QueryCvarCookie_t iCookie, edict_t *pPlayerEntity, EQueryCvarValueStatus eStatus, const char *pCvarName, const char *pCvarValue) { } - - static void Cookie_f(const CCommand &args); - static void OnChangeMax(IConVar *var, const char *pOldValue, float flOldValue); - static void OnSetMaxCl(IConVar *var, const char *pOldValue, float flOldValue); - static void OnBypassAuth(IConVar *var, const char *pOldValue, float flOldValue); - static void OnAntiSharing(IConVar *var, const char *pOldValue, float flOldValue); - static void OnForceUnreserved(IConVar *var, const char *pOldValue, float flOldValue); }; extern l4dtoolz g_l4dtoolz; diff --git a/sig_linux.h b/sig_linux.h index 6c40d74..3c5467b 100644 --- a/sig_linux.h +++ b/sig_linux.h @@ -3,24 +3,19 @@ #include "sigtool.h" -#define tickint_idx 0x09 // rodata -#define rate_idx 0x2C -#define info_off 0x01 -#define info_idx 0x89 +#define FUNC_T __cdecl +#define HOOK_DEF(ret, func, ...) static ret FUNC_T func(void *, __VA_ARGS__) +#define CALL(ret, ptr, ...) ((ret (*)(__VA_ARGS__))ptr) + +#define rules_off 0x01 +#define info_idx 0x89 // rodata #define sv_off 0x06 // bss #define edict_idx 0x85 #define slots_idx 0x5F #define cookie_idx 0x5B -#define maxcl_idx 0x41 #define steam3_idx 0x41 #define steam3_off 0x0D -#define authreq_idx 0x1A // rodata (?) #define authrsp_idx 0x24 // bss #define lobbyreq_idx 0x3E // rodata -uint8_t max_player[] = {0x06, 0x00, 0xB8, '*', 0x00, 0x00, 0x00, 0xC3}; -auto max_player_new = (mem_sig_t *)max_player; -uint8_t lobby_req[] = {0x04, 0x00, '*', '*', '*', '*'}; -auto lobby_req_new = (mem_sig_t *)lobby_req; - #endif // SIG_LINUX_H diff --git a/sig_win32.h b/sig_win32.h index 767cd31..5f50716 100644 --- a/sig_win32.h +++ b/sig_win32.h @@ -3,24 +3,19 @@ #include "sigtool.h" -#define tickint_idx 0x09 -#define rate_idx 0x2C -#define info_off 0x02 +#define FUNC_T __stdcall +#define HOOK_DEF(ret, func, ...) static ret FUNC_T func(__VA_ARGS__) +#define CALL(ret, ptr, ...) ((ret (__thiscall *)(__VA_ARGS__))ptr) + +#define rules_off 0x02 #define info_idx 0x88 #define sv_off 0x08 #define edict_idx 0x87 #define slots_idx 0x60 #define cookie_idx 0x5C -#define maxcl_idx 0x41 #define steam3_idx 0x40 #define steam3_off 0x0D -#define authreq_idx 0x1A #define authrsp_idx 0x20 #define lobbyreq_idx 0x3D -uint8_t max_player[] = {0x06, 0x00, 0xB8, '*', 0x00, 0x00, 0x00, 0xC3}; -auto max_player_new = (mem_sig_t *)max_player; -uint8_t lobby_req[] = {0x04, 0x00, '*', '*', '*', '*'}; -auto lobby_req_new = (mem_sig_t *)lobby_req; - #endif // SIG_WIN32_H diff --git a/sigtool b/sigtool index 2105b1e..5637068 160000 --- a/sigtool +++ b/sigtool @@ -1 +1 @@ -Subproject commit 2105b1ebccc3ed56b6e6b92447b961943926e159 +Subproject commit 5637068f3fa067df17c25914e8b3ad70fb7e0944