{*******************************************************}
{                                                       }
{       Tocsg.NTDLL.Decompress                          }
{                                                       }
{       Copyright (C) 2022 kku                          }
{                                                       }
{*******************************************************}

unit Tocsg.NTDLL.Decompress;

interface

uses
  SysUtils, Winapi.Windows;

const
  COMPRESSION_FORMAT_NONE = 0;
  COMPRESSION_FORMAT_DEFAULT = 1;
  COMPRESSION_FORMAT_LZNT1 = 2;
  COMPRESSION_FORMAT_XPRESS = 3;
  COMPRESSION_FORMAT_XPRESS_HUFF = 4;

  STATUS_SUCCESS = 0;
  STATUS_ACCESS_DENIED = $C0000022;

type
  TRtlHeader = record
    arrSig: array[0..3] of AnsiChar;
    dwSize: DWORD;
  end;

  NTSTATUS = DWORD;
  ULONG = DWORD;
  PULONG = ^ULONG;
  PVOID = Pointer;
  USHORT = WORD;
  UCHAR = Byte;
  PUCHAR = ^UCHAR;
  PWSTR = PWideChar;

TRtlGetCompressionWorkSpaceSize = function(CompressionFormatAndEngine: USHORT;
                                           CompressBufferWorkSpaceSize: PULONG;
                                           CompressFragmentWorkSpaceSize: PULONG): NTSTATUS; stdcall;

TRtlDecompressBufferEx = function(CompressionFormat: USHORT;
                                  UncompressedBuffer: PUCHAR;
                                  UncompressedBufferSize: ULONG;
                                  CompressedBuffer: PUCHAR;
                                  CompressedBufferSize: ULONG;
                                  FinalUncompressedSize: PULONG;
                                  WorkSpace: PVOID): NTSTATUS; stdcall;

function RtlGetCompressionWorkSpaceSize(CompressionFormatAndEngine: USHORT;
                                        CompressBufferWorkSpaceSize: PULONG;
                                        CompressFragmentWorkSpaceSize: PULONG): NTSTATUS; // stdcall external 'ntdll.dll';

function RtlDecompressBufferEx(CompressionFormat: USHORT;
                               UncompressedBuffer: PUCHAR;
                               UncompressedBufferSize: ULONG;
                               CompressedBuffer: PUCHAR;
                               CompressedBufferSize: ULONG;
                               FinalUncompressedSize: PULONG;
                               WorkSpace: PVOID): NTSTATUS; // stdcall external 'ntdll.dll';


function RtlDecompress(pSrc, pDest: Pointer; dwSrcSize, dwDecompSize, dwCompFormat: DWORD): DWORD;

implementation

var
  _hNtdll: THandle = 0;
  _fnRtlGetCompressionWorkSpaceSize: TRtlGetCompressionWorkSpaceSize = nil;
  _fnRtlDecompressBufferEx: TRtlDecompressBufferEx = nil;

function InitNtdllDecompProcedure: Boolean;
begin
  if _hNtdll = 0 then
  begin
    _hNtdll := GetModuleHandle('ntdll.dll');
    if _hNtdll <> 0 then
    begin
      @_fnRtlGetCompressionWorkSpaceSize := GetProcAddress(_hNtdll, 'RtlGetCompressionWorkSpaceSize');
      @_fnRtlDecompressBufferEx := GetProcAddress(_hNtdll, 'RtlDecompressBufferEx');
    end;
  end;
  Result := _hNtdll <> 0;
end;

function RtlGetCompressionWorkSpaceSize(CompressionFormatAndEngine: USHORT;
                                        CompressBufferWorkSpaceSize: PULONG;
                                        CompressFragmentWorkSpaceSize: PULONG): NTSTATUS;
begin
  if InitNtdllDecompProcedure and Assigned(_fnRtlGetCompressionWorkSpaceSize) then
    Result := _fnRtlGetCompressionWorkSpaceSize(CompressionFormatAndEngine,
                                                CompressBufferWorkSpaceSize,
                                                CompressFragmentWorkSpaceSize)
  else
    Result := STATUS_ACCESS_DENIED;

end;

function RtlDecompressBufferEx(CompressionFormat: USHORT;
                               UncompressedBuffer: PUCHAR;
                               UncompressedBufferSize: ULONG;
                               CompressedBuffer: PUCHAR;
                               CompressedBufferSize: ULONG;
                               FinalUncompressedSize: PULONG;
                               WorkSpace: PVOID): NTSTATUS;
begin
  if InitNtdllDecompProcedure and Assigned(_fnRtlDecompressBufferEx) then
    Result := _fnRtlDecompressBufferEx(CompressionFormat,
                                       UncompressedBuffer,
                                       UncompressedBufferSize,
                                       CompressedBuffer,
                                       CompressedBufferSize,
                                       FinalUncompressedSize,
                                       WorkSpace)
  else
    Result := STATUS_ACCESS_DENIED;

end;


function RtlDecompress(pSrc, pDest: Pointer; dwSrcSize, dwDecompSize, dwCompFormat: DWORD): DWORD;
var
  dwOutSize,
  dwResult,
  dwCompBufWorkSpaceSize,
  dwCompFragWorkSpaceSize: DWORD;
  pWorkSpace: array of AnsiChar;
begin
  Result := 0;
  dwResult := RtlGetCompressionWorkSpaceSize(dwCompFormat,
                                             @dwCompBufWorkSpaceSize,
                                             @dwCompFragWorkSpaceSize);
  if dwResult <> STATUS_SUCCESS then
    exit;

  dwOutSize := 0;
  SetLength(pWorkSpace, dwCompBufWorkSpaceSize);
  dwResult := RtlDecompressBufferEx(dwCompFormat,
                                    pDest,
                                    dwDecompSize,
                                    pSrc,
                                    dwSrcSize,
                                    @dwOutSize,
                                    pWorkSpace);
  if dwResult = STATUS_SUCCESS then
    Result := dwOutSize;
end;


end.
