NDIS and TDI Hooking, Part II

SiLan_EAP_AOI_Test_Case.xlsx 立即下载
By: andreas

This is the second and last article on how to hook into the NDIS and TDI
layer. The approach we will use will be slightly different from the NDIS
case. However, a neat side effect is that this method can be used to hook
into any device chain, for example the keyboard to sniff key strokes. It all boils down to getting a pointer to the device object and replace all major functions with our own dispatch function.

To be able to fully control the TDI layer, we need access to the IRP both
before and after the original driver has processed it. If we have that, we
can choose what the original driver should process and we can also alter
results before they are returned to user-space. The "before filtering" can
be accomplished in our own, new dispatch function and the "after filtering" can be accomplished in a completion routine.

First, to be able to overwrite and insert our own dispatch function, we need a pointer to the driver object we are going to hook into. An easy way to get this pointer is to call ObReferenceObjectByName with the appropriate driver name. Then we only have to save all old function pointers and overwrite the existing ones with our own. The code to do this would look something like the following:


DRIVER_OBJECT RealTDIDriverObject;

NTSTATUS HookTDI(void)
{
    NTSTATUS Status;
    UNICODE_STRING usDriverName;
    PDRIVER_OBJECT DriverObjectToHookPtr;
    UINT i;



    RtlInitUnicodeString(&usDriverName,L"//Driver//Tcpip");

    Status =
ObReferenceObjectByName(&usDriverName,OBJ_CASE_INSENSITIVE,NULL,0,IoDriverObjectType,KernelMode,NULL,&DriverObjectToHookPtr);
    if(Status != STATUS_SUCCESS) return Status;

    for(i = 0;i < IRP_MJ_MAXIMUM_FUNCTION;i++) {
        RealTDIDriverObject.MajorFunction[i] =
DriverObjectToHookPtr->MajorFunction[i];
        DriverObjectToHookPtr->MajorFunction[i] = TDIDeviceDispatch;
    }

    return STATUS_SUCCESS;
}




RealTDIDriverObject is a DRIVER_OBJECT where we save the original
information to both be able to call the old functions and also be able to
unhook once we are done. The orignal driver gets all its major functions
overwritten with a pointer to our own dispatch function, TDIDeviceDispatch.

We now have control over the IRPs before TDI can process them. But, we still have to make sure we can also control them once TDI is done with it but before it is returned to the IO handler and user-space. We will solve this in our dispatch function with the help of a completion routine. It is not as straight forward as it sounds, since we might be hooking the last entity in the chain, we can't just insert a completion routine with
IoSetCompletionRoutine (see the DDK docs), since it in that case never will be called. Completion routines are set in the next IRP stack location, not the current. If we are the last entity, there will be no next stack location in the IRP. Searching through the header files reveal IoSetCompletionRoutine as a macro which only gets the next IRP stack location and sets the CompletionRoutine pointer together with the Control element. Following the same principcal, we can set our own completion routine to regain control over the IRP with the following dispach function:


NTSTATUS TDIDeviceDispatch(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp)
{
    NTSTATUS Status;
    PIO_STACK_LOCATION StackLocationPtr;

    if(Irp == NULL) return STATUS_SUCCESS;

    StackLocationPtr = IoGetCurrentIrpStackLocation(Irp);
    if(StackLocationPtr->CompletionRoutine != NULL) StackLocationPtr->Context =
StackLocationPtr->CompletionRoutine;
    else StackLocationPtr->Context = NULL;
    StackLocationPtr->CompletionRoutine =
(PIO_COMPLETION_ROUTINE)TDICompletionRoutine;
    StackLocationPtr->Control = SL_INVOKE_ON_SUCCESS | SL_INVOKE_ON_ERROR |
SL_INVOKE_ON_CANCEL;

    Status =
RealTDIDriverObject.MajorFunction[StackLocationPtr->MajorFunction](DeviceObject,Irp);

    return Status;
}


What we actually do is faking a scenario where the layer above set the
completion routine for us. We also save a potentially already existing
completion routine in the Context element of the IRP. Control is set to
invoke the completion routine in all cases. There are 2 potential issues
with this code. First, we overwrite whatever is in the Context element.
Second, we never save the Control element, so we don't know when to invoke
an already existing completion routine. So far, I have not seen any
side-effects from doing this.

The completion routine would look something like:


NTSTATUS TDICompletionRoutine(PDEVICE_OBJECT DeviceObject,PIRP Irp,PVOID
Context)
{
    COMPLETIONROUTINE RealCompletionRoutine = (COMPLETIONROUTINE)Context;

    if(Context != NULL) return RealCompletionRoutine(DeviceObject,Irp,NULL);
    else return STATUS_SUCCESS;
}


It invokes a potential completion routine as soon as it is done and returns the status from it. Finally, unhooking the driver is just a question of restoring the pointers we overwrote in the hooking function:


NTSTATUS ReleaseTDIDevices(void)
{
    NTSTATUS Status;
    UNICODE_STRING usDriverName;
    PDRIVER_OBJECT DriverObjectToHookPtr;
    UINT i;

    RtlInitUnicodeString(&usDriverName,L"//Driver//Tcpip");

    Status =
ObReferenceObjectByName(&usDriverName,OBJ_CASE_INSENSITIVE,NULL,0,IoDriverObjectType,KernelMode,NULL,&DriverObjectToHookPtr);
    if(Status != STATUS_SUCCESS) return Status;

    for(i = 0;i < IRP_MJ_MAXIMUM_FUNCTION;i++)
        DriverObjectToHookPtr->MajorFunction[i] =
RealTDIDriverObject.MajorFunction[i];

    return STATUS_SUCCESS;
}



There is another way to accomplish the same result which utilizes a more
offically supported mode of operation. It is based upon attaching to the
device chain with GetDeviceObject and AttachToDevice, which will allow us to process all IRPs before the real device. Once in the dispatch function we contruct a new IRP and add a completion routine to regain control of the IRP before it is returned to the IO system and user-space.

One last important thing to mention; This code is quite untested. It seems
to work as intended but it has never been used in any major applications, so use it on your own risk. With that said, hope you have enjoyed this little article series.

This is the second and last article on how to hook into the NDIS and TDI
layer. The approach we will use will be slightly different from the NDIS
case. However, a neat side effect is that this method can be used to hook
into any device chain, for example the keyboard to sniff key strokes. It all boils down to getting a pointer to the device object and replace all major functions with our own dispatch function.

To be able to fully control the TDI layer, we need access to the IRP both
before and after the original driver has processed it. If we have that, we
can choose what the original driver should process and we can also alter
results before they are returned to user-space. The "before filtering" can
be accomplished in our own, new dispatch function and the "after filtering" can be accomplished in a completion routine.

First, to be able to overwrite and insert our own dispatch function, we need a pointer to the driver object we are going to hook into. An easy way to get this pointer is to call ObReferenceObjectByName with the appropriate driver name. Then we only have to save all old function pointers and overwrite the existing ones with our own. The code to do this would look something like the following:


DRIVER_OBJECT RealTDIDriverObject;

NTSTATUS HookTDI(void)
{
    NTSTATUS Status;
    UNICODE_STRING usDriverName;
    PDRIVER_OBJECT DriverObjectToHookPtr;
    UINT i;



    RtlInitUnicodeString(&usDriverName,L"//Driver//Tcpip");

    Status =
ObReferenceObjectByName(&usDriverName,OBJ_CASE_INSENSITIVE,NULL,0,IoDriverObjectType,KernelMode,NULL,&DriverObjectToHookPtr);
    if(Status != STATUS_SUCCESS) return Status;

    for(i = 0;i < IRP_MJ_MAXIMUM_FUNCTION;i++) {
        RealTDIDriverObject.MajorFunction[i] =
DriverObjectToHookPtr->MajorFunction[i];
        DriverObjectToHookPtr->MajorFunction[i] = TDIDeviceDispatch;
    }

    return STATUS_SUCCESS;
}




RealTDIDriverObject is a DRIVER_OBJECT where we save the original
information to both be able to call the old functions and also be able to
unhook once we are done. The orignal driver gets all its major functions
overwritten with a pointer to our own dispatch function, TDIDeviceDispatch.

We now have control over the IRPs before TDI can process them. But, we still have to make sure we can also control them once TDI is done with it but before it is returned to the IO handler and user-space. We will solve this in our dispatch function with the help of a completion routine. It is not as straight forward as it sounds, since we might be hooking the last entity in the chain, we can't just insert a completion routine with
IoSetCompletionRoutine (see the DDK docs), since it in that case never will be called. Completion routines are set in the next IRP stack location, not the current. If we are the last entity, there will be no next stack location in the IRP. Searching through the header files reveal IoSetCompletionRoutine as a macro which only gets the next IRP stack location and sets the CompletionRoutine pointer together with the Control element. Following the same principcal, we can set our own completion routine to regain control over the IRP with the following dispach function:


NTSTATUS TDIDeviceDispatch(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp)
{
    NTSTATUS Status;
    PIO_STACK_LOCATION StackLocationPtr;

    if(Irp == NULL) return STATUS_SUCCESS;

    StackLocationPtr = IoGetCurrentIrpStackLocation(Irp);
    if(StackLocationPtr->CompletionRoutine != NULL) StackLocationPtr->Context =
StackLocationPtr->CompletionRoutine;
    else StackLocationPtr->Context = NULL;
    StackLocationPtr->CompletionRoutine =
(PIO_COMPLETION_ROUTINE)TDICompletionRoutine;
    StackLocationPtr->Control = SL_INVOKE_ON_SUCCESS | SL_INVOKE_ON_ERROR |
SL_INVOKE_ON_CANCEL;

    Status =
RealTDIDriverObject.MajorFunction[StackLocationPtr->MajorFunction](DeviceObject,Irp);

    return Status;
}


What we actually do is faking a scenario where the layer above set the
completion routine for us. We also save a potentially already existing
completion routine in the Context element of the IRP. Control is set to
invoke the completion routine in all cases. There are 2 potential issues
with this code. First, we overwrite whatever is in the Context element.
Second, we never save the Control element, so we don't know when to invoke
an already existing completion routine. So far, I have not seen any
side-effects from doing this.

The completion routine would look something like:


NTSTATUS TDICompletionRoutine(PDEVICE_OBJECT DeviceObject,PIRP Irp,PVOID
Context)
{
    COMPLETIONROUTINE RealCompletionRoutine = (COMPLETIONROUTINE)Context;

    if(Context != NULL) return RealCompletionRoutine(DeviceObject,Irp,NULL);
    else return STATUS_SUCCESS;
}


It invokes a potential completion routine as soon as it is done and returns the status from it. Finally, unhooking the driver is just a question of restoring the pointers we overwrote in the hooking function:


NTSTATUS ReleaseTDIDevices(void)
{
    NTSTATUS Status;
    UNICODE_STRING usDriverName;
    PDRIVER_OBJECT DriverObjectToHookPtr;
    UINT i;

    RtlInitUnicodeString(&usDriverName,L"//Driver//Tcpip");

    Status =
ObReferenceObjectByName(&usDriverName,OBJ_CASE_INSENSITIVE,NULL,0,IoDriverObjectType,KernelMode,NULL,&DriverObjectToHookPtr);
    if(Status != STATUS_SUCCESS) return Status;

    for(i = 0;i < IRP_MJ_MAXIMUM_FUNCTION;i++)
        DriverObjectToHookPtr->MajorFunction[i] =
RealTDIDriverObject.MajorFunction[i];

    return STATUS_SUCCESS;
}



There is another way to accomplish the same result which utilizes a more
offically supported mode of operation. It is based upon attaching to the
device chain with GetDeviceObject and AttachToDevice, which will allow us to process all IRPs before the real device. Once in the dispatch function we contruct a new IRP and add a completion routine to regain control of the IRP before it is returned to the IO system and user-space.

One last important thing to mention; This code is quite untested. It seems
to work as intended but it has never been used in any major applications, so use it on your own risk. With that said, hope you have enjoyed this little article series.
SpringBoot和VueDevOps 发布审批与回滚管理系统源码 包含前后端源码、SQL初始化脚本和启动说明。JDK 17、Spring Boot、Vue;默认H2演示数据库。 立即下载

相关推荐

制造业重点关注的17个Agent智能体落地场景方案.pptx

制造业重点关注的17个Agent智能体落地场景方案.pptx

BASIC TDI DEVICE DRIVER

////////////////////////////////////////////////////////////////////////// BASIC TDI DEVICE DRIVER, version 2// // (c)2004 Rootkit.com//// June 25, 2004 - Initial cut, Greg Hoglund// June 26, 2004 - A

errorlife的专栏 1724

STM32 FreeRTOS 多任务实战手册:优先级反转、任务栈与 FromISR 坑位

任务莫名其妙卡死、优先级翻转、栈溢出查不到现场——RTOS 的问题几乎都不在 API 调用,而在调度时序和临界区边界。 【10 个专题,每个含复现步骤 / 测量数据 / 判据 / 落地代码】 1. STM32 NVIC中断优先级详解 2. STM32 FreeRTOS 软件定时器实测 3. STM32 FreeRTOS 消息队列 ISR 收发实测 4. STM32 FreeRTOS 优先级反转实测 5. STM32 FreeRTOS StreamBuffer 流缓冲区串口DMA不 6. STM32 FreeRTOS 事件组实测 7. STM32 FreeRTOS 任务栈溢出排查实测 8. STM32 FreeRTOS 堆内存管理实测 9. STM32 FreeRTOS CPU占用率统计实测 10. STM32 移植LwIP+FreeRTOS双任务协同 【这份教程解决什么】 · 每类问题都从「现象 → 可疑层 → 实测判据 → 根因 → 修复动作」走一遍,不停留在寄存器配置说明。 · 代码块与实测表格按专题编号,可直接对照自己的工程定位;目录按专题编号,方便对照查阅。 【适合谁】正在把裸机工程迁到 RTOS、或已经被优先级反转/栈溢出/中断里调 API 坑过的嵌入式工程师。 【形态】PDF 教程,10 个专题 + 速查目录,含代码块与实测数据表。

多目标粒子群算法求解综合能源系统最优容量配置研究(Matlab代码实现)

内容概要:本文研究了多目标粒子群算法在综合能源系统最优容量配置中的应用,通过Matlab代码实现求解多目标优化问题。文中系统构建了涵盖经济性、环保性和能源利用效率的多目标优化框架,详细阐述了综合能源系统中各类设备的数学模型,并采用改进的多目标粒子群算法进行高效求解,最终获得Pareto最优解集,为综合能源系统的科学规划与可持续发展提供了坚实的理论支撑与实用的技术路径。; 适合人群:具备一定电力系统、优化算法及Matlab编程基础的研究生、科研人员及相关工程技术人员。; 使用场景及目标:①掌握多目标优化问题在综合能源系统容量配置中的建模方法;②学习多目标粒子群算法的实现过程及其在能源系统规划中的具体应用;③通过Matlab代码实践提升算法编程与仿真分析能力。; 阅读建议:建议读者结合Matlab代码逐段理解算法实现细节,重点关注目标函数构建、约束条件处理及Pareto解集的生成过程,同时可尝试调整算法参数以观察优化结果的变化,深化对算法性能的理解。

科技中介服务机构如何构建智能化服务平台以提升服务效率与专业度?.docx

科技中介服务机构如何构建智能化服务平台以提升服务效率与专业度?

政府科技管理者如何高效完成科技成果评价与价值挖掘?.docx

政府科技管理者如何高效完成科技成果评价与价值挖掘?

科技中介服务机构如何借助智能工具提升服务的专业性与便捷性?.docx

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

政府科技管理者在推动科技成果转化时,如何高效识别具有高转化潜力的科技成果?.docx

政府科技管理者在推动科技成果转化时,如何高效识别具有高转化潜力的科技成果?

港股十档行情tick数据,包含逐笔成交与买卖委托快照 逐笔记录含成交时间、价格、成交量、成交方向及委托单类型 十档委托快照提供买卖各十个价位的挂单价格与挂单数量,可观察盘口深度变化 分钟数据以一分钟为

港股十档行情tick数据,包含逐笔成交与买卖委托快照。逐笔记录含成交时间、价格、成交量、成交方向及委托单类型。十档委托快照提供买卖各十个价位的挂单价格与挂单数量,可观察盘口深度变化。分钟数据以一分钟为单位,包含开盘价、最高价、最低价、收盘价、成交量及成交额。历史行情覆盖近十五年,提供完整日线csv表格,字段包含日期、开盘价、最高价、最低价、收盘价、成交量、成交额,部分还包含调整因子或前收盘价。所有数据均为非实时历史数据。 数据源:CMES金融数据库

政府科技管理者在推动科技成果落地过程中,如何高效识别和筛选具备高转化价值的科技成果?.docx

政府科技管理者在推动科技成果落地过程中,如何高效识别和筛选具备高转化价值的科技成果?

【人工智能工程】完结JEV 决策大模型实战,让 AI 从会聊天到能决策

内容概要:本文介绍了JEV决策大模型的核心理念与工程实践,强调将其作为“快判断”层从通用大模型中剥离使用。JEV不生成文本,而是针对明确的状态和问题,输出结构化、带概率的决策结果,适用于高频、原子化的判断任务。文章详细阐述了JEV的工作机制、与通用大模型的本质区别、典型应用场景(如Agent工具路由)、questions的设计方法、能力边界以及兜底机制的重要性,并指出其在成本、延迟和输出确定性方面的优势。; 适合人群:具备一定AI工程实践经验的研发人员、系统架构师,尤其是正在构建Agent、自动化决策系统或优化大模型调用链的技术团队;; 使用场景及目标:①优化高频、轻量级判断任务(如工单分类、内容初筛、RAG相关性判定)的效率与成本;②实现主模型与决策模块的职责分离,提升系统整体稳定性与可维护性;③学习如何设计高质量的判断问题与概率校准机制; 阅读建议:此资源聚焦于决策模型的工程化落地,建议结合实际业务中的判断流程进行POC验证,重点关注questions设计、阈值校准与兜底策略的构建,避免盲目神化JEV的能力。

产业园区如何精准识别和匹配优质科技成果资源?.docx

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

塔式熔盐光热朗肯循环电站建模及Simulink仿真研究

内容概要:本文围绕塔式熔盐光热朗肯循环电站的建模与Simulink仿真展开系统性研究,重点构建了太阳能集热场、熔盐储热系统及朗肯循环发电单元的数学模型,并基于Simulink平台搭建了完整的集成化仿真系统。研究深入分析了系统的能量转换机制、热力循环特性与动态响应行为,通过设置不同太阳辐照强度、负载变化等工况进行仿真,验证了系统在变工况条件下的运行稳定性与调节能力。同时,系统探讨了熔盐流量、储热容量、换热器效率等关键参数对电站整体热效率与输出功率的影响规律,提出了优化运行策略与参数匹配方案,旨在提升光热电站的能量利用率、运行灵活性与供电可靠性。; 适合人群:具备一定电力系统、热力学或新能源工程背景,从事光热发电、综合能源系统建模与仿真的研究生、科研人员及工程技术人员。; 使用场景及目标:①用于塔式光热电站的教学演示与原理讲解,帮助学生理解光-热-电转换全过程;②为光热系统的设计优化、动态性能评估、控制策略开发(如温度控制、功率调节)提供高保真仿真平台与数据支撑;③支持新型储热调度策略与系统集成方案的验证与测试。; 阅读建议:建议读者结合提供的Simulink模型文件同步操作,深入理解各子系统模块(如集热场、储罐、蒸汽发生器、汽轮机等)的建模逻辑与参数设置方法,重点关注能量流、质量流与控制信号的耦合机制,可进一步在此基础上开发先进控制算法或进行多能互补系统集成研究。

A股分钟数据涵盖股票、ETF、可转债及指数四大类 每条数据记录包含精确到分钟的时间戳,以及开盘价、最高价、最低价、收盘价、成交量、成交额六个核心字段 部分数据还提供前收盘价作为参考 股票与ETF数据细

A股分钟数据涵盖股票、ETF、可转债及指数四大类。每条数据记录包含精确到分钟的时间戳,以及开盘价、最高价、最低价、收盘价、成交量、成交额六个核心字段。部分数据还提供前收盘价作为参考。股票与ETF数据细分至1分钟、5分钟等周期,可转债在交易时段内逐笔生成分钟快照,指数数据则同步覆盖上证、深证等主要宽基指数,便于观察市场整体走势。 数据源:CMES金融数据库

企业IT运维实录:批量部署银河麒麟V10-SP1,Ghost镜像与UKey激活实战

本文详细介绍了企业级银河麒麟V10-SP1操作系统的批量部署全流程,包括标准化镜像制作、自动化封装技术、网络化部署方案及UKey集群激活方案。通过实战案例和技术要点解析,帮助企业IT运维团队大幅提升部署效率,确保系统安全与稳定性。

weixin_30729609的博客 388

光学设计必看:如何用泽尼克系数优化镜头像差?从Zemax到实际案例解析

本文深入解析了如何利用泽尼克系数优化镜头像差,从理解其工程价值、解码软件报告,到在Zemax中主动设置优化目标。通过高倍显微物镜等实际案例,详细展示了如何通过分析泽尼克系数诊断问题,并实施针对性优化策略,从而实现对球差、彗差等像差的精准控制,提升光学设计的精细度和系统稳健性。

gg901的博客 1035
上一篇: Hook Dispatch 实时监控
下一篇: tdi code
iiprogram
博客等级 码龄25年 1068粉丝 1515原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值