From 33f5ed9ef58f26c6b3b52cf605dd4311d658a60d Mon Sep 17 00:00:00 2001 From: salmonik Date: Fri, 6 Nov 2026 16:09:55 +0100 Subject: Fix audit findings: crash safety, correctness, rendering, performance Crash/UB: - gate every hook behind an init-stage flag until config/surface/input are ready - publish module maps as immutable atomic snapshots instead of reallocating shared vectors under unlocked readers - validate the %ebp walk in the RandomSeed/RandomFloat hooks against the stack - bounds-check every RecvTable/RecvProp/string dereference with module_range() - preserve the Itanium vtable header when cloning (client, CInput, model render, studio render) - reject negative usercmd sequence numbers; guard config_load against a null section target; cap the bone parent walk; check mprotect; drop PROT_EXEC on the GOT patch; absorb server.so .bss tail Correctness: - filter dormant entities across ESP, aimbot, triggerbot, melee, items and projectiles (slot self-tested against the local player) - reset the server-health latch per map and only latch on valid model indices - bone cache sized for the 128-target scan; set valid=false on every failure; head_position keeps searching past an invalid bone - vischeck steps past glass by probing until clear, and ignores entities owned by the target (held weapons, bone followers) - aimbot: maxs no longer disables it, AABB-aware FOV prefilter, lock hysteresis, lead point re-checked for FOV and visibility - spread: seed hook arms on the no-spread toggle alone; engine toggle only controls the RandomFloat zeroing - resolve m_hOwnerEntity/m_hOwner; NPC lead velocity from the server entity - vector_angles pitch range, point_ground normal test, underwater jump+duck no longer skips combat, semi-auto press/release edge for synthetic fire - item/projectile markers and blast rings refresh origin per frame while discovery stays at 10 Hz; trajectory uses the real m_DmgRadius and honours the blast-radius toggle Rendering/GUI: - one overlay draw per engine frame (FRAME_RENDER_START boundary), fixing alpha stacking and the speed-graph flicker - clipped lines/outlines and ellipsised text instead of drawing past the content pane or shifting over neighbours - dropdown dismissal consumes the click; hover ignores hidden controls - chams: reset AlphaModulate, reference shared materials once, restore prop tint colour; fonts created once per handle - projection uses Source's 4:3 aspect scaling and roll; screen size refreshed each frame; FOV circle gated on the aim toggles, not the bind Performance: - TTL caches for NPC relation, friendly/neutral and damage class - model names memoised per model index - entity pointer -> index cache for the triggerbot (was a 4096-slot walk/tick) Build: - real Makefile with -MMD dependency tracking, debug/release objects and an always-relink rule; build.sh kept as a thin wrapper --- src/server.cpp | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) (limited to 'src/server.cpp') diff --git a/src/server.cpp b/src/server.cpp index b1661ac..0d14c59 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -68,7 +68,7 @@ static bool g_srv_checked = false; static uintptr_t find_string(const char *s) { size_t n = strlen(s) + 1; - for (auto &r : g_server.ranges) { + for (auto &r : mod_server().ranges) { const uint8_t *base = (const uint8_t *)r.lo; size_t span = r.hi - r.lo; for (size_t i = 0; i + n <= span; i++) @@ -92,7 +92,7 @@ static int datamap_offsets(const char *name, int want_type, int min_off, if (!str) return 0; int n = 0; - for (auto &r : g_server.ranges) { + for (auto &r : mod_server().ranges) { const uint8_t *base = (const uint8_t *)r.lo; size_t span = r.hi - r.lo; for (size_t off = 4; off + 0x18 <= span; off += 4) { @@ -111,7 +111,7 @@ static int datamap_offsets(const char *name, int want_type, int min_off, continue; // DEFINE_KEYFIELD entries have an external name ("health"); plain // DEFINE_FIELD entries have none. Either way it must be in server.so. - if (ext && !g_server.contains(ext)) + if (ext && !mod_server().contains(ext)) continue; bool dup = false; for (int i = 0; i < n; i++) @@ -144,9 +144,9 @@ bool resolve_server_netvars() { if ((retry++ % 100) != 0) return false; // server.so is only mapped once a map is running; refresh the module list. - if (!g_server.valid()) + if (!mod_server().valid()) find_modules(); - if (!g_server.valid()) { + if (!mod_server().valid()) { if (!fail_logged) { fail_logged = true; logd("server datamap: server.so not mapped yet"); @@ -209,7 +209,7 @@ bool resolve_server_netvars() { "followtarget=%d spawnflags=%d hacked=%d npcstate=%d " "takedamage=%d mapname=%d armor=%d detonate=%d dmgradius=%d " "ammo=%d myweapons=%d juice_suit=%d juice_health=%d", - g_server.path.c_str(), g_srv_health, g_srv_maxhealth, g_srv_lifestate, + mod_server().path.c_str(), g_srv_health, g_srv_maxhealth, g_srv_lifestate, g_srv_modelindex, g_srv_absvelocity, g_srv_velocity, g_srv_activeweapon, g_srv_relationship, g_srv_followtarget, g_srv_spawnflags, g_srv_hacked, g_srv_npcstate, g_srv_takedamage, @@ -219,7 +219,7 @@ bool resolve_server_netvars() { } else if (!fail_logged) { fail_logged = true; logf("server datamap: scan failed (server.so at %s)", - g_server.path.c_str()); + mod_server().path.c_str()); toastf(TOAST_WARN, "Server datamap scan failed; jumpbug assist limited"); } return g_srv_ready; @@ -275,6 +275,19 @@ int server_entity_health(int idx, int *maxhealth, int *lifestate, return hp; } +bool server_entity_velocity(int idx, Vector *out) { + if (!out || g_srv_velocity <= 0) + return false; + void *base = nullptr; + if (server_entity_health(idx, nullptr, nullptr, &base) < 0 || !base) + return false; + uintptr_t b = (uintptr_t)base; + out->x = *(float *)(b + g_srv_velocity); + out->y = *(float *)(b + g_srv_velocity + 4); + out->z = *(float *)(b + g_srv_velocity + 8); + return true; +} + int server_model_index(void *base) { if (!base || g_srv_modelindex <= 0) return -1; -- cgit v1.2.3