Hooking into NDIS and TDI-part 1

产业园区如何高效对接企业技术需求与高校科研成果?.docx 科易网基于AI模型+行业大数据,在技术转移、成果转化、技术经纪、知识产权、产业创新、科技招商等垂直领域的多样化应用场景,推出科技创新领域的AI+工具与数智化解决方案,推动科技创新与产业创新智能化发展。 立即下载
By: andreas

 

This is the fist part in a series of 2 articles on how to hook into the NDIS and TDI layer. In this first one, we will discuss where and how to hook in to the NDIS layer.

In the second, we will do the same for TDI.

First, lets take a quick look at a quite simplicit view of the network stack in kernel space:
TDI
NDIS protocol layer
NDIS Intermediate layer
Miniport layer
Hardware

To be able to control data flow in NDIS, we have 3 potential points where we can either add a device / driver or hook into existing. First, we have the miniport layer, these are the drivers controlling the NIC hardware, which is a bit to low of a level for what we want at this time. Next, we have the intermediate layer. This layer would be perfect for this purpose, since it would allow us to contol the dataflow to all NDIS protocol drivers. But, it has a major drawback: To be able to add a driver to this layer, it has to be signed on a default install.



Depending on what system and under what circumstances we are installing this code, it might not be possible to get past this problem in an easy manner. Last, we have the protocol layer. Adding a driver to this layer would be easy, software such as WinPcap does that. However, in that case we will not be able to control what a user would see through for software relaying on these types of drivers, such as Ethereal. So, is there any way we can get around the driver signing issue in the intermediate layer and at the same time control data in the protocol layer and above? Yes! We can virually add a layer in between intermediate and protocol by hooking all NDIS protocol drivers and their protocol functions.

When an NDIS protocol is registered, it is recorded in a linked list. Each element in this linked list carries a pointer to a structure named NDIS_OPEN_BLOCK. This structure carries the pointers for all registered function pointers for the protocol. The linked list elements are made out of a structure looking something like the following:


typedef struct _NDIS_LINKED_LIST {
  PNDIS_OPEN_BLOCK pOpenBlock;
  PVOID p;
  REFERENCE ref;
  struct _NDIS_LINKED_LIST *Next;
} NDIS_LINKED_LIST,*PNDIS_LINKED_LIST;


It was a year or so since I played with this code, so I can actually not remember the real name of this struct. Interested persons can find it through google. This will also reflect in the source code later on, since it is relying on absolute offsets instead of the typedef'ed struct.

To be able to hook into all registered NDIS protocols, we need to find the first element in this linked list. This is actually returned by NdisRegisterProtocol as the NDIS_HANDLE. So, what we have to do is to register a bogus NDIS protocol, save the pointer and then remove the protocol. This will give us the ability to walk through the list of registered NDIS protocols and exchange existing function points to functions we control.

First, we register the bogus protocol to get the pointer. To make sure the registration does not fail, the protocol we register needs to have a ReceiveHandler:


NDIS_STATUS DummyNDISProtocolReceive(
    IN NDIS_HANDLE ProtocolBindingContext,
    IN NDIS_HANDLE MacReceiveContext,
    IN PVOID HeaderBuffer,
    IN UINT HeaderBufferSize,
    IN PVOID LookAheadBuffer,
    IN UINT LookAheadBufferSize,
    IN UINT PacketSize)
{
    return NDIS_STATUS_NOT_ACCEPTED;
}

NDIS_HANDLE RegisterBogusNDISProtocol(void)
{
    NTSTATUS Status = STATUS_SUCCESS;
    NDIS_HANDLE hBogusProtocol = NULL;
    NDIS_PROTOCOL_CHARACTERISTICS BogusProtocol;
    NDIS_STRING ProtocolName;

    NdisZeroMemory(&BogusProtocol,sizeof(NDIS_PROTOCOL_CHARACTERISTICS));
    BogusProtocol.MajorNdisVersion = 0x04;
    BogusProtocol.MinorNdisVersion = 0x0;

    NdisInitUnicodeString(&ProtocolName,L"BogusProtocol");
    BogusProtocol.Name = ProtocolName;
    BogusProtocol.ReceiveHandler = DummyNDISProtocolReceive;

    NdisRegisterProtocol(&Status,&hBogusProtocol,&BogusProtocol,
        sizeof(NDIS_PROTOCOL_CHARACTERISTICS));

    if(Status == STATUS_SUCCESS) return hBogusProtocol;
    else return NULL;
}


Once we have the pointer, we can deregister the protocol again:


void DeregisterBogusNDISProtocol(NDIS_HANDLE hBogusProtocol)
{
    NTSTATUS Status;

    NdisDeregisterProtocol(&Status,hBogusProtocol);
}


Once we start walking the linked list and overwriting function pointers, we need to save the old pointers to be able to call them from our functions. There are atleast 2 ways of doing this:

1. Create a linked list of "hooked instances", holding the old pointers for each protocol. When our NDIS functions are called, the linked list has to be searched for the right element.

2. Allocate one instance of our functions for each protocol we hook and write the old pointer directly into the code of the function. This is slighly more work during hooking, but should be faster during run-time than searching through a linked list for every packet.

When this code was written, I never thought of option number 2, but that is probably the option I would use today. So, enjoy option 1, it works well and I haven't seen any major performance hits from it.

For every element in the NDIS registered protocol linked list, I allocate one element in my own list and save all important pointers together with 2 context handles. The handles values are later used to find the right element for the current protocol. Relevant pointers are then overwritten to point to my versions of the send and receive functions. We also save a pointer to the NDIS_OPEN_BLOCK itself to make unhooking easy. The code walking the list and hooking into the protocol would look something like this:


NTSTATUS HookExistingNDISProtocols(void)
{
    UINT *ProtocolPtr;
    NDIS_HANDLE hBogusProtocol = NULL;
    PNDIS_OPEN_BLOCK OpenBlockPtr = NULL;
    PNDIS_PROTOCOL_HOOK pNode;

    hBogusProtocol = RegisterBogusNDISProtocol();
    if(hBogusProtocol == NULL) return STATUS_UNSUCCESSFUL;

    ProtocolPtr = (UINT*)hBogusProtocol;
    ProtocolPtr = (UINT*)((PBYTE)ProtocolPtr + sizeof(REFERENCE) + 8);
    ProtocolPtr = (UINT*)(*ProtocolPtr);

    while(ProtocolPtr != NULL) {
        OpenBlockPtr = (PNDIS_OPEN_BLOCK)(*ProtocolPtr);
        if(OpenBlockPtr != NULL) {
            pNode = NewNDISNode();
            if(pNode != NULL) {
                pNode->ProtocolBindingContext = OpenBlockPtr->ProtocolBindingContext;
                pNode->MacBindingContext = OpenBlockPtr->MacBindingHandle;
                pNode->OpenBlockPtr = OpenBlockPtr;
                pNode->RealSendHandler = OpenBlockPtr->SendHandler;
                //How about WanSendHandler?
                pNode->RealPostNt31ReceiveHandler = OpenBlockPtr->PostNt31ReceiveHandler;
                
                InsertNDISNode(pNode);

                OpenBlockPtr->SendHandler = NDISSendHandler;
                //How about WanSendHandler?
                OpenBlockPtr->PostNt31ReceiveHandler = NDISPostNt31ReceiveHandler;
            }
        }

        ProtocolPtr = (UINT*)((PBYTE)ProtocolPtr + sizeof(REFERENCE) + 8);
        ProtocolPtr = (UINT*)(*ProtocolPtr);
    }

    DeregisterBogusNDISProtocol(hBogusProtocol);

    return STATUS_SUCCESS;
}


There are more functions in the NDIS_OPEN_BLOCK that might be of interest to hook, but if you only want to control network traffic, send and receive are enough. Another thing worth mentioning is that the NDIS_OPEN_BLOCK changes with OS versions. It looks different in Win2K compared to XP, mostly due to member names changing.

The next thing to do now is to implement send and recieve functions which searches through the linked list to find the original function pointers and then calls them if the traffic is to be passed on. If the traffic is to be altered, that is performed before calling the real protocol function. If the traffic is supposed to be dropped, we can just skip calling the real function and return with the appropriate status:


NDIS_STATUS NDISSendHandler(
    IN NDIS_HANDLE MacBindingHandle,
    IN PNDIS_PACKET Packet)
{
    PNDIS_PROTOCOL_HOOK Node;

    Node = FindNDISNode(MacBindingHandle,2);
    if(Node == NULL) return NDIS_STATUS_SUCCESS;

    return Node->RealSendHandler(MacBindingHandle,Packet);
}

NDIS_STATUS NDISPostNt31ReceiveHandler(
    IN NDIS_HANDLE ProtocolBindingContext,
    IN NDIS_HANDLE MacReceiveContext,
    IN PVOID HeaderBuffer,
    IN UINT HeaderBufferSize,
    IN PVOID LookAheadBuffer,
    IN UINT LookAheadBufferSize,
    IN UINT PacketSize)
{
    PNDIS_PROTOCOL_HOOK Node;

    Node = FindNDISNode(ProtocolBindingContext,1);
    if(Node == NULL) return NDIS_STATUS_SUCCESS;

    return Node->RealPostNt31ReceiveHandler(ProtocolBindingContext,MacReceiveContext,
        HeaderBuffer,HeaderBufferSize,LookAheadBuffer,LookAheadBufferSize,PacketSize);
}


Now, there is only one thing left, unhooking. We do this by walking our linked list of "hooked instances" and replace all pointers:


NTSTATUS ReleaseExistingNDISProtocols(void)
{
    PNDIS_PROTOCOL_HOOK CurrentNode;
    PNDIS_OPEN_BLOCK OpenBlockPtr = NULL;

    CurrentNode = GetFirstNDISNode();
    if(CurrentNode == NULL) return STATUS_UNSUCCESSFUL;

    while(CurrentNode != NULL) {
        OpenBlockPtr = CurrentNode->OpenBlockPtr;
        if(OpenBlockPtr != NULL) {
            OpenBlockPtr->SendHandler = CurrentNode->RealSendHandler;
            OpenBlockPtr->PostNt31ReceiveHandler = CurrentNode->RealPostNt31ReceiveHandler;
        }
        CurrentNode = GetNextNDISNode(CurrentNode);
    }

    return STATUS_SUCCESS;
}


What is left to be done? The code does not hook into NDIS protocol being registred after NDIS is hooked into. This is left up to the reader to figure out, one way to do it can be found in the win32 version of sebek.

Does the code work? Sure, I use it in a win32 version of knockd called sesame that can be found at .http://www.toolcrypt.org/.
国央企创新负责人如何快速掌握本地科技资源分布与匹配情况?.docx 科易网基于AI模型+行业大数据,在技术转移、成果转化、技术经纪、知识产权、产业创新、科技招商等垂直领域的多样化应用场景,推出科技创新领域的AI+工具与数智化解决方案,推动科技创新与产业创新智能化发展。 立即下载

相关推荐

国央企创新负责人如何实现科技成果的精准识别与高效筛选?.docx

科易网基于AI模型+行业大数据,在技术转移、成果转化、技术经纪、知识产权、产业创新、科技招商等垂直领域的多样化应用场景,推出科技创新领域的AI+工具与数智化解决方案,推动科技创新与产业创新智能化发展。

记一道DP题

题意: 给定 n l r 求长度为n的 且元素在 [l-r] 的 且 数组元素和是3的倍数的 数组的 个数 思路: DP dp[i][j] 表示 长度为i的 数组元素mod 3 为 j 的数组的个数 那么转移方程: mod0 表示区间内的数mod 3 = 0的个数 mod1 mod2 同理 dp[i][0] = ((dp[i-1][0]*mod0)%mod+(dp[i-1][1]*mod2)%mod+(dp[i-1][2]*mod1)%mod)%mod dp[i][1] = ((dp[i-1][0]*mo

qq_43461168的博客 187

SAP中寄售结算规则及要点分析

在做MRKO寄售结算时,系统会根据选定的期间和供应商等条件,将符合条件的寄售消耗或寄售上线的物料凭证找出。然后以供应商为单位。合并产生一张会计凭证。下图显示了通过MRKO结算后自动生成的会计凭证。 那么,在MRKO做寄售结算的规则是什么样的?做为寄售业务处理者的物流和财务需要掌握和了解哪些关于寄售结算的规则和控制逻辑。下面以笔者的经验分析一下: 1、寄售物料在系统中有两种处理方法,一种是通过MB1B 411 K ,通常该操作达到两个目的:将物料从仓库转移到线边库(表示即将要投入生产了)的同时将寄售库

专注SAP应用技术文章写作,致力于拉近用户与系统间的距离; 8297

Hooking into NDIS and TDI, part 1

Hooking into NDIS and TDI, part 1 By: andreas This is the fist part in a series of 2 articles on how to hook into the NDIS and TDI layer. In this first one, we will discuss where and how to hook i

白日梦 2415

simulink求解器选择的小tip

给出了simulink选择求解器的一种tip,与积分初值有关。

高能阿博特的博客 2055

单细胞数据导入实战:Read10X函数常见报错与解决方案

本文针对单细胞转录组分析中Read10X函数数据导入的常见问题,提供了详细的实战解决方案。重点解析了因文件路径错误、压缩文件未解压、版本命名不符及内存不足导致的报错,并给出了检查路径、正确解压、重命名文件、调整参数及优化内存等具体操作步骤,帮助用户高效完成单细胞数据导入,为后续分析奠定坚实基础。

weixin_28235513的博客 238

list

的底层是双向链表结构,双向链表中每个元素存储在互不相关的独立节点中,在节点中通过指针指向其前一个元素和后一个元素。,因此反向迭代器的实现可以借助正向迭代器,即:反向迭代器内部可以包含一个正向迭代器,对正向迭代器的接口进行包装即可。是可以在常数范围内在任意位置进行插入和删除的序列式容器,并且该容器可以前后双向迭代。迭代到该位置,在这段位置上迭代需要线性的时间开销;最大的缺陷是不支持任意位置的随机访问,比如:要访问。还需要一些额外的空间,以保存每个节点的相关联信息。个元素,必须从已知的位置。

xie0510_的博客 274

从NASA DataPort下载到PyTorch Dataset:手把手处理USGS光谱库的AVIRIS数据

本文详细介绍了如何从NASA DataPort下载USGS光谱库的AVIRIS高光谱数据,并将其转化为PyTorch Dataset对象。内容涵盖数据获取、预处理、辐射定标及高效数据加载技巧,特别针对AVIRIS数据的水吸收波段剔除和波段分组标准化进行了重点讲解,为环境监测、地质勘探等领域的研究者提供实用指南。

weixin_30607659的博客 283

Redis 数据类型详解:Hash 哈希与 List 列表

大 key 指单个 key 对应的 value 过大(如 Hash 字段数极多、List 元素极多)。危害包括:单次全量命令(

2303_77004089的博客 101

角谱迭代与傅里叶变换迭代算法(GS)的原理及其实例演示分析

角谱迭代与傅里叶变换迭代算法(GS)的原理及其实例演示分析 目前,迭代法和强度传输方程(TIE)法是两类典型的非干涉相位检索技术(Phase Retrieval,被称为相位恢复、相位检索、相位反演法、相位复原等)。迭代法中的经典算法是Gerchberg-Saxton(GS),随后,出现了包括错误减少算法(ER)、混合输入输出法(HIO)、梯度搜索算法、角谱迭代算法等改进算法。...

简单光学 2万+

FPGA新手避坑指南:手把手教你搞定RTL8211千兆网PHY的时序配置(附Verilog代码)

本文详细解析了FPGA与RTL8211千兆网PHY芯片的时序配置问题,重点介绍了TXDLY/RXDLY引脚设置、FPGA发送端和接收端的Verilog实现,以及调试与验证的完整流程。通过硬件电路设计和代码示例,帮助开发者解决网络连接不稳定、丢包等常见问题,提升千兆网通信的稳定性。

weixin_28732953的博客 542

【C++】【STL】list

list 是带头结点的双向循环链表,通过哨兵位消除首尾边界判断,实现任意位置插入删除的常数时间复杂度。其节点独立分配,不支持随机访问,迭代器仅支持前后移动。与 vector 对比,list 在中间插入/删除时更高效,但遍历缓存命中率低;vector 适合随机访问和连续遍历,但头部操作代价高。二者在内存布局、访问效率与适用场景上形成互补。

这里是Cocatrice的博客,感谢大家一直以来的支持和鼓励,如果对C/C++方向感兴趣的话,可以通过主页的微信名片加Cocatrice的好友,也可以通过邮箱:Chen31980094@163.com 联系,一同加油! 633

在 ABAP Push Channel 里玩转 Detached Client:用 Attach Handle 把 WebSocket 连接交接给业务逻辑

摘要:本文介绍了ABAP Push Channels (APC)中的Detached Client技术,该技术通过将WebSocket连接建立与后续处理分离,实现更高效的实时通信。核心流程包括创建连接、使用connect_and_detach交接连接、以及通过attach handle重新附着发送消息。文章还探讨了PCP协议和AMC技术在企业级推送场景中的应用,并通过示例代码展示了Detached Client的具体实现方式。这种设计解决了传统轮询的资源浪费问题,特别适用于生产线监控、客服系统等需要服务端主

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 2316

Java 集合框架(List、Set、Map)与常用基础

本文整理Java集合框架核心知识,涵盖集合体系、Collection接口API、List(ArrayList、LinkedList、Vector)、Set(HashSet、TreeSet)、Map(HashMap、TreeMap、Hashtable)实现类原理、泛型、增强for循环、可变参数与工具类,并附核心易错点速查表。

既然你都点开这里了,那可以给我点个关注吗?可以吗?可以吗? 487

Unity 热更新技术 | (二) AssetBundle - 完整系列教程学习

开始学习热更新方面系列知识,就从这一篇开始吧! 本系列教程 会从热更新基本概念出发,详细介绍热更新相关的全套知识点。 如热更新技术基本原理、热更新主流方案、AssetBundle系列教程、Lua语言编程、Lua与Unity交互教程、Xlua框架使用、热更新实战教程等方面。 热更新作为一个开发者必备技能,如果想学习的话,可以从现在开始了哦~ 接下来从 AssetBundle - 完整系列教程学习 开始学习吧!

努力前行,总会成为自己心中的那道光 1万+

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

Bugku 326 Baby-heap1 题解:glibc 2.23 堆溢出到 FSOP 劫持 _IO_list_all(附完整 exp)

为什么 FSOP 在 2.23 这么好用?glibc 2.23 的_IO_FILE虚表调用没有 vtable 合法性检查是 2.24 才加入的),只要能把指向自己伪造的 FILE,就能让__overflow槽位指向任意函数。exit()一定会走因此把_mode置 0、置 1、置 0,就能进入;把fp首地址写成/bin/shsystem(fp)的参数就齐了。为什么用 fastbin attack 而不是?2.23 没有 tcache,fastbin 的fd。

kingx3的博客 205

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

List(下):LPOP / RPOP、BLPOP / BRPOP 与 LINDEX、LINSERT

这是《Redis C++ 实战笔记》系列的第 07 篇。上一篇是往列表里放,这一篇是往外拿——包括那个会"等"的弹出。

wbs_scy的博客 104

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

[C++]:7.STL:list

好久不见,firdawn小课堂又和大家见面啦。今天我们要学习的内容是list容器,list也是一种常用的数据结构。下面是本章的思维导图,那么让我们开始学习吧!自定义的list,由三个结构构成。分别是链表的最小组成单位,也就是链表节点。以及迭代器类和list类其实要特别说明的是, List的迭代器,它不是单纯的指针,因为我们如果对指针直接进行解引用操作的话,我们得到的是这个节点,而不是节点里面存储的值并且我们对这个指针加加,得到的也不是下一个节点的地址,而是所在节点的下一个单位的地址。

2301_80817679的博客 190

一个链表(Linked List)--为什么要用链表--deepseek

数组(如你定义的大盘子就像你在 FPGA 里例化了一块深度为 2500 的 BRAM。它必须是一块连续的、完整的内存。如果内存里全是碎片,凑不出 2500 个连续空位,数组就建立不起来。链表(Linked List)就像一堆散落在大街小巷的小仓库,每个仓库大小不固定,彼此不挨着。但是,每个仓库的门口都贴了一张小纸条,纸条上写着“下一个仓库的地址”。我们来画个图,这就是链表的核心——节点(Node)text。

AlibabaApple的博客 170

FreeRTos笔记(12c):从事件链表里删除节点 xTaskRemoveFromEventList、

(1) (2) 谢谢

zhangzhangkeji的博客 163

【C++初阶】list使用及相关实现,思路顺滑流畅!

list使用及相关实现

Severus_black的博客 207

List(上):LPUSH / RPUSH 与 LRANGE

这是《Redis C++ 实战笔记》系列的第 06 篇。String 讲完了,进入第二种类型:List。它是一串有顺序、可以重复的值,两头都能进出。

wbs_scy的博客 241

细粒度锁的线程安全list实现

【代码】细粒度锁的线程安全list实现。

weixin_43698578的博客 196

TypeError: must be str, not list

【代码】TypeError: must be str, not list。

Forerunner and Successor 先駆者と後継者 49

Java Arrays.asList 常见坑详解|UnsupportedOperationException、数组联动、基本类型 bug

解析 Arrays.asList 常见开发陷阱,演示 UnsupportedOperationException、底层数组引用共享、基本类型数组问题,区分 Arrays 内部 ArrayList 与 java.util.ArrayList,给出数组转 List 的各种场景正确代码。

weixin_42617033的博客 473
上一篇: 全国百强县排名完全名单——你老家上榜了吗?
下一篇: NDIS_PROTOCOL_BLOCK的定义
iiprogram
博客等级 码龄25年 1068粉丝 1515原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值