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


  Lección 0- "Detección de debuggers"

[ ¿QUE ÉS UN DEBUGGER ? ]


"Se podría definir como un sistema de software integrado en un sistema informático con el fín de identificar los errores lógicos de los programas (bugs) y proporcionar medios para enmendarlos. Tal software es utilizable al propio tiempo que se hacen funcionar los programas al objeto de que facilite información relativa a los procesos mientras estos están teniendo lugar. Un buen depurador (debugger) puede disponer de mandatos para mostrar el contenido de la memoria y de los registros, e incluso para modificarlos, y para provocar la ejecución de rutinas durante la presentación de datos importantes que faciliten el diagnóstico de fallos."


[ ¿CÓMO PODEMOS DETECTARLOS ?]

La detección de un debugger puede resultar complicada, aún así existen metodos muy sencillos que ofrecen buenos resultados. Algunos de estos métodos utilizan instrucciones privilegiadas y resulta complejo utilizarlos cuando nuestra aplicación se ejecuta bajo Windows en ring3 (no problem bajo DOS), esto se debe a que Windows no nos permite utilizar las instrucciones privilegiadas necesarias para completar la detección, este tipo de detecciónes solo las podremos realizar si estamos en ring0 (máximo privilegio), lo cual implica la creación de un VXD o la utilización de algún truco que nos permita entrar en ring0. Cabe destacar tambíen la proliferación de métodos que detectan exclusivamente a nuestro debugger preferido: SoftIce,uno de los más utilizados, se denomina MeltIce, también es el más conocido y es el utilizado por los creadores del SoftIce para comprobar si este está en memória, podemos encontrarlo en la DLL nmtrans.dll dentro del directorio donde se encuentra el SoftIce.

Frente a lo que contrariamente puedas creer, la detección de un debugger no ofrece en si ningúna protección,  en realidad la protección se deriva después: Que hacer una vez se ha detectado la presencia de un debugger ?Muchas aplicaciones simplemente informan al usuario mediante algun cuadro de diálogo (esto nunca se debe hacer) y después finalizan la aplicación. Otras aplicaciones son ménos "consideradas" y se limitan a finalizar la aplicación sin mostrar mensaje alguno (este es un sistema aceptable) y las hay que son más agresivas y ponen en peligro la integridad de nuestra máquina realizando un cuelgue inmediato (esto es muy peligroso y puede llegar a destruir información de otras aplicaciones), y los hay que se autodestruyen. En mi opinión ninguno de los métodos anteriores resulta efectivo, frente a estos casos,la mayoría de los crackers sospecharian lo que sucede y tomarian medidas inmediatas, lo único que ganariamos es dificultar por momentos el trabajo del cracker. Sería más efectivo actuar de la siguiente manera:

Continuar la ejecución del programa, el cracker no sospechará que le hemos detectado y deberá investigar si desea saber con certeza que le hemos detectado. Intentar volver loco al cracker, podemos alterar el funcionamiento de la aplicación para que el cracker no encuentre lo que busca, o incluso podemos enviar comandos al debugger que desactiven los breakpoints (esto es posible si somos capaces de entrar en ring0) y al finalizar la aplicación los volvemos a activar, esto confundirá a muchos crackers y se pasarán un buen rato pensando porqué no funcionan sus breakpoints.


/*
Función: IsSICELoaded
Descripción: Este método de detección es utilizado por la mayoría de compresores/encriptadores que puedes encontrar en internet, se basa en la busqueda de la firma 'BCHK' usando la INT 3 que el SoftIce intercepta para sus servicios. Funciona tanto con MS-DOS como con Windows.
Retorna: TRUE si se detecta SoftIce
*/

__inline bool IsSICELoaded()
{
    _asm {
       push ebp
        mov ebp,'BCHK'   
// 'BCHK' -> 4243484Bh

        mov eax,4          
  // Función 4h
        int 3                    
// Llama a la Interrupción 3
        cmp al,3             
// compara AL con 3
        setnz al             
// si no es igual, SoftIce está presente
        pop ebp

    }
}

El método anterior es uno de los más sencillos de implementar, se basa en el uso de la INT 3 servicio 4h, cuando se le basa el valor 'BCHK' (BoundsChecker) en EBP, esta retornará un valor diferente a 3 en AL. Los crackers suelen defenderse de este método con un breakpoint de interrupción como el siguiente:

BPINT 3 if al==4

Este breakpoint nos permitirá modificar el valor oportuno y así evitar la detección del SoftIce.


/*
Función: IsSICELoaded2
Descripción: Método de detección muy usado por los compresores/encriptadores, se basa en la INT 41, esta interrupción es utilizada por windows para comprobar si hay un debugger instalado. Solo funciona bajo Windows.
Retorna: TRUE si se detecta SoftIce

*/

__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 su hay un debugger presente
       jz SoftICE_detected
        xor eax,eax
SoftICE_detected:

    }
}

El método anterior es también uno de los más sencillos de implementar, se basa en el uso de la INT 41 servicio 4fh esta retorna el valor F386h si hay un debugger presente. Los crackers suelen defenderse de este método con un breakpoint de interrupción como el siguiente:

BPINT 41 if al==4f

Este breakpoint nos permitirá modificar el valor oportuno y así evitar la detección de cualquier debugger que se este ejecutando.


/*
Función: IsSICELoaded3
Descripción: Método de detección muy usado por los compresores/encriptadores, similar al anterior pero usando la INT 68. Solo funciona bajo Windows.
Retorna: TRUE si se detecta SoftIce
*/

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

    }
}

Parecido al anterior pero usando la INT 68, Los crackers suelen defenderse de este método con un breakpoint de interrupción como el siguiente:

BPINT 68 if ah==43


/* Funcion IsSICELoaded4
Descripción: El siguiente método sólo funciona si la aplicación se está ejecutando en modo real (MS-DOS), se basa en el uso de la Interrupción 2Fh, utilizada por Windows para obtener un punto de entrada al dispositivo VXD identificado en el registro BX, el   Identificador del SoftIce es 0202h
*/

__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

    }
}

Los crackers suelen defenderse de este método con un breakpoint de interrupción como el siguiente:

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


// Función: IsSoftIce9xLoaded
// Descripción: Comprueba si el controlador VXD del SoftIce para Win 9x está cargado en memória, para ello utiliza la función
// CreateFile del API de Windows, esta función se encarga (entre otras cosas) de establecer comunicación con los
// dispositivos VXD.
// Retorna: TRUE si SoftIce está en memoria.

__inline BOOL IsSoftIce9xLoaded()
{
    HANDLE hFile;

   // "\\.\SICE" sin las secuencias de escape
    hFile = CreateFile( "\\\\.\\SICE",    
                        GENERIC_READ | GENERIC_WRITE,
                        FILE_SHARE_READ | FILE_SHARE_WRITE,
                        NULL,
                        OPEN_EXISTING,
                        FILE_ATTRIBUTE_NORMAL,
                        NULL);

   // Si se retorna un handle válido, SoftIce está en memória
    if( hFile != INVALID_HANDLE_VALUE )
    {
       CloseHandle(hFile);   
// cierra la comunicación con el VXD
        return TRUE;              // y devuelve TRUE
    }
    return FALSE;                 // SoftIce no detectado
}

// Función: IsSoftIceNTLoaded
// Descripción: Comprueba si el controlador VXD del SoftIce para NT está cargado en memória, para ello utiliza la función
// CreateFile del API de Windows, esta función se encarga (entre otras cosas) de establecer comunicación con los
// dispositivos VXD.
// Retorna: TRUE si SoftIce está en memoria.

__inline BOOL IsSoftIceNTLoaded()
{
    HANDLE hFile;

    // "\\.\NTICE" sin las secuencias de escape
    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;
}

Este método se denomina MeltIce, es de los más utilizados para detectar la presencia del SoftIce pero también es uno de los más fáciles de engañar. Si te decides por usar este metodo, nunca pases la cadena que hace referencia al VXD como en el ejemplo, ya que si lo haces así, está aparecerá dentro del ejecutable como una cadena legible, por lo que solo tendremos que buscar dentro del ejecutable la cadena 'SICE' o 'NTICE' con un editor hexadecimal y reemplazarla por cualquier otro valor como 'XICE', anulando por completo nuestro sistema de protección (esto sucede la mayoría de los casos). Incluso si creamos la cadena dinámicamente  caracter a caracter, siempre podemos detectar este metodo con un breakpoint condicional sobre la función CreateFile:

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

El funcionamiento de este breakpoint es sencillo, se comprueba que el primer parametro pasado a la función CreateFileA apunte a la cadena SICE o NTIC (se suma 4 para omitir la cadena '\\.\' de caracteres de longitud), si se cumple esta condición, el breakpoint se ejecuta (Notese el uso del condicional == y la operación lógica ||, similar a la sintaxis del lenguaje C).Cuando el breakpoint surta efecto, sólo deberemos modificar la cadena pasada para que contenga cualquier otro nombre que no sea un VXD de Windows.

Puedes utilizar los metodos para detectar si hay un breakpoint sobre la función CreateFile, pero estos metodos, también pueden ser detectados. Lo cual deja a este sistema como uno de los más inocentes ante un cracker. Esto es debido a que depende de la DLL kernel32 que contiene la función CreateFileA, y los sistemas de protección que dependen de DLL externas, son como ya sabemos fáciles de detectar.

Pues hasta aquí lo que se daba, estos son los métodos más básicos que existen para la detección del SoftIce o de cualquier otro debugger que se ejecute bajo Windows, existen algunos más, pero estos son más complicados y serán comentados en otro lección.



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 :)