Linux下用lsmod查看LKM,Solaris下用modinfo查看LKM。此外分别有
modload/modunload对应Linux下的insmod/rmmod。
modload slkm 加载slkm模块
modinfo显示的题头如下:
Id Loadaddr Size Info Rev Module Name
100 6099f818 164 - 1 slkm (First Loadable Kernel Module)
Id表示模块号,Loadaddr是16进制表示的文本段起始地址,Size表示文本段、数据段、
BSS段的大小总和(16进制字节单位),Info给出一些模块相关信息,Rev表示可加载模
块系统的修正版本号,Module Name对应文件名和模块描述。
modunload -i 100 卸载slkm模块
如果struct modlmisc的第二个成员为空串"",表示模块名为空,此时modload进去的
内核模块用modinfo看不到,modinfo | grep slkm显示为空,可是Id(100)实际已被
使用,可以通过如下方式验证:
modunload -i 100 卸载slkm模块
修改slkm.c,使得模块描述为空串,重新编译链接
modload slkm 加载slkm模块
modload /usr/kernel/misc/diaudio 加载另外一个misc模块
如果/usr/kernel/strmod/rlmod尚未被加载,可以从远程rlogin刺激内核加载该模块,
然后modinfo查看,明显注意到本该连续的Id号有了一个跳跃,意味着这里可能存在
一个已加载模块。为什么说可能,而不能确认,因为如果一个模块已经被加载过,即
使后来modunload掉了,这个Id号也保留给它了,而modunload这样的一个Id号并不会
报告任何错误信息,你无法判断该Id号对应的模块是否加载在内存中。对于一个从未
使用过的Id号,modunload时会报告can't unload the module: Invalid argument。
(刚才测试的结果并不完全支持此结论,似乎还有其他情况)
在/usr/kernel下有很多LKM,misc模块表示那些不与设备通信的模块,这种模块没有
Info信息,modinfo查看的时候对应栏显示'-'。
gcc -D_KERNEL -DSVR4 -DSOL2 -DDEBUG -O3 -c slkm.c
ld -o slkm -r slkm.o
链接时必须使用-r选项
-r Combine relocatable object files to produce one
relocatable object file. ld will not complain
about unresolved references. This option cannot
be used in dynamic mode or with -a.
很多符号要进入内核空间才能得到正确解析,如果不指定-r选项,链接器认为存在无
法解析的符号而拒绝链接。
--------------------------------------------------------------------------
/*
* File : program for SPARC/Solaris using Loadable Kernel Modules
* Version: 1.0
* Author : Plasmoid / THC
* : The Hacker's Choice Websitehttp://www.infowar.co.uk/thc/
* Complie: gcc -D_KERNEL -DSVR4 -DSOL2 -DDEBUG -O3 -c slkm.c
* : ld -o slkm -r slkm.o
* Usage : modload slkm / modinfo | grep slkm / modunload -i
* Date : 1999-03
*/
/*
* 虽然不是开发设备驱动程序,但同样必须包含如下头文件
*/
#include
#include
#include /* This is the loadable module wrapper. */
extern struct mod_ops mod_miscops;
/* Module linkage information for the kernel. */
static struct modlmisc modlmisc =
{
&mod_miscops,
/*
* 内核模块的名字,如果这里为"",则modinfo不会显示该模块
*/
#ifdef DEBUG
"First Loadable Kernel Module", /* -DDEBUG打开调试开关 */
#else
/* 定义成空串,对比modinfo显示效果,modinfo | grep slkm */
"",
#endif
};
static struct modlinkage modlinkage =
{
/* 应该对应modinfo显示中Rev栏 */
MODREV_1,
/* 通知内核这不是一个设备驱动模块,用modinfo查看时不会显示Info信息 */
( void * )&modlmisc,
NULL
};
/* 一个内核可加载模块必须包含如下三个函数 */
int _init ( void )
{
int i;
if ( ( i = mod_install( &modlinkage ) ) != 0 )
{
cmn_err( CE_NOTE, "Could not install module\n" );
}
else
{
cmn_err( CE_NOTE, "slkm: successfully installed\n" );
}
return( i );
} /* end of _init */
int _info ( struct modinfo * modinfop )
{
return( mod_info( &modlinkage, modinfop ) );
} /* end of _info */
int _fini ( void )
{
int i;
if ( ( i = mod_remove( &modlinkage ) ) != 0 )
{
cmn_err( CE_NOTE, "Could not remove module\n" );
}
else
{
cmn_err( CE_NOTE, "slkm: successfully removed\n" );
}
return( i );
} /* end of _fini */
--------------------------------------------------------------------------
让我们来研究一下/usr/include/sys/systm.h,这个头文件里隐藏了太多秘密。
/* Structure of the system-entry table. */
struct sysent
{
char sy_narg; /* total number of arguments */
char sy_flags; /* various flags as defined below */
int ( *sy_call ) (); /* argp, rvalp-style handler */
krwlock_t * sy_lock; /* lock for loadable system calls */
longlong_t ( *sy_callc ) (); /* C-style call hander or wrapper */
};
extern struct sysent sysent[];
这个数组的下标就是系统调用号,可以查看/usr/include/sys/syscall.h文件。
truss ls发现该命令使用了getdents64()系统调用,现在我们来hook这个系统调用。
Solaris内核并不象Linux内核那样包含很多标准C函数,如果你想用这些标准函数,
需要从/lib/libc.a中析取它们并用ld命令连接到你的模块中。
gcc -D_KERNEL -DSVR4 -DSOL2 -DDEBUG -O3 -c shi.c
ar -x /lib/libc.a memmove.o strstr.o
ld -o shi -r shi.o memmove.o strstr.o
如果直接ld -o shi -r shi.o也可以通过,因为指定了-r选项,但是当实际加载模块
的时候,会报告不能加载模块,无此文件或目录纭纭,实际就是因为无法解析符号,
像memmove、strstr等等。
modload shi
can't load module: No such file or directory
此时可以先去掉-r选项,ld报告一大堆错误,去掉那些明显属于内核符号引用的部分,
检查是否还有一些平时属于标准库函数范畴的符号引用,用ar析取出来重新链接。这
可是血的教训换来的。
memmove、strstr这种函数不是系统调用,完全可以写自己的函数代替它们。
Plasmoid / THC认为strstr()函数在内核中工作时会有点问题,我看不出来这个函数
会有什么独特的地方导致其在内核空间工作异于用户空间,当指定字符串在文件名中
出现不只一次的时候,我们的测试模块依旧达到了隐藏文件的效果,并不像原作者所
说工作不正常。即使strstr真地存在问题,我们完全可以考虑编写自己的替代函数。
(发现一个关于指针的错误同时存在于SLKM和LLKM中,修正后应无Plasmoid所说问题)
字节数组如下:
char * pointer -- 01 02 03 04 05 ... 0D 0A (例子里并没有以00结尾)
此时
strstr( pointer, "\x0D\x0A" )将返回NULL,必须注意到这一点!
鉴于此,可以考虑自己编写子串匹配函数。
测试结果,这个模块工作相当不正常,
char hide[] = "ourtoo"; /* 企图隐藏的文件名 */
本来有五个文件加目录
ourtoo
ourtool/
ourtool1
ourtool2
ourtoolourtool
modload shi之后ls立即导致SPARC/Solaris 2.6重启动
(
自己提供了子串匹配函数,被迫介入strlen()函数,还是重启动,说明问题不在
strstr()本身,要么整个字符串处理函数族都需要替换,要么存在其他未知问题。
)
本来有四个文件
ourtoo ourtool1 ourtool2 ourtoolourtool
modload shi之后ls ourt*看到两个
ourtool1 ourtoolourtool
无论是普通文件还是子目录,如果只有一个匹配,就可以达到正常隐藏效果。现在看
来Plasmoid说的问题的确存在,但不见得是strstr()的毛病,需要进一步确认。尚未
测试自己编写子串匹配函数的效果。前面提到的指针问题依旧,不明白的是,按照我
所理解的正确方式修正后能正确工作,可为什么在我看来是错误的指针用法也能工作?
见鬼了不成,编译器替我做了修正吗?
考虑隐藏一个子目录,正常情况下与该子目录名同匹配的概率相当小,在该子目录下
隐藏一大堆文件。即使修正了前面这个原因未明的问题,同样可以采用这种方式。
(SPARC/Solaris 2.