NtSetInformationThread

NtSetInformationThread can be used to hide threads from debuggers using the ThreadHideFromDebugger ThreadInfoClass (0x11 / 17).

The debugger won’t be able to capture any information about running threads affected by this property.

If a breakpoint is placed inside a thread affected by this property, the debugger will likely crash.

U0119

Code Snippets

Jean-Pierre LESUEUR

Description

You can compile this code snippet as a classical Delphi Console Application.

program ADB_NtSetInformationThread;

{$APPTYPE CONSOLE}

uses
  WinAPI.Windows, System.SysUtils;

type
  // ntddk.h
  TThreadInfoClass = (
                        ThreadBasicInformation,
                        ThreadTimes,
                        ThreadPriority,
                        ThreadBasePriority,
                        ThreadAffinityMask,
                        ThreadImpersonationToken,
                        ThreadDescriptorTableEntry,
                        ThreadEnableAlignmentFaultFixup,
                        ThreadEventPair_Reusable,
                        ThreadQuerySetWin32StartAddress,
                        ThreadZeroTlsCell,
                        ThreadPerformanceCount,
                        ThreadAmILastThread,
                        ThreadIdealProcessor,
                        ThreadPriorityBoost,
                        ThreadSetTlsArrayAddress,
                        ThreadIsIoPending,
                        ThreadHideFromDebugger, {<--}
                        ThreadBreakOnTermination,
                        ThreadSwitchLegacyState,
                        ThreadIsTerminated,
                        ThreadLastSystemCall,
                        ThreadIoPriority,
                        ThreadCycleTime,
                        ThreadPagePriority,
                        ThreadActualBasePriority,
                        ThreadTebInformation,
                        ThreadCSwitchMon,
                        ThreadCSwitchPmu,
                        ThreadWow64Context,
                        ThreadGroupInformation,
                        ThreadUmsInformation,
                        ThreadCounterProfiling,
                        ThreadIdealProcessorEx,
                        ThreadCpuAccountingInformation,
                        ThreadSuspendCount,
                        ThreadActualGroupAffinity,
                        ThreadDynamicCodePolicyInfo,
                        MaxThreadInfoClass
  );

  var hNtDll    : THandle;
      AThread   : THandle;
      AThreadId : Cardinal;

      NtSetInformationThread : function(
                                          ThreadHandle : THandle;
                                          ThreadInformationClass : TThreadInfoClass;
                                          ThreadInformation : PVOID;
                                          ThreadInformationLength : ULONG
                                      ) : NTSTATUS; stdcall;

  const
    STATUS_SUCCESS = $00000000;

{-------------------------------------------------------------------------------
  Hide Thread From Debugger
-------------------------------------------------------------------------------}
function HideThread(AThreadHandle : THandle) : Boolean;
var AThreadInformation : ULONG;
    AStatus            : NTSTATUS;
begin
  result := False;
  ///

  if not assigned(NtSetInformationThread) then
    Exit();



  // https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/ntifs/nf-ntifs-ntsetinformationthread
  AStatus := NtSetInformationThread(AThreadHandle, ThreadHideFromDebugger, nil, 0);

  case AStatus of
    {
      STATUS_INFO_LENGTH_MISMATCH
    }
    NTSTATUS($C0000004) : begin
      WriteLn('Error: Status Info Length Mismatch.');
    end;

    {
      STATUS_INVALID_PARAMETER
    }
    NTSTATUS($C000000D) : begin
      WriteLn('Error: Invalid Parameter.');
    end;

    {
      STATUS_SUCCESS
    }
    NTSTATUS($00000000) : begin
      WriteLn(Format('Thread: %d is now successfully hidden from debuggers.', [AThreadHandle]));

      result := True;
    end;

    {
      Other Errors
    }
    else begin
      WriteLn('Error: Unknown.');
    end;
  end;
end;

{-------------------------------------------------------------------------------
  ___thread:example
-------------------------------------------------------------------------------}
procedure ThreadExample(pParam : PVOID); stdcall;
begin
  WriteLn('Example Thread Begin.');


  {
    If we are attached to a debugger, we trigger a new breakpoint.

    If thread is set with hidden from debugger, process should crash.
  }
  if IsDebuggerPresent() then begin
    asm
      int 3
    end;
  end;

  WriteLn('Example Thread Ends.');

  ///
  ExitThread(0);
end;

{-------------------------------------------------------------------------------
  ___entry
-------------------------------------------------------------------------------}
begin
  try
    hNtDll := LoadLibrary('NTDLL.DLL');
    if (hNtDll = 0) then
      Exit();
    try
      @NtSetInformationThread := GetProcAddress(hNtDll, 'NtSetInformationThread');
      if NOT Assigned(NtSetInformationThread) then
        Exit();

      {
        Create an example thread
      }
      SetLastError(0);

      AThread := CreateThread(nil, 0, @ThreadExample, nil, CREATE_SUSPENDED, AThreadId);
      if (AThread <> 0) then begin
        WriteLn(Format('Example thread created. Thread Handle: %d , Thread Id: %d', [AThread, AThreadid]));

        HideThread(AThread);

        ///
        ResumeThread(AThread);

        WaitForSingleObject(AThread, INFINITE);
      end else begin
        WriteLn(Format('Could not create example thread with error: .', [GetLastError()]));
      end;
    finally
      FreeLibrary(hNtDll);
    end;
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
end.

Additional Resources

Subscribe to our Newsletter


The information entered into this form is mandatory. It will be subjected to computer processing. It is processed by computer in order to support our users and readers. The recipients of the data will be : contact@unprotect.it.

According to the Data Protection Act of January 6th, 1978, you have at any time, a right of access to and rectification of all of your personal data. If you wish to exercise this right and gain access to your personal data, please write to Thomas Roccia at contact@unprotect.it.

You may also oppose, for legitimate reasons, the processing of your personal data.