The Ptrace Anti Re Trick
Introduction
This blog post describes an old Anti-RE technique under Linux using the ptrace syscall. A program is introduced that shows different behavior on whether it is being debugged or not.
Background
When malware is analyzed, it tries to hide itself. There are various different techniques for this. As a first step, malware is often analyzed automatically in a sandbox, due to the high number of malware submissions at antivirus vendors.
This could previously be defeated by letting the program wait using the sleep syscall, before any malicious functionality is executed. Thus, the automated analysis likely runs into a timeout. As a next step in the cat-and-mouse-game antivirus vendors decided to remove sleep syscalls before analyzing the code. However, malware authors used different techniques to waste time, such as computing numerically intense tasks, such as prime factorizations or enough digits of pi. Other methods include checking for more than 8GB RAM, as usually desktop computers have this, but sandboxes not.
Introducing Ptrace
When the malware is reverse-engineered manually, then usually a debugger is involved. There is a neat trick to detect the presence of a debugger using the ptrace syscall.
The ptrace syscall is usually used to debug a process. It asks a program “Hey, may i debug you?”. And the program answers with “Yes, of course.”, or “No, go away!”. When it is already ptraced by another process, then it answers “No, go away!”.
So the idea is that a program can try to ptrace itself (from the same thread). If that fails, then it is already being ptraced by another process, that may be operated by some reverse-engineer. Hence, the program can alter its behavior if it is reverse-engineered. And that is why it is called an Anti-Reverse-Engineering (Anti-RE) technique.
A C Program
First, we show a high-level version in C.
If this program is executed without a debugger, then it prints that it is not traced:
$ ./selfptrace
I am not traced
If, however, it is executed from a debugger, such as executing it with strace or radare2, it prints that it is traced.
$ strace ./selfptrace
execve("./selfptrace", ["./selfptrace"], 0x7ffc1c38fb10 /* 67 vars */) = 0
....
ptrace(PTRACE_TRACEME) = -1 EPERM (The operation is not permitted)
...
write(1, "I am traced", 11I am traced) = 11
exit_group(1) = ?
+++ exited with 1 +++
$ r2 -Ad selfptrace
[0x7fc50d772d80]> dc
I am traced(2888) Process exited with status=0x100
The Same Trick in Assembly
As we are 1337 coderz, we can do the same trick directly in assembly.
I will not show the output of running it with and without a debugger again, as it is similar to the output above.
Epilogue
As any lazy hacker with few knowledge of morals writes at the end of its articles: “Don’t use this for malicious purposes. This is for educational use only.”
Now go and write some interesting code.