Skip to content

Commit

Permalink
潜在问题修复 & 代码优化
Browse files Browse the repository at this point in the history
  • Loading branch information
lakwsh committed Oct 31, 2024
1 parent 0f2f29a commit 6f5b5b2
Show file tree
Hide file tree
Showing 5 changed files with 112 additions and 136 deletions.
205 changes: 99 additions & 106 deletions l4dtoolz.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand All @@ -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;
Expand All @@ -88,18 +103,18 @@ 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;
}
*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();
Expand All @@ -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;
Expand All @@ -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;
Expand All @@ -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;
Expand All @@ -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);
Expand All @@ -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];
Expand All @@ -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);
}
Expand All @@ -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);
}
9 changes: 1 addition & 8 deletions l4dtoolz.h
Original file line number Diff line number Diff line change
Expand Up @@ -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) { }
Expand All @@ -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;

Expand Down
Loading

0 comments on commit 6f5b5b2

Please sign in to comment.