[ Black Fenix's Anti-Debugging Tricks ]
By Black Fenix


  Lesson 0- "Detecting debuggers"

[ ¿WHAT IS A DEBUGGER ? ]


"It could be defined as and integrated software system in a computer system with the purpouse of identify program bugs and provide methods to repair them. This software is usable at the same time the target program is running to be able to collect information about the processes while they are running. A good debugger could have commands to show and modify memory and registers contents , and commands to invoke calls while the data is shown that provide ways to diagnose the bugs in a more efficient way."


[ ¿HOW WE CAN DETECT THEM ?]

Detecting a debugger could be complicated, anyway there are many ways that leads to good results. Some of this methods are using privilegied instructions and its complicated to use them under Windows while running at ring 3 (no problem under DOS), this is due to the fact that windows does not allow us to use this instructions that are needed to comple the detection, we can only use this kind of detections if we are running under ring0, this implies the creation of a VXD or using a trick that allows us to switch to ring0. Nowadays there're a lot of methods that are concentrated in detecting our beloved SoftIce, one of the most common tricks is called MeltIce, this method is the one used by the SoftIce symbol loader to check if SoftIce is loaded, we can find this method in the DLL nmtrans.dll, inside the Softice folder.

Against what you think, detecting a debugger does not offer any protection at all, in reality the protection comes later: What you should do when you detect a debugger? Many applications simply inform the user of this (never do this) and then the application aborts the execution. Other applications are less "friendly" and they abort the execution without showing any message (that's the better way) and many other applicationas just crash the system (note that this is dangerous and can cause lost of data that has nothing to do with the application) other are self-killing applications and destroy itself when a debugger is detected. In my opinion none of the previous methods it's efective, against this cases, the majority of crackers would suspect what's happening and they'll take care of it, the only thing that we can get with this methods is to disturb the cracker work for a while, it'll be better if we act like this:

Continue program execution, the cracker does not suspect anything and he/she would have to search deeply to know that we have detected him/her. Try fool the cracker, we can modify the application behaviour in order to hide what the cracker is looking for, or we can send commands to the debugger to disable the breakpoints and when we exit send another command to enable them (this is possible if you're running under ring 0) this will fool some crackers and many of then will give up.


/*
Function: IsSICELoaded
Description: This method is used by a lot of crypters/compressors, it search the sign 'BCHK' used by the INT 3 that SoftIce hooks
Return: TRUE if SoftIce is loaded
*/

__inline bool IsSICELoaded()
{
    _asm {
      
push ebp
        mov ebp,'BCHK'   
// 'BCHK' -> 4243484Bh
        mov eax,4          
  // Function 4h
        int 3                    
// call int 3
        cmp al,3             
// compare AL with 3
        setnz al             
// if <> SoftIce is loaded
        pop ebp

    }
}

Crackers could detect this method with the following breakpoint interrupt:

BPINT 3 if al==4

Now you can modify EBP contents to bypass the detection.


/*
Function: IsSICELoaded2
Description: This method is used by a lot of crypters/compresors it uses INT 41, this interrupt is used by Windows debugging interface to detect if a debugger is present. Only works under Windows.
Returns: TRUE if a debugger is detected
*/

__inline bool IsSICELoaded2()
{
    _asm {
      
mov eax,0x4f                     // AX = 004Fh
     
  int 0x41                             // INT 41 CPU - MS Windows debugging kernel - DEBUGGER INSTALLATION CHECK
      
cmp ax,0xF386                  // AX = F386h if a debugger is present
      
jz SoftICE_detected
        xor eax,eax
SoftICE_detected:

    }
}

Crackers can use this breakpoint to detect this method:

BPINT 41 if al==4f

Now you can modify whatever you want to bypas the detection.


/*
Function: IsSICELoaded3
Description: Like the previous one but using INT 68. Only works under Windows
Returns: TRUE if a debugger is detected
*/

__inline bool IsSICELoaded3()
{
    _asm {
        mov ah,0x43
        int 0x68
        cmp ax,0xF386
        jz SoftICE_Detected
        xor eax,eax
SoftICE_detected:

    }
}

Crackers can use this breakpoint to detect this method:

BPINT 68 if ah==43


/* Funcion IsSICELoaded4
Description: The next methods only works under ring0 or under a DOS application, it uses the multiplex interrupt 2fh used by windows to get and entry point to a VXD that its identified by the value passed in BX (i.e SoftIce ID = 0202h).
Returns: TRUE if SoftIce Loaded
*/

__inline bool IsSICELoaded4()
{
    _asm {
        xor di,di
        mov es,di
        mov ax, 1684h
        mov bx, 0202h
// VxD ID of winice
        int 2Fh
        mov ax, es
     // ES:DI -> VxD API entry point
        add ax, di
        test ax,ax
        jnz SoftICE_Detected

    }
}

Crackers can detect this method with the following breakpoint

BPINT 2f if (ax==1684) && (bx=0202)


// Function: IsSoftIce9xLoaded
// Description: Checks if SoftIce's VXD is loaded. It uses the API function CreateFile
// Returns: TRUE si SoftIce está en memoria.

__inline BOOL IsSoftIce9xLoaded()
{
    HANDLE hFile;

  
// "\\.\SICE" without esc sequences
    hFile = CreateFile( "\\\\.\\SICE",    
                        GENERIC_READ | GENERIC_WRITE,
                        FILE_SHARE_READ | FILE_SHARE_WRITE,
                        NULL,
                        OPEN_EXISTING,
                        FILE_ATTRIBUTE_NORMAL,
                        NULL);

  
// If a valid handle is returned, SoftIce is loaded
    if( hFile != INVALID_HANDLE_VALUE )
    {
       CloseHandle(hFile);   
// closes the handle
        return TRUE;             
// and returns TRUE
    }
    return FALSE;                
// SoftIce not detected
}

// Function: IsSoftIceNTLoaded
// Description: Like the previous one but for use under Win NT only
// Returns: TRUE if SoftIce is loaded

__inline BOOL IsSoftIceNTLoaded()
{
    HANDLE hFile;

   
// "\\.\NTICE" without esc sequences
    hFile = CreateFile( "\\\\.\\NTICE",
                        GENERIC_READ | GENERIC_WRITE,
                        FILE_SHARE_READ | FILE_SHARE_WRITE,
                        NULL,
                        OPEN_EXISTING,
                        FILE_ATTRIBUTE_NORMAL,
                        NULL);

    if( hFile != INVALID_HANDLE_VALUE )
    {
        CloseHandle(hFile);
        return TRUE;
    }

    return FALSE;
}

This two last methods are called MeltIce and are the most frequently used to detect SoftIce, but is one of the most easiest to detect and fool. If you decide to use this method never pass the string with the VXD name like in the example, if you do it like this, the string will appear in the EXE file as a readable string, and the cracker would bypass the detection by changing the string to anything less "dangerous". Anyway if we create the string dinamically or char by char there is always a way to detect , it's simple cause you're using API and API sucks against cracking, the following breakpoint will detect this method.

BPX CreateFileA if *(esp->4+4)=='SICE' || *(esp->4+4)=='SIWV' || *(esp->4+4)=='NTIC'

The working is easy, it compares the string passed to the function as the first argument with one of the following SICE o NTIC (it adds 4 to skip the string '\\.\' ), if one of this strings is found the breakpoints takes place (notice the use of the conditional == and the logic operand ||, like in C sintax ). When the breakpoints occurs we only have to modify the string to anything different (of course do not put here a VXD that exists).

You can use the
methods to detect breakpoints , anyway this methods could be defeated with many trouble at all. This leaves MeltIce as one of the most innocents ways of detecting a debugger coz you're using API and API is always cracker friendly :).

That's all by now, there are many methods outthere but this ones are the most used ones. Perhaps it's time to another advanced lesson on debugger detection.



You are inside Reversed Minds pages.

por Mr. Silver / WKT!
La información aquí vertida es exclusivamente para uso educacional, no puedo hacerme responsable del uso que se haga de esta, por lo que atiendo a la honradez de cada uno :), recuerda que debes comprar el software que utilices :)