发新话题
打印

[转载]给lkm初学者

[转载]给lkm初学者

信息来源:http://www.computersci.net/

我觉着理解lkm先的了解系统调用,所以抽空看了看内核。写一点心得,请大家指正。
一.中断向量表(idt)
linux中的系统调用(systemcalls),是由中断号0x80来进入系统调用服务函数(System_call)的.
而0x80这个中断向量保存在中断向量表中.整张中断向量表有256个中断向量,第128(0x80)个向量
就保存了我们的system_call的入口地址.这个向量表是怎么生成的呢?系统启动时,先经过是模式
和保护模式的初始化,执行head.s,在startup_32中的setup_idt就是建一张有256 个项的中断向量
表的函数.然后由start_kernel模块调用trap_init()来设置各种中断服务程序的入口地址.哼哼~~到重点了:)
里面的set_system_gate(0x80,&system_call)就是把system_call的地址放到了0x80中断向量中:).
什么还不明白???ok,在include/asm-i386/system.h定义为:
#define set_system_gate(n,addr) _set_gate(&ide[n],15,3,addr)
ok,这样看明白了吗?&ide[n]就是中断向量表中第n个向量的地址,addr就是你要赋值的地址.好了
这就是给中断向量表赋值的过程.还有就是的大家千万别把它当LINXU的起动过程来读就行了:))))).
二.系统调用表(sys_call_tab)
在sct中保存了166个系统调用入口地址,其中有三个保留.不知道大家记得么,刚才在setup_idt中建立了
256个long型的东东:),现在只用到了一部分,剩下的我们可以写出自己的systemcalls.嘿嘿,写关于自己的
系统调用就是把你写的函数地址写到sys_call_table[n](n>166)简单吧(呵呵,大家注意到了没有如果
这个n小于166呢?)具体的在这里就不多说了,请大家参考别人的文章吧(我很懒了:).好了继续,在unistd.h中
定义了每个系统调用所对应的数字,NR_syscalls是256.哈哈,好玩么??大家不要认为这个没什么用哦,
(NR_syscalls-166)*4就是我们可以自己添加系统调用的空间(举手:为什么乘4???,倒~~回答:是long型的拉).
三.使用systemcall
ok,开始使用systemcalls!!!要使用systemcall,首先要展开一个这样的
宏:_syscalln(type,type1,arg1,type2,arg2...).它在include/asm-i386/unistd.h中定义,
n是0-5的一个数(问:为什么只有5个!!!对我们有歧视吗??察汗~回答:只有5个寄存器呀:((),
表示系统调用参数的个数.相应的宏的参数为n*2+2.为什么是这样的??一会儿就会看到了.现在就举个
简单例子(前面的文章用syscall1咱们用syscall2.hehe),_syscall2的定义为:
#define _syscall2(type,name,type1,arg1,type2,arg2)
type name(type1 arg1,type2 arg2) //大家看到了吧,type1就是arg1的类型.
{
long __res;
__asm__ volatile ("int $0x80" //看到咱们的0x80了么?
: "=a" (__res) //__res使用eax寄存器.
: "0" (__NR_##name),"b" ((long)(arg1))),"c" ((long)(arg2))); /*把__NR_name给eax,arg1给
ebx,arg给ecx.*/
if (__res >= 0)
return (type) __res; //现在__res里面是咱们的systemcall的名字
errno = -__res;
return -1;
}
(大家注意到了没有?上面的例子有什么不同??因为我在学校的机房没有别人写好的例子,
只能由我亲手一个字一个字的打出来:((()
好了,因为有人刚才提到了歧视的问题...我觉着有必要进一步说明一下.在上面的那个宏中,
5个参数对应5个寄存器:ebx:arg1,ecx:arg2,edx:arg3,esi:arg4,edi:arg5,eax被用来作返回
sys_call_table中的名字(就是偏移量).这些参数的传递用到了其存器帧结构pt_regs,
在include/asm-i386/ptrace.h(大家看了那个ptrace漏洞了么?)中定义.请大家注意它的结构
要和压入stack的寄存器的顺序保持一致.上面的汇编中的int 0x80是我们到了中断服务程序的
入口system_call中.它现在开始工作了:先保存所有寄存器,检查是否是合法的系统调用(刚才
我们嘲笑的NR_syscalls又该出场了!!就用它来判断我们的偏移量是否出界),然后根据sys_call_table中的
偏移量把控制权交给真正的系统调用代码:(((好累呀!!
四.不用宏的方法
用刚才那个宏好像很麻烦呀!!!有人说:我觉得他就像一个函数的声明!!!(是啊,很正确.但不要抢我的
台词!!!我刚想说的:((().ok,就是像呀.嘿嘿,那我们就用这个办法吧.
int (* syscalln)(arguments); //定义一个系统调用的函数原型;
syscalln=sys_call_table[n]; //把sys_call_table中的系统调用函数地址给函数指针;
syscalln(arguments); //使用系统调用;
好了,明白了吧???我们定义一个系统调用的函数原型,然后把系统调用函数地址给刚才我们定义的
函数指针.使他变成系统调用的入口.其实原理是一样的.这个方法现在被广泛使用在各种特别有名的
lkm后门中.像这样来替换原来的系统调用:
int (*orig_syscall)(const char *path); //原来的系统调用;


int hacked_syscall(const char *path) //我们自己的系统调用;
{
return 0;
}

int init_module(void)
{
orig_syscall=sys_call_table[SYS_syscall]; //把原来的保存;
sys_call_table[SYS_syscall]=hacked_syscall; //替换;
return 0;
}

五.有用的系统调用
自己参考以前的那篇文章,或者看THC的文章.)我在这里就不重复了.
六.strace
这个东东你要是不知道的话可以来看看,要不请不用浪费时间了:))因为和别的没什么不同的.
用这个东西的目的是要找出某一程序中倒底使用了什么系统调用.方法就是:strace program.
然后会列出很多信息,从中可以找出来我们需要hack的系统调用.给个例子先:).
用strace ls,
t_mode=S_IFREG|0644, st_size=110304, ...}) = 0
mmap2(NULL, 110304, PROT_READ, MAP_PRIVATE, 3, 0) = 0x40161000
close(3) = 0
ioctl(1, TCGETS, {B38400 opost isig icanon echo ...}) = 0
ioctl(1, TIOCGWINSZ, {ws_row=24, ws_col=80, ws_xpixel=560, ws_ypixel=336}) = 0
brk(0x8059000) = 0x8059000
open(".", O_RDONLY|O_NONBLOCK|O_LARGEFILE|O_DIRECTORY) = 3
fstat64(3, {st_mode=S_IFDIR|0750, st_size=4096, ...}) = 0
fcntl64(3, F_SETFD, FD_CLOEXEC) = 0
brk(0x805b000) = 0x805b000
getdents64(3, /* 47 entries */, 4096) = 1592
getdents64(3, /* 0 entries */, 4096) = 0
close(3) = 0
open("/etc/mtab", O_RDONLY) = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=233, ...}) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x40028000
read(3, "/dev/hda9 / ext2 rw 0 0nnone /pr"..., 4096) = 233
close(3) = 0
munmap(0x40028000, 4096) = 0
open("/proc/meminfo", O_RDONLY) = 3
fstat64(3, {st_mode=S_IFREG|0444, st_size=0, ...}) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x40028000
read(3, " total: used: free:"..., 4096) = 547
close(3) = 0
munmap(0x40028000, 4096) = 0
fstat64(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 1), ...}) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x40028000
ioctl(1, TCGETS, {B38400 opost isig icanon echo ...}) = 0
write(1, "aaa.c~tadore-0.39b4.tar icmpt "..., 51aaa.c~ adore-0.39b4.tar icmp nsmail superlkm.c) = 51
write(1, "adoretDesktoptt icmp.c strace "..., 44adore Desktop
icmp.c strace superlkm.o) = 44
munmap(0x40028000, 4096) = 0
_exit(0) = ?
大家看到getdents64这个系统调用了么?这就是我们要hack的系统调用,如果把我们的“目标”从buffer里
干掉后再write就显示不出来被我们锁定的目标了,这样我们就实现了对具体文件/进程的隐藏.其实还有一种
办法,注意到么??就是把write替换成我们的函数使它不能输出我们的目标.具体方法在adore里有实现
(好像是这样的:)))看到了write出来的东东了么?因为我正在看adore).
好了,到此结束:)我写这篇文章的原因是为了帮助对于lkm的初学者更好的理解linux下的中断和系统调用的
原理(当然我自己也是:).我希望大家尽快的成长,因为大环境好了我们自己肯定也有提高.希望alert7和大鹰
给我指点,因为我正上学。而且学校很特殊,没有足够的时间去读内核,那里不对请指正:)
ps:最近我真的很惨:(((我要把我自己的机子抵押出去了,我就用一个mm机子写了这文章.感谢她,好人还是多呀:)
_________________
请不要对我说关于ms的东东,我不懂也不想知道!!!
人情如冰六月寒,花做一份艳,为谁笑人间? 如果任何人发现我转载的有图像的文章中图像失效或者文章有问题,请及时短消息通知我。先谢谢。::)) coup de foudre

TOP

引用:
这里是引用第[1 楼]tt6710252006-01-17 22:34发表的:
金州大哥解释一下什么是 lkm
是linux 内核吗?
       /#write by ██████#/
LKM是Linux内核为了扩展其功能所使用的可加载内核模块。LKM的优点:动态加载,无须重新实现整个内核。基于此特性,LKM常被用作特殊设备的驱动程序(或文件系统),如声卡的驱动程序等等。
相关资料有时间可以看看
http://www.eviloctal.com/forum/htm_data/16/0601/18489.html
哈哈 [s:66]
人情如冰六月寒,花做一份艳,为谁笑人间? 如果任何人发现我转载的有图像的文章中图像失效或者文章有问题,请及时短消息通知我。先谢谢。::)) coup de foudre

TOP

引用:
这里是引用第[3 楼]温柔一刀2006-01-30 21:57发表的:
我想学习编程不知该怎样学起请各位老大教教我
参看http://www.eviloctal.com/forum/htm_data/12/0505/10892.html
http://www.eviloctal.com/forum/htm_data/12/0502/7950.html
求人不如求己
千里之行 始于足下
当忍辱负重 知任重道远
人情如冰六月寒,花做一份艳,为谁笑人间? 如果任何人发现我转载的有图像的文章中图像失效或者文章有问题,请及时短消息通知我。先谢谢。::)) coup de foudre

TOP

发新话题