|
17 | 17 | #include "../game_sa/TaskBasicSA.h" |
18 | 18 | #include "../game_sa/CFxSystemBPSA.h" |
19 | 19 | #include "../game_sa/CFxSystemSA.h" |
| 20 | +#include "../game_sa/CColModelSA.h" |
20 | 21 |
|
21 | 22 | extern CCoreInterface* g_pCore; |
22 | 23 |
|
@@ -3098,6 +3099,46 @@ static void __declspec(naked) HOOK_CFire_ProcessFire() |
3098 | 3099 | // clang-format on |
3099 | 3100 | } |
3100 | 3101 |
|
| 3102 | +////////////////////////////////////////////////////////////////////////////////////////// |
| 3103 | +// |
| 3104 | +// CColModel::MakeMultipleAlloc - Validate collision data before converting |
| 3105 | +// single-allocation to multi-allocation format via CCollisionData::Copy. |
| 3106 | +// |
| 3107 | +// Corrupt collision data (e.g. from PC_Scratch buffer overflow) can produce |
| 3108 | +// bogus shadow vertex/triangle counts, causing Copy to read past allocations. |
| 3109 | +// |
| 3110 | +////////////////////////////////////////////////////////////////////////////////////////// |
| 3111 | +#define HOOKPOS_CColModel_MakeMultipleAlloc 0x40F740 |
| 3112 | +#define HOOKSIZE_CColModel_MakeMultipleAlloc 5 |
| 3113 | +static void __fastcall HOOK_CColModel_MakeMultipleAlloc(CColModelSAInterface* pColModel, void*) |
| 3114 | +{ |
| 3115 | + if (CColDataSA* pData = pColModel->m_data) |
| 3116 | + { |
| 3117 | + constexpr std::uint32_t MAX_SHADOW_TRIANGLES = 5000; |
| 3118 | + constexpr std::uint32_t MAX_SHADOW_VERTICES = 10000; |
| 3119 | + |
| 3120 | + const bool shadowCorrupt = pData->m_numShadowTriangles > MAX_SHADOW_TRIANGLES || pData->m_numShadowVertices > MAX_SHADOW_VERTICES || |
| 3121 | + (pData->m_numShadowVertices > 0 && !pData->m_shadowVertices) || |
| 3122 | + (pData->m_numShadowTriangles > 0 && !pData->m_shadowTriangles); |
| 3123 | + |
| 3124 | + if (shadowCorrupt) |
| 3125 | + { |
| 3126 | + pData->m_numShadowTriangles = 0; |
| 3127 | + pData->m_numShadowVertices = 0; |
| 3128 | + pData->m_shadowVertices = nullptr; |
| 3129 | + pData->m_shadowTriangles = nullptr; |
| 3130 | + pData->m_hasShadowInfo = 0; |
| 3131 | + pData->m_hasShadow = 0; |
| 3132 | + |
| 3133 | + OnCrashAverted(9801); |
| 3134 | + } |
| 3135 | + } |
| 3136 | + |
| 3137 | + // Call the original MakeMultipleAlloc |
| 3138 | + using MakeMultipleAlloc_t = void(__thiscall*)(CColModelSAInterface*); |
| 3139 | + reinterpret_cast<MakeMultipleAlloc_t>(0x1564A10)(pColModel); |
| 3140 | +} |
| 3141 | + |
3101 | 3142 | ////////////////////////////////////////////////////////////////////////////////////////// |
3102 | 3143 | // |
3103 | 3144 | // Setup hooks for CrashFixHacks |
@@ -3169,6 +3210,8 @@ void CMultiplayerSA::InitHooks_CrashFixHacks() |
3169 | 3210 | EZHookInstall(FxPrim_c__Enable); |
3170 | 3211 | EZHookInstall(CFire_ProcessFire); |
3171 | 3212 |
|
| 3213 | + EZHookInstall(CColModel_MakeMultipleAlloc); |
| 3214 | + |
3172 | 3215 | // Install train crossing crashfix (the temporary variable is required for the template logic) |
3173 | 3216 | void (*temp)() = HOOK_TrainCrossingBarrierCrashFix<RETURN_CObject_Destructor_TrainCrossing_Check, RETURN_CObject_Destructor_TrainCrossing_Invalid>; |
3174 | 3217 | HookInstall(HOOKPOS_CObject_Destructor_TrainCrossing_Check, (DWORD)temp, 5); |
|
0 commit comments