Linux系統可解除安裝核心模組完全指南(1)(轉)

worldblog發表於2007-08-10
Linux系統可解除安裝核心模組完全指南(1)(轉)[@more@]

  簡介

  將Linux作業系統用於伺服器在現在是越來越普遍了。因此,入侵Linux在今天也變得越來越有趣.目前最好的攻擊Linux的技術就是修改核心程式碼.由於一種叫做可解除安裝核心(Loadable KernelModules(LKMs))的機制,我們有可能編寫在核心級別執行的程式碼,而這種程式碼可以允許我們接觸到作業系統中非常敏感的部分.在過去有一些很好的關於LKM知識的文字或者檔案,他們介紹一些新的想法,方法以及一名Hacker所夢寐以求的完整的LKMs.而且也有一些很有趣的公開的討論(在新聞組,郵件列表).

  然而為什麼我再重新寫這些關於LKMs的東西呢?下面是我的一些理由:

  在過去的教材中常常沒有為那些初學者提供很好的解釋.而這個教材中有很大一部分的基礎章節.這是為了幫助那些初學者理解概念的.我見過很多人使用系統的缺陷或者監聽器然而卻絲毫不瞭解他們是如何工作的.在這篇文章中我包含了很多帶有註釋的原始碼,只是為了幫助那些認為入侵僅僅是一些工具遊戲的初學者!

  每一個釋出的教材不過把話題集中在某個特別的地方.沒有一個完整的指導給那些關注LKMs的Hacker.這篇文章會覆蓋幾乎所有的關於LKMs的資料(甚至是病毒方面的).

  這篇文章是從Hacker或者病毒的角度進行討論的,但是系統管理員或者核心的開發者也可以參考並從中學到很多東西.

  以前的文章介紹一些利用LKMs進行入侵的優點或者方法,但是總是還有一些東西是我們過去從來沒有聽說過的.這篇文章會介紹一些新的想法給大家.(不是所有的新的資料,只是一些對我們有幫助的)

  這篇文章會介紹一些簡單的防止LKM攻擊的方法,同時也會介紹如何透過使用一些像執行時核心補丁(Runtime Kernel Patching)這樣的方法來對付這些防禦措施.

  要記住這些新的想法僅僅是透過利用一些特殊的模組來實現的.要在現實中真正使用他們還需要對他們進行改進.這篇文章的主要目的是給大家在整個LKM上一個大方向上的指導.在附錄A中,我會給大家一些實用的LKMs,並附上一些簡短的註釋(這是為那些新手的),以及如何使用他們.

  整篇文章(除了第五部分)是基於 Linux 2.0.x的80x86機器的.我測試了所有的程式和程式碼段.為了能夠正常使用這裡提供的絕大部分程式碼,你的Linux系統必須有LKM支援.只有在第四部分會給大家一些不需要LKM支援的原始碼.本文的絕大多數想法一樣可以在Linux2.2.x上實現(也許你會需要一些小小的改動).

  這篇文章會有一個特別的章節來幫助系統管理員進行系統安全防護.你(作為一名Hacker)也必須仔細閱讀這些章節.你必須要知道所有系統管理員知道的,甚至更多.你也會從中發現很多優秀的想法.這也會對你開發高階的入侵系統的LKMs有所幫助.

  因此,通讀這篇文章吧.

  第一部分. 基礎知識

  1.1 什麼是LKMs

  LKMs就是可解除安裝的核心模組(Loadable Kernel

  Modules)。這些模組本來是Linux系統用於擴充套件他的功能的。使用LKMs的優點有:他們可以被動態的載入,而且不需要重新編譯核心。由於這些優點,他們常常被特殊的裝置(或者檔案系統),例如音效卡等使用。

  每個LKM至少由兩個基本的函式組成:

  int init_module(void) /*用於初始化所有的資料*/

{

...

}

void cleanup_module(void) /*用於清除資料從而能有一個安全的退出*/

{

...

}

  載入一個模組(常常只限於root能夠使用)的命令是:

  # insmod module.o

  這個命令讓系統進行了如下工作:

  載入可執行的目標檔案(在這兒是module.o)

  呼叫 create_module這個系統呼叫(至於什麼叫系統呼叫,見1.2)來分配記憶體.

  不能解決的引用由系統呼叫get_kernel_syms進行查詢引用.

  在此之後系統呼叫init_module將會被呼叫用來初始化LKM->執行 int inti_module(void) 等等

  (核心符號將會在1.3節中核心符號表中解釋)

  OK,到目前為止,我想我們可以寫出我們第一個小的LKM來演示一下這些基本的功能是如何工作的了.

  #define MODULE

#include

int init_module(void)

{

printk("<1>Hello World ");

return 0;

}

void cleanup_module(void)

{

printk("<1>Bye, Bye");

}

  你可能會奇怪為什麼在這裡我用printk(....)而不是printf(.....).在這裡你要明白核心程式設計是完全不同於普通的使用者環境下的程式設計的.你只能使用很有限的一些函式(見1.6)僅使用這些函式你是幹不了什麼的.因此,你將會學會如何使用你在使用者級別中用的那麼多函式來幫助你入侵核心.耐心一些,在此之前我們必須做一點其他的.....

  上面的那個例子可以很容易的被編譯:

  # gcc -c -O3 helloworld.c

  # insmod helloworld.o

  OK,現在我們的模組已經被載入了並且給我們列印出了那句很經典的話.現在你可以透過下面這個命令來確認你的LKM確實執行在核心級別中:

  # lsmod

  Module     Pages  Used by

  helloworld     1    0

  這個命令讀取在 /proc/modules 的資訊來告訴你當前那個模組正被載入.'Pages'

  顯示的是記憶體的資訊(這個模組佔了多少記憶體頁面).'Used by'顯示了這個模組被系統

  使用的次數(引用計數).這個模組只有當這個計數為0時才可以被除去.在檢查過這個以後,你可以用下面的命令解除安裝這個模組

  # rmmod helloworld

  OK,這不過是我們朝LKMs邁出的很小的一步.我常常把這些LKMs於老的DOS TSR程式做比較,(是的,我知道他們之間有很多地方不一樣),那些TSR能夠常駐在記憶體並且截獲到我們想要的中斷.Microsoft's Win9x有一些類似的東西叫做VxD.關於這些程式的最有意思的一點在於他們都能夠掛在一些系統的功能上,在Linux中我們稱這些功能為系統呼叫.

  1.2什麼是系統呼叫

  我希望你能夠懂,每個作業系統在核心中都有一些最為基本的函式給系統的其他操作呼叫.在Linux系統中這些函式就被稱為系統呼叫(System Call).他們代表了一個從使用者級別到核心級別的轉換.在使用者級別中開啟一個檔案在核心級別中是透過sys_open這個系統呼叫實現的.在/usr/include/sys/syscall.h中有一個完整的系統呼叫列表.下面的列表是我的syscall.h

  #ifndef _SYS_SYSCALL_H

  #define _SYS_SYSCALL_H

  #define SYS_setup 0

  /* 只被init使用,用來啟動系統的*/

  #define SYS_exit 1

  #define SYS_fork 2

  #define SYS_read 3

  #define SYS_write 4

  #define SYS_open 5

  #define SYS_close 6

  #define SYS_waitpid 7

  #define SYS_creat 8

  #define SYS_link 9

  #define SYS_unlink 10

  #define SYS_execve 11

  #define SYS_chdir 12

  #define SYS_time 13

  #define SYS_prev_mknod 14

  #define SYS_chmod 15

  #define SYS_chown 16

  #define SYS_break 17

  #define SYS_oldstat 18

  #define SYS_lseek 19

  #define SYS_getpid 20

  #define SYS_mount 21

  #define SYS_umount 22

  #define SYS_setuid 23

  #define SYS_getuid 24

  #define SYS_stime 25

  #define SYS_ptrace 26

  #define SYS_alarm 27

  #define SYS_oldfstat 28

  #define SYS_pause 29

  #define SYS_utime 30

  #define SYS_stty 31

  #define SYS_gtty 32

  #define SYS_access 33

  #define SYS_nice 34

  #define SYS_ftime 35

  #define SYS_sync 36

  #define SYS_kill 37

  #define SYS_rename 38

  #define SYS_mkdir 39

  #define SYS_rmdir 40

  #define SYS_dup 41

  #define SYS_pipe 42

  #define SYS_times 43

  #define SYS_prof 44

  #define SYS_brk 45

  #define SYS_setgid 46

  #define SYS_getgid 47

  #define SYS_signal 48

  #define SYS_geteuid 49

  #define SYS_getegid 50

  #define SYS_acct 51

  #define SYS_phys 52

  #define SYS_lock 53

  #define SYS_ioctl 54

  #define SYS_fcntl 55

  #define SYS_mpx 56

  #define SYS_setpgid 57

  #define SYS_ulimit 58

  #define SYS_oldolduname 59

  #define SYS_umask 60

  #define SYS_chroot 61

  #define SYS_prev_ustat 62

  #define SYS_dup2 63

  #define SYS_getppid 64

  #define SYS_getpgrp 65

  #define SYS_setsid 66

  #define SYS_sigaction 67

  #define SYS_siggetmask 68

  #define SYS_sigsetmask 69

  #define SYS_setreuid 70

  #define SYS_setregid 71

  #define SYS_sigsuspend 72

  #define SYS_sigpending 73

  #define SYS_sethostname 74

  #define SYS_setrlimit 75

  #define SYS_getrlimit 76

  #define SYS_getrusage 77

  #define SYS_gettimeofday 78

  #define SYS_settimeofday 79

  #define SYS_getgroups 80

  #define SYS_setgroups 81

  #define SYS_select 82

  #define SYS_symlink 83

  #define SYS_oldlstat 84

  #define SYS_readlink 85

  #define SYS_uselib 86

  #define SYS_swapon 87

  #define SYS_reboot 88

  #define SYS_readdir 89

  #define SYS_mmap 90

  #define SYS_munmap 91

  #define SYS_truncate 92

  #define SYS_ftruncate 93

  #define SYS_fchmod 94

  #define SYS_fchown 95

  #define SYS_getpriority 96

  #define SYS_setpriority 97

  #define SYS_profil 98

  #define SYS_statfs 99

  #define SYS_fstatfs 100

  #define SYS_ioperm 101

  #define SYS_socketcall 102

  #define SYS_klog 103

  #define SYS_setitimer 104

  #define SYS_getitimer 105

  #define SYS_prev_stat 106

  #define SYS_prev_lstat 107

  #define SYS_prev_fstat 108

  #define SYS_olduname 109

  #define SYS_iopl 110

  #define SYS_vhangup 111

  #define SYS_idle 112

  #define SYS_vm86old 113

  #define SYS_wait4 114

  #define SYS_swapoff 115

  #define SYS_sysinfo 116

  #define SYS_ipc 117

  #define SYS_fsync 118

  #define SYS_sigreturn 119

  #define SYS_clone 120

  #define SYS_setdomainname 121

  #define SYS_uname 122

  #define SYS_modify_ldt 123

  #define SYS_adjtimex 124

  #define SYS_mprotect 125

  #define SYS_sigprocmask 126

  #define SYS_create_module 127

  #define SYS_init_module 128

  #define SYS_delete_module 129

  #define SYS_get_kernel_syms 130

  #define SYS_quotactl 131

  #define SYS_getpgid 132

  #define SYS_fchdir 133

  #define SYS_bdflush 134

  #define SYS_sysfs 135

  #define SYS_personality 136

  #define SYS_afs_syscall 137

  #define SYS_setfsuid 138

  #define SYS_setfsgid 139

  #define SYS__llseek 140

  #define SYS_getdents 141

  #define SYS__newselect 142

  #define SYS_flock 143

  #define SYS_syscall_flock SYS_flock

  #define SYS_msync 144

  #define SYS_readv 145

  #define SYS_syscall_readv SYS_readv

  #define SYS_writev 146

  #define SYS_syscall_writev SYS_writev

  #define SYS_getsid 147

  #define SYS_fdatasync 148

  #define SYS__sysctl 149

  #define SYS_mlock 150

  #define SYS_munlock 151

  #define SYS_mlockall 152

  #define SYS_munlockall 153

  #define SYS_sched_setparam 154

  #define SYS_sched_getparam 155

  #define SYS_sched_setscheduler 156

  #define SYS_sched_getscheduler 157

  #define SYS_sched_yield 158

  #define SYS_sched_get_priority_max 159

  #define SYS_sched_get_priority_min 160

  #define SYS_sched_rr_get_interval 161

  #define SYS_nanosleep 162

  #define SYS_mremap 163

  #define SYS_setresuid 164

  #define SYS_getresuid 165

  #define SYS_vm86 166

  #define SYS_query_module 167

  #define SYS_poll 168

  #define SYS_syscall_poll SYS_poll

  #endif /* */

  每個系統呼叫都有一個預定義的數字(見上表),那實際上是用來進行這些呼叫的.核心透過中斷0x80來控制每一個系統呼叫.這些系統呼叫的數字以及任何引數都將被放入某些暫存器(eax用來放那些代表系統呼叫的數字,比如說)

  那些系統呼叫的數字是一個被稱之為sys_call_table[]的核心中的陣列結構的索引值.這個結構把系統呼叫的數字對映到實際使用的函式.

  OK,這些是繼續閱讀所必須的足夠知識了.下面的表列出了那些最有意思的系統呼叫以及一些簡短的註釋.相信我,為了你能夠真正的寫出有用的LKM你必須確實懂得那些系統調

  用是如何工作的.

  系統呼叫列表:

  int sys_brk(unsigned long new_brk);

  改變DS(資料段)的大小->這個系統呼叫會在1.4中討論

  int sys_fork(struct pt_regs regs);

  著名的fork()所用的系統呼叫

  int sys_getuid ()

  int sys_setuid (uid_t uid)

  用於管理UID等等的系統呼叫

  int sys_get_kernel_sysms(struct kernel_sym *table)

  用於存取系統函式表的系統呼叫(->1.3)

  int sys_sethostname (char *name, int len);

  int sys_gethostname (char *name, int len);

  sys_sethostname是用來設定主機名(hostname)的,sys_gethostname是用來取的

  int sys_chdir (const char *path);

  int sys_fchdir (unsigned int fd);

  兩個函式都是用於設定當前的目錄的(cd ...)

  int sys_chmod (const char *filename, mode_t mode);

  int sys_chown (const char *filename, mode_t mode);

  int sys_fchmod (unsigned int fildes, mode_t mode);

  int sys_fchown (unsigned int fildes, mode_t mode);

  用於管理許可權的函式

  int sys_chroot (const char *filename);

  用於設定執行程式的根目錄的

  int sys_execve (struct pt_regs regs);

  非常重要的系統呼叫->用於執行一個可執行檔案的(pt_regs是堆疊暫存器)

  long sys_fcntl (unsigned int fd, unsigned int cmd, unsigned long arg);

  改變fd(開啟檔案描述符)的屬性的

  int sym_link (const char *oldname, const char *newname);

  int sys_unlink (const char *name);

  用於管理硬/軟連結的函式

  int sys_rename (const char *oldname, const char *newname);

  用於改變檔名

  int sys_rmdir (const char* name);

  int sys_mkdir (const *char filename, int mode);

  用於新建已經刪除目錄

  int sys_open (const char *filename, int mode);

  int sys_close (unsigned int fd);

  所有和開啟檔案(包括新建)有關的操作,還有關閉檔案的.

  int sys_read (unsigned int fd, char *buf, unsigned int count);

  int sys_write (unsigned int fd, char *buf, unsigned int count);

  讀寫檔案的系統呼叫

  int sys_getdents (unsigned int fd, struct dirent *dirent, unsigned int count);

  用於取得檔案列表的系統呼叫(ls...命令)

  int sys_readlink (const char *path, char *buf, int bufsize);

  讀符號連結的系統呼叫

  int sys_selectt (int n, fd_set *inp, fd_set *outp, fd_set *exp, struct timeval *tvp);

  多路複用I/O操作

  sys_socketcall (int call, unsigned long args);

  socket 函式

  unsigned long sys_create_module (char *name, unsigned long size);

  int sys_delete_module (char *name);

  int sys_query_module (const char *name, int which, void *buf, size_t bufsize,

  size_t *ret);

  用於模組的載入/解除安裝和查詢.

  以上就是我認為入侵者會感興趣的系統呼叫.當然如果要獲得系統的root權你有可能需要一些特殊的系統呼叫,但是作為一個hacker他很可能會擁有一個上面列出的最基本的列表.在第二部分中你會知道如何利用這些系統呼叫來實現你自己的目的.

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752043/viewspace-940273/,如需轉載,請註明出處,否則將追究法律責任。

相關文章