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

简介: 本章`LyShark`将带大家学习如何在内核中使用标准的`Socket`套接字通信接口,我们都知道`Windows`应用层下可直接调用`WinSocket`来实现网络通信,但在内核模式下应用层API接口无法使用,内核模式下有一套专有的`WSK`通信接口,我们对WSK进行封装,让其与应用层调用规范保持一致,并实现内核与内核直接通过`Socket`通信的案例。

本章LyShark将带大家学习如何在内核中使用标准的Socket套接字通信接口,我们都知道Windows应用层下可直接调用WinSocket来实现网络通信,但在内核模式下应用层API接口无法使用,内核模式下有一套专有的WSK通信接口,我们对WSK进行封装,让其与应用层调用规范保持一致,并实现内核与内核直接通过Socket通信的案例。

当然在早期如果需要实现网络通信一般都会采用TDI框架,但在新版本Windows10系统上虽然依然可以使用TDI接口,但是LyShark并不推荐使用,因为微软已经对接口搁置了,为了使WSK通信更加易用,我们需要封装内核层中的通信API,新建LySocket.hpp头文件,该文件中封装了WSK通信API接口,其封装格式与应用层接口保持了高度一致,当需要在内核中使用Socket通信时可直接引入本文件。

我们需要使用WDM驱动程序,并配置以下参数。

  • 配置属性 -> 连接器 -> 输入-> 附加依赖 -> $(DDK_LIB_PATH)\Netio.lib
  • 配置属性 -> C/C++ -> 常规 -> 设置 警告等级2级 (警告视为错误关闭)

配置好以后,我们就开始吧,先来看看服务端如何实现!

对于服务端来说,驱动通信必须保证服务端开启多线程来处理异步请求,不然驱动加载后系统会处于等待状态,而一旦等待则系统将会卡死,那么对于服务端DriverEntry入口说我们不能让其等待,必须使用PsCreateSystemThread来启用系统线程,该函数属于WDM的一部分,官方定义如下;

NTSTATUS PsCreateSystemThread(
  [out]           PHANDLE            ThreadHandle,
  [in]            ULONG              DesiredAccess,
  [in, optional]  POBJECT_ATTRIBUTES ObjectAttributes,
  [in, optional]  HANDLE             ProcessHandle,
  [out, optional] PCLIENT_ID         ClientId,
  [in]            PKSTART_ROUTINE    StartRoutine,
  [in, optional]  PVOID              StartContext
);

我们使用PsCreateSystemThread函数开辟线程TcpListenWorker在线程内部执行如下流程启动驱动服务端,由于我们自己封装实现了标准接口组,所以使用起来几乎与应用层无任何差异了。

  • CreateSocket 创建套接字
  • Bind 绑定套接字
  • Accept 等待接收请求
  • Receive 用于接收返回值
  • Send 用于发送返回值
// 署名权
// right to sign one's name on a piece of work
// PowerBy: LyShark
// Email: me@lyshark.com

#include "LySocket.hpp"

PETHREAD m_EThread = NULL;

// 线程函数
// PowerBy: LySHark
VOID TcpListenWorker(PVOID Context)
{
    WSK_SOCKET* paccept_socket = NULL;
    SOCKADDR_IN LocalAddress = { 0 };
    SOCKADDR_IN RemoteAddress = { 0 };
    NTSTATUS status = STATUS_UNSUCCESSFUL;

    // 创建套接字
    PWSK_SOCKET TcpSocket = CreateSocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, WSK_FLAG_LISTEN_SOCKET);
    if (TcpSocket == NULL)
    {
        return;
    }

    // 设置绑定地址
    LocalAddress.sin_family = AF_INET;
    LocalAddress.sin_addr.s_addr = INADDR_ANY;
    LocalAddress.sin_port = HTON_SHORT(8888);

    status = Bind(TcpSocket, (PSOCKADDR)&LocalAddress);
    if (!NT_SUCCESS(status))
    {
        return;
    }

    // 循环接收
    while (1)
    {
        CHAR* read_buffer = (CHAR*)ExAllocatePoolWithTag(NonPagedPool, 2048, "read");
        paccept_socket = Accept(TcpSocket, (PSOCKADDR)&LocalAddress, (PSOCKADDR)&RemoteAddress);
        if (paccept_socket == NULL)
        {
            continue;
        }

        // 接收数据
        memset(read_buffer, 0, 2048);
        int read_len = Receive(paccept_socket, read_buffer, 2048, 0);
        if (read_len != 0)
        {
            DbgPrint("[内核A] => %s \n", read_buffer);

            // 发送数据
            char send_buffer[2048] = "Hi, lyshark.com B";
            Send(paccept_socket, send_buffer, strlen(send_buffer), 0);

            // 接收确认包
            memset(read_buffer, 0, 2048);
            Receive(paccept_socket, read_buffer, 2, 0);
        }

        // 清理堆
        if (read_buffer != NULL)
        {
            ExFreePool(read_buffer);
        }

        // 关闭当前套接字
        if (paccept_socket)
        {
            CloseSocket(paccept_socket);
        }
    }

    if (TcpSocket)
    {
        CloseSocket(TcpSocket);
    }
    PsTerminateSystemThread(STATUS_SUCCESS);
    return;
}

// 关闭套接字
VOID UnDriver(PDRIVER_OBJECT driver)
{
    WSKCleanup();
    KeWaitForSingleObject(m_EThread, Executive, KernelMode, FALSE, NULL);
    if (m_EThread != NULL)
    {
        ObDereferenceObject(m_EThread);
    }
}

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

    // 初始化
    WSKStartup();

    HANDLE hThread = NULL;
    NTSTATUS status = STATUS_UNSUCCESSFUL;

    // 创建系统线程
    status = PsCreateSystemThread(&hThread, THREAD_ALL_ACCESS, NULL, NULL, NULL, TcpListenWorker, NULL);
    if (!NT_SUCCESS(status))
    {
        return status;
    }

    // 获取线程EProcess结构
    status = ObReferenceObjectByHandle(hThread, THREAD_ALL_ACCESS, NULL, KernelMode, (PVOID*)&m_EThread, NULL);
    if (NT_SUCCESS(status) == FALSE)
    {
        return status;
    }

    ZwClose(hThread);
    Driver->DriverUnload = UnDriver;
    return STATUS_SUCCESS;
}

对于客户端来说,只需要创建套接字并连接到指定地址即可,这个过程大体上可以总结为如下;

  • CreateSocket 创建套接字
  • Bind 绑定套接字
  • Connect 链接服务端驱动
  • Send 发送数据到服务端
  • Receive 接收数据到服务端
// 署名权
// right to sign one's name on a piece of work
// PowerBy: LyShark
// Email: me@lyshark.com

#include "LySocket.hpp"

VOID UnDriver(PDRIVER_OBJECT driver)
{
    // 卸载并关闭Socket库
    WSKCleanup();
}

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

    NTSTATUS      status = STATUS_SUCCESS;
    SOCKADDR_IN   LocalAddress = { 0, };
    SOCKADDR_IN   RemoteAddress = { 0, };

    // 创建套接字
    PWSK_SOCKET TcpSocket = CreateSocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, WSK_FLAG_CONNECTION_SOCKET);
    if (TcpSocket == NULL)
    {
        Driver->DriverUnload = UnDriver;
        return STATUS_SUCCESS;
    }

    LocalAddress.sin_family = AF_INET;
    LocalAddress.sin_addr.s_addr = INADDR_ANY;
    status = Bind(TcpSocket, (PSOCKADDR)&LocalAddress);

    // 绑定失败则关闭驱动
    if (!NT_SUCCESS(status))
    {
        CloseSocket(TcpSocket);

        Driver->DriverUnload = UnDriver;
        return STATUS_SUCCESS;
    }

    // 初始化服务端地址与端口信息
    ULONG address[4] = { 127, 0, 0, 1 };

    RemoteAddress.sin_family = AF_INET;
    RemoteAddress.sin_addr.s_addr = change_uint(address[0], address[1], address[2], address[3]);
    RemoteAddress.sin_port = HTON_SHORT(8888);

    status = Connect(TcpSocket, (PSOCKADDR)&RemoteAddress);

    // 连接服务端,如果失败则关闭驱动
    if (!NT_SUCCESS(status))
    {
        CloseSocket(TcpSocket);
        Driver->DriverUnload = UnDriver;
        return STATUS_SUCCESS;
    }

    // 发送数据
    char send_buffer[2048] = "hello lyshark.com A";
    Send(TcpSocket, send_buffer, strlen(send_buffer), 0);

    // 接收数据
    CHAR* read_buffer = (CHAR*)ExAllocatePoolWithTag(NonPagedPool, 2048, "read");

    memset(read_buffer, 0, 1024);
    Receive(TcpSocket, read_buffer, 2048, 0);
    DbgPrint("[内核B] => %s \n", read_buffer);

    // 发送确认包
    Send(TcpSocket, "ok", 2, 0);

    // 释放内存
    ExFreePool(read_buffer);
    CloseSocket(TcpSocket);
    Driver->DriverUnload = UnDriver;
    return STATUS_SUCCESS;
}

编译两个驱动程序,首先运行server.sys驱动,运行后该驱动会在后台等待客户端连接,接着运行client.sys屏幕上可输出如下提示,说明通信已经建立了。

image.png

目录
相关文章
|
5天前
|
缓存 JavaScript API
【vue实战项目】通用管理系统:封装token操作和网络请求
【vue实战项目】通用管理系统:封装token操作和网络请求
12 0
|
10天前
计算机网络——数据链路层-封装成帧(帧定界、透明传输-字节填充,比特填充、MTU)
计算机网络——数据链路层-封装成帧(帧定界、透明传输-字节填充,比特填充、MTU)
23 0
|
13天前
|
Linux 数据安全/隐私保护 Windows
linux 搭建cloudreve win映射网络驱动器WebDav
linux 搭建cloudreve win映射网络驱动器WebDav
|
14天前
|
消息中间件 网络协议
【消息队列开发】 设计网络通信协议
【消息队列开发】 设计网络通信协议
|
14天前
|
XML 网络协议 Java
53. 【Android教程】Socket 网络接口
53. 【Android教程】Socket 网络接口
16 0
|
17天前
|
安全 网络安全 量子技术
网络安全与信息安全:漏洞、加密技术与安全意识的探索安卓应用开发中的内存管理策略
【5月更文挑战第31天】随着互联网的普及,网络安全问题日益严重。本文将深入探讨网络安全漏洞、加密技术以及安全意识等方面的问题,以期提高公众对网络安全的认识和防范能力。
|
17天前
|
存储 人工智能 物联网
探索操作系统的心脏:内核的奥秘云计算与网络安全:技术融合与挑战
【5月更文挑战第31天】本文将深入探讨操作系统的核心—内核,揭示其运作原理与对计算机性能的影响。从内核的定义和功能出发,我们将逐步剖析其结构组成,包括进程管理、内存管理、文件系统和设备驱动等关键模块。文章旨在为读者提供一扇观察操作系统内部工作机制的窗口,帮助理解现代计算环境中,为何一个高效、稳定的内核对于整个系统的重要性不可或缺。
|
18天前
|
人工智能 自然语言处理 安全
构建未来:AI驱动的自适应网络安全防御系统提升软件测试效率:自动化与持续集成的实践之路
【5月更文挑战第30天】 在数字化时代,网络安全已成为维护信息完整性、保障用户隐私和企业持续运营的关键。传统的安全防御手段,如防火墙和入侵检测系统,面对日益复杂的网络攻击已显得力不从心。本文提出了一种基于人工智能(AI)技术的自适应网络安全防御系统,该系统能够实时分析网络流量,自动识别潜在威胁,并动态调整防御策略以应对未知攻击。通过深度学习算法和自然语言处理技术的结合,系统不仅能够提高检测速度和准确性,还能自主学习和适应新型攻击模式,从而显著提升网络安全防御的效率和智能化水平。 【5月更文挑战第30天】 在快速迭代的软件开发周期中,传统的手动测试方法已不再适应现代高效交付的要求。本文探讨了如
|
19天前
|
机器学习/深度学习 人工智能 安全
构建未来:AI驱动的自适应网络安全防御系统
【5月更文挑战第29天】 随着网络攻击手段的不断演变和升级,传统的基于特征的安全防御机制已不再能够有效地应对日益复杂的安全威胁。本文探讨了如何通过集成人工智能(AI)技术来构建一个自适应的网络安全防御系统,该系统能够在不断变化的网络环境中学习、预测并主动防御未知威胁。通过深度学习算法、实时数据分析和自动化响应策略,这种新型系统旨在提高企业级网络安全的智能化水平,减少人为干预,同时提升防御效率和准确性。
|
19天前
|
存储 安全 网络安全
云计算与网络安全:技术驱动下的信息安全新挑战
云计算与网络安全作为当今技术领域的热门话题,不仅涉及到云服务的发展与应用,还牵扯到信息安全等诸多重要议题。本文将从技术驱动下的视角出发,探讨云计算和网络安全的紧密关联,分析新形势下信息安全面临的挑战和应对之策。
18 0

热门文章

最新文章