Counter-Strike Online 2 (.VTF) Modified with LZMA

Extraction and unpacking of game archives and compression, encryption, obfuscation, decoding of unknown files
cra0
Posts: 17
Joined: Fri Aug 08, 2014 12:51 am

Counter-Strike Online 2 (.VTF) Modified with LZMA

Post by cra0 »

have yet to figure this out

Hey, I've been trying to figure this out but have had no luck at all I'm not sure if ekeys unpacker is at blame or something is going on weird but Counter-Strike Online 2's VTF textures just refuse to decompress. Well the VTF header + all the mips do successfully decompress however the largest mip LZMA block fails

Here is what the files look like
Image

it uses LZMA in the format of

Code: Select all

byte   LZMA[4]
uint32 size
uint32 zsize
byte   Lzmaprops[5]


So for example the first LZMA block decompresses to this and each MIP of the texture follows which is another LZMA block.
Image
Get to the last LZMA block and it just fails. I dump the buffer before the lzma bad data exception and the result is an image chopped up here is what i mean look.
The first 2 Mips are broken but the rest are fine
Image


The function which decompresses the lzma seems normal I don't understand whats going on why is it failing :(

Code: Select all

vtf_lzma_header *__stdcall LzmaVtfDecode(vtf_lzma_header *lzmaHeader, unsigned __int8 *outputBuffer)
{
  vtf_lzma_header *lzmaHeader2; // ebx@1
  unsigned int uncompressedLength; // ebp@4
  unsigned int *probs; // esi@5
  signed int decodeResult; // edi@5
  vtf_lzma_header *result; // eax@6
  CLzmaDecoderState state; // [sp+10h] [bp-14h]@5

  lzmaHeader2 = lzmaHeader;
  if ( !lzmaHeader
    || !outputBuffer
    || lzmaHeader->lzmaMagic != 0x414D5A4C
    || (uncompressedLength = lzmaHeader->uncompressedLength) == 0 )
    goto LABEL_8;
  LzmaDecodeProperties(&state.Properties, lzmaHeader->decoderProperties);
  probs = (unsigned int *)(*(int (__thiscall **)(_DWORD, _DWORD))(**(_DWORD **)&byte_14F5E214[140] + 4))(
                            *(_DWORD *)&byte_14F5E214[140],
                            4 * (768 << (LOBYTE(state.Properties.lp) + state.Properties.lc)) + 0x1CD8);// allocFunc & LzmaGetNumProbs
  state.Probs = probs;
  decodeResult = LzmaDecode(
                   &state,
                   lzmaHeader2->data,
                   lzmaHeader2->compressedLength,
                   (unsigned int *)&outputBuffer,
                   outputBuffer,
                   uncompressedLength,
                   (unsigned int *)&lzmaHeader);
  (*(void (__stdcall **)(_DWORD))(**(_DWORD **)&byte_14F5E214[140] + 20))(probs);// freeFunc
  if ( decodeResult || (result = lzmaHeader, lzmaHeader != (vtf_lzma_header *)uncompressedLength) )
  {
    (*(void (**)(const char *, ...))&byte_14F5E214[24])("Decompress Fail. %d", decodeResult);
LABEL_8:
    result = 0;
  }
  return result;
}


Sample files (source engine shared files not only found in CSO2 but alienswarm/dota2/tf2 free2play game)
https://www.dropbox.com/sh/f8jmz3ppqefp ... wGUMF0LVJa

Here are more Samples (since CSO2 runs the Source Engine i found some files in CSS that are the same in CSO2)
https://dl.dropboxusercontent.com/u/107 ... samples.7z

PM me if you want the filesystem dll
aluigi
Site Admin
Posts: 12984
Joined: Wed Jul 30, 2014 9:32 pm

Re: Counter-Strike Online 2 (.VTF) Modified with LZMA

Post by aluigi »

The last LZMA chunk at offset 0xb66f of alyxmonitor_idle.vtf dumps correctly till the following offsets:
- compressed offset 0x6a9
- uncompressed offset 0x88d
I don't see strange code between 0x6a9 and 0x6b0.
cra0
Posts: 17
Joined: Fri Aug 08, 2014 12:51 am

Re: Counter-Strike Online 2 (.VTF) Modified with LZMA

Post by cra0 »

aluigi wrote:The last LZMA chunk at offset 0xb66f of alyxmonitor_idle.vtf dumps correctly till the following offsets:
- compressed offset 0x6a9
- uncompressed offset 0x88d
I don't see strange code between 0x6a9 and 0x6b0.


Yeah it either the lzma chunk headers are wrong which might be likely because the ones in the CO2 header don't match the lzma header values
https://dl.dropboxusercontent.com/u/107 ... m_stdio.7z

here is the filesystem dll and IDA file I don't understand why this is happening. The map files from the game also seem to have lzma compressed blocks

Image
cyanic
Posts: 13
Joined: Wed Aug 13, 2014 1:44 am

Re: Counter-Strike Online 2 (.VTF) Modified with LZMA

Post by cyanic »

What's interesting is where the decompressed cuts off in your gif. Looks like they might cut off at the same byte position? Maybe after a while the decompressor is reset or something? Come to think of it, maybe it's like how in Evolution Engine the data is split into chunks then compressed. There probably aren't mixed compressed/non-compressed chunks, but maybe that's where that value in the CO2 header we never figured out comes in. I suggest finding a large enough texture that is mostly of uniform color, and one that is quite complex and compresses badly, and experimenting with dumping parts of the stream as uncompressed or resetting the LZMA decoder in the middle to test the theory.