设为首页 加入收藏

TOP

驱动开发:内核封装WSK网络通信接口(一)
2023-07-23 13:30:38 】 浏览:120
Tags:封装 WSK 通信接

本章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");

	
首页 上一页 1 2 下一页 尾页 1/2/2
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇【C Primer PLus 摘录】第 10 章 .. 下一篇OpenGL ES EGL eglCreateWindowSu..

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目