亲密接触恶意代码 文件感染和内存驻留

2008-02-23 06:52:41来源:互联网 阅读 ()

新老客户大回馈,云服务器低至5折

这次,作者将和大家一起讨论病毒的感染技术。另外,从本文开始,我们将陆续接触到一些病毒的高级编码技术。例如,内存驻留、EPO(入口点模糊)技术、加密技术、多态和变形等。通过这些高级技巧,你将进一步感受到病毒技术的精华,从而更好的享受其中精妙的思想与编程技艺。

  在解决了起始目录的问题之后,就可以从这些起始目录开始使用FindFirstFile和FindNextFile开始遍历其下以及其子目录下的所有文件和目录了,遍历方法可采用深度优先或广度优先搜索算法,较常用的还是深度优先算法。具体实现方式可采用递归搜索或非递归搜索两种实现方式。递归搜索需要占用栈空间,有可能造成栈空间耗竭而产生异常,不过在现实应用中这种情况很少出现,而非递归搜索则不存在此问题,但代码实现略复杂。在现实应用中,应用最多的还是递归遍历搜索。搜索时,可指定FindFirstFile的第一形参为*.*以搜索所有文件,根据搜索结果WIN32_FIND_DATA结构的dwFileAttributes成员判断是否为目录,若为目录则需要继续遍历该子目录,根据WIN32_FIND_DATA的cFileName中的文件名成员判断是否具有要感染的文件后缀以采取修改感染动作,以下代码实现了递归搜索某个目录及其下所有子目录的功能:

void enum_path(char *cpath){
 WIN32_FIND_DATA wfd;
 HANDLE hfd;
 char cdir[MAX_PATH];
 char subdir[MAX_PATH];
 int r;
 GetCurrentDirectory(MAX_PATH,cdir);
 SetCurrentDirectory(cpath);
 hfd = FindFirstFile("*.*",&wfd);
 if(hfd!=INVALID_HANDLE_VALUE) {
  do{
   if(wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
   {
    if(wfd.cFileName[0] != '.') {
     // 合成完整路径名
     sprintf(subdir,"%s\\%s",cpath,wfd.cFileName);
     // 递归枚举子目录
     enum_path(subdir);
    }
    }else{
     printf("%s\\%s\n",cpath,wfd.cFileName);
     // 病毒可根据后缀名判断是
     // 否要感染相应的文件
    }
   }while(r=FindNextFile(hfd,&wfd),r!=0);
  }
  SetCurrentDirectory(cdir);
 }
  短短20 多行C 代码就实现了文件遍历的功能,Win32 API的强大功能不仅为开发者提供了便利,同时也为病毒敞开了方便之门。用汇编实现则稍微复杂一些,感兴趣的读者可参阅Elkern 中的enum_path部分,原理是一样的,限于篇幅这里不再给出相应的汇编代码。

  非递归搜索不使用堆栈存储相关的信息,而使用显式分配的链表或栈等结构存储相关的信息,应用一个迭代循环完成递归遍历同样的功能,下面是使用链表以栈方式处理子目录列表的一个简单实现:

void nr_enum_path(char *cpath){
 list dir_list;
 string cdir,subdir;
 WIN32_FIND_DATA wfd;
 HANDLE hfd;
 int r;
 dir_list.push_back(string(cpath));
 while(dir_list.size()) {
  cdir = dir_list.back();
  dir_list.pop_back();
  SetCurrentDirectory(cdir.c_str());
  hfd = FindFirstFile("*.*",&wfd);
  if(hfd!=INVALID_HANDLE_VALUE) {
   do{
    if(wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
     if(wfd.cFileName[0] != '.') {
      // 合成完整路径名
      subdir=cdir "\\" wfd.cFileName;
      cout<<"push subdir: "<      // 递归枚举子目录
      dir_list.push_back(string(subdir));
     }
     }else{
      printf("%s\\%s\n",cpath,wfd.cFileName);
      // 病毒可根据后缀名判断
      // 是否要感染相应的文件
     }
    }while(r=FindNextFile(hfd,&wfd),r!=0);
   }
  }//end while
}


  在以汇编语言实现时,需要自己管理链表以及分配和释放相应的结构,因此较为烦琐,代码量也稍大,因此病毒多采用递归的方式进行搜索。值得注意的是搜索深层次的目录是很费时的,因此大部分病毒为避免CPU占用率过高,搜索一定数量的文件之后,都会调用Sleep 休眠一会,以避免被敏感的用户发觉。文件搜索和感染模块通常是以单独的线程运行的,在病毒获得控制权后,创建相应的搜索和感染线程,而将主现成的控制权交给原程序。

PE 文件的修改和感染策略

  既然已经能够搜索磁盘及网络共享文件中的所有文件,要实现寄生,那么自然下一步就是对搜索到的PE文件进行感染了。感染PE的很重要的一个考虑就是将病毒代码写入到PE 文件的哪个位置。读写文件一般利用Win32 API CreateFile、CreateFileMapping、MapViewOfFile等API以内存映射文件的方式进行,这样可以避免自己管理缓冲的麻烦,因而为较多病毒所采用。为了能够读写具有只读属性的文
件,病毒在操作前首先利用GetFileAttributes 获取其属性并保存,然后用SetFileAttributes将文件的属性修改为可写,在
感染完毕后再恢复其属性值。
  
  一般说来,有如下几种感染PE文件的方案供选择:

  a)添加一个新的节。将病毒代码写入到新的节中,相应修改节表,文件头中文件大小等属性值。由于在PE尾部增加了一个节,因此较容易被用户察觉。在某些情况下,由于原PE头部没有足够的空间存放新增节的节表信息,因此还要对其它数据进行搬移等操作。鉴于上述问
题,PE 病毒使用该方法的并不多。

  b)附加在最后一个节上。修改最后一个节节表的大小和属性以及文件头中文件大小等属性值。由于越来越多的杀毒软件采用了一种尾部扫描的方式,因此很多病毒还要在病毒代码之后附加随机数据以逃避该种扫描。现代PE 病毒大量使用该种方式。

  c)写入到PE文件头部未用空间各个节所保留的空隙之中。PE 头部大小一般为1024 字节,有5-6 个节的普通PE文件实际被占用部分一般仅为600 字节左右,尚有400 多个字节的剩余空间可以利用。PE文件各个节之间一般都是按照512 字节对齐的,但节中的实际数据常常未完全使用全部的512字节,PE文件的对齐设计本来是出于效率的考虑,但其留下的空隙却给病毒留下了栖身之地。这种感染方式感染后原PE 文的总长度可能并不会增加,因此自CIH 病毒首次使用该技术以来,备受病毒作者的青睐。

标签:

版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有

上一篇:黑客技术:入侵时隐藏自己的真正身份

下一篇:新手也能对付病毒:系统安全自检手册