As you may guess my name is Anastasios. My interests are comprised of computer security, linux, operating systems and many more low level programming concepts :P.
Finally and before my first post, I would like to thank Kostas for taking care of junkbytes.com because i wasn't involved in the creation process. May the source be with you Kostas :) .
So regarding my first post, last days i encountered a very interesting way to execute ptrace. What is ptrace system call ?
ptrace is a system call found in several Unix and Unix-like operating systems. By using ptrace (the name is an abbreviation of "process trace") one process can control another, enabling the controller to inspect and manipulate the internal state of its target. ptrace is used by debuggers and other code-analysis tools, mostly as aids to software development. (wikipedia.org)
As you can see it is used mainly on debuggers during development process. But debuggers are also used during advanced dynamic malware analysis. It is true that malwares in order to avoid being traced by debuggers, use ptrace system call.
The ptrace's prototype is the following:
long ptrace(enum __ptrace_request request, pid_t pid,
void *addr, void *data);
By properly executing ptrace malwares can detect the "tracer" process (e.g. debuggers, ltrace, strace).
In terms of my static analysis using IDA PRO, i discovered this way to call ptrace:
The first three lines is the prologue of the certain assembly subroutine, nothing interesting. The ptrace system call takes place in the last four lines. At first, eax and ebx registers are wiped out and then the value 1A(hex)=26(dec) are passed to al (which is the lower 8 bits of eax register). After that an interrupt is made in order to transfer execution from user to kernel mode .
But what's the purpose of moving the value 1A(hex) to al?
Digging the linux system call table, i realized that in order to execute ptrace the value 26(dec) should be present on eax! Bing! This explains why "mov al, 1Ah" was executed.
Regarding calling conventions, i also noticed that this piece of assembly code is not the appropriate way that gcc compiler translates C code to assembly. The gcc usually uses stack in order to pass arguments and call functions. So this piece of code is a inline assembly addition often used in C.
Assembly code can be added in C code using a function. In this case named insert_assembly().
__attribute__((always_inline)) void inline insert_assembly()
{
__asm__ __volatile__(".byte 0xb3, 0x00, 0xb1, 0x00, 0xb2, 0x00, 0xb0, 0x1a, 0xcd, 0x80" );
}
This hex code will execute the ptrace system call with the following arguments:
ptrace(PTRACE_TRACEME, 0, 0, 0)
If ptrace's return value is -1 then the process will be traced by a "tracer". In that way, the malware can detect its tracer and follow a different code path.
So tweaking with this concept i wrote the following assembly code (file ass_ptrace.s):
.text
.global _start
_start:
movb $0, %ebx
movb $0, %ecx
movb $0, %edx
movb $0x1A, %al
int $0x80
cmp $0xFFFFFFFF, %eax
jz exit
xor %eax, %eax
movb $1, %al
xor %ebx, %ebx
int $0x80
exit:
movl $len, %edx
movl $msg, %ecx
xor %ebx, %ebx
movb $1, %bl
xor %eax, %eax
movb $4, %al
int $0x80
xor %eax, %eax
movb $1, %al
xor %ebx, %ebx
int $0x80
.data
msg:
.ascii "Tracer detected!\n"
len = . - msg
Briefly, this assembly code executes ptrace(PTRACE_TRACEME, 0, 0, 0) and according to the result it exits or it prints a message and then exits. It prints the message every time it detects a tracer.
Assembled and linked the assembly file,
as --32 ass_ptrace.s -o ass_ptrace.o
ld -m elf_i386 ass_ptrace.o -o ass_ptrace
and then executed it.
As you can see when ass_ptrace is executed without a tracer it does nothing and exits. But when i try to trace it using strace system command, it detects strace, prints "Debugger detected!\n" and exits with the same exit code (0).
The result of "objdump -d ass_ptrace" follows:
The interesting thing despite of the detection of ptrace system call using strace is that ptrace doesn't exist on symbols' table even if i never stripped ass_ptrace (strip removes unnecessary symbols from an ELF, in this case "strip ass_ptrace").
Combining this technique (calling ptrace in this way using assembly and importing it to C code) with some kind of obfuscation can make things nasty. Obfuscation techniques will be discussed in another post.
It is not my intent to train new bad guys, but to make people (particularly security guys) aware of techniques used by them.
Feel free to post your comment. Have a nice day!
Comments
Post a Comment