NtSetInformationThread

Created the Monday 18 March 2019. Updated 3 years, 6 months ago.

NtSetInformationThread can be used to hide threads from debuggers using the ThreadHideFromDebugger ThreadInfoClass (0x11 / 17). This is intended to be used by an external process, but any thread can use it on itself.

After the thread is hidden from the debugger, it will continue running but the debugger won’t receive events related to this thread. This thread can perform anti-debugging checks such as code checksum, debug flags verification, etc.


Technique Identifier

U0119

Technique Tag

NtSetInformationThread


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.

Detection Rules

rule Detect_NtSetInformationThread: AntiDebug {
    meta: 
        description = "Detect NtSetInformationThread as anti-debug"
        author = "Unprotect"
        comment = "Experimental rule"
    strings:
        $1 = "NtSetInformationThread" fullword ascii
    condition:   
       uint16(0) == 0x5A4D and filesize < 1000KB and $1
}

Additional Resources

External Links

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.