0 - Introduction
1 - Techniques related to the PEB
1.1 - asm way (inline asm)
1.2 - C Win32 way
2 - Timing based detection
3 - OllyDbg specific
3.1 - OllyDbg v1
3.2 - OllyDbg v2
4 - Custom ways
4.1 - OutputDebugString(): Again (Xp SP 3 only)
4.2 - Parent Process Id (PPID) check
4.3 - Terminate the debugger
5 - Resources
Introduction
In this paper, we'll go over some basic anti-debug tricks. I won't introduce
anti-dump
techniques nor other adavanced protections. By the way, all of this is Windows specific.
Most (if not all) anti-debug techniques rely on the fact that the system and the concerned app have a
different behaviour when an app is being debugged than when it isn't.
We'll simply use these differences to check the presence of a debugger.
The Process Environment Block is a user mode data structure inside the process virtual address space. The PEB is used internally by the system. It contains info about the process such as the base address, startup parameters... We could say it's the equivalent of the kernel mode data structure EPROCESS.
That done, we can start the funny part.
1.1 - asm way
We'll start querying the PEB using assembly. The PEB struct contains a byte field named BeingDebugged
.
It is set to 1 when the process is being debugged, otherwise it's set to 0.
We'll use this field to tell if a debugger is being ran on our process.
For this, we'll make the fs
segment register point at offset 0x30.
Thus we'll have the PEB base offset ([fs:30h]
always points to the PEB).
At this point, we now have to add this offset 2 to get the BeingDebugged
field
inside the PEB, since BeingDebugged
is the second field in this data structure (the first field occupying 2 bytes).
Let's get to work.
1.2 - C Win32 way
Now we'll achieve the same as we've done above but using the C language with the Win32 api.
The WinApi includes a function called IsDebuggerPresent()
.
It has no argument and returns a boolean indicating if a debugger is being ran on the callee.
A similar Win32 function which checks the PEB exists to determine whether a specified process is being debugged.
This api is CheckRemoteDebuggerPresent()
. It takes two parameters: a handle to the process
and a pointer to a variable to set to either TRUE
or FALSE
depending on whether the
specified process is being debugged or not.
We can use this api to check for a debugger on our process by giving it a handle to the current process as first argument.
This indeed comes down to calling the API seen above.
We can obtain a handle to the current process using the GetCurrentProcess()
api which takes no parameters.
We can use the fact that a program executes more slowly when run under a debugger to trap it.
The GetTickCount()
api, which takes no argument, reports the time elapsed in
milliseconds since the system was started.
Calling this API twice and ensuring the difference doesn't exceed a defined threshold is a way to
tell our process isn't beind debugged.
Note that there are different ways to achieve the same thing using other APIs like
QueryPerformanceCounter()
or some CPU instruction in assembly, like RDTSC
for x86.
There are some techniques that are specific to OllyDbg. We need to distinguish between OllyDbg v1 and v2. Some tricks work for both versions, some don't.
3.1 - OllyDbg v1
The first trick consists in finding the main window of olly using its name via the FindWindow()
API.
It takes the windows name as sole argument and returns a window handle (HWND
) to this window on success.
Note that the string doesn't have to be case sensitive.
Olly 1 uses the name of the debugee executable in its window title.
Say we want to protect an app named 'Storm_Inj3ctor.exe' ... We'd need the following code to bust olly:
The second trick for olly 1 relies on exploiting a bug in the way it handles the OutputDebugString()
API.
This api is supposed to send the debugger a string for it to display it. We found out that using
this function in a certain manner crashes olly.
This technique is specific to Olly v2; to be fair, I've never tried it on other debuggers
but wouldn't be surprised its applicable too.
A regular process has its SeDebugPrivilege
token disabled by default.
Before a debugger loads its target however, it usually asks the system for elevated privilege.
Once the debugger loads and opens the debugee, it inherits this token as well.
This elevated token allows a process, amongst other things, to open privileged (ie system) processes.
At this point it becomes clear how one can exploit this to detect a debugger: let's try to open a system process.
If we succeed, we're certainly being debugged.
This last part will cover some custom/home made techniques to bust a debugger. There are lots of custom techniques,
and most programmers/reverse engineers have their own tricks that they keep for themselves.
These can be considered as the best tips since you won't find them easily on the internet.
The following techniques are still basic though.
4.1 - OutputDebugString()
: Again (Xp SP 3 only)
I've already covered this API in this very paper, but there's another way one can use it to detect a debugger.
This time we can rely on the fact that it has a different behaviour depending on whether our app is being debugged or not.
On success, it sets LAST_ERROR to ERROR_SUCCESS
(ie 0). If there's no debugger however, its sets LAST_ERROR to some non-zero value.
One can use this simple trick as an anti-debug technique.
4.2 - Parent Process Id (PPID) check
In 'normal' conditions, a process is created by the shell (explorer.exe).
So the parent process ID (PPID) of this process will be the shell's PID. When a process is launched by a debugger, its PPID is the
debugger's PID.
We can use this as an anti-debug technique. We check that our app's PPID corresponds to the shell's.
4.3 - Terminate the debugger
Anti-debug ? Kill the debugger.
This technique is not the most efficient for obivous reasons (relying on process names...) but quite simple.
Why not try to search all the running processes for a known debugger ? Open it, call TerminateProcess()
, done.
Again, easy but not very reliable since you may need elevated privileges to kill the debugger.
Resources