admin 发表于 2009-12-12 23:06:58

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

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;
   PVOID Base;
   ULONG Size;
   ULONG Flags;
   USHORT Index;
   USHORT Unknown;
   USHORT LoadCount;
   USHORT ModuleNameOffset;
   CHAR ImageName;
} 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;                     // Reserved words
   WORD   e_oemid;                     // OEM identifier (for e_oeminfo)
   WORD   e_oeminfo;                   // OEM information; e_oemid specific
   WORD   e_res2;                   // 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_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;
   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;
   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;
   };

}
页: [1]
查看完整版本: 内核级HOOK的几种实现与应用2