登录社区:用户名: 密码: 忘记密码 网页功能:加入收藏 设为首页 网站搜索  

文档

下载

图书

论坛

安全

源码

硬件

游戏
首页 信息 空间 VB VC Delphi Java Flash 补丁 控件 安全 黑客 电子书 笔记本 手机 MP3 杀毒 QQ群 产品库 分类信息 编程网站
 内容搜索 网页 下载 源代码
热点文章
  利用鼠标键盘钩子截获密码
  利用鼠标键盘钩子截获密码
  如何将多个文件捆绑成一个可..
  如何将多个文件捆绑成一个可..
  内核级HOOK的几种实现与应用
  内核级HOOK的几种实现与应用
  书写基于内核的linux键盘纪录..
  书写基于内核的linux键盘纪录..
  CIH病毒原码
  CIH病毒原码
  编写进程/线程监视器
  编写进程/线程监视器
本站原创
  利用鼠标键盘钩子截获密码
  利用鼠标键盘钩子截获密码
最新招聘信息

您现在的位置:立华软件园->安全防线->黑客编程
内核级HOOK的几种实现与应用
发表日期:2003-10-14作者:[] 出处:  

原始文档:http://www.xfocus.net/articles/200303/499.html

创建时间:2003-03-26

浏览次数:87

原创:sinister (jiasys_at_21cn.com)

来源:http://www.whitecell.org

内核级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[i] = 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        &n

我来说两句】 【发送给朋友】 【加入收藏】 【返加顶部】 【打印本页】 【关闭窗口
中搜索 内核级HOOK的几种实现与应用
关于我们 / 合作推广 / 给我留言 / 版权举报 / 意见建议 / 广告投放 / 友情链接

Copyright ©2001-2003 Allrights reserved
e_mail:站长:webmaster(at)lihuasoft.net
网站编程QQ群  
京ICP备05001064号

页面生成时间:0.00507