驅動開發:內核封裝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: [email protected]

#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: [email protected]

#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;
}

首先運行應用層開啓服務端偵聽,然後運行驅動程序,會輸出如下信息;

TDI 多線程收發包: 實現驅動內部發送數據包後開啓一個線程用於等待應用層返回並輸出結果,多線程收發在發送數據包後需要創建新的線程等待接收。

首先是服務端代碼。

// 署名權
// right to sign one's name on a piece of work
// PowerBy: LyShark
// Email: [email protected]

#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: [email protected]

#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;
}

運行應用層服務端等待偵聽,運行驅動程序輸出如下效果;

TDI 傳數結構實現認證: 驅動內部發送結構體給應用層,應用層驗證結構體成員,此功能可實現對驅動程序的控制機制,例如是否允許驅動加載卸載等,通常用於驅動輔助認證。

應用層代碼

// 署名權
// right to sign one's name on a piece of work
// PowerBy: LyShark
// Email: [email protected]

#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: [email protected]
#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;
}

運行應用層服務端,並運行驅動程序,則會驗證該驅動是否合法,如果合法則加載不合法則拒絕;

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章