申请邀请码,文章一

在防火墙或者某些特殊场合,需要拦截udp或者tcp,可能是按进程来拦截,可能是按ip或者端口来拦截。

这里发一段TDI层hook udp的代码,是object hook,非dispatch hook,tcp或者udp的dispatch hook通常是通过InterlockedExchange交换出tcp或者udp的dispatch函数,网上资料容易找到,这里不做探讨。

这篇文章没有包括全部代码,但是整个思路已经说清,再说看雪的兄弟们都这么聪明,我偷点懒你们也能整明白。有些函数和变量的命名,纯属娱乐。

object hook,每种IRP都要处理,这是跟dispatch hook不同的地方,当然重点是放在IRP_MJ_INTERNAL_DEVICE_CONTROL的处理上。

1、DriverEntry中,设置IRP_MJ_INTERNAL_DEVICE_CONTROL处理例程入口:

代码:
//pDriverObject是入口传入的驱动对象
pDriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = TDI_DispatchInternalDeviceControl;
pDriverObject->MajorFunction[IRP_MJ_CREATE] = TDI_DispatchCreate;//如果需要处理本地地址时,IRP_MJ_CREATE的处理是个关键的地方,本文不做细究
另外在DriverEntry的适当位置添加:
代码:
status = HookUdpDevice(pDriverObject);
if (!NT_SUCCESS(status))
{
//KdPrint(("monitor.sys: Failed to hook udp device\n"));
}
2、HookUdpDevice的实现如下:
代码:
#define SYSTEM_DEVICE_UDP_NAME            L"\\Device\\Udp"
#define AVKILLER_DEVICE_UDP_NAME        L"\\Device\\UdpMonitor"

NTSTATUS HookUdpDevice(IN PDRIVER_OBJECT DriverObject)
{
    NTSTATUS nsStatus;
    UNICODE_STRING  uString;
    PFILE_OBJECT    pUdpFileObject = NULL;
    PDEVICE_OBJECT    pUdpDeviceObject = NULL;
    PDEVICE_OBJECT    pAVKillerUdpDeviceObject = NULL;
    PDEVICE_OBJECT    pTargetDeviceObject = NULL;
    PAVKILLER_DEVICE_EXTENSION    pDeviceExtention = NULL;
    int nRetCode = 0;

    //取udp对象
    RtlInitUnicodeString(&uString, SYSTEM_DEVICE_UDP_NAME);
    nsStatus = IoGetDeviceObjectPointer(&uString, FILE_ALL_ACCESS, 
        &pUdpFileObject, &pUdpDeviceObject);
    if (!NT_SUCCESS(nsStatus))
    {
        //KdPrint(("HookUdpDevice: Failed to get udp device\n"));
        goto Exit0;
    }
    
    //创建udp hook对象
    RtlInitUnicodeString(&uString, AVKILLER_DEVICE_UDP_NAME);
    nsStatus = IoCreateDevice(
        DriverObject, sizeof(AVKILLER_DEVICE_EXTENSION),
        &uString, pUdpDeviceObject->DeviceType,
        pUdpDeviceObject->Characteristics, FALSE, &pAVKillerUdpDeviceObject);
    if (!NT_SUCCESS(nsStatus))
    {
        //KdPrint(("HookUdpDevice: Failed to create hook udp device\n"));
        goto Exit1;
    }
    
    //设备扩展处理,自个发挥
    pDeviceExtention = (PAVKILLER_DEVICE_EXTENSION)(pAVKillerUdpDeviceObject->DeviceExtension);
    nRetCode = InitDeviceExtension(pDeviceExtention, pAVKillerUdpDeviceObject);    
    
    //将udp hook对象“挂载”到udp对象之上
    pTargetDeviceObject = IoAttachDeviceToDeviceStack(pAVKillerUdpDeviceObject, pUdpDeviceObject);
    if (pTargetDeviceObject != NULL)
    {
        //设备扩展,自个发挥
        pDeviceExtention->pTdiDeviceObject    = pUdpDeviceObject;
        pDeviceExtention->pTdiFileObject      = pUdpFileObject;
        pDeviceExtention->pTargetDeviceObject = pTargetDeviceObject;
        pDeviceExtention->bTdiAttached        = TRUE;
        
        pAVKillerUdpDeviceObject->Flags |= pUdpDeviceObject->Flags & (DO_BUFFERED_IO | DO_DIRECT_IO);
        
        gAvkillerUdpDeviceObject = pAVKillerUdpDeviceObject;
        goto Exit0;
    }
    
    IoDeleteDevice(pAVKillerUdpDeviceObject);
    pAVKillerUdpDeviceObject = NULL;
    
Exit1:
    
    ObDereferenceObject(pUdpFileObject);
    
Exit0:
    
    return nsStatus;
}

3. 关键的拦截部分
代码:
NTSTATUS TDI_DispatchInternalDeviceControl(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
{
    NTSTATUS nsStatus = STATUS_SUCCESS;
    HANDLE hProcessID = 0;
    UCHAR* procName = NULL;    
    PIO_STACK_LOCATION pCurrentStackLocation = IoGetCurrentIrpStackLocation(Irp);
    UCHAR uMinorFunction = pCurrentStackLocation->MinorFunction;
    PFILE_OBJECT pFileObject = pCurrentStackLocation->FileObject;
    ULONG uContext = (ULONG)(pFileObject->FsContext2);
    PAVKILLER_DEVICE_EXTENSION pDeviceExtension = (PAVKILLER_DEVICE_EXTENSION)(DeviceObject->DeviceExtension);

    if (DeviceObject != gAvkillerUdpDeviceObject)
    {        
        Irp->IoStatus.Status = nsStatus;
        Irp->IoStatus.Information = 0;
        IoCompleteRequest(Irp, IO_NO_INCREMENT);
        goto Exit0;
    }

    //看你根据ip还是port拦截,怎么取这些拦截参数,这里只举处理TDI_SEND_DATAGRAM时的情况,其它自行查ddk文档
    switch (uMinorFunction)
    {            
    case TDI_SEND_DATAGRAM:
         nsStatus = TDISendDatagramXXX(pDeviceExtension, Irp, pCurrentStackLocation);
         break;    
    case TDI_RECEIVE_DATAGRAM:
         nsStatus = TDIReceiveDatagramXXX(pDeviceExtension, Irp, pCurrentStackLocation);
         break;                            
    case TDI_SET_EVENT_HANDLER:
         nsStatus = TDISetEventHandlerXXX(pDeviceExtension, Irp, pCurrentStackLocation);
         break;    
    case TDI_QUERY_INFORMATION:
         nsStatus = TDIQueryInformationXXX(pDeviceExtension, Irp, pCurrentStackLocation);
         break;    
    default:
         nsStatus = AllowCallLowerObject(pDeviceExtension, Irp);
         break;
    }

    /*如果要拦截某个进程:
   1. 获取当前进程
   1.1 获取当前进程名:PsGetProcessImageFileName(PsGetCurrentProcess());
   1.2 获取当前进程id: PsGetCurrentProcessId();
   1.3 其实还有很多方法获取进程,看雪论坛总结得更好得文章,这里不再举例
   2. 直接如下面这样处理
   */
    if (拒绝连接)
    {
        nsStatus = DenyCallLowerObject(Irp);
    }
    if (允许连接)
    {
        nsStatus = AllowCallLowerObject(pDeviceExtension, Irp);
    }

    return nsStatus;
}

NTSTATUS TDISendDatagramXXX(IN PDEVICE_EXTENSION DeviceExtension, IN PIRP Irp, IN PIO_STACK_LOCATION IoStackLocation)
{
    NTSTATUS nsStatus = STATUS_SUCCESS;
    PTDI_REQUEST_KERNEL_SENDDG pTDI_Request_Kernel_Senddg = (PTDI_REQUEST_KERNEL_SENDDG)(&(IoStackLocation->Parameters.DeviceIoControl));
    ULONG uSendLength = pTDI_Request_Kernel_Senddg->SendLength;//发送长度
    PTDI_CONNECTION_INFORMATION pTDI_Connection_Information = pTDI_Request_Kernel_Senddg->SendDatagramInformation;
    PVOID pRemoteAddress = pTDI_Connection_Information->RemoteAddress;//发送地址
    ULONG uRemoteAddress;
    USHORT uRemotePort;
        
    /*这是取远端地址参数,假如取本地地址参数,比较麻烦,光从TDISendDatagramXXX函数里面是取不到的,需要在处理IRP_MJ_CREATE时,从Irp包中的Irp->AssociatedIrp.SystemBuffer中分析出来, Irp->AssociatedIrp.SystemBuffer指向FILE_FULL_EA_INFORMATION结构,可以从FILE_FULL_EA_INFORMATION中解析本地地址参数,具体可参考ddk。
    */  
    uRemoteAddress = GetIP(pRemoteAddress);//查ddk说明,解析出ip
    uRemotePort = GetPort(pRemoteAddress);//查ddk说明,解析出port

    if (拒绝连接)
    {
        nsStatus = DenyCallLowerObject(Irp);
    }
    if (允许连接)
    {
        nsStatus = AllowCallLowerObject(pDeviceExtension, Irp);
    }
}

//允许连接
NTSTATUS AllowCallLowerObject(IN PAVKILLER_DEVICE_EXTENSION DeviceExtension, IN PIRP Irp)
{
    NTSTATUS nsStatus = STATUS_SUCCESS;
    
    IoSkipCurrentIrpStackLocation(Irp);
    //IoCopyCurrentIrpStackLocationToNext(Irp);
    
    nsStatus = IoCallDriver(DeviceExtension->pTargetDeviceObject, Irp);
    
    return nsStatus;
}

//拒绝连接
NTSTATUS DenyCallLowerObject(PIRP Irp)
{
    NTSTATUS nsStatus = STATUS_ACCESS_DENIED;
    
    Irp->IoStatus.Status = nsStatus;
    Irp->IoStatus.Information = 0;
    
    IoCompleteRequest(Irp, IO_NO_INCREMENT);
    
    return nsStatus;
}