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


  Lección 2- "Detección de debuggers, la historia continua"

Para aquellos que no sepan de que va la historia les recomiendo que lean antes la bullet.gif (296 bytes)lección 0, en ella encontrarán información más detallada sobre que es un debugger y cómo funciona. Esta lección pretende añadir nuevos métodos de detección de debuggers, estos métodos los considero más extraños y algunos resultan díficiles de detectar. Pero para eso estamos aquí, para mostrar en que se basan y así poder mejorarlos y si alguno de ellos se interpone en nuestro camino, ya sabes...


marcador.gif (1024 bytes) METODO 1:

Descripción: Este método se suele utilizar muy poco, aunque es bastante efectivo ya que detectará el SoftIce aunque no este en memoria, su funcionamiento es muy simple: comprueba la existencia en el registro de una de las siguientes claves, esto delatará la presencia de nuestro estimado amigo SoftIce.

    - #1 : HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Uninstall\SoftICE
    - #2 : HKEY_LOCAL_MACHINE\Software\NuMega\SoftICE

Para comprobar la existencia de claves en el registro podemos usar la función del API RegOpenKey, RegOopenKeyEx,

Para detectar este método podemos utilizar un breakpoint en el SoftIce tal como -> BPX _regopenkey if *(esp->8+0x13)=='tICE' || *(esp->8+0x37)=='tICE'


marcador.gif (1024 bytes) METODO 2:

Descripción: Este método es muy efectivo ya que detecta cualquier debugger, aunque solo funciona bajo Win 9x, se basa en la comparación de las direcciones donde estan los manejadores de la INT 1 y la INT 3. icy debe ser la dirección de un buffer de un mínimo de 6 bytes. El único método de detección de este método que conozco es por busqueda de los opcodes de la instrucción SIDT (0F 01) o del CMP, pero este puede tener combinaciones más diversas. Personalmente desconocía este método hasta que me encontré con el en el BlindWrite (gracias a fanega por pasarmelo), un programa de grabación de CD-R que usa este sistema. La verdad que este sistema se puede explotar mucho más ya que de su funcionamiento se deriva un fallo en el Windows que nos permitiría ejecutar código en Ring0 desde nuestra aplicación en Ring3. El fallo reside en que el area de memória donde reside la IDT (Interrupt Descriptor Table), no está protegida contra lectura/escritura, pero esto solo sucede en Win9x y no en NT. La IDT viene a ser algo así como una tabla de vectores (similar a la antigua tabla del DOS), donde se almacenan las direcciones de memória que apuntan al código que ejecuta al llamar a una interrupción.

#include <windows.h>

// alinea las estructuras a WORD
#pragma pack(2)

typedef struct _IDTGATE
{
    unsigned short gateOffsetLow;
    unsigned short gateSelector;
    unsigned short gateFlags;
    unsigned short gateOffsetHigh;
} IDTGATE;

typedef struct _IDT
{
    unsigned short idtLimit;
    IDTGATE*    idtGate;
} IDT;

bool IsDebuggerRunning()
{
    IDT icy;

   _asm {
        SIDT [icy];
        mov eax,dword ptr [icy.idtGate]
        add eax,0x8
        mov ebx, dword ptr [eax]
        add eax,0x10
        mov eax, dword ptr [eax]
        and eax,0x0000FFFF
        and ebx,0x0000FFFF
        sub eax,ebx
        cmp eax,0x1E
        je Sice
        xor eax,eax
Sice:

    }
}


marcador.gif (1024 bytes) METODO 3:

Descripción: Este método se basa en la busqueda de la cadena WINICE.BR en la memória, su funcionamiento es muy sencillo ya que es una simple busqueda en memória. Resulta muy efectivo y bien implementado puede ser difícil de detectar, aunque sabiendo la dirección de memória que se analiza se puede utilizar un BPM (breakpoint on memory access) para detectarlo. Doy las gracias a R!SC y a Stone por enseñarme este método.

bool FindSoftIceString()
{
    _asm {
        mov    al, 'W'
        mov    edi, 0x10000
        mov    ecx, 0x400000-0x10000
More:
        repnz    SCASB               
// "W"
        jecxz    NotFound
        cmp    dword ptr [edi], 'CINI'    
// INIC
        jz    Ok1

        jmp    More
Ok1:   
        add    edi, 4
        cmp    dword ptr [edi], 'RB.E'    
// E.BR
        jnz    More
        mov    eax,1
NotFound:

    }
}


marcador.gif (1024 bytes) METODO 4:

Descripción: Consiste en ver si el registro de trazado DR7 contiene un valor distinto de 0,en caso afirmativo, el sistema esta bajo un debugger (Esto podemos comprobarlo si estando en SoftIce tecleamos el comando CPU). Este método se basa en los registros de trazado (Debug Registers DRx) de los Pentium para su correcto funcionamiento, la aplicación que lo utilize debe tener privilegios de Ring0, esto implica programarnos nuestro VXD o hacer uso de algún tipo de truco que nos permita pasar de Ring3 a Ring0. Existe un método que modificando la IDT nos permite redireccionar una interrupción a una dirección de código que este en nuestra aplicación, el código al ser ejecutado como una interrupción tendrá privilegios Ring0, el siguiente código de muestra como podemos implementar esto desde C. Notese que este método no funciona bajo NT, también destacar que puede utilizarse otra interrupción que no sea la del ejemplo. Si por ejemplo elejimos la INT 1, el SoftIce se irá a hacer puñetas ;), ya que él usa esta interrupción.

void Ring0Proc()
{
    _asm {

        mov     eax, dr7        // Instrucciones privilegiadas en Ring0 :)
        iretd  
                    // Esto se ejecutará como una interrupción por lo que deberemos retornar tal y como lo hacen las interrupciones
    }
}

DWORD GetDebugReg7()
{
    _IDT addr;                                     // mirate el bullet.gif (296 bytes) método 2 para ver la descripción de la estructura
    unsigned long lpOldGate;               // esto es para guardar la dirección original

    _asm {        
        sidt fword ptr [addr]
        mov ebx,dword ptr [addr+2]
        add ebx,8*5
        mov    dx, word ptr [ebx+6]       
// Salva el word alto de la puerta IDT
        shl    edx, 16d
        mov    dx, word ptr [ebx]          
  // word bajo
        mov    [lpOldGate], edx

        mov    eax, offset Ring0Proc      
// "instala nuestra rutina" - Que se ejecutará en Ring0
        mov    word ptr [ebx], ax           
//  word bajo
        shr    eax, 16d
        mov    word ptr [ebx+6], ax        
// word alto

        int 5                                        
// llama a la INT 5 que es la que hemos sustituido, esto ejecutará nuestra rutina en Ring0
        cmp eax,0
        jne Sice
        xor eax,eax
Sice:       
        mov    ebx, dword ptr [addr+2]        
// restaura la dirección original
        add    ebx, 8*5
        mov    edx, [lpOldGate]
        mov    word ptr [ebx], dx
        shr    edx, 16d
        mov    word ptr [ebx+6], dx

    }
}


marcador.gif (1024 bytes) METODO 5:

Descripción: Consiste en utilizar una función del VWIN32 que se encarga de despachar los servicios de la INT 41, a esta función se le pasan unos determinados valores que servirán para determinar la presencia del debugger. Solo funciona bajo Win9x. Para poder detectar este método podemos utilizar uno de los siguientes breakpoints: BPINT 41 if ax==4f , BPINT 30 if ax==0xF386, BPX Exec_PM_Int if eax==41 && edx->1c==4f && edx->10==002A002A o BPX Kernel32!ord_0001 if esp->4==002A002A && esp->8==4f

push 0000004fh       // función 4fh
push 002a002ah    
// el word alto especifica el VXD (VWIN32), el word bajo especifica el servicio (VWIN32_Int41Dispatch)
call Kernel32!ORD_001
// VxdCall
cmp ax, 0f386h    
// número mágico devuelto por los debuggers
jz SoftICE_detected


marcador.gif (1024 bytes) METODO 6:

Descripción: Consiste en utilizar una llamada VXD que nos permite averiguar si hay instalado el controlador de dispositivo virtual que le indiquemos, para ello podemos utilizar dos de los identificadores de los que el SoftIce dispone ( 202h o 7a5fh ). Este método solo funciona  en Ring0 por lo que es bastante restrictivo a no ser que utilizemos el truco del bullet.gif (296 bytes) método 4.

mov eax, Device_ID      // 202h para SICE o 7a5Fh para SIWVID VxD ID
mov edi, Device_Name
// solo se usa si no tenemos el ID del VxD, en nuestro caso será 0 (NULL)
VMMCall Get_DDB
mov [DDB], ecx
          // ecx=DDB si es dispositivo está instalado o ecx= 0 si el VxD no esta instalado


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