PHP RtlCompressBuffer & RtlDecompressBuffer

AceInfinity

Emeritus, Contributor
Joined
Feb 21, 2012
Posts
1,728
Location
Canada
I seen a reference to these functions during some debugging, and thought I'd see how they do for file compression...

Here's some code I finally put together after some time, and it works pretty well:
Code:
#include <iostream>
#include <Windows.h>
#include <fstream>

typedef unsigned long NTSTATUS;

#define STATUS_SUCCESS                 ((NTSTATUS)0x00000000UL)
#define STATUS_BUFFER_ALL_ZEROS        ((NTSTATUS)0x00000117UL)
#define STATUS_INVALID_PARAMETER       ((NTSTATUS)0xC000000DUL)
#define STATUS_UNSUPPORTED_COMPRESSION ((NTSTATUS)0xC000025FUL)
#define STATUS_NOT_SUPPORTED_ON_SBS    ((NTSTATUS)0xC0000300UL)
#define STATUS_BUFFER_TOO_SMALL        ((NTSTATUS)0xC0000023UL)
#define STATUS_BAD_COMPRESSION_BUFFER  ((NTSTATUS)0xC0000242UL)

HMODULE ntdll = GetModuleHandle("ntdll.dll");

typedef NTSTATUS(__stdcall *_RtlCompressBuffer)(
   USHORT CompressionFormatAndEngine,
   PUCHAR UncompressedBuffer,
   ULONG UncompressedBufferSize,
   PUCHAR CompressedBuffer,
   ULONG CompressedBufferSize,
   ULONG UncompressedChunkSize,
   PULONG FinalCompressedSize,
   PVOID WorkSpace
);

typedef NTSTATUS(__stdcall *_RtlDecompressBuffer)(
   USHORT CompressionFormat,
   PUCHAR UncompressedBuffer,
   ULONG UncompressedBufferSize,
   PUCHAR CompressedBuffer,
   ULONG CompressedBufferSize,
   PULONG FinalUncompressedSize
);

typedef NTSTATUS(__stdcall *_RtlGetCompressionWorkSpaceSize)(
   USHORT CompressionFormatAndEngine,
   PULONG CompressBufferWorkSpaceSize,
   PULONG CompressFragmentWorkSpaceSize
);

void get_ntstatus_err(NTSTATUS ntstatus)
{
   switch (ntstatus) {
   case STATUS_BUFFER_ALL_ZEROS:
      std::cout << "Error: STATUS_BUFFER_ALL_ZEROS";
      break;
   case STATUS_INVALID_PARAMETER:
      std::cout << "Error: STATUS_INVALID_PARAMETER";
      break;
   case STATUS_UNSUPPORTED_COMPRESSION:
      std::cout << "Error: STATUS_UNSUPPORTED_COMPRESSION";
      break;
   case STATUS_NOT_SUPPORTED_ON_SBS:
      std::cout << "Error: STATUS_NOT_SUPPORTED_ON_SBS";
      break;
   case STATUS_BUFFER_TOO_SMALL:
      std::cout << "Error: STATUS_BUFFER_TOO_SMALL";
      break;
   case STATUS_BAD_COMPRESSION_BUFFER:
      std::cout << "Error: STATUS_BAD_COMPRESSION_BUFFER";
      break;
   default:
      std::cout << "(Unknown Error)";
   }
   std::endl(std::cout);
}

// ----------------------------------------------------------------------------------------------------
char *get_file_buffer(const char *filepath, int &buffer_len)
{
   std::ifstream ifs(filepath, std::ofstream::binary);
   if (!ifs.is_open()) return 0;
   ifs.seekg(0, ifs.end);
   buffer_len = ifs.tellg();
   ifs.seekg(0, ifs.beg);
   char *buffer = new char[buffer_len];
   ifs.read(buffer, buffer_len);
   return buffer;
}

// ----------------------------------------------------------------------------------------------------
int write_file_buffer(const char *filepath,  char *buffer, int buffer_len)
{
   std::ofstream ofs(filepath, std::ofstream::binary);
   if (!ofs.is_open()) return 1;
   ofs.write(buffer, buffer_len);
   ofs.close();
   return 0;
}
// ----------------------------------------------------------------------------------------------------
UCHAR *compress_buffer(const char *buffer, const ULONG bufferLen, ULONG compBufferLen, ULONG *compBufferSize)
{
   _RtlCompressBuffer RtlCompressBuffer = (_RtlCompressBuffer) GetProcAddress(ntdll, "RtlCompressBuffer");
   _RtlGetCompressionWorkSpaceSize RtlGetCompressionWorkSpaceSize = (_RtlGetCompressionWorkSpaceSize) GetProcAddress(ntdll, "RtlGetCompressionWorkSpaceSize");

   ULONG bufWorkspaceSize;  // Workspace Size
   ULONG fragWorkspaceSize; // Fragmented Workspace Size (Unused)
   NTSTATUS ret = RtlGetCompressionWorkSpaceSize(
                     COMPRESSION_FORMAT_LZNT1 | COMPRESSION_ENGINE_MAXIMUM, // CompressionFormatAndEngine
                     &bufWorkspaceSize,                                     // CompressBufferWorkSpaceSize
                     &fragWorkspaceSize                                     // CompressFragmentWorkSpaceSize
                  );

   if (ret != STATUS_SUCCESS) {
      std::cout << "An error ocurred while trying to calculate the compression workspace size." << std::endl;
      get_ntstatus_err(ret);
      return 0;
   }

   std::cout << "Compression Workspace Size: 0x" << std::hex << bufWorkspaceSize
             << std::dec << " (" << bufWorkspaceSize << ")" << std::endl;

   VOID *workspace = (VOID *)LocalAlloc(LMEM_FIXED, bufWorkspaceSize);
   if (workspace == NULL) {
      std::cout << "Failed to allocate space for workspace" << std::endl;
      return 0;
   }

   UCHAR *compBuffer = new UCHAR[compBufferLen];
   NTSTATUS result = RtlCompressBuffer(
                        COMPRESSION_FORMAT_LZNT1 | COMPRESSION_ENGINE_MAXIMUM, // CompressionFormatAndEngine
                        (UCHAR *)buffer,                                       // UncompressedBuffer
                        bufferLen,                                             // UncompressedBufferSize
                        compBuffer,                                            // CompressedBuffer
                        compBufferLen,                                         // CompressedBufferSize
                        4096,                                                  // UncompressedChunkSize
                        compBufferSize,                                        // FinalCompressedSize
                        workspace                                              // WorkSpace
                     );

   LocalFree(workspace);
   if (result != STATUS_SUCCESS) {
      get_ntstatus_err(result);
      return 0;
   }

   // std::cout << "Compressed DATA: " << compBuffer << std::endl;
   std::cout << "Compressed Length: " << compBufferSize << std::endl;
   return compBuffer;
}

// ----------------------------------------------------------------------------------------------------
UCHAR *decompress_buffer(const char *buffer, const int bufferLen, const int uncompBufferLen, ULONG *uncompBufferSize)
{
   _RtlDecompressBuffer RtlDecompressBuffer = (_RtlDecompressBuffer) GetProcAddress(ntdll, "RtlDecompressBuffer");

   UCHAR *uncompBuffer = new UCHAR[uncompBufferLen];
   NTSTATUS result = RtlDecompressBuffer(
                        COMPRESSION_FORMAT_LZNT1 | COMPRESSION_ENGINE_MAXIMUM, // CompressionFormat
                        uncompBuffer,                                          // UncompressedBuffer
                        uncompBufferLen,                                       // UncompressedBufferSize
                        (UCHAR *)buffer,                                       // CompressedBuffer
                        bufferLen,                                             // CompressedBufferSize
                        uncompBufferSize                                       // FinalUncompressedSize
                     );

   if (result != STATUS_SUCCESS) {
      get_ntstatus_err(result);
      return 0;
   }

   // std::cout << "Uncompressed DATA: " << uncompBuffer << std::endl;
   std::cout << "Uncompressed Length: " << uncompBufferSize << std::endl;
   return uncompBuffer;
}

// ----------------------------------------------------------------------------------------------------

// #define COMPRESS

int main()
{
#ifdef COMPRESS
   const char originalFile[]     = "Z:\\ai.gif";
#endif
   const char compressedFile[]   = "Z:\\ai-compressed.gif";
#ifndef COMPRESS
   const char decompressedFile[] = "Z:\\ai-decompressed.gif";
#endif

#ifdef COMPRESS
   int bufferLen;
   char *buffer = get_file_buffer(originalFile, bufferLen);
   if (buffer == 0) {
      std::cout << "An error ocurred while trying to read the bytes of the specified file into the buffer." << std::endl;
      return 1;
   }
   ULONG realCompSize;
   UCHAR *compressed_buffer = compress_buffer(buffer, bufferLen, bufferLen + 512, &realCompSize);
   if (compressed_buffer == 0) return 1;

   if (write_file_buffer(compressedFile, (char *)compressed_buffer, (int)realCompSize) != 0) {
      std::cout << "An error ocurred while trying to write the bytes of the compressed buffer to a file." << std::endl;
      return 1;
   }
   std::cout << compressed_buffer << std::endl;
#else
   int bufferLen;
   char *buffer = get_file_buffer(compressedFile, bufferLen);
   if (buffer == 0) {
      std::cout << "An error ocurred while trying to read the bytes of the specified file into the buffer." << std::endl;
      return 1;
   }

   ULONG realDecompSize;
   UCHAR *decompressed_buffer = decompress_buffer(buffer, bufferLen, bufferLen * 100, &realDecompSize);
   if (decompressed_buffer == 0) return 1;

   if (write_file_buffer(decompressedFile, (char *)decompressed_buffer, (int)realDecompSize) != 0) {
      std::cout << "An error ocurred while trying to write the bytes of the compressed buffer to a file." << std::endl;
      return 1;
   }
#endif

   return 0;
}
*edit: Cleaned up code a bit.

I was able to compress a file down to 714 bytes from an original 9.18 kb (9408 bytes). That's ~7% of the original filesize...

Right now, I haven't thought of a good way to guess the decompressed size from the compressed size, unless that value is stored. You would have to guess at that based on the compressed filesize.

I've provided an example of a compressed txt file and it's original in an attachment at this url: RtlCompressBuffer & RtlDecompressBuffer. I can successfully compress to the compressed version, and decompress that output file to get back to the original.

Note: Combined with zip, I can get this data down to a compact 310 bytes and probably even less with some trial and error for other compression methods out there before they start producing larger output than input.

Edit: 202 bytes with bzip2.
 
Last edited:
Original file basically looked like this:
Code:
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
00000000000000000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
00000000000000000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
00000000000000000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
00000000000000000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
00000000000000000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
00000000000000000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
00000000000000000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
00000000000000000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
00000000000000000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
00000000000000000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
00000000000000000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
00000000000000000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
00000000000000000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
00000000000000000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
00000000000000000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
00000000000000000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
00000000000000000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
00000000000000000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
00000000000000000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
00000000000000000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000
0000000000000

Result:
2HtwhrN.png
 

Has Sysnative Forums helped you? Please consider donating to help us support the site!

Back
Top