网络通信 频道

SLKM入侵初探

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.

文章转载地址:http://www.cnpaf.net/Class/hack/06101110491521140234.html

0
相关文章