免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 1478 | 回复: 0
打印 上一主题 下一主题

检测并禁用隐藏服务 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2007-03-13 20:50 |只看该作者 |倒序浏览


    隐藏服务的概念是由hxdef 和rootkit这些后门工具提出的。这些后门工具通过挂钩系统本地调用来隐藏自己,原本通过调用Windows API调用查看系统服务的企图都是徒劳的。所以这时的系统是不可靠的,不值得信任的。目前针对查找隐藏服务的工具已经有很多,比如IceSword,knlsc,FHS等等。虽然这些软件都是免费的,但是它们到目前为止都不是开源,所以将自己的实现版本展示出来,正如knlsc的作者所说的那样,这是一个简单的小程序。
    Knlsc是通过将%SystemRoot%/System32/Config/System这个Hive文件转储出来,提取出ControlSet001/Services的子项再与RegEnumKeyEx的输出结果进行比对,发现若是在RegEnumKeyEx的输出结果中没有的子项就可以认为是一个隐藏的服务。当然knlsc还认为隐藏服务必须同时拥有ImagePath,Start,Type三个键值。据说knlsc运行时还将从资源段中放出一个驱动程序,但是估计这个驱动是假的。将knlsc托壳后用VC从资源段中导出的文件是一个没有EntryPoint但有MZ标志的驱动,没有办法进行反汇编。或许作者使用了SMC技术,放出资源文件后在进行修改,在执行文件中也有NtLoadDriver的调用片段,但是同一作者的knlps中的资源驱动却未作任何的处理。要实现检测隐藏服务的功能其实没有必要使用驱动程序,即使可以验证knlsc驱动的真实性。直接对Hive文件的转储也不是必须的,虽然这只要通过修改Gary Nebbett的示例代码就可做到。
    Hive文件的转储可以通过RegSaveKey函数来进行,rootkitrevealer就是使用这个API的扩充函数RegSaveKeyEx工作的,至少到目前为止还没有挂钩这类函数的后门,但是世上没有永远的安全,在理论上是可行的,可能不得不对该函数的输出文件进行处理,这将在一定程度上影响该函数的执行时间。使用该函数时还必须赋予调用进程以SE_BACKUP_NAME权限。
    在实现中将“HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Services“的子项都转储为Hive格式文件(使用DumpServiceInfo函数),存放在C:\tmp.hive,在C盘下不可有同名文件,否则会发生Dump错误。现在的问题是如何对Hive格式文件进行处理,在这一点上必须感谢Petter Nordahl-Hagen所写的NT Registry Hive access library,它是The Offline NT Password Editor的一部分。本人的实现很大程度上就是参照他的程序,然而这个库工作在Linux环境,但是它向VC编译器移植的工作量是极少的,只需稍加修改。
1.将 #include 〈unistd.h〉 去掉
2.将程序中三处的
#define D_OFFS(o) ( (void *)&(key-〉o)-(void *)hdesc-〉buffer-vofs )
改为
#define D_OFFS(o) ( (int *)&(key-〉o)-(int *)hdesc-〉buffer-vofs )
因为在VC中无法打印void * 类型,只得改为int * 。
3.将程序中唯一的一处使用snprintf函数该为_snprintf,即
snprintf(path,maxlen,“(...)%s“,tmp);改为
_snprintf(ptth,maxlen,”(…)%s”,tmp);
4.添加两个VC不支持的函数来使编译通过
void bzero(void *s,int n)
{
memset(s,0,n);
}
int strncasecmp(const char *s1, const char *s2, size_t n)
{
return _stricmp(s1,s2);
}
    为了表示对Petter Nordahl-Hagen的尊重,我不再修改他的库文件ntreg.c和ntreg.h(除了以上移植的需要),而是将所有需要重写和添加的函数放到KHS.C文件中,这样可以使原来的库文件保持其独立性。
    由于在Petter库中openHive函数使用open 和 read 函数来进行hive文件的读取,在VC条件下的read函数有一个问题,每当文件中存在一个0x1a的二进制数值时,read函数就会在那儿终止,这样就会导致hive文件无法完全导入。所以就使用了Windows API重写openHive,命名为My_openHive。相应的还重写了closeHive,writeHive并加上了前缀My_。
    随后GetPatterns函数将使用RegEnumKey枚举的服务键值名称保存在pattern的全局变量指针中,为以后的匹配作准备。ShowHideService函数是由nk_ls函数改写的,将由Hive文件导出的buffer中的服务名称与pattern[I]作比较,这个比较过程使用CompareHive函数。若比较结果为相同,CompareHive会将pattern[I]置为NULL,以提高匹配速度,或许有更好的匹配算法,但在这个小程序中也不使用了。若结果不同,则说明该服务是隐藏的,显示出该隐藏服务的名称,文件路径(ShowPathImage是由cat_vk改写的),启动类型和服务类型,并将该隐藏服务的启动类型改为SERVICE_DISABLED。如果存在隐藏服务并且禁止了该隐藏服务(仅在buffer中的修改),通过调用My_writeHive将修改过的hive 的buffer保存在C:\tmp2.hiv文件中,此时提供用户一个选择“是否要禁用隐藏服务”,默认的选择是“否”,如果用户确实想要禁用,可输入“Yes”或“Y",接着使用RestoreServiceInfo函数将C:\tmp2.hiv文件导回原来的%SystemRoot%/System32/Config/System这个Hive文件中,这一步由系统自己来完成,值得一提的是Win32函数RegRestoreKey即使在dwFlags参数中使用了REG_FORCE_RESTORE (8) ,在第一次调用时往往会错误返回,一般在第二次调用就会成功,所以就使用了一个循环直到它成功后为止,并且调用它的进程需要有SE_RESTORE_NAME的权限。
    至于让隐藏服务真正失去作用,仍然需要重新启动计算机之后。
下面给出KHS.C的完整源代码:
/*
* KHS.cpp - Kill Hide Services v0.1
* Copyright (c) 2005 linux2linux.
*
* It takes notes from knlsc and FHS.
* Thank you, Petter Nordahl-Hagen, for your “NT Registry Hive access library“
*
* Freely distributable in source or binary for noncommercial purposes.
*
* THIS SOFTWARE IS PROVIDED BY PETTER NORDAHL-HAGEN `AS IS’’ AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*/
#include “ntreg.h“
#include 〈windows.h〉
char **pattern;
int pattern_count;
int nohideservice;
int ischange;
extern char *val_types[REG_MAX+1];
struct hive *My_openHive(char *filename, int mode);
void My_closeHive(struct hive *hdesc);
int CompareHive(char *sample)
{
      int i;
      for(i = 0; i 〈 pattern_count ; i++)
      {
           if(pattern!=NULL)
           {
                 if( strcmp ( sample , pattern[ i ] ) == 0 )
                 {
                      free(pattern);
                      pattern=NULL;
                      return 1;
                 }
           }
      }
      return 0;
}
//Because read can’t work well in windows.
//while it read 0x1a from the opened file, the function read will stop there.
//I don’t know the reason why, it work well in linux envoriment.
// read the dumped hive file to fill hive struct.
// return the point
struct hive *My_openHive(char *filename, int mode)
{
  HANDLE hFile;
  int szread;
  struct hive *hdesc;
  int vofs;
  unsigned long pofs;
  char *c;
  struct hbin_page *p;
  struct regf_header *hdr;
  int verbose = (mode & HMODE_VERBOSE);
  CREATE(hdesc,struct hive,1);
  hdesc-〉filename = str_dup(filename);
  hdesc-〉state = 0;
  hdesc-〉size = 0;
  hdesc-〉buffer = NULL;
  hFile = CreateFile(hdesc-〉filename,
    GENERIC_READ,                 // open for reading
    0,                            // do not share
    NULL,                         // no security
    OPEN_ALWAYS,                // existing file only
    FILE_ATTRIBUTE_NORMAL,        // normal file
    NULL);                                   // no attr. template
  if (hFile == INVALID_HANDLE_VALUE)
  {
    printf(“Could not open hive file.“);  // process error
      return 0;
  }
  /* Read the whole file */
  hdesc-〉size = GetFileSize(hFile,  NULL);
  ALLOC(hdesc-〉buffer,1,hdesc-〉size);
  ReadFile(hFile, (void *)hdesc-〉buffer, hdesc-〉size, &szread, NULL);
  CloseHandle(hFile);
  if (szread 〈 hdesc-〉size) {
    printf(“Could not read file, got %d bytes while expecting %d\n“,
          szread, hdesc-〉size);
    My_closeHive(hdesc);
    return(NULL);
  }
  /* Now run through file, tallying all pages */
  /* NOTE/KLUDGE: Assume first page starts at offset 0x1000 */
   pofs = 0x1000;
   hdr = (struct regf_header *)hdesc-〉buffer;
   if (hdr-〉id != 0x66676572) {
     printf(“openHive(%s): File does not seem to be a registry hive!\n“,filename);
     return(hdesc);
   }
   for (c = hdr-〉name; *c && (c 〈 hdr-〉name + 64); c += 2) putchar(*c);
   hdesc-〉rootofs = hdr-〉ofs_rootkey + 0x1000;
   while (pofs 〈 hdesc-〉size) {
#ifdef LOAD_DEBUG
   if (verbose) hexdump(hdesc-〉buffer,pofs,pofs+0x20,1);
#endif
     p = (struct hbin_page *)(hdesc-〉buffer + pofs);
     if (p-〉id != 0x6E696268) {
       printf(“Page at 0x%lx is not ’hbin’, assuming file contains garbage at end“,pofs);
       break;
     }
     hdesc-〉pages++;
#ifdef LOAD_DEBUG
     if (verbose) printf(“\n###### Page at 0x%0lx has size 0x%0lx, next at 0x%0lx ######\n“,pofs,p-〉len_page,p-〉ofs_next);
#endif
     if (p-〉ofs_next == 0) {
#ifdef LOAD_DEBUG
       if (verbose) printf(“openhive debug: bailing out.. pagesize zero!\n“);
#endif
       return(hdesc);
     }
#if 0
     if (p-〉len_page != p-〉ofs_next) {
#ifdef LOAD_DEBUG
       if (verbose) printf(“openhive debug: len & ofs not same. HASTA!\n“);
#endif
       exit(0);
     }
#endif
     vofs = pofs + 0x20; /* Skip page header */
#if 1
     while (vofs-pofs 〈 p-〉ofs_next) {
       vofs += parse_block(hdesc,vofs,verbose);
     }
#endif
     pofs += p-〉ofs_next;
   }
  return(hdesc);
}
void My_closeHive(struct hive *hdesc)
{
  FREE(hdesc-〉filename);
  FREE(hdesc-〉buffer);
  FREE(hdesc);
}
int My_writeHive(struct hive *hdesc)
{
  HANDLE hFile;
  DWORD dwBytesWritten;
  hFile = CreateFile(“C:\\tmp2.hiv“,
    GENERIC_WRITE,                // open for writing
    0,                            // do not share
    NULL,                         // no security
    CREATE_ALWAYS,                  // open or create
    FILE_ATTRIBUTE_NORMAL,        // normal file
    NULL);
  if(hFile == INVALID_HANDLE_VALUE)
  {      printf(“Can’t open dump file“);
           return 0;
  }
  WriteFile(hFile, hdesc-〉buffer, hdesc-〉size,&dwBytesWritten, NULL);
  if(dwBytesWritten != hdesc-〉size)
  {
        printf(“WriteHive error\n“);
  }
  CloseHandle(hFile);
  return 0;
}
void CleanPatterns()
{
      int i;
      if(pattern!=NULL)
      {
           for(i = 0; i 〈 pattern_count; i++)
           {
                 if(pattern!=NULL)
                      free(pattern);
           }
           free(pattern);
      }
}
void GetPatterns()
{
      HANDLE hService;
      CHAR     achKey[MAX_PATH];
      DWORD i;
      DWORD retCode;
      int Nohide = 1;
      DWORD SubKeyNum = 0;
      pattern_count = 0;
      if(RegOpenKeyEx(
           HKEY_LOCAL_MACHINE,         // handle to open key
           “SYSTEM\\ControlSet001\\Services“, // subkey name
           NULL,   // reserved
           KEY_ALL_ACCESS,// security access mask
           &hService    // handle to open key
           ) != ERROR_SUCCESS)
      {
           printf(“sorry %d\n“,GetLastError());
           return;
      }
    RegQueryInfoKey( hService,
        NULL,
        NULL,
        NULL,
        &SubKeyNum,
        NULL,
        NULL,
        NULL,
        NULL,
        NULL,
        NULL,
        NULL);
      //Before it don’t work well , because i set the wrong premission of HKEY
      //KEY_ALL_ACCESS is needed
      if(SubKeyNum == 0)
      {
           printf(“SubKey’s Number is NULL, it’s too strange.\n“);
           return;
      }
      pattern = malloc(sizeof(char *) * SubKeyNum );
      for (i = 0, retCode = ERROR_SUCCESS; retCode == ERROR_SUCCESS; i++)
    {
        retCode = RegEnumKey(
                 hService,      // handle to key to query
                 i,  // index of subkey to query
                 achKey,  // buffer for subkey name
                 MAX_PATH   // size of subkey name buffer
                 );
        if (retCode == (DWORD)ERROR_SUCCESS)
        {
          //What i add to get pattern Services Table.
              pattern[ pattern_count ] = strdup ( achKey ) ;
              pattern_count++;
        }
       }
      CloseHandle(hService);
}
void ShowPathImage(struct hive *hdesc, int nkofs, char *path)
{
  void *data;
  int len,i,type;
  char string[SZ_MAX+1];
  type = get_val_type(hdesc, nkofs, path);
  if (type == -1) {
    printf(“No such value 〈%s〉\n“,path);
    return;
  }
  len = get_val_len(hdesc, nkofs, path);
  if (!len) {
    printf(“Value 〈%s〉 has zero length\n“,path);
    return;
  }
  data = (void *)get_val_data(hdesc, nkofs, path, 0);
  if (!data) {
    printf(“Value 〈%s〉 references NULL-pointer (bad boy!)\n“,path);
    abort();
    return;
  }
  switch (type) {
  case REG_SZ:
  case REG_EXPAND_SZ:
  case REG_MULTI_SZ:
    cheap_uni2ascii(data,string,len);
    for (i = 0; i 〈 (len〉〉1)-1; i++) {
      if (string == 0) string = ’\n’;
      if (type == REG_SZ) break;
    }
    puts(string);
    break;
  case REG_DWORD:
    printf(“0x%08x“,*(unsigned short *)data);
    break;
  default:
    printf(“Don’t know how to handle type yet!\n“);
  case REG_BINARY:
    hexdump((char *)data, 0, len, 1);
  }
}
void EnablePriv(LPCTSTR lpName)
{
      HANDLE hToken;
      LUID sedebugnameValue;
      TOKEN_PRIVILEGES tkp;
      if ( ! OpenProcessToken( GetCurrentProcess(),
           TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken ) )
      {    printf(“open process error\n“);
           return;
      }
      if ( ! LookupPrivilegeValue( NULL, lpName  , &sedebugnameValue ) ){
           printf(“can’t find privilege error\n“);
           CloseHandle( hToken );
           return;
      }
      tkp.PrivilegeCount = 1;
      tkp.Privileges[0].Luid = sedebugnameValue;
      tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
      if ( ! AdjustTokenPrivileges( hToken, FALSE, &tkp, sizeof (tkp), NULL, NULL ) )
      {
           printf(“adjust error\n“);
           CloseHandle( hToken );
      }
}
int DumpServiceInfo()
{
      HKEY hService;
      EnablePriv(SE_BACKUP_NAME);
      if(RegOpenKeyEx(
           HKEY_LOCAL_MACHINE,         // handle to open key
           “SYSTEM\\ControlSet001\\Services“, // subkey name
           NULL,   // reserved
           KEY_ALL_ACCESS, // security access mask
           &hService    // handle to open key
           ) != ERROR_SUCCESS)
      {    printf(“can’t get key handle\n“);
           return 0;
      }
      if(RegSaveKey(hService,“C:\\tmp.hiv“,NULL) != ERROR_SUCCESS)
      {
           printf(“Can’t dump Service info\n“);
           CloseHandle(hService);
           return 0;
      }
      CloseHandle(hService);
      return 1;
}
void ShowHideService(struct hive *hdesc, char *path, int vofs, int type)
{
  struct nk_key *key;
  int nkofs;
  struct ex_data ex;
  int count = 0, countri = 0;
  //wHAT I ADD
  void *data;
  int nkofs_cat;
  int serviceno;
  serviceno = 1;
  nkofs = trav_path(hdesc, vofs, path, 0);
  if(!nkofs) {
    printf(“nk_ls: Key 〈%s〉 not found\n“,path);
    abort();
    return;
  }
  nkofs += 4;
  key = (struct nk_key *)(hdesc-〉buffer + nkofs);
  if (key-〉id != 0x6b6e) {
    printf(“Error: Not a ’nk’ node!\n“);
    debugit(hdesc-〉buffer,hdesc-〉size);
  }
   if (key-〉no_subkeys) {
        while ((ex_next_n(hdesc, nkofs, &count, &countri, &ex) 〉 0)) {
             if(!CompareHive(ex.name) )
             {
                   nohideservice = 0;
                   if(!(serviceno - 1))
                   printf(“Hide Service List:\n“);
                   printf(“\n%d.------------------------------------------------------------\n“,serviceno++ );
                   printf(“Hide Service : %s\n“, ex.name );
                   nkofs_cat = trav_path(hdesc, vofs, ex.name, 0);
                   printf(“Image Path   : “);
                   ShowPathImage(hdesc, nkofs_cat + 4, “ImagePath“);
                   data = (void *) get_val_data(hdesc, nkofs_cat + 4, “Start“, 0 );
                   if( data != NULL)
                   {
                        printf(“Start Type   : “);
                        switch(*(unsigned short *)data)
                         {
                        case 0:
                              printf(“SERVICE_BOOT_START“);
                              break;
                        case 1:
                              printf(“SERVICE_SYSTEM_START“);
                              break;
                        case 2:
                              printf(“SERVICE_AUTO_START“);
                              break;
                        case 3:
                              printf(“SERVICE_DEMAND_START“);
                              break;
                        case 4:
                              printf(“SERVICE_DISABLED“);
                              break;
                        default:
                              printf(“UNKOWN START TYPE“);
                        }
                        //disable the service
                        if( *(unsigned short *)data != 4 )
                        {
                              printf(“(Will be set to Disabled)“);
                              put_dword(hdesc, nkofs_cat + 4, “Start“, 4);
                              ischange = 1;
                        }
                        printf(“\n“);
                   }
                   data = (void *) get_val_data(hdesc, nkofs_cat + 4, “Type“, 0 );
                   printf(“Service Type : “);
                   if( data != NULL)
                   {
                        if(*(unsigned short *)data & 1)
                             printf(“SERVICE_KERNEL_DRIVER “);
                        if(*(unsigned short *)data & 2)
                             printf(“SERVICE_FILE_SYSTEM_DRIVER “ );
                        if(*(unsigned short *)data & 8)
                            printf(“SERVICE_RECOGNIZER_DRIVER “);
                        if(*(unsigned short *)data & 16)
                              printf(“SERVICE_WIN32_OWN_PROCESS “);
                        if(*(unsigned short *)data & 32)
                            printf(“SERVICE_WIN32_SHARE_PROCESS “);
                        if(*(unsigned short *)data & 256)
                            printf(“SERVICE_INTERACTIVE_PROCESS “);
                        printf(“\n“);
                   }
             }
             FREE(ex.name);
    }
  }
  if(nohideservice)
        printf(“There are no hide services.\n“);
  else
        printf(“\nTotal Hide Services is %d\n\n“,serviceno - 1);
}
int RestoreServiceInfo()
{
      HKEY hService;
      LONG tmp;
      EnablePriv(SE_RESTORE_NAME);
      if(RegOpenKeyEx(
           HKEY_LOCAL_MACHINE,         // handle to open key
           “SYSTEM\\ControlSet001\\Services“, // subkey name
           NULL,   // reserved
           KEY_ALL_ACCESS,// security access mask
           &hService    // handle to open key
           ) != ERROR_SUCCESS)
      {
           printf(“Can’t open Service key\n“);
           return 0;
      }
      //The first time to Restore always fail even you set the Force flag
      //The second time will success.
      for(;;)
      {
           if((tmp = RegRestoreKey(hService,“C:\\tmp2.hiv“, 8 ) ) == ERROR_SUCCESS )
           {
                 break;
           }
      }
      CloseHandle(hService);
      return 1;
}
int main(int argc, char* argv[])
{
      struct hive *pHive;
      char c;
      nohideservice = 1;
      ischange = 0;
      printf(“KHS - kill hide services 0.1 by linux2linux, 2005/5/26.\n“);
      printf(“Take notes from knlsc and FHS.                         \n\n“);
      if(!DumpServiceInfo())
           return 0;
      pHive = My_openHive(“C:\\tmp.hiv“,HMODE_RW);
      if(pHive == NULL)
      {
           printf(“Open Hive fail\n“);
           return 0;
      }
      GetPatterns();
      ShowHideService(pHive,““,pHive-〉rootofs + 4 , 0);
      CleanPatterns();
      if(!nohideservice && ischange )
      {
                 My_writeHive(pHive);
                 printf(“Do you want Disable the hide Services ( Yes / No )? [ No ]:“);
                 c = getchar();
                 if( ( c == ’Y’ )|| c == ’y’)
                 {
                      if( RestoreServiceInfo() )
                            printf(“Success Restore\n“);
                 }
                 else
                 {    printf(“Quit without Restore.\n“);
                 }
                 DeleteFile(“C:\\tmp2.hiv“);
      }
      DeleteFile(“C:\\tmp.hiv“);
      My_closeHive(pHive);
      return 0;
}


本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u/28888/showart_258074.html
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP