in the name of zero

June 24, 2006

anti-anti-ptrace via shared library function overriding in c

Filed under: hermetic studies

i was reading the manpage of ld.so (man 8 ld.so) when i chanced upon the environment variable LD_PRELOAD

LD_PRELOAD
A whitespace-separated list of additional, user-specified, ELF
shared libraries to be loaded before all others. This can be
used to selectively override functions in other shared
libraries. For setuid/setgid ELF binaries, only libraries in
the standard search directories that are also setuid will be
loaded.

wanting to give function overriding a shot, i decided to make a program that has anti-ptrace to see if i can bypass that without resorting to manual patching. a program would call ptrace() with PTRACE_TRACEME request initiating that it wants to be traced. since only one process is allowed this technique works against ptrace() based applications like strace and gdb

#include <stdio.h>
#include <sys/ptrace.h>
	
int main(t, c)
{
	if (ptrace(PTRACE_TRACEME, 0, 1, 0) == -1) {
		printf("ptrace protection\n");
		return 1;
	}
	printf("--- normal program procedure here ---\n");
	return 0;
}

and when i ran that under gdb (and strace afterwards) i got this

steph@gdb $ file traceme
Using host libthread_db library \"/lib/libthread_db.so.1\".
steph@gdb $ r
ptrace protection
	
Program exited with code 01.
so clearly, the anti-ptrace routine was being executed. then i made a custom ptrace() function that i hoped would override libc’s ptrace() like so.

/* fake ptrace() */
#include <stdio .h>
	
long ptrace(int x, int y, int z)
{
	printf("--this is the ptrace clone block--\n");
	return 0;
}

then made a shared library out of it.

steph@heaven ~/git/null/c/ptrace $ gcc -shared -fPIC -o fakeptrace fakeptrace.c 

and then ran strace with LD_PRELOAD environment set.

steph@heaven ~/git/null/c/ptrace $ strace -E LD_PRELOAD=./fakeptrace ./traceme
— snipped —
write(1, "–this is the ptrace clone block"…, 35–this is the ptrace clone block–) = 35
write(1, "— normal program procedure her"…, 38— normal program procedure here —) = 38
munmap(0xb7f0f000, 4096)                = 0
exit_group(0)                           = ?

whereas, under the normal circumstance, strace would have given me:

write(1, "ptrace protection\n", 18ptrace protection)     = 18
munmap(0xb7f16000, 4096)                = 0
exit_group(1)

[ protection ]
i haven’t gotten into the details about how to go about munmap()ing a specific library in memory and do plt-patching inside the program itself. so for now, i just extended the traceme program to detect LD_PRELOAD presence before the actual anti-ptrace. if LD_PRELOAD checks out bad, (that is, there are preloaded libraries) the program quits. i wouldn’t really call this protection because if anyone can defeat ptrace() tracing, what’s to prevent him/her from defeating the LD_PRELOAD detection function too? it’s pointless, but at least it didn’t hurt when i placed it.

char *preloaded;
	
preloaded = getenv("LD_PRELOAD");
	
if (preloaded) {
	printf("detected pre-reloaded functions: \n");
	printf("%s\n", preloaded);
	return -1;
}
i’m going nowhere with the whole matter am i?

Comments »

The URI to TrackBack this entry is: http://gnurbs.blogsome.com/2006/06/24/anti-anti-ptrace-via-shared-library-function-overloading-in-c/trackback/

No comments yet.

RSS feed for comments on this post.

Leave a comment

Line and paragraph breaks automatic, e-mail address never displayed, HTML allowed: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <code> <em> <i> <strike> <strong>


Get free blog up and running in minutes with Blogsome | Theme designs available here