Results 1 to 12 of 12

Thread: NtSetDebugFilterState as Anti-Dbg Trick

  1. #1
    Registered User
    Join Date
    Aug 2005
    Blog Entries

    NtSetDebugFilterState as Anti-Dbg Trick

    The following paper will uncover some intersting Undocumented functions relative to Windows Debugging Support. NT is capable of generating and collecting text Debug Messages with an high grade of customization. User-mode and kernel-mode drivers use different routines to send output to the debugger.

    User Mode: Uses OutputDebugString, that sends a null-terminated string to the debugger of the calling process. In a user-mode driver, OutputDebugString displays the string in the Debugger Command window. If a debugger is not running, this routine has no effect. OutputDebugString does not support the variable arguments of a printf formatted string.

    Kernel Mode: Uses DbgPrint, that displays output in the debugger window. This routine supports the basic printf format parameters. Only kernel-mode drivers can call DbgPrint. There is also DbgPrintEx that is similar to DbgPrint, but it allows you to "tag" your messages. When running the debugger, you can permit only those messages with certain tags to be sent. This allows you to view only those messages that you are interested in.

    This operation is called Filtering Debug Messages, how it works is a little bit undocumented, to understand how to go inside this aspect, let's start from DbgPrint / DbgPrintEx.

    In Windows XP, DbgPrint has been extended by adding _vDbgPrintExWithPrefix, in this way DbgPrint and DbgPrintEx became wrappers of this function.

      vDbgPrintExWithPrefix	(
    	IN PCCH	Prefix,
    	IN ULONG    ComponentId,
    	IN ULONG    Level,
    	IN PCCH     Format,
    	IN va_list  arglist
    vDbgPrintExWithPrefix routine sends a string to the kernel debugger if certain conditions are met. This routine can append a prefix to debugger output to help organize debugging results.

    Let's see what ComponentId means:

    The component that is calling this routine. This parameter must be one of the component name filter IDs that are defined in Dpfilter.h. Each component is referred to in different ways, depending on the context. In the ComponentId parameter of DbgPrintEx, the component name is prefixed with DPFLTR_ and suffixed with _ID. In the registry, the component filter mask has the same name as the component itself. In the debugger, the component filter mask is prefixed with Kd_ and suffixed with _Mask.

    Now let's see Level parameter:

    The severity of the message that is being sent. This parameter can be any 32-bit integer. Values between 0 and 31 (inclusive)) are treated differently than values between 32 and 0xFFFFFFFF.
    Filter masks that are created by the debugger take effect immediately and persist until Windows is restarted.

    The debugger can override a value that is set in the registry, but the component filter mask returns to the value that is specified in the registry if the computer is restarted. There is also a system-wide mask called WIN2000. By default, this mask is equal to 0x1, but you can change it through the registry or the debugger like all other components. When filtering is performed, each component filter mask is first combined with the WIN2000 mask by using a bitwise OR. In particular, this combination means that components whose masks have never been specified default to 0x1.

    By inspecting deeply vDbgPrintExWithPrefix we can see that it represent a wrap around NtQueryDebugFilterState that retrieves the state of the selected Debug Filter Mask. By inspecting xRefs we discover that NtQueryDebugFilterState is also used by DbgQueryDebugFilterState()

    NTSTATUS __stdcall DbgQueryDebugFilterState(ULONG ComponentId, ULONG Level)
    0045000C 	ComponentId     = dword ptr  8
    0045000C 	Level           = dword ptr  0Ch
    0045000C     mov     edi, edi
    0045000E     push    ebp
    0045000F     mov     ebp, esp
    00450011     pop     ebp
    00450012     jmp     NtQueryDebugFilterState
    00450012 _DbgQueryDebugFilterState end proc
    As is obvious, DbgQueryDebugFilterState asks for the actual state of Debug Filters. Near the Query function we can see DbgSetFilterState()

    NTSTATUS __stdcall DbgSetDebugFilterState(ULONG ComponentId, ULONG Level, BOOLEAN State)
    0045001C     mov     edi, edi
    0045001E     push    ebp
    0045001F     mov     ebp, esp
    00450021     pop     ebp
    00450022     jmp     NtSetDebugFilterState
    00450022     DbgSetDebugFilterState endp
    DbgSetDebugFilterState is a wrapper of a native NtSetDebugFilterState(ULONG ComponentId, ULONG Level, BOOLEAN State)
    As you can understand this is an intersting API cause attempts to modify the Debug Filter Mask:

    0056384C NtSetDebugFilterState(ULONG ComponentId, unsigned int Level, char State)
    0056384C	  mov     edi, edi
    0056384E      push    ebp
    0056384F      mov     ebp, esp
    00563851      mov     eax, large fs:124h       ;KTHREAD
    00563857      movsx   eax, byte ptr [eax+140h] ;KTHREAD->PreviousMode
    0056385E      push    eax             
    0056385F      push    ds:_SeDebugPrivilege.HighPart
    00563865      push    ds:_SeDebugPrivilege.LowPart ;PrivilegeValue
    0056386B      call    SeSinglePrivilegeCheck
    00563870      test    al, al
    00563872      jz      short loc_5638BE ;If PrivilegeValue does not match, exit 							and return 0xC00000022 error
    SeSinglePrivilegeCheck checks for the passed privilege value in the context of the current thread, If PreviousMode is KernelMode, the privilege check always succeeds. Otherwise, this routine uses the token of the user-mode thread to determine whether the current (user-mode) thread has been granted the given privilege.
    Here the rest of the function

    v3 = &Kd_WIN2000_Mask;
     if ( ComponentId >= KdComponentTableSize )
          if ( ComponentId != 0xFFFFFFFF )
            return 0xC00000EF;
          v3 = (int *)*(&KdComponentTable + ComponentId);
        if ( Level <= 0x1F )
          v4 = 1 << (char)Level;
          v4 = Level;
        v6 = v4;
        if ( !State )
          v6 = 0;
        *v3 = v6 | *v3 & ~v4;
        result = STATUS_SUCCESS;
    Now we can implement a little Anti-Debug trick based on Debug State Awareness, indeed with NtSetDebugFilterState we are able to determine if the process is debugged or not:

    #define WIN32_LEAN_AND_MEAN
    #include <Windows.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include "ntDefs.h"
    #pragma comment(lib,"ntdll.lib")
    int main(void)
    	NTSTATUS ntStatus;
    	ntStatus = NtSetDebugFilterState(0,0,TRUE);
    	if (ntStatus != STATUS_SUCCESS)
    		MessageBoxA(NULL,"Not Debugged","Warning",MB_OK);		
    	return (EXIT_SUCCESS);
    -> ntDefs.h

    typedef LONG NTSTATUS;
    #define STATUS_SUCCESS ((NTSTATUS)0x00000000L)
    extern "C"
    ULONG __stdcall 
    					 ULONG ComponentId,
    					 ULONG Level,
    					 BOOLEAN State					 
    Trick is really basilar if the Process is Debugged NtSetDebugFilterState returns STATUS_SUCCESS else returns 0xC00000022 Error Code. May be that this trick is already used, but for sure I haven's seen nothing about NtQueryDebugFilterState/NtSetDebugFilterState =)


    Thanks to #bug channel especially ratsoul 'n swirl

    Giuseppe 'Evilcry' Bonfa'
    Last edited by evilcry; January 9th, 2009 at 13:58.

  2. #2
    Musician member evaluator's Avatar
    Join Date
    Sep 2001
    Blog Entries
    at the and of paper imho WILL GOOD, if you open-big-secret:
    which debugger will affected by this trick?

  3. #3
    ring3 debuggers for sure

  4. #4
    Registered User
    Join Date
    Aug 2005
    Blog Entries

    Tested on WinDBG, VS Debugger and IDA 5.2 works,
    in IDA causes also a crash in idag.exe, I'm working to discover why this happens.

    Untested in Olly and Syser

    Giuseppe 'Evilcry' Bonfa' (Repository)

  5. #5
    I tested it with Olly and something weird happened.
    The first time I open the program it returns not debugged, afterwards it always detects the debugger.


    In my case it only fails to detect the debugger when I open the program for the first time using olly's shell extension.
    Last edited by Cthulhu; January 13th, 2009 at 07:00.

  6. #6
    Registered User
    Join Date
    Aug 2005
    Blog Entries
    Great Information!

    Thanks for you contribution!

    The worst thing happens in IDA that deadly crashes! (Repository)

  7. #7
    Super Moderator Shub-nigurrath's Avatar
    Join Date
    May 2004
    Obscure Kadath
    I tried to implement it and what I always have is a positive result, even outside of any debugger, always and only positive results.
    I honestly didn't investigate it any further, just blindly implemented it like you said. I'm with XP SP3.
    (`._.[*~-.,.-~* ŜħůβŇĝŕřāŧħ ₪*~-.,.-~*]._.)
    There are only 10 types of people in the world: Those who understand binary, and those who don't

  8. #8
    when i run on Windows 7 with Olly not affect , always "Not Debugged"
    Last edited by GI4C4T; August 9th, 2009 at 05:58.
    I promise that I have read the FAQ and tried to use the Search to answer my question.

  9. #9
    The call to the "NtQueryDebugFilterState" function succeeds only if the process has the "SeDebugPrivilege" privilege. It should not be considered an anti-debug trick. But it's as useful as the "CsrGetProcessId/OpenProcess" trick.

  10. #10
    ProcessBreakOnTermination, ThreadBreakOnTermination, SystemFlagsInformation, SystemVerifierInformation
    or get(NtPrivilegeCheck etc).

    IsDebugPrivilege proc
    Local Info:BOOLEAN
    	mov Info,FALSE
    	invoke ZwSetInformationThread, NtCurrentThread, ThreadBreakOnTermination, addr Info, sizeof(ULONG)
    	.if !Eax
    		mov eax,TRUE
    		mov eax,FALSE
    IsDebugPrivilege endp
    Last edited by Indy; August 21st, 2012 at 23:20.

  11. #11
    hurray SoftICE is not affected from this

  12. #12
    Quote Originally Posted by Indy View Post

    ProcessBreakOnTermination, ThreadBreakOnTermination, SystemFlagsInformation, SystemVerifierInformation
    or get(NtPrivilegeCheck etc).
    Also, ProcessInstrumentationCallback 0x28. It is generally any system call that wraps up the following code or similar.

    PAGE:00000001403D34A3 mov rcx, cs:SeDebugPrivilege
    PAGE:00000001403D34AA call SeSinglePrivilegeCheck
    PAGE:00000001403D34AF cmp al, sil
    PAGE:00000001403D34B2 jnz short PrivOkay
    PAGE:00000001403D34B4 mov eax, 0C0000061h ; PRIVILEGE_NOT_HELD
    PAGE:00000001403D34B9 jmp ENDDDD

    You will find more if you search ntoskrnl.

Similar Threads

    By walied in forum Advanced Reversing and Programming
    Replies: 9
    Last Post: October 1st, 2012, 08:31
  2. Yet Another Anti-Debug Trick
    By walied in forum Malware Analysis and Unpacking Forum
    Replies: 0
    Last Post: January 22nd, 2012, 11:31
  3. RtlQueryProcessHeapInformation as Anti-Dbg Trick
    By evilcry in forum Blogs Forum
    Replies: 0
    Last Post: April 14th, 2009, 12:18
  4. RtlQueryProcessDebugInformation as Anti-Dbg Trick
    By evilcry in forum Blogs Forum
    Replies: 2
    Last Post: April 12th, 2009, 00:31
  5. Is This A New Anti Debug Trick
    By DaBoo in forum The Newbie Forum
    Replies: 6
    Last Post: June 15th, 2007, 10:15


Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts