This DLL bypasses all anti-debugging methods from my project Guided Hacking Anti-Debugging. I did both projects for learning purpose and bellow I'll explain a bit about each debugger detection method and how this DLL proceeds to bypass it. I tried to come up with a different way of bypassing each, if you are interested in anti-debugging techniques, you should follow along.
Each button above activates a detection method. We'll bypass each one of those. You can inject the DLL generated by this project using any DLL injector (or come up with your own). To generate the DLL just download and compile this project as x86. No further instructions needed.
IsDebuggerPresent() is a method imported from Kernel32.dll
. It checks for the BeingDebugged flag in the PEB (Process Environment Block) and will return a non-zero value if it is indeed being debugged. To bypass it, just set that specific flag to 0 (it's located on offsex 0x2 on a x86 PEB):
void setPEBDebuggerBypass() {
auto peb = (char*) __readfsdword(0x30);
*(peb+0x2) = 0x0;
}
This method is similar to the above, but with some caveats. The PEB also contains a field called NtGlobalFlag (at offsex 0x68). This field can assume different values, but we are interested in the 5th, 6th and 7th bits (from right to left). Those are set when the process is being debugged, so here's the bypass code that simply changes unsets the 5th bit.
void bypassNtGlobalFlag() {
auto peb = (char*) __readfsdword(0x30);
*(peb + 0x68) = (*(peb + 0x68) &= ~(1UL << 5));
}
The IsDebuggerPresent()
from Kernel32.dll
is a wrapper to this PEB field check, so our bypass specified above applies here as well.
This method uses CreateToolhelp32Snapshot to loop thru the system processes and get the Parent Process name. Then it compares the parent process name with a list that contains the names of common debuggers (like x64dbg, ollydbg, cheat engine...). To bypass this, the DLL finds the array and replace the names with "UWONTFINDME". So unless your debugger is called UWONTFINDME, it won't find it (see file bypasses/bypassCreateToolhelp32Snapshot.h
).
Ok, this one brought me a massive opportunity to learn about WoW64 (a subsystem of Windows capable of running 32bit applications on 64bit Windows). CheckRemoteDebuggerPresent() is a function from kernel32.dll
that calls ZwQueryInformationProcess under the hood passing 7 as ProcessInformationClass
which is a check for the ProcessDebugPort
. A non 0 value means there is a debugger present.
Since the GH Anti Debugging application is 32bit, and we're running it on a 64bit system, it has to go thru what we call Heaven's Gate
, which is a transiction from the 32bit ntdll.dll
to a 64bit ntdll.dll
that will call the Winapi/kernel functions. There's this amazing writeup from Hoang Bui that explains all about it. In a nutshell, all calls to Winapi/kernel functions will pass thru this transiction, so you can hook all syscalls by just hooking there. The bypass then consists in identifying the Winapi ZwQueryInformationProcess call, and returning eax
as 0. If you can read thru the article I mentioned and take a look at bypasses/bypassCheckRemoteDebuggerPresent
you will understand exactly how it is done. Neat stuff!
This is a really simple debugger detection method that uses SetUnhandledExceptionFilter, a function used to define an exception handler function. The debugger detection method works like this: it sets a beingDebugged
bool variable as true, calls SetUnhandledExceptionFilter passing a function that sets that same variable to false and raises an exception (in this case using int3
instruction). On a non debugged application the function you passed to SetUnhandledExceptionFilter would be called and the beingDebugged
variable would be set back to false (meaning no debugger found). If there's a debugger attached to the process tho, when the exception is raised the debugger would respond instead of the function passed to SetUnhandledExceptionFilter, so that variable would never be set to false again.
To bypass it, I got lazy and just nopped out the int3
call, and made the function that was returning 1 to return 0;
This method works by checking the 64bit PEB->IsBeingDebugged attribute. It switches to long mode to have access to the 64bit PEB, and simply check the third byte on it (PEB64->IsBeingDebugged). To bypass it, we simply set that byte to 0. I did this in ASM just for learning purposes (and to be honest I'm still studying the long mode transition).
Nothing here is new and all those methods and bypasses have been used and discussed all over the internet since the 2000s. A great reference for more anti debugging methods is this pdf from 2011 by Peter Ferrie. If you are also interested in Reverse Engineering and Game Hacking, you should check Guided Hacking.