在上一篇文章《驱动开发:内核封装WSK网络通信接口》
中,LyShark
已经带大家看过了如何通过WSK接口实现套接字通信,但WSK实现的通信是内核与内核模块之间的,而如果需要内核与应用层之间通信则使用TDK会更好一些因为它更接近应用层,本章将使用TDK实现,TDI全称传输驱动接口,其主要负责连接Socket
和协议驱动,用于实现访问传输层的功能,该接口比NDIS
更接近于应用层,在早期Win系统中常用于实现过滤防火墙,同样经过封装后也可实现通信功能,本章将运用TDI接口实现驱动与应用层之间传输字符串,结构体,多线程收发等技术。
- TDI传输字符串
- TDI多线程收发
- TDI传数结构实现认证
SDK库提取,将其命名为MyTDI.hpp
放入到代码同级目录下。
拷贝SDK代码
#include <ntifs.h>
#include <tdikrnl.h>
#include <ntstatus.h>
// TCP驱动设备名称
#define COMM_TCP_DEV_NAME L"\\Device\\Tcp"
// 地址转换的宏
#define INETADDR(a, b, c, d) (a + (b<<8) + (c<<16) + (d<<24))
#define HTONL(a) (((a & 0xFF)<<24) + ((a & 0xFF00)<<8) + ((a & 0xFF0000)>>8) + (a&0xFF000000)>>24)
#define HTONS(a) (((a & 0xFF)<<8) + ((a & 0xFF00)>>8))
// 完成回调函数
NTSTATUS TdiCompletionRoutine(PDEVICE_OBJECT pDevObj, PIRP pIrp, PVOID pContext)
{
if (NULL != pContext)
{
KeSetEvent((PKEVENT)pContext, IO_NO_INCREMENT, FALSE);
}
return STATUS_MORE_PROCESSING_REQUIRED;
}
// TDI初始化设置
NTSTATUS TdiOpen(PDEVICE_OBJECT *ppTdiAddressDevObj, PFILE_OBJECT *ppTdiEndPointFileObject, HANDLE *phTdiAddress, HANDLE *phTdiEndPoint)
{
NTSTATUS status = STATUS_UNSUCCESSFUL;
PFILE_FULL_EA_INFORMATION pAddressEaBuffer = NULL;
ULONG ulAddressEaBufferLength = 0;
PTA_IP_ADDRESS pTaIpAddr = NULL;
UNICODE_STRING ustrTDIDevName;
OBJECT_ATTRIBUTES ObjectAttributes = { 0 };
IO_STATUS_BLOCK iosb = { 0 };
HANDLE hTdiAddress = NULL;
PFILE_OBJECT pTdiAddressFileObject = NULL;
PDEVICE_OBJECT pTdiAddressDevObj = NULL;
PFILE_FULL_EA_INFORMATION pContextEaBuffer = NULL;
ULONG ulContextEaBufferLength = 0;
HANDLE hTdiEndPoint = NULL;
PFILE_OBJECT pTdiEndPointFileObject = NULL;
KEVENT irpCompleteEvent = { 0 };
PIRP pIrp = NULL;
do
{
// 为本地地址拓展属性结构申请内存及初始化
ulAddressEaBufferLength = sizeof(FILE_FULL_EA_INFORMATION) + TDI_TRANSPORT_ADDRESS_LENGTH + sizeof(TA_IP_ADDRESS);
pAddressEaBuffer = (PFILE_FULL_EA_INFORMATION)ExAllocatePool(NonPagedPool, ulAddressEaBufferLength);
if (NULL == pAddressEaBuffer)
{
break;
}
RtlZeroMemory(pAddressEaBuffer, ulAddressEaBufferLength);
RtlCopyMemory(pAddressEaBuffer->EaName, TdiTransportAddress, (1 + TDI_TRANSPORT_ADDRESS_LENGTH));
pAddressEaBuffer->EaNameLength = TDI_TRANSPORT_ADDRESS_LENGTH;
pAddressEaBuffer->EaValueLength = sizeof(TA_IP_ADDRESS);
// 初始化本机IP地址与端口
pTaIpAddr = (PTA_IP_ADDRESS)((PUCHAR)pAddressEaBuffer->EaName + pAddressEaBuffer->EaNameLength + 1);
pTaIpAddr->TAAddressCount = 1;
pTaIpAddr->Address[0].AddressLength = TDI_ADDRESS_LENGTH_IP;
pTaIpAddr->Address[0].AddressType = TDI_ADDRESS_TYPE_IP;
pTaIpAddr->Address[0].Address[0].sin_port = 0; // 0表示本机任意随机端口
pTaIpAddr->Address[0].Address[0].in_addr = 0; // 0表示本机本地IP地址
RtlZeroMemory(pTaIpAddr->Address[0].Address[0].sin_zero, sizeof(pTaIpAddr->Address[0].Address[0].sin_zero));
// 创建TDI驱动设备字符串与初始化设备对象
RtlInitUnicodeString(&ustrTDIDevName, COMM_TCP_DEV_NAME);
InitializeObjectAttributes(&ObjectAttributes, &ustrTDIDevName, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
// 根据本地地址拓展属性结构创建本地地址对象
status = ZwCreateFile(&hTdiAddress, GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
&ObjectA