admin 发表于 2009-12-12 23:03:40

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

创建时间:2003-03-26
文章属性:原创
文章来源:http://www.whitecell.org
文章提交:sinister (jiasys_at_21cn.com)

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

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.OffsetLow,OIdt.OffsetHigh);
   
   NIdt = &(OIdt);

   __asm {
         cli
         lea eax,NewInt2eService;   //得到新的 INT 2E 服务例程偏移
         mov ebx, NIdt;
         mov ,ax;   //INT 2E 服务例程低 16 位
         shr eax,16       //INT 2E 服务例程高 16 位
         mov ,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);

   _asm {
         cli
         lea eax,OldInt2eService;
         mov ebx, NIdt;
         mov ,ax;
         shr eax,16
         mov ,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, "???");
         }
}
页: [1]
查看完整版本: 内核级HOOK的几种实现与应用1