Log in

View Full Version : Bypassing IsDebuggerPresent


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:

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
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:

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
}
}
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/

evlncrn8
December 6th, 2007, 01:41
Quote:

Now, that won’t fool any programs clever enough to read in the value of PEB->DebugPort (which can’t be overwritten from ring3)


you are 100% sure on that?

Admiral
December 6th, 2007, 11:02
Quote:
[Originally Posted by evlncrn8;70761]you are 100% sure on that?

What, the fooling bit, or the read-only bit?

But no, I'm not 100%. I figured I had it on good authority, being from a huge article on OpenRCE.

Judging from the disassembly of a C++ call to NtQueryInformationProcess (which resolves to ZwQueryInformationProcess), reading the status of the debug port requires a kernel-mode transition. A quick Google gives me the strong impression that the _EPROCESS structure is well out of ring3 bounds, and my brief attempts to use ZwSetProcessInformation have all failed.

So unless you know something I don't (in which case, please share ) I'd guess that the debug-port can't be modified from ring3, and almost certainly not without a ring0 transition.

Admiral

evaluator
December 9th, 2007, 15:59
maybe he means, ring3 can call driver in ring0.. which must NOT!! change DebugPort!
instead hook procedure ZwQuery..