Windows防火墙的应用程序访问网络控制
[b]以往的防火墙只能古板的允许或者禁止整个系统去访问网络上的目标,比如允许了系统可以访问外网的http端口,就允许了所有进程,不能只控制IE等几个进程有权这样做。该技术的出现解决了这个问题,对每个陌生的进程都会询问客户是否允许访问网络,因此还有一定的查杀未知木马病毒的能力。由于NDIS里面的那些send/receive handler全都是由tdi缓冲之后再调用的,运行的上下文全都是kernel,并且不保存原先进行tdi操作的进程号,因此在封包过滤的NDIS钩子层次无法取得进行操作的进程ID。想要解决应用程序访问网络控制的问题,就需要在tdi或者更高的层次上使用钩子。一般来说,主流是使用tdi钩子,在进程的网络调用栈进行到tdi的TDI_CONNECT,TDI_LISTEN,TDI_RECEIVE,TDI_SET_EVENT_HANDLER等调用时,进行进程判断和提示。
对于winsock的应用程序来说,最重要的是主动连接请求,TDI_CONNECT;接受连接请求,TDI_SET_EVENT_HANDLER中的TDI_EVENT_CONNECT。对于udp收发,还要处理TDI_SEND_DATAGRAM,TDI_RECEIVE_DATAGRAM和TDI_SET_EVENT_HANDLER中的TDI_EVENT_RECEIVE_DATAGRAM请求。这个时候,直接PsGetCurrentProcessId就可以得到进程号。
tdi钩子有一个问题,就是对于TDI_SET_EVENT_HANDLER的hook,很可能不能及时发挥作用,必须要重起以后。由于不像ndis钩子需要hook系统函数或者修改系统数据结构,tdi钩子可以直接使用微软提供的过滤器驱动程序接口,在安装编写上要比ndis钩子简单的多,IoAttachDeviceToDeviceStack就可以了。
给出一段detour的tdi的dispatch routine的代码:
NTSTATUS hook_disp(IN PDEVICE_OBJECT parampdrvob, IN PIRP irp)
{
....
case IRP_MJ_INTERNAL_DEVICE_CONTROL:
switch(irpsp->MinorFunction)
{
///原来想得要监控的几个似乎afd并不使用,而是用set event handler
case TDI_LISTEN:
#ifdef bydbg
DbgPrint("bytdiflt:TDI_LISTEN traped.should caused by kmd other than AFD.\n");
#endif
stat=gettcpportbyfile(irpsp->FileObject);
#ifdef bydbg
DbgPrint("bytdiflt:**********TDI_EVENT_CONNECT port:%d.***********\n",stat);
#endif
if(stat==0 || stat==-1){break;}//non-tcp or internal error
if(denyport[(unsigned short)stat]==1)//直接失败请求
{
#ifdef bydbg
DbgPrint("bytdiflt:*********port %d blocked!!*********\n",stat);
//DbgBreakPoint();
#endif
stat=STATUS_ACCESS_VIOLATION;
irp->IoStatus.Status=stat;
irp->IoStatus.Information=0;
IoCompleteRequest(irp, IO_NO_INCREMENT);
return stat;
}
break;
case TDI_RECEIVE:
#ifdef bydbg
DbgPrint("bytdiflt:TDI_RECEIVE traped.should caused by kmd other than AFD.\n");
//DbgBreakPoint();
#endif
break;
case TDI_SET_EVENT_HANDLER:
#ifdef bydbg
DbgPrint("bytdiflt:TDI_SET_EVENT_HANDLER traped.req local_node:%x\n",irpsp->FileObject);
DbgPrint("TDI_SET_EVENT_HANDLER EventType:%d EventHandler:%x EventContext:%x\n",
((TDI_REQUEST_KERNEL_SET_EVENT*)&(irpsp->Parameters))->EventType,
((TDI_REQUEST_KERNEL_SET_EVENT*)&(irpsp->Parameters))->EventHandler,
((TDI_REQUEST_KERNEL_SET_EVENT*)&(irpsp->Parameters))->EventContext
);
#endif
switch(((TDI_REQUEST_KERNEL_SET_EVENT*)&(irpsp->Parameters))->EventType){
case TDI_EVENT_CONNECT:
tmpstrptr="TDI_EVENT_CONNECT";
stat=gettcpportbyfile(irpsp->FileObject);
#ifdef bydbg
DbgPrint("bytdiflt:**********TDI_EVENT_CONNECT port:%d.***********\n",stat);
#endif
if(stat==0 || stat==-1){break;}//non-tcp or internal error
if(denyport[(unsigned short)stat]==1)//完成请求但不做事情
{
#ifdef bydbg
DbgPrint("bytdiflt:*********port %d blocked!!*********\n",stat);
//DbgBreakPoint();
#endif
stat=STATUS_SUCCESS;
irp->IoStatus.Status=stat;
irp->IoStatus.Information=0;
IoCompleteRequest(irp, IO_NO_INCREMENT);
return stat;
}
break;
case TDI_EVENT_RECEIVE:
tmpstrptr="TDI_EVENT_RECEIVE";
break;
case TDI_EVENT_CHAINED_RECEIVE:
tmpstrptr="TDI_EVENT_CHAINED_RECEIVE";
break;
case TDI_EVENT_RECEIVE_EXPEDITED:
tmpstrptr="TDI_EVENT_RECEIVE_EXPEDITED";
break;
case TDI_EVENT_CHAINED_RECEIVE_EXPEDITED:
tmpstrptr="TDI_EVENT_CHAINED_RECEIVE_EXPEDITED";
break;
case TDI_EVENT_RECEIVE_DATAGRAM:
tmpstrptr="TDI_EVENT_RECEIVE_DATAGRAM";
break;
default:
tmpstrptr="Other TDI_EVENT";
break;
}
#ifdef bydbg
DbgPrint("EventType is:%s\n",tmpstrptr);
#endif
break;
case TDI_CONNECT://处理主动外出连接
stat=gettcpportbyfile(irpsp->FileObject);
#ifdef bydbg
if(stat==0 || stat==-1)//non-tcp or internal error
{DbgPrint("bytdiflt:**********TDI_CONNECT local port UNKNOWN.***********\n");}
else
{DbgPrint("bytdiflt:**********TDI_CONNECT local port:%d.************\n",stat);}
//DbgBreakPoint();
#endif
break;
....
PsGetCurrentProcessId....//判断进程号
....
}
[/b]
页:
[1]
