1. 程式人生 > >TDI簡單的UDP網路通訊

TDI簡單的UDP網路通訊

#include "ntifs.h"
#include "tdi.h"
#include "tdikrnl.h"
#include "KernelSocket.h"


HANDLE g_hSocket = NULL;
PFILE_OBJECT g_pSocketUdpObject = NULL;

#define RECVBUFF			2048

CHAR Packet[30786] = { 0 };
//建立本地地址
NTSTATUS CreateLocalAddress();

//發生UDP資料
NTSTATUS TdiSendDatagram(char* szIpAddress, unsigned short Port, char* pData, unsigned long bufferLength);

//接受UDP資料
unsigned long TdiReceiveDatagram(char* szIpAddress, unsigned short Port, char* pData, unsigned long Length, PLARGE_INTEGER Timeout);

void DriverUnload(_In_ PDRIVER_OBJECT pdriverObject)
{

}


NTSTATUS DriverEntry(_In_ PDRIVER_OBJECT pDriverObject, _In_ PUNICODE_STRING registryPath)
{
	//KdBreakPoint();
	pDriverObject->DriverUnload = DriverUnload;
	NTSTATUS status = STATUS_UNSUCCESSFUL;

	//建立本地地址
	status = CreateLocalAddress();
	if (!NT_SUCCESS(status))
	{
		KdPrint(("CreateLocalAddress error\n"));
		return status;
	}

	//傳送UDP資料
	char szSendMessage[] = "你這個傻瓜真可笑!\n";
	status = TdiSendDatagram("192.168.2.223", 1234, szSendMessage, sizeof(szSendMessage));
	if (status != STATUS_SUCCESS)
	{
		KdPrint(("TdiSendDatagram error\n"));
		ObDereferenceObject(g_pSocketUdpObject);
		ZwClose(g_hSocket);
		return status;
	}


	//接受UDP資料
	LARGE_INTEGER Timeout;
	Timeout.QuadPart = 5 * 1000 * (-10000);	//5秒
	ULONG RecvSize = RECVBUFF;
	//fx 2016年10月14日20:53:03	//RecvSize這個大小在udp中不能太大
	unsigned long uRecvSize = 0;
	uRecvSize = TdiReceiveDatagram("192.168.2.223", 1234, Packet, RecvSize, &Timeout);
	if (uRecvSize <= 0)
	{
		KdPrint(("TdiReceiveDatagram error\n"));
		ObDereferenceObject(g_pSocketUdpObject);
		ZwClose(g_hSocket);
		return status;
	}
	KdPrint(("uRecvSize=%d\n", uRecvSize));
	KdPrint(("%s\n", Packet));
	ObDereferenceObject(g_pSocketUdpObject);
	ZwClose(g_hSocket);
	return STATUS_SUCCESS;
}


//建立本地地址
NTSTATUS CreateLocalAddress()
{
	UNICODE_STRING Name;
	OBJECT_ATTRIBUTES Attr;
	unsigned char LocalAddrBuffer[sizeof(FILE_FULL_EA_INFORMATION) + TDI_TRANSPORT_ADDRESS_LENGTH + sizeof(TA_IP_ADDRESS)] = { 0 };
	PFILE_FULL_EA_INFORMATION Ea;
	PTA_IP_ADDRESS Sin;
	IO_STATUS_BLOCK IoStatus;
	NTSTATUS Status;


	Ea = (PFILE_FULL_EA_INFORMATION)ExAllocatePool(NonPagedPool, sizeof(LocalAddrBuffer));
	if (Ea == NULL)return  STATUS_UNSUCCESSFUL;

	Ea->NextEntryOffset = 0;
	Ea->Flags = 0;
	Ea->EaNameLength = TDI_TRANSPORT_ADDRESS_LENGTH;
	Ea->EaValueLength = sizeof(TA_IP_ADDRESS);
	RtlCopyMemory(Ea->EaName, TdiTransportAddress, Ea->EaNameLength + 1);

	Sin = (PTA_IP_ADDRESS)(Ea->EaName + Ea->EaNameLength + 1);
	Sin->TAAddressCount = 1;
	Sin->Address[0].AddressLength = TDI_ADDRESS_LENGTH_IP;
	Sin->Address[0].AddressType = TDI_ADDRESS_TYPE_IP;
	Sin->Address[0].Address[0].sin_port = 0; //
	Sin->Address[0].Address[0].in_addr = 0; //本地自動
	RtlZeroMemory(Sin->Address[0].Address[0].sin_zero, sizeof(Sin->Address[0].Address[0].sin_zero));

	RtlInitUnicodeString(&Name, L"\\Device\\Udp");
	InitializeObjectAttributes(&Attr, &Name, OBJ_CASE_INSENSITIVE, 0, 0);
	Status = ZwCreateFile(&g_hSocket, 0, &Attr, &IoStatus, 0, FILE_ATTRIBUTE_NORMAL, 0, FILE_OPEN, 0, Ea, sizeof(LocalAddrBuffer));
	ExFreePool((PVOID)Ea);
	if (!NT_SUCCESS(Status))
	{
		return Status;
	}

	Status = ObReferenceObjectByHandle(g_hSocket, GENERIC_READ | GENERIC_WRITE, 0, KernelMode, (PVOID *)&g_pSocketUdpObject, 0);
	return Status;
}


//發生UDP資料
NTSTATUS TdiSendDatagram(char* szIpAddress, unsigned short Port, char* pData, unsigned long bufferLength)
{
	PIRP Irp;
	PMDL Mdl;
	PDEVICE_OBJECT DeviceObject;
	PTDI_CONNECTION_INFORMATION ConnectInfo;
	PTA_IP_ADDRESS TA;
	PTDI_ADDRESS_IP IpAddress;
	IO_STATUS_BLOCK Iosb;
	KEVENT Event;
	NTSTATUS Status;



	DeviceObject = IoGetRelatedDeviceObject(g_pSocketUdpObject);
	ConnectInfo = (PTDI_CONNECTION_INFORMATION)ExAllocatePool(NonPagedPool, sizeof(TDI_CONNECTION_INFORMATION) + sizeof(TA_IP_ADDRESS));
	if (ConnectInfo == NULL) return STATUS_INSUFFICIENT_RESOURCES;

	KeInitializeEvent(&Event, NotificationEvent, FALSE);
	Irp = TdiBuildInternalDeviceControlIrp(TDI_SEND_DATAGRAM, DeviceObject, g_pSocketUdpObject, &Event, &Iosb);
	if (Irp == NULL)
	{
		ExFreePool(ConnectInfo);
		return STATUS_INSUFFICIENT_RESOURCES;
	}

	//分配MDL
	Mdl = IoAllocateMdl(pData, bufferLength, FALSE, FALSE, NULL);
	if (Mdl == NULL)
	{
		IoFreeIrp(Irp);
		ExFreePool(ConnectInfo);
		return STATUS_INSUFFICIENT_RESOURCES;
	}

	__try
	{
		MmProbeAndLockPages(Mdl, KernelMode, IoModifyAccess);
	}
	__except (EXCEPTION_EXECUTE_HANDLER)
	{
		IoFreeMdl(Mdl);
		IoFreeIrp(Irp);
		ExFreePool(ConnectInfo);
		return STATUS_UNSUCCESSFUL;
	}

	RtlZeroMemory(ConnectInfo, sizeof(TDI_CONNECTION_INFORMATION) + sizeof(TA_IP_ADDRESS));
	ConnectInfo->RemoteAddressLength = sizeof(TA_IP_ADDRESS);
	ConnectInfo->RemoteAddress = (PUCHAR)((ULONG_PTR)ConnectInfo + sizeof(TDI_CONNECTION_INFORMATION));
	TA = (PTA_IP_ADDRESS)(ConnectInfo->RemoteAddress);
	TA->TAAddressCount = 1;
	TA->Address[0].AddressLength = sizeof(TDI_ADDRESS_IP);
	TA->Address[0].AddressType = TDI_ADDRESS_TYPE_IP;
	IpAddress = (PTDI_ADDRESS_IP)(TA->Address[0].Address);

	IpAddress->sin_port = ntohs(Port);
	IpAddress->in_addr = inet_addr(szIpAddress);

	TdiBuildSendDatagram(Irp, DeviceObject, g_pSocketUdpObject, NULL, NULL, Mdl, bufferLength, ConnectInfo);

	Status = IoCallDriver(DeviceObject, Irp);
	if ((Status == STATUS_PENDING) && (&Event != NULL))
	{
		Status = KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
		if (Status == STATUS_TIMEOUT)
		{
			IoCancelIrp(Irp);
			Iosb.Status = STATUS_TIMEOUT;
		}
		Status = Iosb.Status;
	}

	ExFreePool(ConnectInfo);
	return Status;
}

//接受UDP資料
unsigned long TdiReceiveDatagram(char* szIpAddress, unsigned short Port, char* pData, unsigned long Length, PLARGE_INTEGER Timeout)
{

	PTDI_CONNECTION_INFORMATION ReceiveInfo;
	PTDI_CONNECTION_INFORMATION ReturnInfo;
	PTA_IP_ADDRESS ReturnAddress;
	PDEVICE_OBJECT DeviceObject;
	PTDI_ADDRESS_IP IpAddress;
	PTA_IP_ADDRESS TA;
	IO_STATUS_BLOCK Iosb;
	KEVENT Event;
	PVOID MdlBuffer;
	NTSTATUS Status;
	PIRP Irp;
	PMDL Mdl;
	unsigned long uRecvSize = 0;



	DeviceObject = IoGetRelatedDeviceObject(g_pSocketUdpObject);
	if (DeviceObject == NULL)return STATUS_INVALID_PARAMETER;

	ReceiveInfo = (PTDI_CONNECTION_INFORMATION)ExAllocatePool(NonPagedPool,
		sizeof(TDI_CONNECTION_INFORMATION) +
		sizeof(TA_IP_ADDRESS) +
		sizeof(TDI_CONNECTION_INFORMATION) +
		sizeof(TA_IP_ADDRESS));

	if (ReceiveInfo == NULL)return STATUS_INSUFFICIENT_RESOURCES;
	MdlBuffer = ExAllocatePool(PagedPool, Length);
	if (MdlBuffer == NULL)return STATUS_INSUFFICIENT_RESOURCES;

	RtlZeroMemory(ReceiveInfo, sizeof(TDI_CONNECTION_INFORMATION) + sizeof(TA_IP_ADDRESS) + sizeof(TDI_CONNECTION_INFORMATION) +
		sizeof(TA_IP_ADDRESS));

	RtlCopyMemory(MdlBuffer, pData, Length);
	ReceiveInfo->RemoteAddressLength = sizeof(TA_IP_ADDRESS);
	ReceiveInfo->RemoteAddress = (PUCHAR)((ULONG_PTR)ReceiveInfo + sizeof(TDI_CONNECTION_INFORMATION));

	TA = (PTA_IP_ADDRESS)(ReceiveInfo->RemoteAddress);
	TA->TAAddressCount = 1;
	TA->Address[0].AddressLength = sizeof(TDI_ADDRESS_IP);
	TA->Address[0].AddressType = TDI_ADDRESS_TYPE_IP;
	IpAddress = (PTDI_ADDRESS_IP)(TA->Address[0].Address);
	IpAddress->sin_port = ntohs(Port);
	IpAddress->in_addr = inet_addr(szIpAddress);


	ReturnInfo = (PTDI_CONNECTION_INFORMATION)((ULONG_PTR)ReceiveInfo + sizeof(TDI_CONNECTION_INFORMATION) + sizeof(TA_IP_ADDRESS));
	ReturnInfo->RemoteAddressLength = sizeof(TA_IP_ADDRESS);
	ReturnInfo->RemoteAddress = (PUCHAR)((ULONG_PTR)ReturnInfo + sizeof(TDI_CONNECTION_INFORMATION));

	ReturnAddress = (PTA_IP_ADDRESS)(ReturnInfo->RemoteAddress);
	ReturnAddress->TAAddressCount = 1;
	ReturnAddress->Address[0].AddressLength = sizeof(TDI_ADDRESS_IP);
	ReturnAddress->Address[0].AddressType = TDI_ADDRESS_TYPE_IP;
	IpAddress = (PTDI_ADDRESS_IP)(ReturnAddress->Address[0].Address);
	IpAddress->sin_port = 0;
	IpAddress->in_addr = 0;

	KeInitializeEvent(&Event, NotificationEvent, FALSE);
	Irp = TdiBuildInternalDeviceControlIrp(TDI_RECEIVE_DATAGRAM, DeviceObject, g_pSocketUdpObject, &Event, &Iosb);
	if (Irp == NULL)
	{
		ExFreePool(MdlBuffer);
		ExFreePool(ReceiveInfo);
		return STATUS_INSUFFICIENT_RESOURCES;
	}

	Mdl = IoAllocateMdl(MdlBuffer, Length, FALSE, FALSE, NULL);
	if (Mdl == NULL)
	{
		IoFreeIrp(Irp);
		ExFreePool(MdlBuffer);
		ExFreePool(ReceiveInfo);
		return STATUS_INSUFFICIENT_RESOURCES;
	}

	__try
	{
		MmProbeAndLockPages(Mdl, KernelMode, IoModifyAccess);
	}
	__except (EXCEPTION_EXECUTE_HANDLER)
	{
		IoFreeMdl(Mdl);
		IoFreeIrp(Irp);
		ExFreePool(MdlBuffer);
		ExFreePool(ReceiveInfo);
		return STATUS_INSUFFICIENT_RESOURCES;
	}


	TdiBuildReceiveDatagram(Irp, DeviceObject, g_pSocketUdpObject, NULL, NULL, Mdl, Length, ReceiveInfo, ReturnInfo, TDI_RECEIVE_NORMAL);

	Status = IoCallDriver(DeviceObject, Irp);
	if ((Status == STATUS_PENDING) && (&Event != NULL))
	{
		Status = KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, Timeout);
		if (Status == STATUS_TIMEOUT)
		{
			IoCancelIrp(Irp);
			Iosb.Status = STATUS_TIMEOUT;
		}
		Status = Iosb.Status;
	}

	if (NT_SUCCESS(Status))
	{
		uRecvSize = Iosb.Information;
		if (uRecvSize > 0)RtlCopyMemory(pData, MdlBuffer, Iosb.Information);
	}

	ExFreePool(MdlBuffer);
	ExFreePool(ReceiveInfo);
	return uRecvSize;
}



#include <stdio.h>
#include <Winsock2.h>
#pragma comment (lib,"ws2_32.lib")

int main(void)
{
	WSADATA WsaData = { 0 };
	WSAStartup(MAKEWORD(2, 2), &WsaData);

	SOCKET m_SrvSocker = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);

	SOCKADDR_IN m_SrvAddr;
	m_SrvAddr.sin_family = AF_INET;
	m_SrvAddr.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
	m_SrvAddr.sin_port = htons(1234);

	if (bind(m_SrvSocker, (SOCKADDR*)&m_SrvAddr, sizeof(SOCKADDR)) == SOCKET_ERROR)
	{
		printf("繫結失敗\n");
		getchar();
		getchar();
		return -1;
	}



	char szBuff[MAX_PATH] = { 0 };
	SOCKADDR_IN m_ClientAddr;
	int nlen = sizeof(SOCKADDR);
	recvfrom(m_SrvSocker, szBuff, sizeof(szBuff), 0, (SOCKADDR*)&m_ClientAddr, &nlen);
	printf("%s:%s\n", inet_ntoa(m_ClientAddr.sin_addr), szBuff);

	ZeroMemory(szBuff, sizeof(szBuff));
	CopyMemory(szBuff, "這個服務端發的訊息", sizeof("這個服務端發的訊息"));
	sendto(m_SrvSocker, szBuff, sizeof("這個服務端發的訊息"), 0, (SOCKADDR*)&m_ClientAddr, sizeof(SOCKADDR));




	getchar();
	getchar();
	closesocket(m_SrvSocker);
	WSACleanup();
	return 0;
}