Monday, 21 April 2014

Introduction to Detecting Anti-Debugging Techniques

Malicious Software is able to detect if it's running within a debugging environment or a debugger has been attached to the process, and thus will not generate of it's malicious behaviors in order to avoid detection from the security analyst or whoever is attempting to debug the process. In this article, I'm going to describe some of the common anti-debugging techniques which are used to detect the presence of a debugger.

NtGlobalFlag:

The NtGlobalFlag is located within the Process Environment Block (PEB) at offset 0x68 on x86 Windows, and at offset 0xBC on x64 Windows.

 Windows 7 SP1 x86
The default value is always 0, and doesn't change when a debugger is attached to the process. There are several methods in which the NtGlobalFlag can be changed to detect the presence of a debugger. The NtGlobalFlag contains many flags which affect the running of a process.

The most common flags which are set with NtGlobalFlag when a debugger creates a process, is the heap checking flags:

FLG_HEAP_ENABLE_TAIL_CHECK (0x10)
FLG_HEAP_ENABLE_FREE_CHECK (0x20)
FLG_HEAP_VALIDATE_PARAMETERS (0x40)

I've spoken about the purpose of these flags in a previous blog post which can be found here. These flags can be checked to detect the presence of a debugger. The general code from CodeProject, for checking the above flags:
unsigned long NtGlobalFlags = 0;

__asm {

mov eax, fs:[30h]
mov eax, [eax + 68h]
mov NtGlobalFlags, eax
}

if(NtGlobalFlags & 0x70)
// 0x70 =  FLG_HEAP_ENABLE_TAIL_CHECK |
//         FLG_HEAP_ENABLE_FREE_CHECK |
//         FLG_HEAP_VALIDATE_PARAMETERS
{
// Debugger is present
"application and restart the program"),
TEXT("Debugger Found!"), 0);
ExitProcess(0);
}
// Normal execution
IsDebuggerPresent():

The IsDebuggerPresent() is a Kernel32 function which will return the Boolean value of True, if a debugger is attached to the process. It can be found by checking the IAT.

It can check the BeingDebugged field of the PEB:

char IsDbgPresent = 0;
__asm {
mov eax, fs:[30h]
mov al, [eax + 2h]
mov IsDbgPresent, al
}

if(IsDbgPresent)
{
"application and restart the program"),
TEXT("Debugger Found!"), 0);
ExitProcess(0);
}
// Normal Execution
The CheckRemoteDebuggerPresent() is a similar function, and can be detected with the same method.

The NtSetInformationThread() function has a hidden undocumented parameter called ThreadHideFromDebugger (0x11), which can be used to prevent any debugging events being sent to the debugger. Debugging Events are events which will notify the debugger, these can be the creation of new threads; generation of an exception; loading and unloading of DLLs and creating child processes.

You can check if this function is imported in the IAT. PeStudio or a similar program like PeBear may check for this function.

Execution Timing:

This is a simple idea and is implies that the execution time when be slightly more with the presence of the debugger. This technique measures the execution time, and if slightly longer than usual, can imply the use of a debugger. The common instructions include:
• RDTSC, RDPMC and RDMSR instructions.
• GetTickCount(), GetLocalTime() and GetSystemTime() are all functions within the Kernel32 library.
Again, you can check if these functions are imported within the IAT.

Software Breakpoint Detection:

The instruction 0xCC - INT 3 is used  to stop the execution of the debugged process and then pass the control to the debugger. The instruction is saved before the implementation of the breakpoint. Any comparison instructions (CMP, CMPXCHG) which use this instruction as a operand are considered as a anti-debugging technique.