Search code examples
debuggingassemblyx86reverse-engineeringmalware

Does reading a debug register raise an exception if the GD flag is set?


I've been doing some research on debug registers lately and how some malware programs are able to manipulate them as an anti-debugging tactic. One of the things I have read a few times now is that this can be prevented by using the General Detect flag in DR7, which raises a debug exception if a MOV instruction is used to access any of DR0-DR7.

However, what I am not clear on is what exactly access means - if, for instance, a mov instruction is used to only place the address of DR0-DR3 into a general purpose register so it can be read, would this still cause a debug exception to be raised when the GD flag is set? Or does this only happen if a MOV instruction is used to actually change the contents of the register? What I have read so far has been slightly ambiguous on this.

I encountered the assembly below in a text that shows manipulation of the debug registers, but in this case mov is only used to get the address of the debug registers and the actual modification is done by the or instruction, so I am not sure if this code would raise an exception if GD was set.

    xor eax, eax
    push offset except_callback
    push d fs:[eax]
    mov fs:[eax], esp
    int 3 ;force an exception to occur
    ...        

    except_callback:
     mov eax, [esp+0ch] ;get ContextRecord
     mov ecx, [eax+4] ;Dr0
     or ecx, [eax+8] ;Dr1
     or ecx, [eax+0ch] ;Dr2
     or ecx, [eax+10h] ;Dr3
     jne <Debugger_detected>

Solution

  • Intel is pretty clear about it:

    An attempt to read or write the debug registers from any other privilege level generates a general-protection exception (#GP).

    So reading or writing a debug register when not running at CPL 0 will raise an exception, independently of the GD flag.

    In fact, I've analyzed quite a bit of malwares and none of them access the debug registers directly. They get the current thread context (GetThreadContext or NtGetContextThread or similar WOW64 variants) and check the values of the debug registers from there, note that it is the Windows' kernel that read the debug register in this case. This antidebug trick can be worked around manually (with a breakpoint on the API retrieving the context) or with a debugger plugin. Malwares running at CPL 0 could use the GD flag but I've never found one so far.

    Answering your title question, any read or write access (at CPL 0) to a debug register will raise a #GP if GD is set. I have not tested it but considering its intended use (to support hardware debugger emulator), the idea is to "virtualize" the debug registers. The hardware debugger emulated in software can then use the debug register even if the OS debugged is already using them. This is done by faulting on every access and properly swapping in and out the OS vs emulator values.

    If only writes were faulting the emulator could not prevent the debugged OS from reading an incorrect value (placed there by the emulator) from a debug register.

    Enables (when set) debug-register protection, which causes a debug exception to be generated prior to any MOV instruction that accesses a debug register.
    When such a condition is detected, the BD flag in debug status register DR6 is set prior to generating the exception. This condition is provided to support in-circuit emulators. When the emulator needs to access the debug registers, emulator software can set the GD flag to prevent interference from the program currently executing on the processor.
    The processor clears the GD flag upon entering to the debug exception handler, to allow the handler access to the debug registers.