[ 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 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...
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'
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:
}
}
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:
}
}
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
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
}
}
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
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 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! |