In the world of reverse engineering, there are many obstacles. One of those is anti-debugging techniques that was design to interrupt reversers’ ability to attach a debugger to an application. A debugger let us set break point and view the application stack frame, as well as registers’ value.
Today, we will look at the most simplest anti-debugging technique, isDebuggerPresent().

From the MSDN’s documentation, we can see that it is a winapi function that take in no argument and return a non-zero if it detects a debugger (TRUE) or a zero which means it does not detect any debugger (FALSE).
We will be using this code as an example:
int main()
{
if (IsDebuggerPresent())
{
std::cout << “Debugger is present\n”;
}
else
{
std::cout << “Business as usual, no debugger\n”;
}
//Pause the console so it does not close
std::cin.get();
return 0;
}
Which resulted in this when run normally:

However, running it under a debugger such as x64dbg, you will get a whooping:

And while we could use x64/32dbg built in anti-anti-debugger with the command, Hide, that wouldn’t be very interesting.


Why not use this command for everything you ask? That is because isDebuggerPresent as well as all the other anti-debugger x64dbg bypasses are the most basic type of anti-debugging. They are rarely use as the sole detection method. Some malware as well as anti-cheat uses their own method of detecting debugger. The knowledge of how one work will carry you further than a command to bypass them.
So…How does isDebuggerPresent works???
To look at any winapi’s functionality, it is an IDA Pro away. Loading up kernelbase.dll and we will see isDebuggerPresent’s under the hood…and it is a whooping 3 instructions long…

For those who aren’t assembly/x86 savy, these 3 instructions does:
1. Store whatever FS segment register store in offset 0x30 into eax
2. read the value 2 bytes offset from fs:30 and overwrite eax with it
3. return that value (eax)
At this point, there are two things we need to know about before making sense of this function. What does the FS segment register store in offset 0x30 and what does that value store in the offset 0x2. So, the first thing we are going to do is look at what FS segment register holds.
According to wikipedia,
Win32 Thread Information Block (TIB) is a data structure in Win32 on x86 that stores information about the currently running thread….It is accessed from the FS segment register when operating on 32 bits
They were even nice enough to provide us with the entire table, including the object at 0x30.

So FS points to TIB, and TIB+0x30 points to PEB… Now I guess we will just have to find out what PEB is..
Process Environment Block (abbreviated PEB) is a data structure in the Windows NT operating system family. It is an opaque data structure that is used by the operating system internally, most of whose fields are not intended for use by anything other than the operating system

This is exactly what we need to know. 0x2 in PEB struct is a BYTE flag that tell us if that thread in that context is BeingDebugged. IsDebuggerPresent() is simply reading that value and then return back to the WINAPI Function. This can be further demonstrated with windbg and !peb command, displaying the PEB table of the debugged program.

Now, you may wonder what actually set this flag in TIB->PEB->BeingDebugged to True. There is a short answer, and a long answer. However, I will only cover the short answer and that is DbgkpMarkProcessPeb(). This function is trigger whenever you call DebugActiveProcess(), which is what the debugger use.
Now we know what is triggering IsDebuggerPresent, how are we going to combat it? Well, there are a few options such as:
1. NOP the check when isDebuggerPresent()’s return value is checked
2. Modify BeingDebugged byte
3. All other unreasonable methods
But for the sake of time, we will go with the first method. This will requires us to find where isDebuggerPresent is being called. To achieve this, we just have to look at all the loaded modules and it’s exported symbols.

We know that isdebuggerpresent is in kernelbase.dll, so we will go there and filter for isDebuggerPresent on the symbol’s list.

Going to 0x7455FA60, we will see isDebuggerPresent’s assembly like I shown earlier

At this point, we are currently looking at kernelbase.dll’s code and not actually our application’s code. However, our application will have to reference to this function somewhere and there is a handy function to find that. That is the find reference function!



This is the section of our code that calls IsDebuggerPresent. 3 lines down, notices a
test eax, eax
If you know how values are return on x86 architecture, you will know that return value is stored onto eax after the ret instruction is called. This is probably where the check on the result of IsDebuggerPresent is being evaluated. We also see all the strings references as well as the std::cout/std::cin.get() that we will call depending on how the evaluation happens.

So from the line of IsDebuggerPresent, 3 lines down you can see a test and a jne instruction. A little bit on JNE and how test instruction work required to know what is happening next.
Test instruction compares two values and set a bunch of flag registers such as ZF (zero flag) or (CF) carry flag, etc. The JNE (jump if not equal) instruction checks if ZF == 0, and it is the exact same instruction as JNZ (jump if zero). Therefore, it is more appropriate to consider JNE as JNZ in this situation. If this JNZ/JNE flag evaluate to TRUE, it will jump over the std::cout that say “Business as casual” and hit the std::cin.get() that pause the program. So, our job here is clear. That is to make sure this JNE/JNZ NEVER happens. The only way to do that is to NOP (no operation) the opcodes that make up this instruction. When a processor see a NOP (0x90) instruction, it will go to the next instruction and skip over the NOP.



Now, let’s see what happen if we patch this and run with a debugger attached!
As you can see, we make the patch – run the new patched executable with x32dbg attached and we received the “Business as usual, no debugger” message! IsDebuggerPresent() BYPASSED!
Next up, whatever I feel like writing about!