作者:林納 來源:silversand.net
第一部分. 基礎知識
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\n"); 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時才可以被除去.在檢查過這個以後,你可以用下面的命令卸載這個模塊
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他很可能會擁有一個上面列出的最基本的列表.在第二部分中你會知道如何利用這些系統調用來實現你自己的目的。