笔者最近在学习NDIS 驱动方面的内容。NDIS 分为三类:协议驱动、中间层驱动以及小
端口驱动。如果读者学习过 NDIS 驱动,都应该知道除了小端口驱动外,协议驱动和中间层
驱动都调用了 NdisRegisterProtocol 来注册一个协议,从而达到进行自主发包、过滤或者
修改数据包的功能。
由此可见,NdisRegisterProtocol 对于攻击和防守的两方都有重要意义。目前主动防
御已经对 NdisRegisterProtocol进行了各种各样的hook。从而让 rootkit进入系统后,难
以用底层的技术来隐藏自身的数据连接。那么如何绕过主动防御中的限制,让我们能够调用
NdisRegisterProtocol呢?
因为无法确定各HIPS 进行的是何种hook,所以笔者只想到了以下通用的方法:1.加载
原始 NDIS.SYS文件,再解析PE文件,找到函数地址进行调用。这种方法优点是可以无视对
NdisRegisterProtocol的各种 hook,并且易做到通用性;缺点是代码量较大,HIPS 可能会
对 MapViewOfSection之类的函数进行hook,从而导致该方法的失败。2.在模块中自己实现
NdisRegisterProtocol 的操作,不调用系统提供的函数。这种方法的优点是无视
NdisRegisterProtocol和MapViewOfSection之类的hook;缺点是代码量同样较大,通用性
比较难做到。
由于对 PE文件的解析类文章比较多了,再加上网上貌似比较少NdisRegisterProtocol
的资料比较少,所以笔者这里选择了第二种方法,自己实现NdisRegisterProtocol的操作。
下面我将带大家一起来了解 NdisRegisterProtocol 中的操作及一些结构。关于
NdisRegisterProtocol 中的操作,正如其名,就是向系统中注册我们的协议。那么是如何
注册的呢?笔者就结合逆向出来的C代码,来向大家讲解 NdisRegisterProtocol中的操作。
首先,笔者不打算一开始就钻入代码中进行讲解。正如编码前先架构,那么讲解代码前
我们先了解大致的步骤。系统中的一个协议链表,其链表头是名为_ndisProtocolList的变
量, _ndisProtocolList 指向一个类型为 NDIS_PROTOCOL_BLOCK 的结构体,
NDIS_PROTOCOL_BLOCK 中有 NextProtocol 域指向下一个 NDIS_PROTOCOL_BLOCK 体,从而把
注册的协议串成一个链。同时NDIS_PROTOCOL_BLOCK中还有ProtocolCharacteristics域,
这个域是用户自定义的协议特征,本质是一系列的处理函数。如图1 所示:

图中没有显示出ProtocolCharacteristics,但起读者记住些结构中有这个域。其中的
OpenQueue并不在本文的讨论中,但很重要,其结构为_NDIS_OPEN_BLOCK,有兴趣的读者,
请自行探索。
接着该讨论代码了,看看 NdisRegisterProtocol 是如何一步一步把协议加入到
_ndisProtocolList中去的,这里只给出主要步骤,先来看看NDIS_PROTOCOL_BLOCK结构的
代码,如下:
typedef struct{
PVOID OpenQueue; //: Ptr32 _NDIS_OPEN_BLOCK 0X00
REFERENCE Ref; //: _REFERENCE 0X04
PKEVENT DeregEvent; //: Ptr32 _KEVENT 0X0C
PNDIS_PROTOCOL_BLOCK NextProtocol; //: Ptr32 _NDIS_PROTOCOL_BLOCK 0X10
NDIS50_PROTOCOL_CHARACTERISTICS ProtocolCharacteristics; //:
_NDIS50_PROTOCOL_CHARACTERISTICS 0X14
WORKQUEUEITEM WorkItem; //: WORKQUEUEITEM 0X80
KMUTANT Mutex; //: _KMUTANT 0X90
ULONG MutexOwner; //: Uint4B 0XB0
PUNICODE_STRING BindDeviceName; //: Ptr32 _UNICODE_STRING 0XB4
PUNICODE_STRING RootDeviceName; //: Ptr32 _UNICODE_STRING 0XB8
PUNICODE_STRING AssociatedMiniDriver; //: Ptr32 _NDIS_M_DRIVER_BLOCK
0XBC
PVOID BindingAdapter; //: Ptr32 _NDIS_MINIPORT_BLOCK 0XC0
// USHORT NameBuff[Characteristics->Name.Length+2]; //0XC4
} MYNDISPROTOCOLBLOCK, *PMYNDISPROTOCOLBLOCK;
每个域后面都标出了偏移,方便大家查看。下面就开始分析 NdisRegisterProtocol 的
代码了,代码如下:
1.
size = 0x6c;
p_protocol =
(PMY_NDIS_PROTOCOL_BLOCK)ExAllocatePoolWithTag(NonPagedPool, |