|
| 1 | +#include "StdInc.h" |
| 2 | + |
| 3 | +#include "Hooking.FlexStruct.h" |
| 4 | +#include "Hooking.Patterns.h" |
| 5 | +#include "Hooking.Stubs.h" |
| 6 | + |
| 7 | +static hook::cdecl_stub<bool(int)> fwAnimManager_IsValidSlot([]() |
| 8 | +{ |
| 9 | + return hook::get_call(hook::get_pattern("E8 ? ? ? ? 84 C0 74 ? 8B D3 48 8B CF E8 ? ? ? ? FF C3")); |
| 10 | +}); |
| 11 | + |
| 12 | +static int32_t clipDictIdOffset; |
| 13 | + |
| 14 | +static int (*g_origTaskGeneralSweepOnUpdate)(hook::FlexStruct*); |
| 15 | +static int TaskGeneralSweepOnUpdate(hook::FlexStruct* task) |
| 16 | +{ |
| 17 | + int clipDictId = task->Get<int>(clipDictIdOffset); |
| 18 | + |
| 19 | + if (!fwAnimManager_IsValidSlot(clipDictId)) |
| 20 | + { |
| 21 | + return 0x2; // FSM_QUIT |
| 22 | + } |
| 23 | + |
| 24 | + return g_origTaskGeneralSweepOnUpdate(task); |
| 25 | +} |
| 26 | + |
| 27 | +static HookFunction hookFunction([]() |
| 28 | +{ |
| 29 | + // This hook prevents a client crash caused by invalid clip dictionary IDs in SweepAim tasks. |
| 30 | + // When a player triggers TaskSweepAimEntity using a clip dictionary that exists only on their |
| 31 | + // local client (e.g., a modded or unloaded anim dict), the task is replicated to remote clients. |
| 32 | + // During replication, the clipDictId may resolve to an invalid local index on other clients. |
| 33 | + // Later, the CTaskGeneralSweep task uses this invalid clipDictId inside fwAnimManager, which |
| 34 | + // eventually reaches fwClipDictionaryStore::GetNumRefs and tries to access: |
| 35 | + // m_aStorage[index * size] |
| 36 | + // If 'index' is invalid, this causes an out-of-range pointer dereference, leading to a client |
| 37 | + // crash. |
| 38 | + g_origTaskGeneralSweepOnUpdate = hook::trampoline(hook::get_pattern("EB ? 8B 93 ? ? ? ? 48 81 C1", -0x2F), TaskGeneralSweepOnUpdate); |
| 39 | + clipDictIdOffset = *hook::get_pattern<int32_t>("8B 93 ? ? ? ? 48 81 C1 ? ? ? ? E8 ? ? ? ? 84 C0", 0x2); |
| 40 | +}); |
0 commit comments