Search code examples
windowsdelphidelphi-10.3-riont

Detect whether or not TESTSIGNING is enabled


I'm trying make a translation of this C++ code that was suggested as possible solution to verify if TESTSIGNING is enabled.

My code almost worked fine, but in this part:

while (status = STATUS_BUFFER_OVERFLOW) or (status = STATUS_INFO_LENGTH_MISMATCH) do
begin
  n := Max(br, n * 2);
  ReallocMem(Buffer, n * SizeOf(TSystemCodeIntegrityInformation));
  Status := NtQuerySystemInformation({SystemCodeIntegrityInformation}103, Buffer, n * SizeOf(TSystemCodeIntegrityInformation), @br);
  Writeln('0x'+IntToHex(Status));
end;

where i'm receiving an error:

out of memory

How this can be solved?

Full code:

program test;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  Windows,
  SysUtils,
  Math;

type
  NTSTATUS = DWORD;
  
  TSystemInformationClass = SYSTEM_INFORMATION_CLASS;

  TNativeQuerySystemInformation = function(SystemInformationClass: TSystemInformationClass; SystemInformation: Pointer; SystemInformationLength: ULONG; ReturnLength: PULONG): NTSTATUS; stdcall;
  
  SYSTEM_CODEINTEGRITY_INFORMATION = record
    Length: ULONG;
    CodeIntegrityOptions: ULONG;
  end;
  TSystemCodeIntegrityInformation = SYSTEM_CODEINTEGRITY_INFORMATION;
  PSystemCodeIntegrityInformation = ^TSystemCodeIntegrityInformation;
  
const
  NTDLL_DLL = 'NTDLL.DLL';
  STATUS_SUCCESS = $00000000;
  STATUS_BUFFER_OVERFLOW = $80000005;
  STATUS_INFO_LENGTH_MISMATCH = $C0000004;
  
var
  NtQuerySystemInformation: TNativeQuerySystemInformation = nil;
  NTDLLHandle: THandle = 0;
  UnloadNTDLL: Boolean;
  Buffer: Pointer;
  Status: Cardinal;
  psci: PSystemCodeIntegrityInformation;
  n, br: Cardinal;
  
function InitNativeAPI: Boolean;
begin
  NTDLLHandle := GetModuleHandle(NTDLL_DLL);
  UnloadNTDLL := NTDLLHandle = 0;

  if NTDLLHandle = 0 then
    NTDLLHandle := LoadLibrary(NTDLL_DLL);

  if NTDLLHandle <> 0 then
  begin
    @NtQuerySystemInformation := GetProcAddress(NTDLLHandle, 'NtQuerySystemInformation');
  end;

  Result := (NTDLLHandle <> 0) and Assigned(NtQuerySystemInformation);
end;

procedure FreeNativeAPI;
begin
  if (NTDLLHandle <> 0) and UnloadNTDLL then
  begin
    if not FreeLibrary(NTDLLHandle) then
      raise Exception.Create(Format('Unload Error: %s - 0x%x', [NTDLL_DLL, GetModuleHandle(NTDLL_DLL)]))
    else
      NTDLLHandle := 0;
  end;
end;

begin
  try
    Writeln(InitNativeAPI);

    Buffer := nil;
    n := $100;
    Buffer := AllocMem(n * SizeOf(TSystemCodeIntegrityInformation));
    Status := NtQuerySystemInformation(SystemCodeIntegrityInformation, Buffer, n * SizeOf(TSystemCodeIntegrityInformation), @br);

    while (status = STATUS_BUFFER_OVERFLOW) or (status = STATUS_INFO_LENGTH_MISMATCH) do
    begin
      n := Max(br, n * 2);
      ReallocMem(Buffer, n * SizeOf(TSystemCodeIntegrityInformation));
      Status := NtQuerySystemInformation(SystemCodeIntegrityInformation, Buffer, n * SizeOf(TSystemCodeIntegrityInformation), @br);
      Writeln('0x'+IntToHex(Status));
    end;

    try
      if Status = STATUS_SUCCESS then
      begin
        psci := PSystemCodeIntegrityInformation(Buffer);
        Writeln(IntToHex(psci.CodeIntegrityOptions));
      end;
    finally
      Reallocmem(Buffer, 0);
      Buffer := nil;
    end;

    FreeNativeAPI;
    
    except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
  Readln;
end.

Solution

  • You are allocating way more memory than you need. The C++ code allocates only 1 SYSTEM_CODEINTEGRITY_INFORMATION but you are allocating a huge array of them. That is not necessary.

    But, more importantly, you are not initializing the SYSTEM_CODEINTEGRITY_INFORMATION.Length field before calling NtQuerySystemInformation(), like the C++ code is doing.

    Try this instead:

    program test;
    
    {$APPTYPE CONSOLE}
    
    {$R *.res}
    
    uses
      Windows,
      SysUtils,
      Math;
    
    type
      NTSTATUS = DWORD;
    
      TSystemInformationClass = SYSTEM_INFORMATION_CLASS;
    
      TNativeQuerySystemInformation = function(SystemInformationClass: TSystemInformationClass; SystemInformation: Pointer; SystemInformationLength: ULONG; ReturnLength: PULONG): NTSTATUS; stdcall;
    
      SYSTEM_CODEINTEGRITY_INFORMATION = record
        Length: ULONG;
        CodeIntegrityOptions: ULONG;
      end;
      TSystemCodeIntegrityInformation = SYSTEM_CODEINTEGRITY_INFORMATION;
      PSystemCodeIntegrityInformation = ^TSystemCodeIntegrityInformation;
    
    const
      NTDLL_DLL = 'NTDLL.DLL';
      STATUS_SUCCESS = $00000000;
    
    var
      NtQuerySystemInformation: TNativeQuerySystemInformation = nil;
      NTDLLHandle: THandle = 0;
      UnloadNTDLL: Boolean = False;
      Status: DWORD;
      sci: TSystemCodeIntegrityInformation;
      br: ULONG;
    
    function InitNativeAPI: Boolean;
    begin
      Result := False;
    
      NTDLLHandle := GetModuleHandle(NTDLL_DLL);
    
      if NTDLLHandle = 0 then
      begin
        NTDLLHandle := LoadLibrary(NTDLL_DLL);
        UnloadNTDLL := (NTDLLHandle <> 0);
      end;
    
      if NTDLLHandle <> 0 then
      begin
        @NtQuerySystemInformation := GetProcAddress(NTDLLHandle, 'NtQuerySystemInformation');
        Result := Assigned(NtQuerySystemInformation);
      end;
    end;
    
    procedure FreeNativeAPI;
    begin
      if (NTDLLHandle <> 0) and UnloadNTDLL then
      begin
        if not FreeLibrary(NTDLLHandle) then
          raise Exception.Create(Format('Unload Error: %s - 0x%x', [NTDLL_DLL, GetModuleHandle(NTDLL_DLL)]);
        NTDLLHandle := 0;
      end;
    end;
    
    begin
      try
        Writeln(InitNativeAPI);
        try
          sci.Length := sizeof(sci);
    
          Status := NtQuerySystemInformation(SystemCodeIntegrityInformation, @sci, SizeOf(sci), @br);
          Writeln('0x'+IntToHex(Status));
    
          if Status = STATUS_SUCCESS then
          begin
           Writeln(IntToHex(sci.CodeIntegrityOptions));
          end;
        finally
          FreeNativeAPI;
        end;
      except
        on E: Exception do
          Writeln(E.ClassName, ': ', E.Message);
      end;
      Readln;
    end.