5

I am trying to detect on Linux if a debugger is attached to my binary. I have found two solutions. One simpler:

#include <stdio.h>
#include <sys/ptrace.h>

int main()
{
    if (ptrace(PTRACE_TRACEME, 0, 1, 0) == -1) 
    {
        printf("don't trace me !!\n");
        return 1;
    }
    // normal execution
    return 0;
}

and another one:

#include <sys/types.h>
#include <errno.h>
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ptrace.h>
#include <sys/wait.h>

int spc_detect_ptrace(void) {
  int   status, waitrc;
  pid_t child, parent;

  parent = getpid();
  if (!(child = fork())) {
    /* this is the child process */
    if (ptrace(PT_ATTACH, parent, 0, 0)) exit(1);
    do {
      waitrc = waitpid(parent, &status, 0);
    } while (waitrc == -1 && errno == EINTR);
    ptrace(PT_DETACH, parent, (caddr_t)1, SIGCONT);
    exit(0);
  }

  if (child == -1) return -1;

  do {
    waitrc = waitpid(child, &status, 0);
  } while (waitrc == -1 && errno == EINTR);

  return WEXITSTATUS(status);
}

Is the second method better than the first, simpler one? If yes, why?

robert
  • 3,539
  • 3
  • 35
  • 56
  • In either example, what's to stop me from attaching a debugger after the check has passed? Additionally, not all debuggers will necessarily use `ptrace`, so this may not be the most reliable way of determining if someone is debugging your program. – tonysdg Nov 11 '15 at 08:26
  • @tonysdg, the above code can be called multiple times. Do you have any idea how to check it better? – robert Nov 11 '15 at 08:28
  • To be honest? No, unfortunately. I do know that an active field of research is testing whether or not programs can determine if they're in a virtual machine (which is sometimes desirable and sometimes not) - I suspect the same type of questions apply here. Is the goal here to ward off attempts at reverse engineering though? If so, there may be better ways to protect yourself - I'm not exactly sure what those are, but someone in the community likely would. Regardless - I'm unfortunately of no more help on this question (most likely) :( – tonysdg Nov 11 '15 at 08:32
  • First method checks only once so you probably will need to call it multiple times, while second keeps attachment so noone else can [directly] attach to your process (since it could only be one). There are methods to bypass it of course, e.g. patched kernel in worst case, and with direct access to process memory - there might not be a need for attachable debugger at all. – keltar Nov 11 '15 at 10:42
  • @keltar, are you sure that the second keeps attachment? Isn't the statement `ptrace(PT_DETACH, parent, (caddr_t)1, SIGCONT);` detaching? – robert Nov 11 '15 at 13:42
  • @franz1 well but `waitpid`. Hard to say with do-nothing examples, but I'm fairly sure it supposed to detach only when process is finished. – keltar Nov 11 '15 at 14:42

1 Answers1

0

As well as the ptrace() method, it's also possible to signal SIGTRAP ( How to detect if the current process is being run by GDB? )

I'd say that your first method is better (and better than SIGTRAP), since forking is terribly inefficient for such a check, and there will be many circumstances (like multithreaded code) that forking is undesirable.

Peeter Joot
  • 7,848
  • 7
  • 48
  • 82