From b9c80a3ae121f31c369a2110f5af0ad36d343ca5 Mon Sep 17 00:00:00 2001 From: GAMMACASE Date: Sun, 30 May 2021 17:53:57 +0300 Subject: [PATCH] Initial release --- README.md | 12 +- .../sourcemod/gamedata/headbugfix.games.txt | 38 +++++ addons/sourcemod/scripting/headbugfix.sp | 136 ++++++++++++++++++ .../scripting/include/glib/addressutils.inc | 54 +++++++ .../scripting/include/glib/assertutils.inc | 58 ++++++++ 5 files changed, 297 insertions(+), 1 deletion(-) create mode 100644 addons/sourcemod/gamedata/headbugfix.games.txt create mode 100644 addons/sourcemod/scripting/headbugfix.sp create mode 100644 addons/sourcemod/scripting/include/glib/addressutils.inc create mode 100644 addons/sourcemod/scripting/include/glib/assertutils.inc diff --git a/README.md b/README.md index f9d100a..4cd1bf7 100644 --- a/README.md +++ b/README.md @@ -1 +1,11 @@ -# HeadBugFix \ No newline at end of file +# HeadBugFix +This plugin is a port from [momentum mod](https://momentum-mod.org/) that fixes the head boundary box poping up when you start ducking, this allows you to abuse it to reach the triggers that are above you and blocked by a thin ceiling, when it shouldn't be possible to reach otherwise. + +This fix is a port of [this exact commit](https://github.com/momentum-mod/game/commit/dbcc8cc5f8dde2a4e049348dfbac761c8b8db7b7) in the momentum mod repository. So big thanks to that! + +Currently there's a support for CSGO and CSS, and I'm not planning on supporting any other game. + +# Video examples +[Video Example of the plugin](https://www.youtube.com/watch?v=6--_WFe5P3Q) + +[Practical Video Example](https://www.youtube.com/watch?v=X9Cg42gFKtc) \ No newline at end of file diff --git a/addons/sourcemod/gamedata/headbugfix.games.txt b/addons/sourcemod/gamedata/headbugfix.games.txt new file mode 100644 index 0000000..4be7494 --- /dev/null +++ b/addons/sourcemod/gamedata/headbugfix.games.txt @@ -0,0 +1,38 @@ +"Games" +{ + "csgo" + { + "Signatures" + { + "CBasePlayer::UpdateCollisionBounds" + { + "windows" "\x56\x57\x8B\xF9\x8B\x0D\x2A\x2A\x2A\x2A\xF6\x87\x2A\x2A\x2A\x2A\x2A\x8B\x01\x74\x24\xFF\x50\x78\x8B\x0D\x2A\x2A\x2A\x2A\x8D\x70\x30\x8B\x11\xFF\x52\x78\x83\xC0\x24\x8D\x8F" + "linux" "\x55\x89\xE5\x83\xEC\x18\x89\x5D\xF8\x8B\x5D\x08\x89\x75\xFC\xA1\x2A\x2A\x2A\x2A\xF6\x83\x2A\x2A\x2A\x2A\x2A\x8B\x10\x89\x04\x24\x75\x36\xFF\x52\x7C\x89\xC6\xA1\x2A\x2A\x2A\x2A" + } + + "CCSGameMovement::Duck" + { + "windows" "\x55\x8B\xEC\x81\xEC\x2A\x2A\x2A\x2A\x56\x57\x8B\xF9\x8B\x57\x04\x8B\x8A\x2A\x2A\x2A\x2A\x83\xF9\xFF\x74\x33\x0F\xB7\xC1\x8D\x04\x40\x8D\x04\xC5\x2A\x2A\x2A\x2A\x85\xC0\x74\x22" + "linux" "\x55\x89\xE5\x57\x56\x53\x81\xEC\x2A\x2A\x2A\x2A\x8B\x5D\x08\x8B\x43\x04\x89\x04\x24\xE8\x2A\x2A\x2A\x2A\xC6\x85\x2A\x2A\x2A\x2A\x2A\x85\xC0\x0F\x95\xC0" + } + } + } + + "cstrike" + { + "Signatures" + { + "CCollisionProperty::SetCollisionBounds" + { + "windows" "\x55\x8B\xEC\x83\xEC\x2C\x53\x8B\x5D\x0C\x56\x57\x8B\x7D\x08\x8B\xF1\x8D\x56\x08\x89\x75\xFC\x8B\x07\x89\x45\xE0\xF3\x0F\x10\x45\x2A\x0F\x2E\x02\x8B\x47\x04\x89\x45\xE4" + "linux" "@_ZN18CCollisionProperty18SetCollisionBoundsERK6VectorS2_" + } + + "CCSGameMovement::Duck" + { + "windows" "\x55\x8B\xEC\x81\xEC\x2A\x2A\x2A\x2A\x53\x56\x8B\xF1\x8B\x46\x04\x8B\x98\x2A\x2A\x2A\x2A\xF6\xC3\x01\x74\x59\x8B\x56\x08\x8B\x4A\x24\x8B\xC1\x83\xE0\x04" + "linux" "@_ZN15CCSGameMovement4DuckEv" + } + } + } +} \ No newline at end of file diff --git a/addons/sourcemod/scripting/headbugfix.sp b/addons/sourcemod/scripting/headbugfix.sp new file mode 100644 index 0000000..741a3be --- /dev/null +++ b/addons/sourcemod/scripting/headbugfix.sp @@ -0,0 +1,136 @@ +#include "sourcemod" +#include "sdktools" +#include "sdkhooks" +#include "dhooks" +#include "glib/assertutils" +#include "glib/addressutils" + +#define SNAME "[HeadBugFix] " + +public Plugin myinfo = +{ + name = "HeadBugFix", + description = "Fixes headbug bbox exploits", + author = "GAMMA CASE", + version = "1.0.0", +}; + +Handle gUpdateCollisionBounds; +Handle gSetCollisionBounds; +EngineVersion gEngineVersion; + +int gFlagsPropOffset = -1; +bool gLate; + +float gCSSStandingBBox[][] = { + { -16.0, -16.0, 0.0 }, + { 16.0, 16.0, 62.0} +}; + +float gCSSDuckingBBox[][] = { + { -16.0, -16.0, 0.0 }, + { 16.0, 16.0, 45.0} +}; + +public void OnPluginStart() +{ + gEngineVersion = GetEngineVersion(); + ASSERT_MSG(gEngineVersion == Engine_CSS || gEngineVersion == Engine_CSGO, "This plugin is only supported for CSGO and CSS."); + + GameData gd = new GameData("headbugfix.games"); + + SetupSDKCalls(gd); + SetupDhooks(gd); + + delete gd; + + if(gLate) + { + for(int i = 1; i <= MaxClients; i++) + { + if(!IsClientInGame(i) || IsFakeClient(i)) + continue; + + OnClientPutInServer(i); + } + } +} + +public APLRes AskPluginLoad2(Handle myself, bool late, char[] error, int err_max) +{ + gLate = late; +} + +void SetupSDKCalls(GameData gd) +{ + if(gEngineVersion == Engine_CSGO) + { + //CBasePlayer::UpdateCollisionBounds + StartPrepSDKCall(SDKCall_Raw); + + ASSERT_MSG(PrepSDKCall_SetFromConf(gd, SDKConf_Signature, "CBasePlayer::UpdateCollisionBounds"), "Failed to find signature for \"CBasePlayer::UpdateCollisionBounds\"."); + + gUpdateCollisionBounds = EndPrepSDKCall(); + ASSERT_MSG(gUpdateCollisionBounds, "Failed to setup sdkcall to \"CBasePlayer::UpdateCollisionBounds\"."); + } + else + { + //CCollisionProperty::SetCollisionBounds + StartPrepSDKCall(SDKCall_Raw); + + ASSERT_MSG(PrepSDKCall_SetFromConf(gd, SDKConf_Signature, "CCollisionProperty::SetCollisionBounds"), "Failed to find signature for \"CCollisionProperty::SetCollisionBounds\"."); + + PrepSDKCall_AddParameter(SDKType_Vector, SDKPass_ByRef); + PrepSDKCall_AddParameter(SDKType_Vector, SDKPass_ByRef); + + gSetCollisionBounds = EndPrepSDKCall(); + ASSERT_MSG(gSetCollisionBounds, "Failed to setup sdkcall to \"CCollisionProperty::SetCollisionBounds\"."); + } +} + +void SetupDhooks(GameData gd) +{ + //CCSGameMovement::Duck + DynamicDetour dhook = new DynamicDetour(Address_Null, CallConv_THISCALL, ReturnType_Void, ThisPointer_Address); + + ASSERT_MSG(dhook.SetFromConf(gd, SDKConf_Signature, "CCSGameMovement::Duck"), "Failed to find signature for \"CCSGameMovement::Duck\"."); + + ASSERT_MSG(dhook.Enable(Hook_Post, Duck_Dhook), "Failed to enable detour for \"CCSGameMovement::Duck\"."); +} + +public MRESReturn Duck_Dhook(Address pThis) +{ + // pThis + 4 refers to player member of gamemovement instance. + if(gEngineVersion == Engine_CSGO) + { + SDKCall(gUpdateCollisionBounds, LoadFromAddress(pThis + 4, NumberType_Int32)); + } + else if(gFlagsPropOffset != -1) + { + static int collision_offset = -1; + + if(collision_offset == -1) + { + collision_offset = FindSendPropInfo("CBasePlayer", "m_Collision"); + ASSERT_MSG(collision_offset != -1, "Failed to find \"CBasePlayer::m_Collision\" prop."); + } + + Address player = view_as
(LoadFromAddress(pThis + 4, NumberType_Int32)); + int buttons = LoadFromAddress(player + gFlagsPropOffset, NumberType_Int32); + + if(buttons & FL_DUCKING) + SDKCall(gSetCollisionBounds, player + collision_offset, gCSSDuckingBBox[0], gCSSDuckingBBox[1]); + else + SDKCall(gSetCollisionBounds, player + collision_offset, gCSSStandingBBox[0], gCSSStandingBBox[1]); + } +} + +public void OnClientPutInServer(int client) +{ + if(gFlagsPropOffset == -1) + { + gFlagsPropOffset = FindDataMapInfo(client, "m_fFlags"); + ASSERT_MSG(gFlagsPropOffset != -1, "Failed to find \"m_fFlags\" prop."); + } +} + diff --git a/addons/sourcemod/scripting/include/glib/addressutils.inc b/addons/sourcemod/scripting/include/glib/addressutils.inc new file mode 100644 index 0000000..bbe8f14 --- /dev/null +++ b/addons/sourcemod/scripting/include/glib/addressutils.inc @@ -0,0 +1,54 @@ +#if defined _addressutils_included +#endinput +#endif +#define _addressutils_included + +methodmap AddressBase +{ + property Address Address + { + public get() { return view_as
(this); } + } +} + +//-==Operator overloadings +stock Address operator+(Address l, int r) +{ + return l + view_as
(r); +} + +stock Address operator+(int l, Address r) +{ + return view_as
(l) + r; +} + +stock Address operator-(Address l, int r) +{ + return l - view_as
(r); +} + +stock Address operator-(int l, Address r) +{ + return view_as
(l) - r; +} + +stock Address operator*(Address l, int r) +{ + return l * view_as
(r); +} + +stock Address operator*(int l, Address r) +{ + return view_as
(l) * r; +} + +stock Address operator/(Address l, int r) +{ + return l / view_as
(r); +} + +stock Address operator/(int l, Address r) +{ + return view_as
(l) / r; +} +//Operator overloadings==- \ No newline at end of file diff --git a/addons/sourcemod/scripting/include/glib/assertutils.inc b/addons/sourcemod/scripting/include/glib/assertutils.inc new file mode 100644 index 0000000..054d381 --- /dev/null +++ b/addons/sourcemod/scripting/include/glib/assertutils.inc @@ -0,0 +1,58 @@ +#if defined _assertutils_included +#endinput +#endif +#define _assertutils_included + +/* Compile time settings for this include. Should be defined before including this file. +* #define ASSERTUTILS_DISABLE //Disables all assertions +* #define ASSERTUTILS_FAILSTATE_FUNC //Define the name of the function that should be called when assertion is hit +*/ + +#if !defined SNAME +#define __SNAME "" +#else +#define __SNAME SNAME +#endif + +#define ASSERT_FMT_STRING_LEN 512 + +#if defined ASSERTUTILS_DISABLE + +#define ASSERT(%1)%2; +#define ASSERT_MSG(%1,%2)%3; +#define ASSERT_FINAL(%1)%2; +#define ASSERT_FINAL_MSG(%1,%2)%3; + +#elseif defined ASSERTUTILS_FAILSTATE_FUNC + +#define ASSERT(%1) if(!(%1)) ASSERTUTILS_FAILSTATE_FUNC(__SNAME..."Assertion failed: \""...#%1..."\"") +#define ASSERT_MSG(%1,%2) if(!(%1)) ASSERTUTILS_FAILSTATE_FUNC(__SNAME...%2) +#define ASSERT_FINAL(%1) if(!(%1)) SetFailState(__SNAME..."Assertion failed: \""...#%1..."\"") +#define ASSERT_FINAL_MSG(%1,%2) if(!(%1)) SetFailState(__SNAME...%2) + +#else + +#define ASSERT(%1) if(!(%1)) SetFailState(__SNAME..."Assertion failed: \""...#%1..."\"") +#define ASSERT_MSG(%1,%2) if(!(%1)) SetFailState(__SNAME...%2) +#define ASSERT_FINAL(%1) ASSERT(%1) +#define ASSERT_FINAL_MSG(%1,%2) ASSERT_MSG(%1,%2) + +#endif + +// Might be redundant as default ASSERT_MSG accept format arguments just fine. +#if 0 +stock void ASSERT_FMT(bool result, char[] fmt, any ...) +{ +#if !defined ASSERTUTILS_DISABLE + if(!result) + { + char buff[ASSERT_FMT_STRING_LEN]; + VFormat(buff, sizeof(buff), fmt, 3); + + SetFailState(__SNAME..."%s", buff); + } +#endif +} +#endif + +#undef ASSERT_FMT_STRING_LEN \ No newline at end of file