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


  Lección 1- "Cómo detectar si hay breakpoints (BPX) en tus funciones"

[ ¿QUE ÉS UN BREAKPOINT ? ]


"Si no sabes lo que es un breakpoint (punto de ruptura), creo que deberías mirarte los bullet.gif (296 bytes)tutoriales antes de comenzar con esta lección. Aún así voy a explicar brevemente para que sirven y que son los breakpoint. Los breakpoints son una de las grandes ventajas que todo debugger brinda al cracker, mediante un breakpoint, el cracker puede establecer un punto en el cual el debugger parará la ejecución del programa, posteriormente el debugger pasará el control del programa al cracker, con lo cual este podrá examinar que es lo que sucede al llegar al punto del código donde se estableció el breakpoint. La mayor utilidad de los breakpoints es utilizarlos con funciones del API de Windows (p. ej. con MessageBoxA), esto nos permite tomar el control del programa antes de que se llame a la función del API sobre la que hayamos puesto un breakpoint. Es por eso que no es aconsejable informar al usuario de ningún error del sistema de protección mediante una función del API o de cualquier DLL externa."


[ ¿CÓMO FUNCIONA UN BREAKPOINT ?]


Los breakpoints (utilizaré BPX para abreviar) siempre han funcionado de la misma manera a lo largo de la larga vida de los debuggers, cuando el usuario decide establecer un BPX en alguna parte del código, este manda una instrucción al debugger (en bullet.gif (296 bytes)SoftIce: bpx dirección_código) y el debugger reemplaza el primer byte del código por el código hexadecimal 'CCh', este código equivale a la instrucción INT 3, la cual genera una interrupción (la 3 en este caso). Cada vez que esta instrucción se ejecuta, se devuelve el control al debugger, este, reemplaza la INT 3 (CCh) por el byte de código que habia previamente y muestra al usuario el código actual donde se encuentra el programa. Ahora el usuario puede seguir trazando el programa si lo desea y examinar el código para cambiar el comportamiento del programa, pudiendo llegar anular nuestro sistema de protección. Esta claro que si pudieramos detectar si en nuestro código se han puesto BPX, podriamos abortar la ejecución del programa debido a una violación del sistema de seguridad (siempre debes de realizar esto sin mostrar ningún mensaje de error, mirate mis bullet.gif (296 bytes)consejos).


[ ¿CÓMO PODEMOS DETECTARLOS ?]


Pues bien, esto lo podemos conseguir facilmente en ensamblador pero en C resulta algo más complicado, pero no por eso imposible. La teoria sería la siguiente: obtener un puntero a la función o al inicio del código que queremos comprobar, leer el primer byte de código, comprobar si es igual a 'CCh' (INT 3) y actuar en consequencia. A continuación tienes un pequeño programa realizado en C que detecta si existe algún BPX sobre la función MessageBox del API de Windows. El código a sido comprobado y funciona perfectamente compilandolo con Visual C++, no lo he probado con otros compiladores pero creo que funcionaría igual. Este código puede detectar cualquier debugger, ya que todos actuan igual, yo lo he probado con el SoftIce v4.0 para Windows 9x y funciona.
Para comprobar el funcionamiento de este código, compila el programa, pon un BPX sobre la función MessageBoxA (bpx MessageBoxA si usas el SoftIce) y ejecuta el programa, luego prueba desactivando el breakpoint.


#include <stdio.h>
#include <windows.h>

#pragma warning( disable : 4035 ) /* desactiva la generación de warnings para las funciones que aparentemente no retornan nada*/

/* Las funciones estan declaradas como funciones __inline, esto provoca que sean compiladas como si se tratara de macros y no funciones, es decir, cada vez que en nuestro código en C llamemos a una de estas funciones, el compilador no generará ninguna llamada si no que el código se añadira cada vez que las llamemos. Esto evita que el cracker pueda parchear la función y con esto evitar que todas las llamadas para comprobar si hay un BPX fuesen inutilizadas con un solo cambio. Recomiendo hacer un uso bastante intensivo de cualquiera de estas dos funciones para complicar la vida al cracker */

__inline bool IsBPX(void * address)
{
    _asm {

mov esi,address    // carga la dirección de la función
mov al,[esi]          
// comprueba si existe un breakpoint sobre la función
cmp al,0xCC        
// esto se realiza comprobando que el primer byte de código
                           
// de la función sea diferente que CCh, que es el código
                           
// de operación de la INT 3 usada por TODO debugger
je BPXed               
// si encontramos CCh, la función tiene puesto un breakpoint
                          
// saltamos para devolver TRUE
xor eax,eax         
// FALSE,
jmp NOBPX          
// no hay breakpoint

BPXed:

mov eax,1              // hay un breakpoint
NOBPX:
    }
}

// Esta segunda versión de la función, realiza lo mismo, pero lo hace de una manera menos evidente, para que el cracker no pueda buscar posibles comparaciones
// de un registrp con CC, en el desensamblado del código

__inline bool IsBPX_v2(void * address)
{
    _asm {

mov esi,address   // carga la dirección de la función
mov al,[esi]        
// comprueba si existe un breakpoint sobre la función
mov ah,0x66      
// carga ah con 66h (mitad de CCh)
add ah,ah           
// lo suma a si mismo dando 0xCC, y se compara
cmp ah,al           
// esto se realiza comprobando que el primer byte de código
                         
// de la función sea diferente que CCh, que es el código
                         
// de operación de la INT 3 usada por TODO debugger
je BPXed
xor eax,eax      
  // no hay breakpoint
jmp NOBPX

BPXed:

mov eax,1          // hay un breakpoint
NOBPX:
    }
}

#pragma warning( default : 4035 ) // establece la generación de warning para las funciones que no retornan valor, al valor por defecto del compilador

void main()
{
    void *addr;
    addr=MessageBox;

    if (IsBPX_v2(addr))
    {
        MessageBox(NULL,"Estas intentando crackear este programa?","Mensaje",MB_OK|MB_ICONEXCLAMATION);
    }
    else MessageBox(NULL,"Bien chaval pareces legal...","Mensaje",MB_OK);
}


Bueno, puedes ver que tampoco es tan difícil de implementar y resulta bastante efectivo, no creo que el código necesite mucha explicación ya que las partes interesantes estan perfectamente comentadas, quizá la variable addr no es necesaria pero creo que así se ve más claro. Analizemos ahora los pros y contras de este método:

marcador.gif (1024 bytes)Si el cracker llega a detectar el código que causa la detección del BPX, puede crear un pequeño programa o utilizar un editor hexadecimal que busque los códigos que pertenecen a las funciones de detección y que realize las modificaciones oportunas, evitandose así tener que ir de una en una, esto es debido a que el compilador siempre generará el mismo código para las macros. Podriamos solucionar esto creando multiples versiones de las macros con instrucciones diferentes.

marcador.gif (1024 bytes)El método es difícil de detectar si se utiliza una macro bien camuflada, en este caso, la primera macro es muy sencilla de encontrar debido a la instrucción cmp al,0xcc y probablemente sería poco efectiva ante un cracker poco experto.

marcador.gif (1024 bytes)Existe un metodo infalible para detectar la comprobación del breakpoint que muchos crackers ignoran (ahora habrá menos :) ), si en el SoftIce colocamos un BPM (Breakpoint on Memory access) sobre la función que sospechamos, el debugger se detendrá justo después de leer el byte de código. En el ejemplo hariamos: BPM MessageBoxA R, esto le indica al Softice que detenga la ejecución si se intentan leer bytes de la función MessageBoxA.

Como puedes comprobar, cualquier truco anti-debugging no está exento de su correspondiente truco anti-anti-debugging :=) . Pues esto es todo por ahora, habrá más en la siguiente 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 :)