Hooking into NDIS and TDI, part 1

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

基于拟蒙特卡洛模拟法的随机潮流计算matlab程序

由式(4-11)可知,蒙特卡洛模拟法的计算量不受电力系统规模大小影响,因此该方法在一些复杂的电力系统中可以得到应用,包括处理电力系统中有多个间歇性新能源接入的问题,解决系统中多个节点之间相关性问题等等。本章在此基础上提出了基于拟蒙特卡洛模拟的随机潮流计算方法,并且对拟蒙特卡洛法中的拟随机数序列进行了改进,大大提高了随机潮流的计算效率。模拟法的具体思路如下:基于实际工程问题的求解需要,建立与之相对应的随机模拟过程和随机概率模型,使得它们的参数,包括概率分布或者数学期望,能够等于问题的实际解;

weixin_47365903的博客 1795

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 in to the NDIS layer. In the second

1797

Zipformer在RK3588上的性能实测:比Conformer快多少?内存省多少?

本文在RK3588平台上对Zipformer和Conformer语音识别模型进行了全面的性能实测。结果显示,Zipformer在模型部署中展现出显著优势:推理速度比Conformer快约56%,峰值内存占用降低约60%,同时在AISHELL-1等测试集上保持了相当的识别准确率。这为边缘ASR应用提供了更高效、更节省资源的解决方案。

metal的博客 482

VS Code配置MASM32汇编环境:从安装到调试的完整指南

本文提供了一份详尽的指南,教你如何在VS Code中配置MASM32汇编开发环境,实现从安装、环境变量设置到编写、编译和调试32位Windows汇编窗口程序的完整工作流。通过集成现代编辑器的便利性与经典汇编工具链,旨在降低学习门槛,提升底层开发效率。

nn3456的博客 486

list

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

xie0510_的博客 274

STM32 使用IO口模拟I2C时序

上一篇《I2C协议详解》 我们了解了I2C的操作流程,这一篇,我们就使用I2C,来对EEPROM进行操作吧。 我们做两种选择: 1.时序由IO口模拟高低电平,需要了解协议并按照协议操作相应的IO口。 2.时序由硬件自行产生,不需要人工干预; 由硬件产生的I2C时序,我们借助Stm32Cube配置实现便可,我们这一篇,抛开Stm32Cube,手撕代码,根据I2C的时序,一步步地实现I2C对...

8937

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

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

2303_77004089的博客 105

论文学习:Towards Automated Infographic Design:Deep Learning-based Auto-generation of Extensible Timeline

title: “Towards Automated Infographic Design:Deep Learning-based Auto-generation of Extensible Timeline” tags: [“论文评述”, “报告”] date: 2019-08-22 author: 叶慧 mathjax: true 论文:Towards Automated Infograph...

xiaoyehahaha的博客 731

基于ENVI完成影像的去云操作以及后续处理

利用ENVI完成重采样影像的去云操作 由于SNAP重采样之后的影像是分波段保存的,ENVI的波段运算工具一次也只能输出一个波段,所以去云的操作分波段进行,原理是掩膜法 下面是打开所有波段后的界面 去云的依据是以quality_scene_classification栅格文件为基础,该文件是哨兵2数据自带的场景质量分类图,包含12个级别,可以通过SNAP软件查看,如下图所示: 对于去云操作而言,我们只需要DARK_FEATURE_SHADOW(地形等),CLOUD_SHADOW(云阴影)、CL

lemon_tttea的博客 2万+

【C++】【STL】list

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

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

LangGraph 中 Human-in-the-loop

摘要:本文探讨了在自主AI Agent系统中实现"人工介入关键节点"(HIL)的技术方案,主要基于LangGraph框架构建。针对Agent可能执行高风险操作(如删除数据库)的问题,提出通过断点机制在关键节点暂停流程,实现人工审批后再继续执行。具体实现包括:(1)使用checkpointer组件持久化状态;(2)通过interrupt_before/after参数设置断点;(3)支持三种交互模式:批准、编辑和输入。文章还提供了代码示例,展示如何在不同场景(如工具调用)中动态触发人工审核机

qq_52053775的博客 153

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

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

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

SAP GUI 经典事务在 Fiori Launchpad 中的穿越之道:原理、配置与实践指南

在许多企业的 S/4HANA 或 ECC 系统里,经典 SAP GUI 事务依旧承载着关键业务。如何把这些老将自然地嵌入到 Fiori Launchpad,让用户在统一入口里无缝切换新旧 UI,是项目中经常遇到的主题。本文结合社区博文、官方文档与实际项目经验,系统梳理这一过程的技术原理、配置步骤、性能优化以及常见坑点,并给出贴近中国读者的案例解析与改进建议。阅读完毕,你将不仅知道怎么做,还会理解。

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

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

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的博客 211

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

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

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

wbs_scy的博客 105

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

[C++]:7.STL:list

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

2301_80817679的博客 193

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

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

AlibabaApple的博客 171

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

(1) (2) 谢谢

zhangzhangkeji的博客 163

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

list使用及相关实现

Severus_black的博客 208

List(上):LPUSH / RPUSH 与 LRANGE

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

wbs_scy的博客 243

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

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

weixin_43698578的博客 198

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的博客 475
上一篇: 新年音乐会
下一篇: NDIS and TDI Hooking, Part II
CDrea
博客等级 码龄23年 1粉丝 11原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值