NorthstarLauncher/NorthstarDLL/exploitfixes_lzss.cpp

80 lines
1.7 KiB
C++

#include "pch.h"
AUTOHOOK_INIT()
static constexpr int LZSS_LOOKSHIFT = 4;
struct lzss_header_t
{
unsigned int id;
unsigned int actualSize;
};
// Rewrite of CLZSS::SafeUncompress to fix a vulnerability where malicious compressed payloads could cause the decompressor to try to read
// out of the bounds of the output buffer.
// clang-format off
AUTOHOOK(CLZSS__SafeDecompress, engine.dll + 0x432A10,
unsigned int, __fastcall, (void* self, const unsigned char* pInput, unsigned char* pOutput, unsigned int unBufSize))
// clang-format on
{
unsigned int totalBytes = 0;
int getCmdByte = 0;
int cmdByte = 0;
lzss_header_t header = *(lzss_header_t*)pInput;
if (!pInput || !header.actualSize || header.id != 0x53535A4C || header.actualSize > unBufSize)
return 0;
pInput += sizeof(lzss_header_t);
for (;;)
{
if (!getCmdByte)
cmdByte = *pInput++;
getCmdByte = (getCmdByte + 1) & 0x07;
if (cmdByte & 0x01)
{
int position = *pInput++ << LZSS_LOOKSHIFT;
position |= (*pInput >> LZSS_LOOKSHIFT);
position += 1;
int count = (*pInput++ & 0x0F) + 1;
if (count == 1)
break;
// Ensure reference chunk exists entirely within our buffer
if (position > totalBytes)
return 0;
totalBytes += count;
if (totalBytes > unBufSize)
return 0;
unsigned char* pSource = pOutput - position;
for (int i = 0; i < count; i++)
*pOutput++ = *pSource++;
}
else
{
totalBytes++;
if (totalBytes > unBufSize)
return 0;
*pOutput++ = *pInput++;
}
cmdByte = cmdByte >> 1;
}
if (totalBytes != header.actualSize)
return 0;
return totalBytes;
}
ON_DLL_LOAD("engine.dll", ExploitFixes_LZSS, (CModule module))
{
AUTOHOOK_DISPATCH()
}