Ring3 Circus
December 5th, 2007, 16:45
The Win32 API function IsDebuggerPresent is commonly used in rudimentary anti-hack techniques. It’s generally safe to conclude, if somebody is debugging your program, that there’s some foul play going on. Now, once you’ve convinced yourself that this really doesn’t matter ("http://www.ring3circus.com/gameprogramming/protecting-your-game-against-the-hackers/"), allow me to explain the guts of this Kernel32 function. Here’s a disassembly:
It’s really all there is to it. The first line gets a pointer to the thread environment block (often abbreviated to TEB). This is a lump of system-maintained memory that keep track of per-thread data. At offset 0×30 into the TEB is a pointer to the process environment block, or PEB. The second line of the disassembly loads this address into the EAX register. Last of all, it reads and returns the third byte of the PEB (the ‘BeingDebugged’ member) as a boolean value.
This code is very simple to implement manually, and doing just that is a quick and easy way to thwart the attempts of those out-of-the-loop crackers who attempt to patch the IsDebuggerPresent function itself. But equivalently, the disassembly betrays a way to render IsDebuggerPresent truly useless:
So without the need for any messy code patches, we can hide the presence of a debugger from IsDebuggerPresent - or anything that reads from PEB->BeingDebugged - by executing this function in the process’s address-space. Now, that won’t fool any programs clever enough to read in the value of PEB->DebugPort (which can’t be overwritten from ring3) or that use CheckRemoteDebuggerPresent (which requires XP SP1 or later), but it’s nice to know.
http://www.ring3circus.com/rce/bypassing-isdebuggerpresent/
Code:
7C813093 MOV EAX, DWORD PTR FS:[18]
7C813099 MOV EAX, DWORD PTR DS:[EAX+30]
7C81309C MOVZX EAX, BYTE PTR DS:[EAX+2]
7C8130A0 RETN
This code is very simple to implement manually, and doing just that is a quick and easy way to thwart the attempts of those out-of-the-loop crackers who attempt to patch the IsDebuggerPresent function itself. But equivalently, the disassembly betrays a way to render IsDebuggerPresent truly useless:
Code:
void HideIsDebuggerPresent(bool hide) {
unsigned char being_debugged = (hide ? 0 : 1);
__asm {
MOV EAX, FS:[0x18]
MOV EAX, [EAX + 0x30]
MOV CL, being_debugged
MOV BYTE PTR [EAX + 2], CL
}
}
http://www.ring3circus.com/rce/bypassing-isdebuggerpresent/