内核级HOOK的几种实现与应用

实现内核级 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;
};

}


文章来自: 本站原创
Tags:
评论: 0 | 查看次数: 9359