驱动开发:内核封装TDI网络通信接口

简介: 在上一篇文章`《驱动开发:内核封装WSK网络通信接口》`中,`LyShark`已经带大家看过了如何通过WSK接口实现套接字通信,但WSK实现的通信是内核与内核模块之间的,而如果需要内核与应用层之间通信则使用TDK会更好一些因为它更接近应用层,本章将使用TDK实现,TDI全称传输驱动接口,其主要负责连接`Socket`和协议驱动,用于实现访问传输层的功能,该接口比`NDIS`更接近于应用层,在早期Win系统中常用于实现过滤防火墙,同样经过封装后也可实现通信功能,本章将运用TDI接口实现驱动与应用层之间传输字符串,结构体,多线程收发等技术。

在上一篇文章《驱动开发:内核封装WSK网络通信接口》中,LyShark已经带大家看过了如何通过WSK接口实现套接字通信,但WSK实现的通信是内核与内核模块之间的,而如果需要内核与应用层之间通信则使用TDK会更好一些因为它更接近应用层,本章将使用TDK实现,TDI全称传输驱动接口,其主要负责连接Socket和协议驱动,用于实现访问传输层的功能,该接口比NDIS更接近于应用层,在早期Win系统中常用于实现过滤防火墙,同样经过封装后也可实现通信功能,本章将运用TDI接口实现驱动与应用层之间传输字符串,结构体,多线程收发等技术。

  • TDI传输字符串
  • TDI多线程收发
  • TDI传数结构实现认证

TDI 传输字符串: 服务端在应用层侦听,客户端是驱动程序,驱动程序加载后自动连接应用层并发送消息。

首先来看应用层(服务端)代码,具体我就不说了,来看教程的都是有基础的。

// 署名权
// right to sign one's name on a piece of work
// PowerBy: LyShark
// Email: me@lyshark.com

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>  
#include <winsock2.h>  

#pragma comment(lib,"ws2_32.lib")
#define PORT 8888 

int main(int argc, char *argv[])
{
  printf("hello lyshark.com \n");
  WSADATA WSAData;
  SOCKET sock, msgsock;
  struct sockaddr_in ServerAddr;

  if (WSAStartup(MAKEWORD(2, 0), &WSAData) != SOCKET_ERROR)
  {
    ServerAddr.sin_family = AF_INET;
    ServerAddr.sin_port = htons(PORT);
    ServerAddr.sin_addr.s_addr = INADDR_ANY;

    sock = socket(AF_INET, SOCK_STREAM, 0);
    int BindRet = bind(sock, (LPSOCKADDR)&ServerAddr, sizeof(ServerAddr));
    int LinsRet = listen(sock, 10);
  }

  while (1)
  {
    char buf[1024] = { 0 };
    msgsock = accept(sock, (LPSOCKADDR)0, (int *)0);
    memset(buf, 0, sizeof(buf));

    recv(msgsock, buf, 1024, 0);
    printf("内核返回: %s \n", buf);

    char send_buffer[1024] = { 0 };
    memset(send_buffer, 0, 1024);
    strcpy(send_buffer, "Hi,R0 !");
    send(msgsock, send_buffer, strlen(send_buffer), 0);
    closesocket(msgsock);
  }
  closesocket(sock);
  WSACleanup();
  return 0;
}

再来是驱动层代码,如下所示;

// 署名权
// right to sign one's name on a piece of work
// PowerBy: LyShark
// Email: me@lyshark.com

#include "MyTDI.hpp"

// 发送接收数据
NTSTATUS SendOnRecv()
{
  NTSTATUS status = STATUS_SUCCESS;
  HANDLE hTdiAddress = NULL;
  HANDLE hTdiEndPoint = NULL;
  PDEVICE_OBJECT pTdiAddressDevObj = NULL;
  PFILE_OBJECT pTdiEndPointFileObject = NULL;
  LONG pServerIp[4] = { 127, 0, 0, 1 };
  LONG lServerPort = 8888;
  UCHAR szSendData[] = "hello lyshark";
  ULONG ulSendDataLength = 1 + strlen(szSendData);
  HANDLE hThread = NULL;

  // TDI初始化
  status = TdiOpen(&pTdiAddressDevObj, &pTdiEndPointFileObject, &hTdiAddress, &hTdiEndPoint);
  if (!NT_SUCCESS(status))
  {
    return STATUS_SUCCESS;
  }

  // TDI TCP连接服务器
  status = TdiConnection(pTdiAddressDevObj, pTdiEndPointFileObject, pServerIp, lServerPort);
  if (!NT_SUCCESS(status))
  {
    return STATUS_SUCCESS;
  }

  // TDI TCP发送信息
  status = TdiSend(pTdiAddressDevObj, pTdiEndPointFileObject, szSendData, ulSendDataLength);
  if (!NT_SUCCESS(status))
  {
    return STATUS_SUCCESS;
  }
  DbgPrint("发送: %s\n", szSendData);

  // 创建接收信息多线程, 循环接收信息

  char szRecvData[1024] = { 0 };
  ULONG ulRecvDataLenngth = 1024;
  RtlZeroMemory(szRecvData, ulRecvDataLenngth);

  // TDI TCP接收信息
  do
  {
    ulRecvDataLenngth = TdiRecv(pTdiAddressDevObj, pTdiEndPointFileObject, szRecvData, ulRecvDataLenngth);
    if (0 < ulRecvDataLenngth)
    {
      DbgPrint("接收数据: %s\n", szRecvData);
      break;;
    }

  } while (TRUE);

  // 释放
  TdiClose(pTdiEndPointFileObject, hTdiAddress, hTdiEndPoint);
  return STATUS_SUCCESS;
}

VOID UnDriver(PDRIVER_OBJECT driver)
{
  DbgPrint("驱动卸载成功 \n");
}

NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath)
{
  for (int x = 0; x < 10; x++)
  {
    SendOnRecv();
  }

  DbgPrint("驱动加载成功 \n");
  Driver->DriverUnload = UnDriver;
  return STATUS_SUCCESS;
}

首先运行应用层开启服务端侦听,然后运行驱动程序,会输出如下信息;

image.png

TDI 多线程收发包: 实现驱动内部发送数据包后开启一个线程用于等待应用层返回并输出结果,多线程收发在发送数据包后需要创建新的线程等待接收。

首先是服务端代码。

// 署名权
// right to sign one's name on a piece of work
// PowerBy: LyShark
// Email: me@lyshark.com

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>  
#include <winsock2.h>  

#pragma comment(lib,"ws2_32.lib")
#define PORT 8888 

int main(int argc, char *argv[])
{
    printf("hello lyshark.com \n");
    WSADATA WSAData;
    SOCKET sock, msgsock;
    struct sockaddr_in ServerAddr;

    if (WSAStartup(MAKEWORD(2, 0), &WSAData) != SOCKET_ERROR)
    {
        ServerAddr.sin_family = AF_INET;
        ServerAddr.sin_port = htons(PORT);
        ServerAddr.sin_addr.s_addr = INADDR_ANY;

        sock = socket(AF_INET, SOCK_STREAM, 0);
        int BindRet = bind(sock, (LPSOCKADDR)&ServerAddr, sizeof(ServerAddr));
        int LinsRet = listen(sock, 10);
    }

    while (1)
    {
        char buf[1024] = { 0 };
        msgsock = accept(sock, (LPSOCKADDR)0, (int *)0);
        memset(buf, 0, sizeof(buf));

        recv(msgsock, buf, 1024, 0);
        printf("内核返回: %s \n", buf);

        char send_buffer[1024] = { 0 };
        memset(send_buffer, 0, 1024);
        strcpy(send_buffer, "Hi,R0 !");
        send(msgsock, send_buffer, strlen(send_buffer), 0);
        closesocket(msgsock);
    }
    closesocket(sock);
    WSACleanup();
    return 0;
}

驱动程序代码如下,RecvThreadProc主要负责数据接收,SendThreadData负责数据发送。

// 署名权
// right to sign one's name on a piece of work
// PowerBy: LyShark
// Email: me@lyshark.com

#include "LySocket.hpp"

typedef struct _MY_DATA
{
    PDEVICE_OBJECT pTdiAddressDevObj;
    PFILE_OBJECT pTdiEndPointFileObject;
    HANDLE hTdiAddress;
    HANDLE hTdiEndPoint;
}MY_DATA, *PMY_DATA;

// 接收信息多线程
VOID RecvThreadProc(_In_ PVOID StartContext)
{
    PMY_DATA pMyData = (PMY_DATA)StartContext;
    NTSTATUS status = STATUS_SUCCESS;
    char szRecvData[1024] = { 0 };
    ULONG ulRecvDataLenngth = 1024;
    RtlZeroMemory(szRecvData, ulRecvDataLenngth);

    // TDI TCP接收信息
    do
    {
        ulRecvDataLenngth = TdiRecv(pMyData->pTdiAddressDevObj, pMyData->pTdiEndPointFileObject, szRecvData, ulRecvDataLenngth);
        if (0 < ulRecvDataLenngth)
        {
            DbgPrint("线程句柄:%x --> 接收数据包: %s\n", pMyData->hTdiEndPoint, szRecvData);
            break;;
        }

    } while (TRUE);

    // 释放
    TdiClose(pMyData->pTdiEndPointFileObject, pMyData->hTdiAddress, pMyData->hTdiEndPoint);
    ExFreePool(pMyData);
}

// 多线程发送
NTSTATUS SendThreadData()
{
    NTSTATUS status = STATUS_SUCCESS;
    HANDLE hTdiAddress = NULL;
    HANDLE hTdiEndPoint = NULL;
    PDEVICE_OBJECT pTdiAddressDevObj = NULL;
    PFILE_OBJECT pTdiEndPointFileObject = NULL;
    LONG pServerIp[4] = { 127, 0, 0, 1 };
    LONG lServerPort = 8888;
    UCHAR szSendData[] = "hello lyshark";
    ULONG ulSendDataLength = 1 + strlen(szSendData);
    HANDLE hThread = NULL;

    // TDI初始化
    status = TdiOpen(&pTdiAddressDevObj, &pTdiEndPointFileObject, &hTdiAddress, &hTdiEndPoint);
    if (!NT_SUCCESS(status))
    {
        return STATUS_SUCCESS;
    }

    // TDI TCP连接服务器
    status = TdiConnection(pTdiAddressDevObj, pTdiEndPointFileObject, pServerIp, lServerPort);
    if (!NT_SUCCESS(status))
    {
        return STATUS_SUCCESS;
    }

    // TDI TCP发送信息
    status = TdiSend(pTdiAddressDevObj, pTdiEndPointFileObject, szSendData, ulSendDataLength);
    if (!NT_SUCCESS(status))
    {
        return STATUS_SUCCESS;
    }
    DbgPrint("发送 %s\n", szSendData);

    // 创建接收信息多线程, 循环接收信息
    PMY_DATA pMyData = ExAllocatePool(NonPagedPool, sizeof(MY_DATA));
    pMyData->pTdiAddressDevObj = pTdiAddressDevObj;
    pMyData->pTdiEndPointFileObject = pTdiEndPointFileObject;
    pMyData->hTdiAddress = hTdiAddress;
    pMyData->hTdiEndPoint = hTdiEndPoint;

    PsCreateSystemThread(&hThread, 0, NULL, NtCurrentProcess(), NULL, RecvThreadProc, pMyData);
}

VOID UnDriver(PDRIVER_OBJECT driver)
{
    DbgPrint("驱动卸载成功 \n");
}

NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath)
{
    DbgPrint("hello lyshark.com \n");

    for (int x = 0; x < 10; x++)
    {
        SendThreadData();
    }
    Driver->DriverUnload = UnDriver;
    return STATUS_SUCCESS;
}

运行应用层服务端等待侦听,运行驱动程序输出如下效果;

image.png

TDI 传数结构实现认证: 驱动内部发送结构体给应用层,应用层验证结构体成员,此功能可实现对驱动程序的控制机制,例如是否允许驱动加载卸载等,通常用于驱动辅助认证。

应用层代码

// 署名权
// right to sign one's name on a piece of work
// PowerBy: LyShark
// Email: me@lyshark.com

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>  
#include <winsock2.h>  

#pragma comment(lib,"ws2_32.lib")
#define PORT 8888

// 传输结构体
typedef struct
{
    int uuid;
    char username[256];
    char password[256];
}SocketData;

int main(int argc, char *argv[])
{
    printf("hello lyshark.com \n");

    WSADATA WSAData;
    SOCKET sock, msgsock;
    struct sockaddr_in ServerAddr;

    if (WSAStartup(MAKEWORD(2, 0), &WSAData) != SOCKET_ERROR)
    {
        ServerAddr.sin_family = AF_INET;
        ServerAddr.sin_port = htons(PORT);
        ServerAddr.sin_addr.s_addr = INADDR_ANY;

        sock = socket(AF_INET, SOCK_STREAM, 0);
        int BindRet = bind(sock, (LPSOCKADDR)&ServerAddr, sizeof(ServerAddr));
        int LinsRet = listen(sock, 10);
    }

    while (1)
    {
        char buf[8192] = { 0 };
        msgsock = accept(sock, (LPSOCKADDR)0, (int *)0);
        memset(buf, 0, sizeof(buf));

        // 接收返回数据
        recv(msgsock, buf, sizeof(SocketData), 0);

        // 强转结构体
        SocketData* msg = (SocketData*)buf;

        printf("UUID = %d \n", msg->uuid);
        printf("名字 = %s \n", msg->username);
        printf("密码 = %s \n", msg->password);

        // 验证通过则继续使用
        if ((strcmp(msg->username, "lyshark") == 0) && (strcmp(msg->password, "123") == 0))
        {
            char send_buffer[8192] = { 0 };
            memset(send_buffer, 0, 8192);
            strcpy(send_buffer, "success");
            send(msgsock, send_buffer, strlen(send_buffer), 0);
            closesocket(msgsock);
        }
        // 不通过则禁止驱动加载
        else
        {
            char send_buffer[8192] = { 0 };
            memset(send_buffer, 0, 8192);
            strcpy(send_buffer, "error");
            send(msgsock, send_buffer, strlen(send_buffer), 0);
            closesocket(msgsock);
        }
    }
    closesocket(sock);
    WSACleanup();
    return 0;
}

驱动层代码

// 署名权
// right to sign one's name on a piece of work
// PowerBy: LyShark
// Email: me@lyshark.com
#include "LySocket.hpp"

// 传输结构体
typedef struct
{
    int uuid;
    char username[256];
    char password[256];
}SocketData;

// 验证账号密码是否正确
BOOLEAN CheckDriver()
{
    NTSTATUS status = STATUS_SUCCESS;
    HANDLE hTdiAddress = NULL;
    HANDLE hTdiEndPoint = NULL;
    PDEVICE_OBJECT pTdiAddressDevObj = NULL;
    PFILE_OBJECT pTdiEndPointFileObject = NULL;
    LONG pServerIp[4] = { 127, 0, 0, 1 };
    LONG lServerPort = 8888;

    // TDI初始化
    status = TdiOpen(&pTdiAddressDevObj, &pTdiEndPointFileObject, &hTdiAddress, &hTdiEndPoint);
    if (!NT_SUCCESS(status))
    {
        return STATUS_SUCCESS;
    }

    // TDI TCP连接服务器
    status = TdiConnection(pTdiAddressDevObj, pTdiEndPointFileObject, pServerIp, lServerPort);
    if (!NT_SUCCESS(status))
    {
        return STATUS_SUCCESS;
    }

    SocketData ptr;

    RtlZeroMemory(&ptr, sizeof(SocketData));

    // 填充结构
    ptr.uuid = 1001;
    RtlCopyMemory(ptr.username, "lyshark", strlen("xxxxxxx"));
    RtlCopyMemory(ptr.password, "123123", strlen("xxxxxx"));

    // TDI TCP发送信息
    status = TdiSend(pTdiAddressDevObj, pTdiEndPointFileObject, &ptr, sizeof(SocketData));
    if (!NT_SUCCESS(status))
    {
        return STATUS_SUCCESS;
    }

    // 创建接收信息多线程, 循环接收信息
    char szRecvData[8192] = { 0 };
    ULONG ulRecvDataLenngth = 8192;
    RtlZeroMemory(szRecvData, ulRecvDataLenngth);

    // TDI TCP接收信息
    do
    {
        ulRecvDataLenngth = TdiRecv(pTdiAddressDevObj, pTdiEndPointFileObject, szRecvData, ulRecvDataLenngth);
        if (0 < ulRecvDataLenngth)
        {
            DbgPrint("接收数据: %s\n", szRecvData);

            if (strncmp(szRecvData, "success", 7) == 0)
            {
                // 释放
                TdiClose(pTdiEndPointFileObject, hTdiAddress, hTdiEndPoint);
                return TRUE;
            }
            else if (strncmp(szRecvData, "error", 5) == 0)
            {
                // 释放
                TdiClose(pTdiEndPointFileObject, hTdiAddress, hTdiEndPoint);
                return FALSE;
            }
            break;;
        }
    } while (TRUE);

    // 释放
    TdiClose(pTdiEndPointFileObject, hTdiAddress, hTdiEndPoint);
    return STATUS_SUCCESS;
}

VOID UnDriver(PDRIVER_OBJECT driver)
{
    DbgPrint("驱动卸载成功 \n");
}

NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath)
{
    DbgPrint("hello lyshark.com \n");

    BOOLEAN ref = CheckDriver();

    if (ref == FALSE)
    {
        DbgPrint("[LyShark.com] 驱动已过期,无法加载 \n");
        Driver->DriverUnload = UnDriver;
        return STATUS_SUCCESS;
    }

    DbgPrint("[*] 驱动正常使用 \n");
    Driver->DriverUnload = UnDriver;
    return STATUS_SUCCESS;
}

运行应用层服务端,并运行驱动程序,则会验证该驱动是否合法,如果合法则加载不合法则拒绝;

image.png

目录
相关文章
|
1月前
|
机器学习/深度学习 自然语言处理 数据处理
大模型开发:描述长短期记忆网络(LSTM)和它们在序列数据上的应用。
LSTM,一种RNN变体,设计用于解决RNN处理长期依赖的难题。其核心在于门控机制(输入、遗忘、输出门)和长期记忆单元(细胞状态),能有效捕捉序列数据的长期依赖,广泛应用于语言模型、机器翻译等领域。然而,LSTM也存在计算复杂度高、解释性差和数据依赖性强等问题,需要通过优化和增强策略来改进。
|
1月前
|
机器学习/深度学习
大模型开发:解释卷积神经网络(CNN)是如何在图像识别任务中工作的。
**CNN图像识别摘要:** CNN通过卷积层提取图像局部特征,池化层减小尺寸并保持关键信息,全连接层整合特征,最后用Softmax等分类器进行识别。自动学习与空间处理能力使其在图像识别中表现出色。
24 2
|
1月前
|
域名解析 网络协议 Linux
【Shell 命令集合 网络通讯 】Linux 设置和管理网络接口配置信息 netconfig命令 使用指南
【Shell 命令集合 网络通讯 】Linux 设置和管理网络接口配置信息 netconfig命令 使用指南
56 1
|
17天前
|
网络协议 Linux
在Linux中,管理和配置网络接口
在Linux中管理网络接口涉及多个命令,如`ifconfig`(在新版本中被`ip`取代)、`ip`(用于网络设备配置)、`nmcli`(NetworkManager的CLI工具)、`nmtui`(文本界面配置)、`route/ip route`(处理路由表)、`netstat/ss`(显示网络状态)和`hostnamectl/systemctl`(主机名和服务管理)。这些命令帮助用户启动接口、设置IP地址、查看连接和路由信息。不同发行版可能有差异,建议参考相应文档。
19 4
|
1月前
|
监控 网络协议 Linux
【Shell 命令集合 网络通讯 】Linux 显示网络 连接、路由表和网络接口信息 netstat命令 使用指南
【Shell 命令集合 网络通讯 】Linux 显示网络 连接、路由表和网络接口信息 netstat命令 使用指南
62 1
|
1天前
【计算机网络】第三章 数据链路层(概述 封装成桢 差错检错)
【计算机网络】第三章 数据链路层(概述 封装成桢 差错检错)
|
3天前
|
Ubuntu 网络协议 Linux
Linux(20) Ubuntu 20.04 网络接口自动切换路由配置
Linux(20) Ubuntu 20.04 网络接口自动切换路由配置
26 0
|
18天前
|
机器学习/深度学习 人工智能 运维
构建未来:AI驱动的自适应网络安全防御系统
【4月更文挑战第7天】 在数字时代的浪潮中,网络安全已成为维系信息完整性、保障用户隐私和确保商业连续性的关键。传统的安全防御策略,受限于其静态性质和对新型威胁的响应迟缓,已难以满足日益增长的安全需求。本文将探讨如何利用人工智能(AI)技术打造一个自适应的网络安全防御系统,该系统能够实时分析网络流量,自动识别并响应未知威胁,从而提供更为强大和灵活的保护机制。通过深入剖析AI算法的核心原理及其在网络安全中的应用,我们将展望一个由AI赋能的、更加智能和安全的网络环境。
28 0
|
22天前
|
SQL 前端开发 Java
五邑大学餐厅网络点餐系统设计与实现(包含完整源码详细开发过程)
五邑大学餐厅网络点餐系统设计与实现(包含完整源码详细开发过程)
|
30天前
|
存储 Unix Linux
深入理解 Linux 系统下的关键网络接口和函数,gethostent,getaddrinfo,getnameinfo
深入理解 Linux 系统下的关键网络接口和函数,gethostent,getaddrinfo,getnameinfo
15 0