宝峰科技

 找回密码
 注册

QQ登录

只需一步,快速开始

智能终端设备维修查询系统注册会员邮箱认证须知!
查看: 1587|回复: 0

[转载] 内核级HOOK的几种实现与应用1

[复制链接]
  • TA的每日心情
    开心
    2024-12-9 18:45
  • 签到天数: 124 天

    [LV.7]常住居民III

    admin 发表于 2009-12-12 23:03:40 | 显示全部楼层 |阅读模式

    欢迎您注册加入!这里有您将更精采!

    您需要 登录 才可以下载或查看,没有账号?注册

    x
    创建时间: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 中断,使之指向我们自己的中断服务处理例程来实现的。掌握
    此方法需要你对保护模式有一定的基础。下面的程序演示了这一过程。


    1. /*****************************************************************
    2. 文件名         : WssHookInt2e.c
    3. 描述           : 系统调用跟踪
    4. 作者           : sinister
    5. 最后修改日期   : 2002-11-02
    6. *****************************************************************/

    7. #include "ntddk.h"
    8. #include "string.h"

    9. #define DWORD unsigned __int32
    10. #define WORD unsigned __int16
    11. #define BYTE unsigned __int8
    12. #define BOOL __int32

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

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

    18. #define SYSTEMCALL 0x2e
    19. #define SYSNAME "System"
    20. #define PROCESSNAMELEN 16

    21. #pragma pack(1)

    22. //定义 IDTR
    23. typedef struct tagIDTR {
    24.          WORD IDTLimit;
    25.          WORD LowIDTbase;
    26.          WORD HiIDTbase;
    27. }IDTR, *PIDTR;

    28. //定义 IDT
    29. typedef struct tagIDTENTRY{
    30.      WORD OffsetLow;
    31.      WORD selector;
    32.      BYTE unused_lo;
    33.      unsigned char unused_hi:5;
    34.      unsigned char DPL:2;
    35.      unsigned char P:1;
    36.      WORD OffsetHigh;
    37. } IDTENTRY, *PIDTENTRY;


    38. #pragma pack()

    39. DWORD     OldInt2eService;
    40. ULONG     ProcessNameOffset;
    41. TCHAR   ProcessName[PROCESSNAMELEN];

    42. static NTSTATUS   MydrvDispatch (IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);
    43. VOID DriverUnload (IN PDRIVER_OBJECT pDriverObject);
    44. ULONG GetProcessNameOffset();
    45. VOID GetProcessName( PCHAR Name );
    46. VOID InstallNewInt2e();
    47. VOID UninstallNewInt2e();

    48. VOID __fastcall NativeApiCall()
    49. {
    50.      KIRQL OldIrql;
    51.    
    52.      DWORD ServiceID;
    53.      DWORD ProcessId;

    54.      __asm mov ServiceID,eax;


    55.      ProcessId = (DWORD)PsGetCurrentProcessId();
    56.      GetProcessName(ProcessName);

    57.      KeRaiseIrql(HIGH_LEVEL, &OldIrql); // 提升当前的 IRQL 级别防止被中断


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

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


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

    71.      KeLowerIrql(OldIrql); //恢复原始 IRQL

    72. }

    73. __declspec(naked) NewInt2eService()
    74. {
    75.      __asm{
    76.          pushad
    77.          pushfd
    78.          push fs
    79.          mov bx,0x30
    80.          mov fs,bx
    81.          push ds
    82.          push es

    83.          sti
    84.          call NativeApiCall; // 调用记录函数
    85.          cli

    86.          pop es
    87.          pop ds
    88.          pop fs
    89.          popfd
    90.          popad

    91.          jmp     OldInt2eService;   //跳到原始 INT 2E 继续工作
    92.      }
    93. }

    94. VOID InstallNewInt2e()
    95. {

    96.      IDTR         idtr;
    97.      PIDTENTRY     OIdt;
    98.      PIDTENTRY     NIdt;

    99.      //得到 IDTR 中得段界限与基地址
    100.      __asm {
    101.          sidt idtr;
    102.      }

    103.      //得到IDT基地址
    104.      OIdt = (PIDTENTRY)MAKELONG(idtr.LowIDTbase,idtr.HiIDTbase);

    105.      //保存原来的 INT 2E 服务例程
    106.      OldInt2eService = MAKELONG(OIdt[SYSTEMCALL].OffsetLow,OIdt[SYSTEMCALL].OffsetHigh);
    107.    
    108.      NIdt = &(OIdt[SYSTEMCALL]);

    109.      __asm {
    110.          cli
    111.          lea eax,NewInt2eService;   //得到新的 INT 2E 服务例程偏移
    112.          mov ebx, NIdt;
    113.          mov [ebx],ax;   //INT 2E 服务例程低 16 位
    114.          shr eax,16       //INT 2E 服务例程高 16 位
    115.          mov [ebx+6],ax;
    116.          lidt idtr   //装入新的 IDT
    117.          sti
    118.      }

    119. }

    120. VOID UninstallNewInt2e()
    121. {
    122.      IDTR         idtr;
    123.      PIDTENTRY     OIdt;
    124.      PIDTENTRY     NIdt;

    125.      __asm {
    126.          sidt idtr;
    127.      }

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

    129.      NIdt = &(OIdt[SYSTEMCALL]);

    130.      _asm {
    131.          cli
    132.          lea eax,OldInt2eService;
    133.          mov ebx, NIdt;
    134.          mov [ebx],ax;
    135.          shr eax,16
    136.          mov [ebx+6],ax;
    137.          lidt idtr
    138.          sti
    139.      }

    140. }




    141. // 驱动入口
    142. NTSTATUS   DriverEntry( IN PDRIVER_OBJECT DriverObject,   IN PUNICODE_STRING RegistryPath )
    143. {
    144.    
    145.      UNICODE_STRING   nameString, linkString;
    146.      PDEVICE_OBJECT   deviceObject;
    147.      NTSTATUS         status;
    148.      HANDLE           hHandle;
    149.      int                 i;
    150.    

    151.      //卸载驱动
    152.      DriverObject->DriverUnload = DriverUnload;

    153.      //建立设备
    154.      RtlInitUnicodeString( &nameString, L"\\Device\\WssHookInt2e" );
    155.    
    156.      status = IoCreateDevice( DriverObject,
    157.                              0,
    158.                              &nameString,
    159.                              FILE_DEVICE_UNKNOWN,
    160.                              0,
    161.                              TRUE,
    162.                              &deviceObject
    163.                            );
    164.                            

    165.      if (!NT_SUCCESS( status ))
    166.          return status;
    167.    

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

    169.      status = IoCreateSymbolicLink (&linkString, &nameString);

    170.      if (!NT_SUCCESS( status ))
    171.      {
    172.          IoDeleteDevice (DriverObject->DeviceObject);
    173.          return status;
    174.      }   
    175.    

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

    177.            DriverObject->MajorFunction[i] = MydrvDispatch;
    178.      }

    179.        DriverObject->DriverUnload = DriverUnload;

    180.      ProcessNameOffset = GetProcessNameOffset();
    181.      InstallNewInt2e();

    182.    return STATUS_SUCCESS;
    183. }



    184. //处理设备对象操作

    185. static NTSTATUS MydrvDispatch (IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
    186. {
    187.      Irp->IoStatus.Status = STATUS_SUCCESS;
    188.      Irp->IoStatus.Information = 0L;
    189.      IoCompleteRequest( Irp, 0 );
    190.      return Irp->IoStatus.Status;
    191.    
    192. }



    193. VOID DriverUnload (IN PDRIVER_OBJECT     pDriverObject)
    194. {
    195.      UNICODE_STRING   nameString;

    196.      UninstallNewInt2e();
    197.      RtlInitUnicodeString( &nameString, L"\\DosDevices\\WssHookInt2e" );   
    198.      IoDeleteSymbolicLink(&nameString);
    199.      IoDeleteDevice(pDriverObject->DeviceObject);

    200.      return;
    201. }



    202. ULONG GetProcessNameOffset()
    203. {
    204.          PEPROCESS curproc;
    205.          int i;
    206.         
    207.          curproc = PsGetCurrentProcess();

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

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

    213.                  return i;
    214.              }
    215.          }

    216.          //
    217.          // Name not found - oh, well
    218.          //
    219.          return 0;
    220. }

    221. VOID GetProcessName( PCHAR Name )
    222. {

    223.          PEPROCESS curproc;
    224.          char *nameptr;
    225.          ULONG i;

    226.          if( ProcessNameOffset ) {

    227.              curproc = PsGetCurrentProcess();
    228.              nameptr = (PCHAR) curproc + ProcessNameOffset;
    229.              strncpy( Name, nameptr, 16 );

    230.          } else {

    231.              strcpy( Name, "???");
    232.          }
    233. }
    复制代码
    您需要登录后才可以回帖 登录 | 注册

    本版积分规则

    免责声明

    本站中所有被研究的素材与信息全部来源于互联网,版权争议与本站无关。本站所发布的任何软件编程开发或软件的逆向分析文章、逆向分析视频、补丁、注册机和注册信息,仅限用于学习和研究软件安全的目的。全体用户必须在下载后的24个小时之内,从您的电脑中彻底删除上述内容。学习编程开发技术或逆向分析技术是为了更好的完善软件可能存在的不安全因素,提升软件安全意识。所以您如果喜欢某程序,请购买注册正版软件,获得正版优质服务!不得将上述内容私自传播、销售或者用于商业用途!否则,一切后果请用户自负!

    QQ|Archiver|手机版|小黑屋|联系我们|宝峰科技 ( 滇公网安备 53050202000040号 | 滇ICP备09007156号-2 )

    Copyright © 2001-2023 Discuz! Team. GMT+8, 2025-5-8 13:41 , File On Powered by Discuz! X3.49

    快速回复 返回顶部 返回列表