diff options
author | Tom Barham <me@cpdt.dev> | 2022-06-15 08:05:06 +1000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-06-15 00:05:06 +0200 |
commit | 25dbf729cfc75107a0fcf0186924b58ecc05214b (patch) | |
tree | 313d033ea3f557a6a537f46d0b8fd6eb3dce9a48 /NorthstarDedicatedTest/miscserverfixes.cpp | |
parent | b84cd76f671e44a686df6f2b36be6642b0bd24a5 (diff) | |
download | NorthstarLauncher-25dbf729cfc75107a0fcf0186924b58ecc05214b.tar.gz NorthstarLauncher-25dbf729cfc75107a0fcf0186924b58ecc05214b.zip |
Fix segfault on badly formed compressed packets (#160)
* Fix segfault on badly formed compressed packets
* Remove superfluous line
Diffstat (limited to 'NorthstarDedicatedTest/miscserverfixes.cpp')
-rw-r--r-- | NorthstarDedicatedTest/miscserverfixes.cpp | 106 |
1 files changed, 105 insertions, 1 deletions
diff --git a/NorthstarDedicatedTest/miscserverfixes.cpp b/NorthstarDedicatedTest/miscserverfixes.cpp index 30cd5777..ddbfcfbb 100644 --- a/NorthstarDedicatedTest/miscserverfixes.cpp +++ b/NorthstarDedicatedTest/miscserverfixes.cpp @@ -25,4 +25,108 @@ void InitialiseMiscServerFixes(HMODULE baseAddress) } } -void InitialiseMiscEngineServerFixes(HMODULE baseAddress) {}
\ No newline at end of file +typedef unsigned int(__fastcall* CLZSS__SafeUncompressType)( + void* self, const unsigned char* pInput, unsigned char* pOutput, unsigned int unBufSize); +CLZSS__SafeUncompressType CLZSS__SafeUncompress; + +struct lzss_header_t +{ + unsigned int id; + unsigned int actualSize; +}; + +static constexpr int LZSS_LOOKSHIFT = 4; + +// 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. +static unsigned int CLZSS__SafeUncompressHook(void* self, const unsigned char* pInput, unsigned char* pOutput, unsigned int unBufSize) +{ + unsigned int totalBytes = 0; + int getCmdByte = 0; + int cmdByte = 0; + + lzss_header_t header = *(lzss_header_t*)pInput; + + if (pInput == NULL) + { + return 0; + } + if (header.id != 0x53535a4c) + { + return 0; + } + if (header.actualSize == 0) + { + return 0; + } + if (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; + + return 0; +} + +void InitialiseMiscEngineServerFixes(HMODULE baseAddress) +{ + HookEnabler hook; + ENABLER_CREATEHOOK(hook, (char*)baseAddress + 0x432a10, &CLZSS__SafeUncompressHook, reinterpret_cast<LPVOID*>(&CLZSS__SafeUncompress)); +} |