• 內核級HOOK的幾種實現與應用


    Author : sinister
    Email   : sinister@whitecell.org
    HomePage: http://www.whitecell.org


    實現內核級 HOOK 對於攔截、分析、跟蹤系統內核起著致關重要的作用。實現的方法不同意味著應用側重點的不同。

    如想要攔截 NATIVE API 那麼可能常用的就是 HOOK SERVICE TABLE 的方法。
    如果要分析一些系統調用,那麼可能想到用 HOOK INT 2E 中斷來實現。

    如果想要攔截或跟蹤其他內核 DRIVER 的調用,那麼就要用到HOOK PE 的方法來實現。

    這裏我們更注重的是實現,原理方面已有不少高手在網上發表過文章。

    大家可以結合起來讀。
    下面以我寫的幾個實例程式來講解一下各種方法的實現。
    錯誤之處還望各位指正。


    1、HOOK SERVICE TABLE 方法:
      這種方法對於攔截 NATIVE API 來說用的比較多。
    原理就是通過替換系統導
    出的一個 SERVICE TABLE 中相應的 NATIVE API 的位址來達到攔截的目的。
    因為此方法較為簡單,網上也有不少資料來介紹。
    所以這裏就不給出實例程式了。SERVICE TABLE 的結構如下:

    typedef struct ServiceDescriptorEntry {
      unsigned int *ServiceTableBase;
      unsigned int *ServiceCounterTableBase;
      unsigned int NumberOfServices;
      unsigned char *ParamTableBase;
    } ServiceDescriptorTableEntry_t, *PServiceDescriptorTableEntry_t;
     

    2、HOOK INT 2E 方法:
      這種方法對於跟蹤、分析系統調用來說用的比較多。原理是通過替換 IDT
    表中的 INT 2E 中斷,使之指向我們自己的中斷服務處理常式來實現的。
    掌握此方法需要你對保護模式有一定的基礎。下面的程式演示了這一過程。


    /*****************************************************************
    檔案名     : WssHookInt2e.c
    描述       : 系統調用跟蹤
    作者       : sinister
    最後修改日期 : 2002-11-02
    *****************************************************************/

    #include "ntddk.h"
    #include "string.h"

    #define DWORD unsigned __int32
    #define WORD unsigned __int16
    #define BYTE unsigned __int8
    #define BOOL __int32

    #define LOWORD(l)       ((WORD)(l))
    #define HIWORD(l)       ((WORD)(((DWORD)(l) >> 16) & 0xFFFF))
    #define LOBYTE(w)       ((BYTE)(w))
    #define HIBYTE(w)       ((BYTE)(((WORD)(w) >> 8) & 0xFF))

    #define MAKELONG(a, b) ((LONG) (((WORD) (a)) | ((DWORD) ((WORD) (b))) << 16))

    #define SYSTEMCALL 0x2e
    #define SYSNAME "System"
    #define PROCESSNAMELEN 16

    #pragma pack(1)

    //定義 IDTR
    typedef struct tagIDTR {
        WORD IDTLimit;
        WORD LowIDTbase;
        WORD HiIDTbase;
    }IDTR, *PIDTR;

    //定義 IDT
    typedef struct tagIDTENTRY{
      WORD OffsetLow;
      WORD selector;
      BYTE unused_lo;
      unsigned char unused_hi:5;
      unsigned char DPL:2;
      unsigned char P:1;
      WORD OffsetHigh;
    } IDTENTRY, *PIDTENTRY;


    #pragma pack()

    DWORD   OldInt2eService;
    ULONG   ProcessNameOffset;
    TCHAR   ProcessName[PROCESSNAMELEN];

    static NTSTATUS MydrvDispatch (IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);
    VOID DriverUnload (IN PDRIVER_OBJECT pDriverObject);
    ULONG GetProcessNameOffset();
    VOID GetProcessName( PCHAR Name );
    VOID InstallNewInt2e();
    VOID UninstallNewInt2e();

    VOID __fastcall NativeApiCall()
    {
      KIRQL OldIrql;
     
      DWORD ServiceID;
      DWORD ProcessId;

      __asm mov ServiceID,eax;


      ProcessId = (DWORD)PsGetCurrentProcessId();
      GetProcessName(ProcessName);

      KeRaiseIrql(HIGH_LEVEL, &OldIrql); // 提升當前的 IRQL 級別防止被中斷


      switch ( ServiceID )
      {
            case 0x20:
              DbgPrint("NEWINT2E: ProcessName: %s; ProcessID: %d; Native Api: NtCreateFile() \n",ProcessName,ProcessId);
              break;

            case 0x2b:
              DbgPrint("NEWINT2E: ProcessName: %s; ProcessID: %d; Native Api: NtCreateSection() \n",ProcessName,ProcessId);          
              break;


            case 0x30:
              DbgPrint("NEWINT2E: ProcessName: %s; ProcessID: %d; Native Api: NtCreateToken() \n",ProcessName,ProcessId);          
              break;
             
      }

      KeLowerIrql(OldIrql); //恢復原始 IRQL

    }

    __declspec(naked) NewInt2eService()
    {
      __asm{
        pushad
        pushfd
        push fs
        mov bx,0x30
        mov fs,bx
        push ds
        push es

        sti
        call NativeApiCall; // 調用記錄函數
        cli

        pop es
        pop ds
        pop fs
        popfd
        popad

        jmp   OldInt2eService; //跳到原始 INT 2E 繼續工作
      }
    }

    VOID InstallNewInt2e()
    {

      IDTR       idtr;
      PIDTENTRY   OIdt;
      PIDTENTRY   NIdt;

      //得到 IDTR 中得段界限與基底位址
      __asm {
        sidt idtr;
      }

      //得到IDT基底位址
      OIdt = (PIDTENTRY)MAKELONG(idtr.LowIDTbase,idtr.HiIDTbase);

      //保存原來的 INT 2E 服務常式
      OldInt2eService = MAKELONG(OIdt[SYSTEMCALL].OffsetLow,OIdt[SYSTEMCALL].OffsetHigh);
     
      NIdt = &(OIdt[SYSTEMCALL]);

      __asm {
        cli
        lea eax,NewInt2eService; //得到新的 INT 2E 服務常式偏移
        mov ebx, NIdt;
        mov [ebx],ax;   //INT 2E 服務常式低 16 位元
        shr eax,16     //INT 2E 服務常式高 16 位元
        mov [ebx+6],ax;
        lidt idtr //裝入新的 IDT
        sti
      }

    }

    VOID UninstallNewInt2e()
    {
      IDTR       idtr;
      PIDTENTRY   OIdt;
      PIDTENTRY   NIdt;

      __asm {
        sidt idtr;
      }

      OIdt = (PIDTENTRY)MAKELONG(idtr.LowIDTbase,idtr.HiIDTbase);

      NIdt = &(OIdt[SYSTEMCALL]);

      _asm {
        cli
        lea eax,OldInt2eService;
        mov ebx, NIdt;
        mov [ebx],ax;
        shr eax,16
        mov [ebx+6],ax;
        lidt idtr
        sti
      }

    }




    // 驅動入口
    NTSTATUS DriverEntry( IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath )
    {
     
      UNICODE_STRING nameString, linkString;
      PDEVICE_OBJECT deviceObject;
      NTSTATUS     status;
      HANDLE       hHandle;
      int           i;
     

      //卸載驅動
      DriverObject->DriverUnload = DriverUnload;

      //建立設備
      RtlInitUnicodeString( &nameString, L"\\Device\\WssHookInt2e" );
     
      status = IoCreateDevice( DriverObject,
                      0,
                      &nameString,
                      FILE_DEVICE_UNKNOWN,
                      0,
                      TRUE,
                      &deviceObject
                      );
                     

      if (!NT_SUCCESS( status ))
        return status;
     

      RtlInitUnicodeString( &linkString, L"\\DosDevices\\WssHookInt2e" );

      status = IoCreateSymbolicLink (&linkString, &nameString);

      if (!NT_SUCCESS( status ))
      {
        IoDeleteDevice (DriverObject->DeviceObject);
        return status;
      }  
     

      for ( i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++)   {

          DriverObject->MajorFunction = MydrvDispatch;
      }

        DriverObject->DriverUnload = DriverUnload;

      ProcessNameOffset = GetProcessNameOffset();
      InstallNewInt2e();

    return STATUS_SUCCESS;
    }



    //處理設備物件操作

    static NTSTATUS MydrvDispatch (IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
    {
      Irp->IoStatus.Status = STATUS_SUCCESS;
      Irp->IoStatus.Information = 0L;
      IoCompleteRequest( Irp, 0 );
      return Irp->IoStatus.Status;
     
    }



    VOID DriverUnload (IN PDRIVER_OBJECT   pDriverObject)
    {
      UNICODE_STRING nameString;

      UninstallNewInt2e();
      RtlInitUnicodeString( &nameString, L"\\DosDevices\\WssHookInt2e" );  
      IoDeleteSymbolicLink(&nameString);
      IoDeleteDevice(pDriverObject->DeviceObject);

      return;
    }



    ULONG GetProcessNameOffset()
    {
        PEPROCESS curproc;
        int i;
       
        curproc = PsGetCurrentProcess();

        //
        // Scan for 12KB, hopping the KPEB never grows that big!
        //
        for( i = 0; i < 3*PAGE_SIZE; i++ ) {

            if( !strncmp( SYSNAME, (PCHAR) curproc + i, strlen(SYSNAME) )) {

              return i;
            }
        }

        //
        // Name not found - oh, well
        //
        return 0;
    }

    VOID GetProcessName( PCHAR Name )
    {

        PEPROCESS curproc;
        char *nameptr;
        ULONG i;

        if( ProcessNameOffset ) {

            curproc = PsGetCurrentProcess();
            nameptr = (PCHAR) curproc + ProcessNameOffset;
            strncpy( Name, nameptr, 16 );

        } else {

            strcpy( Name, "???");
        }
    }


    3、 HOOK PE 方法
    這種方法對於攔截、分析其他內核驅動的函數調用來說用的比較多。
    原理
    是根據替換 PE 格式導出表中的相應函數來實現的。
    此方法中需要用到一些小技巧。
    如內核模式並沒有直接提供類似應用層的 GetModuleHandl()、GetProcAddress() 等函數來獲得模組的位址。
    那麼我們就需要自己來編寫,這裏用到了一個未公開的函數與結構。
    ZwQuerySystemInformation 與 SYSTEM_MODULE_INFORMATION 來實現得到模組的基底位址。
    這樣我們就可以根據PE 格式來枚舉導出表中的函數來替換了。
    但這又引出了一個問題,那就是從WINDOWS 2000 後內核資料的頁屬性都是唯讀的,不能更改。
    內核模式也沒有提供類似應用層的 VirtualProtectEx() 等函數來修改頁面屬性。
    那麼也需要我們自己來編寫。
    因為我們是在內核模式所以我們可以通過修改 cr0 寄存器的的防寫位元來達到我們的目的。
    這樣我們所期望的攔截內核模式函數的功能便得以實現。
    此方法需要你對 PE 格式有一定的基礎。下面的程式演示了這一過程。



    /*****************************************************************
    檔案名     : WssHookPE.c
    描述       : 攔截內核函數
    作者       : sinister
    最後修改日期 : 2002-11-02
    *****************************************************************/

    #include "ntddk.h"
    #include "windef.h"


    typedef enum _SYSTEM_INFORMATION_CLASS {
      SystemBasicInformation,
      SystemProcessorInformation,
      SystemPerformanceInformation,
      SystemTimeOfDayInformation,
      SystemNotImplemented1,
      SystemProcessesAndThreadsInformation,
      SystemCallCounts,
      SystemConfigurationInformation,
      SystemProcessorTimes,
      SystemGlobalFlag,
      SystemNotImplemented2,
      SystemModuleInformation,
      SystemLockInformation,
      SystemNotImplemented3,
      SystemNotImplemented4,
      SystemNotImplemented5,
      SystemHandleInformation,
      SystemObjectInformation,
      SystemPagefileInformation,
      SystemInstructionEmulationCounts,
      SystemInvalidInfoClass1,
      SystemCacheInformation,
      SystemPoolTagInformation,
      SystemProcessorStatistics,
      SystemDpcInformation,
      SystemNotImplemented6,
      SystemLoadImage,
      SystemUnloadImage,
      SystemTimeAdjustment,
      SystemNotImplemented7,
      SystemNotImplemented8,
      SystemNotImplemented9,
      SystemCrashDumpInformation,
      SystemExceptionInformation,
      SystemCrashDumpStateInformation,
      SystemKernelDebuggerInformation,
      SystemContextSwitchInformation,
      SystemRegistryQuotaInformation,
      SystemLoadAndCallImage,
      SystemPrioritySeparation,
      SystemNotImplemented10,
      SystemNotImplemented11,
      SystemInvalidInfoClass2,
      SystemInvalidInfoClass3,
      SystemTimeZoneInformation,
      SystemLookasideInformation,
      SystemSetTimeSlipEvent,
      SystemCreateSession,
      SystemDeleteSession,
      SystemInvalidInfoClass4,
      SystemRangeStartInformation,
      SystemVerifierInformation,
      SystemAddVerifier,
      SystemSessionProcessesInformation
    } SYSTEM_INFORMATION_CLASS;


    typedef struct tagSYSTEM_MODULE_INFORMATION {
      ULONG Reserved[2];
      PVOID Base;
      ULONG Size;
      ULONG Flags;
      USHORT Index;
      USHORT Unknown;
      USHORT LoadCount;
      USHORT ModuleNameOffset;
      CHAR ImageName[256];
    } SYSTEM_MODULE_INFORMATION, *PSYSTEM_MODULE_INFORMATION;

    #define IMAGE_DOS_SIGNATURE     0x5A4D     // MZ
    #define IMAGE_NT_SIGNATURE     0x50450000 // PE00
    #define IMAGE_NT_SIGNATURE1     0x00004550   // 00EP

    typedef struct _IMAGE_DOS_HEADER {     // DOS .EXE header
      WORD   e_magic;               // Magic number
      WORD   e_cblp;               // Bytes on last page of file
      WORD   e_cp;                 // Pages in file
      WORD   e_crlc;               // Relocations
      WORD   e_cparhdr;             // Size of header in paragraphs
      WORD   e_minalloc;             // Minimum extra paragraphs needed
      WORD   e_maxalloc;             // Maximum extra paragraphs needed
      WORD   e_ss;                 // Initial (relative) SS value
      WORD   e_sp;                 // Initial SP value
      WORD   e_csum;               // Checksum
      WORD   e_ip;                 // Initial IP value
      WORD   e_cs;                 // Initial (relative) CS value
      WORD   e_lfarlc;             // File address of relocation table
      WORD   e_ovno;               // Overlay number
      WORD   e_res[4];             // Reserved words
      WORD   e_oemid;               // OEM identifier (for e_oeminfo)
      WORD   e_oeminfo;             // OEM information; e_oemid specific
      WORD   e_res2[10];             // Reserved words
      LONG   e_lfanew;             // File address of new exe header
    } IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;


    typedef struct _IMAGE_FILE_HEADER {
      WORD   Machine;
      WORD   NumberOfSections;
      DWORD   TimeDateStamp;
      DWORD   PointerToSymbolTable;
      DWORD   NumberOfSymbols;
      WORD   SizeOfOptionalHeader;
      WORD   Characteristics;
    } IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;

    typedef struct _IMAGE_DATA_DIRECTORY {
      DWORD   VirtualAddress;
      DWORD   Size;
    } IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;

    #define IMAGE_NUMBEROF_DIRECTORY_ENTRIES   16

    //
    // Optional header format.
    //

    typedef struct _IMAGE_OPTIONAL_HEADER {
      //
      // Standard fields.
      //

      WORD   Magic;
      BYTE   MajorLinkerVersion;
      BYTE   MinorLinkerVersion;
      DWORD   SizeOfCode;
      DWORD   SizeOfInitializedData;
      DWORD   SizeOfUninitializedData;
      DWORD   AddressOfEntryPoint;
      DWORD   BaseOfCode;
      DWORD   BaseOfData;

      //
      // NT additional fields.
      //

      DWORD   ImageBase;
      DWORD   SectionAlignment;
      DWORD   FileAlignment;
      WORD   MajorOperatingSystemVersion;
      WORD   MinorOperatingSystemVersion;
      WORD   MajorImageVersion;
      WORD   MinorImageVersion;
      WORD   MajorSubsystemVersion;
      WORD   MinorSubsystemVersion;
      DWORD   Win32VersionValue;
      DWORD   SizeOfImage;
      DWORD   SizeOfHeaders;
      DWORD   CheckSum;
      WORD   Subsystem;
      WORD   DllCharacteristics;
      DWORD   SizeOfStackReserve;
      DWORD   SizeOfStackCommit;
      DWORD   SizeOfHeapReserve;
      DWORD   SizeOfHeapCommit;
      DWORD   LoaderFlags;
      DWORD   NumberOfRvaAndSizes;
      IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
    } IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32;

    typedef struct _IMAGE_NT_HEADERS {
      DWORD Signature;
      IMAGE_FILE_HEADER FileHeader;
      IMAGE_OPTIONAL_HEADER32 OptionalHeader;
    } IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;

    typedef IMAGE_NT_HEADERS32             IMAGE_NT_HEADERS;
    typedef PIMAGE_NT_HEADERS32           PIMAGE_NT_HEADERS;

    //
    // Section header format.
    //

    #define IMAGE_SIZEOF_SHORT_NAME         8

    typedef struct _IMAGE_SECTION_HEADER {
      BYTE   Name[IMAGE_SIZEOF_SHORT_NAME];
      union {
            DWORD   PhysicalAddress;
            DWORD   VirtualSize;
      } Misc;
      DWORD   VirtualAddress;
      DWORD   SizeOfRawData;
      DWORD   PointerToRawData;
      DWORD   PointerToRelocations;
      DWORD   PointerToLinenumbers;
      WORD   NumberOfRelocations;
      WORD   NumberOfLinenumbers;
      DWORD   Characteristics;
    } IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;

    #define IMAGE_SIZEOF_SECTION_HEADER       40
    //
    // Export Format
    //

    typedef struct _IMAGE_EXPORT_DIRECTORY {
      DWORD   Characteristics;
      DWORD   TimeDateStamp;
      WORD   MajorVersion;
      WORD   MinorVersion;
      DWORD   Name;
      DWORD   Base;
      DWORD   NumberOfFunctions;
      DWORD   NumberOfNames;
      DWORD   AddressOfFunctions;   // RVA from base of image
      DWORD   AddressOfNames;       // RVA from base of image
      DWORD   AddressOfNameOrdinals; // RVA from base of image
    } IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY;

    #define BASEADDRLEN 10

    NTSYSAPI
    NTSTATUS
    NTAPI
    ZwQuerySystemInformation(
      IN SYSTEM_INFORMATION_CLASS SystemInformationClass,
      IN OUT PVOID SystemInformation,
      IN ULONG SystemInformationLength,
      OUT PULONG ReturnLength OPTIONAL
      );


    typedef NTSTATUS (* ZWCREATEFILE)(
    OUT PHANDLE FileHandle,
    IN ACCESS_MASK DesiredAccess,
    IN POBJECT_ATTRIBUTES ObjectAttributes,
    OUT PIO_STATUS_BLOCK IoStatusBlock,
    IN PLARGE_INTEGER AllocationSize OPTIONAL,
    IN ULONG FileAttributes,
    IN ULONG ShareAccess,
    IN ULONG CreateDisposition,
    IN ULONG CreateOptions,
    IN PVOID EaBuffer OPTIONAL,
    IN ULONG EaLength
    );

    ZWCREATEFILE   OldZwCreateFile;

    static NTSTATUS MydrvDispatch (IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);
    VOID DriverUnload (IN PDRIVER_OBJECT pDriverObject);
    VOID DisableWriteProtect( PULONG pOldAttr);
    VOID EnableWriteProtect( ULONG ulOldAttr );
    FARPROC HookFunction(   PCHAR pModuleBase, PCHAR pHookName, FARPROC pHookFunc );

    NTSTATUS
    HookNtCreateFile(
    OUT PHANDLE FileHandle,
    IN ACCESS_MASK DesiredAccess,
    IN POBJECT_ATTRIBUTES ObjectAttributes,
    OUT PIO_STATUS_BLOCK IoStatusBlock,
    IN PLARGE_INTEGER AllocationSize OPTIONAL,
    IN ULONG FileAttributes,
    IN ULONG ShareAccess,
    IN ULONG CreateDisposition,
    IN ULONG CreateOptions,
    IN PVOID EaBuffer OPTIONAL,
    IN ULONG EaLength
    );



    PCHAR MyGetModuleBaseAddress( PCHAR pModuleName )
    {
      PSYSTEM_MODULE_INFORMATION   pSysModule;  

      ULONG         uReturn;
      ULONG         uCount;
      PCHAR         pBuffer = NULL;
      PCHAR         pName   = NULL;
      NTSTATUS     status;
      UINT         ui;

      CHAR         szBuffer[BASEADDRLEN];
      PCHAR         pBaseAddress;
     
      status = ZwQuerySystemInformation( SystemModuleInformation, szBuffer, BASEADDRLEN, &uReturn );

      pBuffer = ( PCHAR )ExAllocatePool( NonPagedPool, uReturn );

      if ( pBuffer )
      {
        status = ZwQuerySystemInformation( SystemModuleInformation, pBuffer, uReturn, &uReturn );

        if( status == STATUS_SUCCESS )
        {
            uCount = ( ULONG )*( ( ULONG * )pBuffer );
            pSysModule = ( PSYSTEM_MODULE_INFORMATION )( pBuffer + sizeof( ULONG ) );

            for ( ui = 0; ui < uCount; ui++ )
            {
              pName = MyStrchr( pSysModule->ImageName, '\\' );

              if ( !pName )
              {
                pName = pSysModule->ImageName;
              }

              else {
                pName++;
              }

              if( !_stricmp( pName, pModuleName ) )
              {
                pBaseAddress = ( PCHAR )pSysModule->Base;
                ExFreePool( pBuffer );
                return pBaseAddress;
              }

              pSysModule ++;
            }
        }

        ExFreePool( pBuffer );
      }

      return NULL;
    }


    FARPROC HookFunction( PCHAR pModuleBase, PCHAR HookFunName, FARPROC HookFun )
    {
      PIMAGE_DOS_HEADER       pDosHdr;
      PIMAGE_NT_HEADERS       pNtHdr;
      PIMAGE_SECTION_HEADER   pSecHdr;
      PIMAGE_EXPORT_DIRECTORY pExtDir;

      UINT             ui,uj;
      PCHAR             FunName;
      DWORD             *dwAddrName;
      DWORD             *dwAddrFun;
      FARPROC             pOldFun;
      ULONG             uAttrib;


      pDosHdr = ( PIMAGE_DOS_HEADER )pModuleBase;

      if ( IMAGE_DOS_SIGNATURE == pDosHdr->e_magic )
      {
        pNtHdr = ( PIMAGE_NT_HEADERS )( pModuleBase + pDosHdr->e_lfanew );

        if( IMAGE_NT_SIGNATURE == pNtHdr->Signature ||   IMAGE_NT_SIGNATURE1 == pNtHdr->Signature )
        {
            pSecHdr = ( PIMAGE_SECTION_HEADER )( pModuleBase + pDosHdr->e_lfanew + sizeof( IMAGE_NT_HEADERS ) );

            for ( ui = 0; ui < (UINT)pNtHdr->FileHeader.NumberOfSections; ui++ )
            {
              if ( !strcmp( pSecHdr->Name, ".edata" ) )
              {          
                pExtDir = ( PIMAGE_EXPORT_DIRECTORY )( pModuleBase + pSecHdr->VirtualAddress );
                dwAddrName = ( PDWORD )(pModuleBase + pExtDir->AddressOfNames );
                dwAddrFun = ( PDWORD )(pModuleBase + pExtDir->AddressOfFunctions );

                for ( uj = 0; uj < (UINT)pExtDir->NumberOfFunctions; uj++ )
                {
                    FunName = pModuleBase + *dwAddrName;

                    if( !strcmp( FunName, HookFunName ) )
                    {
                      DbgPrint(" HOOK %s()\n",FunName);
                      DisableWriteProtect( &uAttrib );
                      pOldFun = ( FARPROC )( pModuleBase + *dwAddrFun );
                      *dwAddrFun = ( PCHAR )HookFun - pModuleBase;
                      EnableWriteProtect( uAttrib );
                      return pOldFun;
                    }

                  dwAddrName ++;
                  dwAddrFun ++;
                }
              }

              pSecHdr++;
            }
        }
      }

      return NULL;
    }


    // 驅動入口
    NTSTATUS DriverEntry( IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath )
    {
     
      UNICODE_STRING nameString, linkString;
      PDEVICE_OBJECT deviceObject;
      NTSTATUS     status;
      HANDLE       hHandle;
      PCHAR         pModuleAddress;
      int           i;
     

      //卸載驅動
      DriverObject->DriverUnload = DriverUnload;

      //建立設備
      RtlInitUnicodeString( &nameString, L"\\Device\\WssHookPE" );
     
      status = IoCreateDevice( DriverObject,
                      0,
                      &nameString,
                      FILE_DEVICE_UNKNOWN,
                      0,
                      TRUE,
                      &deviceObject
                      );
                     

      if (!NT_SUCCESS( status ))
        return status;
     

      RtlInitUnicodeString( &linkString, L"\\DosDevices\\WssHookPE" );

      status = IoCreateSymbolicLink (&linkString, &nameString);

      if (!NT_SUCCESS( status ))
      {
        IoDeleteDevice (DriverObject->DeviceObject);
        return status;
      }  
     
      pModuleAddress = MyGetModuleBaseAddress("ntoskrnl.exe");
      if ( pModuleAddress == NULL)
      {
        DbgPrint(" MyGetModuleBaseAddress()\n");
        return 0;
      }

      OldZwCreateFile = (ZWCREATEFILE)HookFunction( pModuleAddress, "ZwCreateFile",(ZWCREATEFILE)HookNtCreateFile);
      if ( OldZwCreateFile == NULL)
      {
        DbgPrint(" HOOK FAILED\n");
        return 0;
      }

      DbgPrint("HOOK SUCCEED\n");

      for ( i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++)   {

          DriverObject->MajorFunction = MydrvDispatch;
      }

        DriverObject->DriverUnload = DriverUnload;
     
    return STATUS_SUCCESS;
    }



    //處理設備物件操作

    static NTSTATUS MydrvDispatch (IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
    {
      Irp->IoStatus.Status = STATUS_SUCCESS;
      Irp->IoStatus.Information = 0L;
      IoCompleteRequest( Irp, 0 );
      return Irp->IoStatus.Status;
     
    }



    VOID DriverUnload (IN PDRIVER_OBJECT   pDriverObject)
    {
      UNICODE_STRING nameString;
      PCHAR         pModuleAddress;

      pModuleAddress = MyGetModuleBaseAddress("ntoskrnl.exe");
      if ( pModuleAddress == NULL)
      {
        DbgPrint("MyGetModuleBaseAddress()\n");
        return ;
      }

      OldZwCreateFile = (ZWCREATEFILE)HookFunction( pModuleAddress, "ZwCreateFile",(ZWCREATEFILE)OldZwCreateFile);
      if ( OldZwCreateFile == NULL)
      {
        DbgPrint(" UNHOOK FAILED!\n");
        return ;
      }

      DbgPrint("UNHOOK SUCCEED\n");

      RtlInitUnicodeString( &nameString, L"\\DosDevices\\WssHookPE" );  
      IoDeleteSymbolicLink(&nameString);
      IoDeleteDevice(pDriverObject->DeviceObject);

      return;
    }

    NTSTATUS
    HookNtCreateFile(
    OUT PHANDLE FileHandle,
    IN ACCESS_MASK DesiredAccess,
    IN POBJECT_ATTRIBUTES ObjectAttributes,
    OUT PIO_STATUS_BLOCK IoStatusBlock,
    IN PLARGE_INTEGER AllocationSize OPTIONAL,
    IN ULONG FileAttributes,
    IN ULONG ShareAccess,
    IN ULONG CreateDisposition,
    IN ULONG CreateOptions,
    IN PVOID EaBuffer OPTIONAL,
    IN ULONG EaLength
    )
    {
      NTSTATUS   status;

      DbgPrint("Hook ZwCreateFile()\n");

      status = ((ZWCREATEFILE)(OldZwCreateFile))(
              FileHandle,
              DesiredAccess,
              ObjectAttributes,
              IoStatusBlock,
              AllocationSize,
              FileAttributes,
              ShareAccess,
              CreateDisposition,
              CreateOptions,
              EaBuffer,
              EaLength
            );

      return status;
    }


    VOID DisableWriteProtect( PULONG pOldAttr)
    {

      ULONG uAttr;

      _asm
      {
          push eax;
          mov eax, cr0;
          mov uAttr, eax;
          and eax, 0FFFEFFFFh; // CR0 16 BIT = 0
          mov cr0, eax;
          pop eax;
      };

      *pOldAttr = uAttr; //保存原有的 CRO 屬性

    }

    VOID EnableWriteProtect( ULONG uOldAttr )
    {

    _asm
    {
        push eax;
        mov eax, uOldAttr; //恢復原有 CR0 屬性
        mov cr0, eax;
        pop eax;
    };

    }
  • 相关阅读:
    必备课程之3:Windows Server 2003 R2 高效分支机构管理体验(Level 200)
    阻止自动升级到IE7。
    最真实Cisco模拟器dynamips使用指南本人原创.
    任务部署
    在Microsoft VirtualPC虚拟机上运行SafeGuard Easy.
    广域网概念T1和CSU/DSU
    Exchange做增量备份必须关闭循环日志
    国际航班出发流程
    必备课程之4:Windows Server 2003 构建高可用性的业务平台体验(Level 350)
    IBM笔记本换硬盘步骤-转载
  • 原文地址:https://www.cnblogs.com/Safe3/p/1314976.html
Copyright © 2020-2023  润新知