21

I am trying to scan all possible techniques to disrupt the usage of a debugger on a Unix platform (ie POSIX and a bit more).

I am thinking about techniques such as the PTRACE test at the beginning of a program (or at various points of its execution), the insertion of fake breakpoints (eg int3/0xcc x86 opcode) or time checks. But, also global strategies defined on the program to slow down the analysis of the program.

For now, all the techniques I found on Internet were easily worked around as soon as the anti-debug technique has been understood. So, I wonder if there are stronger ones.

6
  • "all the techniques I found on Internet were easily worked around as soon as the anti-debug technique has been understood" <- this is the case with most of them but not a reason to discount them just because of that.
    – Igor Skochinsky
    Mar 22, 2013 at 17:42
  • You may want to check [this][1] topic. [1]: reverseengineering.stackexchange.com/questions/1930/…
    – jvoisin
    Jun 20, 2013 at 16:44
  • You can't. It is impossible for any software to detect if it runs on a real machine or a perfect emulation which can be analyzed from the outside. Don't try to do something mathematically impossible. Oct 12, 2020 at 17:45
  • @12431234123412341234123 Modern CPU's are perfect emulations of the abstract instruction set. That said, perfection is very hard to achieve. May 14 at 17:01
  • @ThorbjørnRavnAndersen The possible instructions a CPU can make is limited, so it isn't THAT hard. However, doing it fast, efficient and at the same time without exploitable side effect is very hard. May 15 at 6:57

3 Answers 3

22

Here's some I've seen or heard about:

  • Stripping the section headers. A simple and fully legal action that stops GDB dead in its tracks. Does not work against some other debuggers (e.g. IDA). Can be done using the sstrip tool.

  • Using syscall function or direct syscalls instructions instead of calling specific functions like ptrace(). Can be defeated by setting the breakpoint on syscall function or just stepping through the file, but may be non-obvious if you don't know about it.

  • Performing anti-debugging actions before main(), e.g. in constructors of global objects or using __attribute__((constructor)). Since GDB usually sets initial breakpoint in main(), it takes care of the default situation. Workaround is simple: put breakpoint on the actual file's entrypoint (info file in GDB).

  • Sending itself debugging-related signals like SIGTRAP. (Note that this can be ignored with handle SIGTRAP nostop in GDB.)

  • Forking and tracing itself with ptrace.

  • Fake breakpoints insertion: Inserting int3/0xcc will force the debugger to stop on these bytes as they will be treated as software breakpoints. If they are numerous it might slow down considerably the analysis.

  • Breakpoint detection: I saw this technique in this paper, you can attach a function that will be triggered when a breakpoint is encoutered. This paper covers also some other tricks.

5
  • Ok, this seems a reasonable list of techniques but nothing surprising til now. And, you are missing the breakpoints tricks (insertion of fake breakpoints to confuse the debugger when PTRACEd and checking the hash of the next code block to see if new software breakpoints have been inserted or not). But, would you know a paper describing all these techniques for Unix (I know some papers for MS-Windows but none for Unix systems).
    – perror
    Mar 22, 2013 at 17:42
  • @Emmanuel: feel free to edit it and add more, that's why I made it a wiki. I'm not aware of any papers, but possibly you can find some more tricks in something like Phrack.
    – Igor Skochinsky
    Mar 22, 2013 at 17:46
  • My IDA died while trying to load an ARM binary that had its section headers stripped. So #1 may still be a useful trick (though I ultimately wrote a script to reconstitute the headers).
    – nneonneo
    Jun 9, 2014 at 1:38
  • @nneonneo: if that happens with the current version, please send a bug report. thanks.
    – Igor Skochinsky
    Jun 9, 2014 at 21:09
  • The real fun is fork and use ptrace() on yourself as a form of IPC.
    – Joshua
    Sep 7, 2018 at 4:02
12

My understanding of anti-debugging technology is that it is a game of cat and mouse (or cat and also cat). A technique works until it is understood by the opposing side and then it doesn't work any more. I think that ultimately the advantage is on the side of the debugger. Consider dynamic binary instrumentation or virtual machine systems. You can detect the presence of DBI or emulation by looking for cracks or faults in the emulation of the platform, but those are just errors in the emulation/translation software. If you had a "perfect" emulation system, then a debugged application could not know that it was being traced?

So I think the best you can do is little things that are easily worked around. The Shiva system still I think represents "okay" protection from debugging on Unix platforms, since it decrypts small portions of itself to run on demand and then re-encryptes them, as I recall.

1
  • I would tag the Shiva system as an advanced packer but not really an anti-debug technique (even if its main effect is to render the usage of a debugger extremely tedious because your window in memory where you can effectively set breakpoints is extremely small compared to a "normal" program).
    – perror
    Mar 22, 2013 at 17:37
3

They aren't any, do not try to do the mathematically impossible.

For now, all the techniques I found on Internet were easily worked around as soon as the anti-debug technique has been understood. So, I wonder if there are stronger ones.

Yes, because there is no way of detecting a debugger that can not be faked. Software can not detect if it runs in a perfect emulation or in the real world. And a emulator can be stopped, the software can be analyzed, variables can be changed, basically everything can be done that can be done in a debugger.

Let's say you want to detect if the parent process is a debugger. So you make a system call to get the parent PID? The debugger can intercept the system call and return any PID which does not have to be the real PID. You want to intercept every SIGTRAP so the debugger can't use it anymore? Well the debugger can just stop in this case and send the SIGTRAP also to your process. You want to measure the time when you send SIGTRAP to know if the process stops for a short time by the debugger for sending SIGTRAP so you know when there is a debugger? The debugger can replace your calls to get the time and return a fake time. Let's say you run on a Processor that has a instruction that returns the time, so no function call is needed to get the time. Now you can know that the time you are getting is real? No, the debugger can replace this instruction with a SIGTRAP instruction and return any time he wants or in case such a instruction does not exist, run the Software in a emulator that can be programmed in any way. Everything you can come up with to detect a debugger or emulator can be faked by the environment and you have 0 change to detect it.

The only way to stop debugging is by not giving the software to the customers but keep it in your hands. Make a cloud service and run the software on your server. In this case the customer can not debug your program since he does not run it and has no control over it. Except the customer can access the server or the data somehow, but that is a different story.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.