This is about a hack to disguise a process. It does not need root privileges nor a root kit. How a process is listed in
w is changed, also data in the proc filesystem.
Rename process names
PR_SET_NAME sets the current process’ name. The system call is used by daemons to give them useful names. Only the current process can be renamed, however. With the
LD_PRELOAD environment variable and gcc’s
__attribute ((constructor)) we can set the victim’s name before execution enters
LD_PRELOAD is used by reverse engineers to trick compiled executables into executing arbitrary code. Functions in libraries and the command itself can be hijacked. It’s poor man’s monkey patching in C. It works like this: One compiles code to be injected to a dynamic library
hack.so and invokes the command prepended with
__attribute ((constructor)) is similar to C++ static initialization. In fact, I also could have written the hack in C++. I use this feature because I don’t want hijack functions. I want code to be executed before anything else.
Combined these three features
can force any name to any process a user starts.
This is not good enough.
ps -f shows all arguments.
cmdline in the proc filesystem also blabs the arguments.
How to trash cmdline?
program_invocation_name seems to be essentially a pointer to data in
argv. I don’t know how these things relate exactly to each other but in my experiments, if I change either
cmdline is not writable), the other two also change. That’s very neat to trick
The memory for the arguments follows
cmdline also show this: the arguments are separated by a ASCII NUL character. So what if I overwrite the arguments by writing beyond the end of
This is undefined behavior and dangerous ground but it seems to “work”. In experiments however I trashed a local variable when I exceeded the memory range of
cmdline. So I must never write more than the original
cmdline contains. I get the length by reading the file from the proc filesystem and use the length as an upper bound.
This is nice and changes the behavior of
ps -f and
cmdline. This also causes the victim to complain about bad arguments. What happened? I overwrote the arguments before the victim had a chance to evaluate them…!
What if I somehow could change the arguments after the parsing of the victim process? What if I somehow could wait one second and let the victim do its thing? Bingo! Use a thread (POSIX pthreads) and wait one second.
Most processes evaluate arguments as soon as they are started and never need them again.
Let’s recapitulate again: With these features
- File length of
/proc/self/cmdline== memory size of cmdline
- Use a thread to overwrite cmdline later
one can trash a process’ cmdline (but not enlarge). Note that
argv are not available, because we work in a function which is executed even before main().
Compiling and invocation
I wrote a small C file
rptitle.c (about 60 lines) and compiled it with
gcc -Wall -fPIC -c rptitle.c -o rptitle.o gcc -shared -o rptitle rptitle.o
LD_PRELOAD=./rptitle.so \ RPTITLE='changedcommand args' \ command -options args
I change the process to be listed as
It is a «simple» hack - simple in the sense that everybody who can start a process can do it. No need for root access or a root kit. In essence, the system admin cannot trust
w to tell the truth if a user went «black hat» and hides what he does. Tools like
lsof tell which connections are active, however.
- prctl man page
- Reverse Engineering use of LD_PRELOAD
- gcc Function Attributes
- program_invocation_name man page
- Monkey Patching
- POSIX pthreads
exe in the proc filesystem still links to the original executable. I have an idea about this… I will write about this in a later post.
What do you think about this hack?
It is too simple or too basic to be worth mentioning? What could be done about this in the kernel? Please comment below!