系统服务挂钩(HOOK)-2

      上一篇介绍了系统服务挂钩并提供了最简单的例子,接下来主要记录我对这种技术应用的研究心得,比较初浅,不对请高手指教!

下面主要以代码为主(未经严格测试,仅供学习参考),实现了

1、 保护文件/目录不被删除
2、 隐藏文件/目录
3、 隐藏进程
4、 保护进程不被结束
5、 保护注册表键不被打开
6、 保护注册表键不被删除

网上有几篇文章介绍了部分功能,并提供的源码。所以我主要把对源码的理解写下来,并对源码做简化,更利于理解。

 

保护文件/目录不被删除

挂钩 ZwSetInformationFile

NTSTATUS

  ZwSetInformationFile(

    IN HANDLE  FileHandle,
    OUT PIO_STATUS_BLOCK  IoStatusBlock,
    IN PVOID  FileInformation,
    IN ULONG  Length,
    IN FILE_INFORMATION_CLASS  FileInformationClass
    );

 

当FileInformationClass= FileDispositionInformation时,FileInformation指向一个

FILE_DISPOSITION_INFORMATION 结构,其定义如下:

typedef struct _FILE_DISPOSITION_INFORMATION {
  BOOLEAN DeleteFile;
} FILE_DISPOSITION_INFORMATION;

如果DeleteFile被设为TRUE时,那么当 ZwClose 被调用后文件将被删除。这种情况下我们只要返回STATUS_NO_SUCH_FILE或STATUS_ACCESS_DENIED。

 

NTSTATUS Hook_ZwSetInformationFile(

    IN HANDLE  FileHandle,

    OUT PIO_STATUS_BLOCK  IoStatusBlock,

    IN PVOID  FileInformation,

    IN ULONG  Length,

    IN FILE_INFORMATION_CLASS  FileInformationClass

    )

{    

       NTSTATUS rc ;

       // sets the DeleteFile member of a FILE_DISPOSITION_INFORMATION to TRUE,

       // so the file can be deleted when ZwClose is called to release the last open

      // handle to the file object.

      // The caller must have opened the file with the DELETE flag set

      // in the DesiredAccess parameter.
    

       if ( FileInformationClass == FileDispositionInformation )

       {           

              // 取文件名称

              PVOID Object;                        

              if ( ObReferenceObjectByHandle( FileHandle , 0 , 0 , KernelMode ,

                        &Object , NULL ) == STATUS_SUCCESS )

              {

                     int BytesReturn ;

                     UCHAR Name[1024] ;

                     BOOLEAN *pbDeleteFile = NULL ;

                     PUNICODE_STRING lpuName = NULL ;

                   

                     extern NTSTATUS ObQueryNameString(void *, void *, int size, int *);                   

                     RtlZeroMemory( Name , sizeof(Name) ) ;

                     if ( ObQueryNameString( Object , Name , sizeof(Name) ,

                                &BytesReturn ) == STATUS_SUCCESS )

                     {

                            lpuName  = (PUNICODE_STRING) Name ;                      

                     }
                             

                     ObDereferenceObject(Object) ;

                     if ( lpuName->Length > 0 &&

                            wcscmp( lpuName->Buffer , L”要保护的文件名” ) == 0 )

                     {                         

                            return STATUS_NO_SUCH_FILE ;                      

                     }

              }

       }

       rc = gfn_RealZwSetInformationFile( FileHandle , IoStatusBlock ,

                    FileInformation , Length , FileInformationClass ) ;

       return rc ;

}

 

隐藏文件/目录

挂钩 ZwQueryDirectoryFile

注:该函数未文档化,在ntifs.h内定义,挂钩前先用 extern 声明。

extern NTSYSAPI NTSTATUS NTAPI ZwQueryDirectoryFile(

             IN HANDLE hFile,

             IN HANDLE hEvent OPTIONAL,

             IN PIO_APC_ROUTINE IoApcRoutine OPTIONAL,

             IN PVOID IoApcContext OPTIONAL,

             OUT PIO_STATUS_BLOCK pIoStatusBlock,

             OUT PVOID FileInformationBuffer,

             IN ULONG FileInformationBufferLength,

             IN FILE_INFORMATION_CLASS FileInfoClass,

             IN BOOLEAN bReturnOnlyOneEntry,

             IN PUNICODE_STRING PathMask OPTIONAL,

IN BOOLEAN bRestartQuery);

参数比较多,看得头都大了^_^,其实真正重要的参数就三个

钩子函数先调用真正的函数,当FileInfoClass= FileBothDirectoryInformation(3)时,

FileInformationBuffer返回请求的目录下的子目录和文件,是一组FILE_BOTH_DIR_

INFORMATION结构:

typedef struct _FILE_BOTH_DIR_INFORMATION {

    ULONG           NextEntryOffset;

    ULONG           FileIndex;

    LARGE_INTEGER   CreationTime;

    LARGE_INTEGER   LastAccessTime;

    LARGE_INTEGER   LastWriteTime;

    LARGE_INTEGER   ChangeTime;

    LARGE_INTEGER   EndOfFile;

    LARGE_INTEGER   AllocationSize;

    ULONG           FileAttributes;

    ULONG           FileNameLength;

    ULONG           EaSize;

    CCHAR           ShortNameLength;

    WCHAR           ShortName[12];

    WCHAR           FileName[1];

} FILE_BOTH_DIR_INFORMATION, *PFILE_BOTH_DIR_INFORMATION;

 

我们要隐藏某个文件或目录,只需要把该结点从链表中删除。需要注意的是,hEvent

参数或IoApcRoutine参数如果传入有效的值,表示函数以异步的方式处理,这时应该不做其它处理,直接调用真正的函数。

 

NTSTATUS Hook_ZwQueryDirectoryFile (

       IN HANDLE hFile,

    IN HANDLE hEvent OPTIONAL,

    IN PIO_APC_ROUTINE IoApcRoutine OPTIONAL,

    IN PVOID IoApcContext OPTIONAL,

    OUT PIO_STATUS_BLOCK pIoStatusBlock,

    OUT PVOID FileInformationBuffer,

    IN ULONG FileInformationBufferLength,

    IN FILE_INFORMATION_CLASS FileInfoClass,

    IN BOOLEAN bReturnOnlyOneEntry,

    IN PUNICODE_STRING PathMask OPTIONAL,

    IN BOOLEAN bRestartQuery

)

{

       NTSTATUS rc;

       // 执行真正的ZwQueryDirectoryFile函数

       rc = ((gfn_RealZwQueryDirectoryFile))(

              hFile,

              hEvent,

              IoApcRoutine,

              IoApcContext,

              pIoStatusBlock,

              FileInformationBuffer,

              FileInformationBufferLength,

              FileInfoClass,

              bReturnOnlyOneEntry,

              PathMask,

              bRestartQuery);

 

 

 

       if (  NT_SUCCESS(rc) &&

               FileInfoClass == FileBothDirectoryInformation &&

               hEvent == NULL &&

               IoApcRoutine == NULL )

       {           

 

              PVOID Object;          

              BOOLEAN bLastOne ;

              PFILE_BOTH_DIR_INFORMATION  pLastFileInfo ;

              PFILE_BOTH_DIR_INFORMATION  pFileInfo ;

              WCHAR wszPath[1024] = L"" ;

     

              // 取父目录路径

              if ( ObReferenceObjectByHandle( hFile , 0 , 0 , KernelMode ,

                                &Object , NULL ) == STATUS_SUCCESS )

              {

            

              // 遍历链表,重点部分!           

              pLastFileInfo = NULL;

              pFileInfo = (PFILE_BOTH_DIR_INFORMATION)FileInformationBuffer ;
 

              do

              {

                     bLastOne = !( pFileInfo->NextEntryOffset );


                     if ( pFileInfo->FileName )

                     {
                            DbgPrint( "[hooksys] find file&directory = %S " , pFileInfo->FileName ) ;

                            if ( wcsstr( pFileInfo->FileName , L"hidefile" ) != NULL )

                            {

                                   if( bLastOne )

                                   {

                                          if(pFileInfo ==

                                             (PFILE_BOTH_DIR_INFORMATION)

                                                FileInformationBuffer )
                                          {

                                                 rc = STATUS_NO_SUCH_FILE ;

                                          }

                                          else
                                          {
                                                 pLastFileInfo->NextEntryOffset = 0;

                                          }                                       

                                          break;

                                   }

                                   else

                                   {

                                          int iPos = ((ULONG)pFileInfo) –

                                                 (ULONG)FileInformationBuffer;

                                 

                                          int iLeft = (ULONG)FileInformationBufferLength - iPos –

                                                pFileInfo->NextEntryOffset;

                                        

                                          RtlCopyMemory( (PVOID)pFileInfo, (PVOID)( (char *)pFileInfo

                                                + pFileInfo->NextEntryOffset ), (ULONG)iLeft );

            

                                          continue;

                                   }

                            }

                     }

                     // 移到下一个结点

                     pLastFileInfo = pFileInfo;

                     pFileInfo = (PFILE_BOTH_DIR_INFORMATION)( (ULONG)pFileInfo

        + pFileInfo->NextEntryOffset );


              }while(!bLastOne);

       }

       return rc ; }

pFileInfo->FileName 只提供文件名或目录名,如果要取得完整路径,需要通过hFile取,如同上面的例子一样。我使用比较简单的算法,只要文件/目录名中含有”hidefile”,就让它消失!其实这个只能在explorer中隐藏,在命令提示符下仍然可以cd进去,为了更彻底点,
我拦截了ZwOpenFile

NTSTATUS Hook_ZwOpenFile(
    OUT PHANDLE  FileHandle,
    IN ACCESS_MASK  DesiredAccess,
    IN POBJECT_ATTRIBUTES  ObjectAttributes,
    OUT PIO_STATUS_BLOCK  IoStatusBlock,
    IN ULONG  ShareAccess,
    IN ULONG  OpenOptions
    )
{
    NTSTATUS rc;
   
    if ( ObjectAttributes->ObjectName )
    {
        DbgPrint( "[hooksys] ZwOpenFile = %S " ,
                    ObjectAttributes->ObjectName->Buffer ) ;

        if ( wcsstr( ObjectAttributes->ObjectName->Buffer , L"hidefile" ) != 0 )
            return STATUS_NO_SUCH_FILE ;
    }  

    rc = gfn_RealZwOpenFile( FileHandle , DesiredAccess ,
            ObjectAttributes , IoStatusBlock , ShareAccess , OpenOptions ) ;

    return rc ;
}


由于代码都大同小异,后面几项功能的代码不一一帖出了。
隐藏进程挂钩 ZwQuerySystemInformation ,未文档化的函数,函数定义参考:
NTSYSAPI
NTSTATUS
NTAPI
ZwQuerySystemInformation
(
    IN SYSTEM_INFORMATION_CLASS SystemInformationClass,
    IN OUT PVOID SystemInformation,
    IN ULONG SystemInformationLength,
    OUT PULONG ReturnLength OPTIONAL
);

可以在 winternl.h 中找到 SYSTEM_INFORMATION_CLASS 的定义
typedef enum _SYSTEM_INFORMATION_CLASS {
    SystemBasicInformation = 0,
    SystemPerformanceInformation = 2,
    SystemTimeOfDayInformation = 3,
    SystemProcessInformation = 5,
    SystemProcessorPerformanceInformation = 8,
    SystemInterruptInformation = 23,
    SystemExceptionInformation = 33,
    SystemRegistryQuotaInformation = 37,
    SystemLookasideInformation = 45
} SYSTEM_INFORMATION_CLASS;
 
当 SystemInformationClass== SystemProcessInformation时,
SystemInformation指向一个SYSTEM_PROCESS_INFORMATION 结构数组,其中每个成员表示系统中运行的每个进程。注:MSDN上如是说,但网上的代码却是说指向
SYSTEM_PROCESSES
 
struct _SYSTEM_PROCESSES
{
       ULONG NextEntryDelta;
       ULONG ThreadCount;      
       ULONG Reserved[6]; 
       LARGE_INTEGER CreateTime;      
       LARGE_INTEGER UserTime;   
       LARGE_INTEGER KernelTime;
       UNICODE_STRING ProcessName; 
       KPRIORITY BasePriority;  
       ULONG ProcessId;     
       ULONG InheritedFromProcessId;    
       ULONG HandleCount;
       ULONG Reserved2[2];      
       VM_COUNTERS VmCounters; 
       IO_COUNTERS IoCounters;    
       struct _SYSTEM_THREADS Threads[1];      
};
两个结构大小差距甚大,意义也不尽相同。
测试后发现 SYSTEM_PROCESSES可以正常工作。
 
保护进程不被结束可以挂钩 ZwTerminateProcess ,
 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值