[ 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! |