0

So recently I've been reading up on anti-debug mechanisms and a popular method I've come across to check if the current process is being debugged is OutputDebugString. I've written this piece of code but it doesn't exactly work as intended can someone shed some light on why or what I'm doing wrong?

private static bool stub_OutputDebugString()
{
    uint ErrCode = 0x12A6;
    Native.SetLastError(ErrCode);
    Native.OutputDebugString("System.Core\n");
    if (Marshal.GetLastWin32Error() == (int)ErrCode)
    {
        //Debugger Detected
        return true;
    }
    else
    {
        //No Debugger Detected
        return false;
    }
}

My P/Invoke signatures

[DllImport("kernel32.dll", SetLastError = true)]
public static extern void SetLastError(uint dwErrCode);

[DllImport("kernel32.dll", SetLastError = true)]
public static extern void OutputDebugString(string lpOutputString);

Note I readup on how GetLastError shouldn't be called from the native environment as the value can be changed so I'm using Marshal.GetLastWin32Error()

The code should work but the last error doesn't change when i try to debug the application with windbg or any other debugger.

Adriano Repetti
  • 65,416
  • 20
  • 137
  • 208
Cra0
  • 19
  • 1
  • 4

2 Answers2

5

Your reasoning about GetLastError() (it shouldn't be used because last error may be overwritten by .NET Framework because of any other internal/invisible/background operation) also applies to SetLastError(). Simply you can't reliably call it and expect its value is preserved intact until you call Marshal.GetLastWin32Error().

We may discuss how to circumvent this issue however...

...that technique has (somehow) sense for native code because OutputDebugString() is widely used and disassembling compiled code is harder (then you protect yourself with some obfuscated code). However managed code is easy to decompile and it's still easy to read and understand, such simple obfuscation will not help and you should simply go with System.Diagnostics.Debugger.IsAttached property.


If you really really want to detect a debugger (even if it's very easy to see what you're doing then it won't offer much protection) you have to make things more complicate because you may want to protect against a managed debugger or a native debugger. Yes they're different.

Unless managed debugger is built on top of native one if you call native IsDebuggerPresent() you will always get FALSE for a managed debugger where Debugger.IsAttached would return true. Also opposite scenario is true: with a native debugger attached you will get TRUE from IsDebuggerPresent() but false from Debugger.IsAttached. In the big world you will meet all three types of debugger. For a better discussion about IsDebuggerPresent() you may read Anti-Debugging.

You may check both but you're still far from detecting debuggers because they only check for local managed/native debuggers but you don't have information about remote debuggers (unless you also call CheckRemoteDebuggerPresent()) or debuggers that don't live in user-mode (unless you also play with NtQuerySystemInformation). There are some slightly more robust techniques but you can't do it in managed world (see also Detecting System Debugger).

One possible solution is to debug your own process using DebugActiveProcess(), it you fail (and it's not a permission error) then another debugger is attached, moreover until you stay attached another debugger can't attach. Note that a process can not debug itself (AFAIK) then it must be done from a child process (which somehow communicate with main process you want to protect). It's nothing new, basically the same technique described in How to detect if the current process is being run by GDB? but Windows specific.

Read see also Debuggers aren't supposed to change behavior and Managed vs. Native debugging APIs for more information about this topic.

Community
  • 1
  • 1
Adriano Repetti
  • 65,416
  • 20
  • 137
  • 208
  • I'm aware of the fact native code can be decompiled and seen. But thats another issue. Things like IsDebuggerPresent and such are trivial to bypass to but I would like to check for most of them even though a simple hook would bypass it. – Cra0 Dec 04 '15 at 14:49
  • 1
    You didn't get my point. The only reason to use OutputDebugString() over IsDebuggerPresent() - in native code - is to **OBFUSCATE** this check. It's not better or more reliable nor safer. In managed code this obfuscation is meaningless because when you decompile it...you even have pretty formatted source code. Back to your main question then: you can't do like this because SetLastError() won't work. However side question would be: why do you need it? Do you want to prevent debugging...why? – Adriano Repetti Dec 04 '15 at 14:57
  • Yes the main goal is to prevent or hinger the debugging of my native process employing as many different techniques as possible. – Cra0 Dec 04 '15 at 15:09
  • woops ment managed I've looked at obfuscaters out there for .NET applications such as confuserEx and learn't a few tricks just trying to comprehend a decent way to stop debugging thanks for your response though was informative. – Cra0 Dec 04 '15 at 15:13
  • No, my _question_ is different. I see you want to stop debugging, I would know why you need it. Code is deployed and executed on client computer then, unless you have a DRM enabled device, it doesn't matter how much effort you put on that...they can inspect, change and eventually debug your code. – Adriano Repetti Dec 04 '15 at 15:16
0

why not just use the IsDebuggerPresent function?.. I believe is exists for the purpose you want.

CaldasGSM
  • 3,032
  • 16
  • 26