系統服務掛鉤(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 ,
 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章