-
-
Save ssrlive/09677556429a6ed945ac075a63bff09e to your computer and use it in GitHub Desktop.
| /* SPDX-License-Identifier: GPL-2.0 | |
| * | |
| * Copyright (C) 2018-2021 WireGuard LLC. All Rights Reserved. | |
| */ | |
| #include <winsock2.h> | |
| #include <Windows.h> | |
| #include <ws2ipdef.h> | |
| #include <iphlpapi.h> | |
| #include <mstcpip.h> | |
| //#include <ip2string.h> | |
| #include <in6addr.h> | |
| #include <winternl.h> | |
| #include <stdarg.h> | |
| #include <stdio.h> | |
| #include <stdlib.h> | |
| #if !defined(_Must_inspect_result_) | |
| #define _Must_inspect_result_ | |
| #endif | |
| #if !defined(_Return_type_success_) | |
| #define _Return_type_success_(x) | |
| #endif | |
| #if !defined(_Post_writable_byte_size_) | |
| #define _Post_writable_byte_size_(x) | |
| #endif | |
| #if !defined(_In_reads_bytes_) | |
| #define _In_reads_bytes_(x) | |
| #endif | |
| #if !defined(_Out_writes_bytes_all_) | |
| #define _Out_writes_bytes_all_(x) | |
| #endif | |
| #if !defined(LOAD_LIBRARY_SEARCH_APPLICATION_DIR) | |
| #define LOAD_LIBRARY_SEARCH_APPLICATION_DIR 0x00000200 | |
| #endif | |
| #if !defined(LOAD_LIBRARY_SEARCH_SYSTEM32) | |
| #define LOAD_LIBRARY_SEARCH_SYSTEM32 0x00000800 | |
| #endif | |
| #include "wintun.h" | |
| #pragma comment(lib, "iphlpapi.lib") | |
| #pragma comment(lib, "ws2_32.lib") | |
| static WINTUN_CREATE_ADAPTER_FUNC *WintunCreateAdapter; | |
| static WINTUN_CLOSE_ADAPTER_FUNC *WintunCloseAdapter; | |
| static WINTUN_OPEN_ADAPTER_FUNC *WintunOpenAdapter; | |
| static WINTUN_GET_ADAPTER_LUID_FUNC *WintunGetAdapterLUID; | |
| static WINTUN_GET_RUNNING_DRIVER_VERSION_FUNC *WintunGetRunningDriverVersion; | |
| static WINTUN_DELETE_DRIVER_FUNC *WintunDeleteDriver; | |
| static WINTUN_SET_LOGGER_FUNC *WintunSetLogger; | |
| static WINTUN_START_SESSION_FUNC *WintunStartSession; | |
| static WINTUN_END_SESSION_FUNC *WintunEndSession; | |
| static WINTUN_GET_READ_WAIT_EVENT_FUNC *WintunGetReadWaitEvent; | |
| static WINTUN_RECEIVE_PACKET_FUNC *WintunReceivePacket; | |
| static WINTUN_RELEASE_RECEIVE_PACKET_FUNC *WintunReleaseReceivePacket; | |
| static WINTUN_ALLOCATE_SEND_PACKET_FUNC *WintunAllocateSendPacket; | |
| static WINTUN_SEND_PACKET_FUNC *WintunSendPacket; | |
| static HMODULE | |
| InitializeWintun(void) | |
| { | |
| HMODULE Wintun = | |
| LoadLibraryExW(L"wintun.dll", NULL, LOAD_LIBRARY_SEARCH_APPLICATION_DIR | LOAD_LIBRARY_SEARCH_SYSTEM32); | |
| if (!Wintun) | |
| return NULL; | |
| #define X(Name) ((*(FARPROC *)&Name = GetProcAddress(Wintun, #Name)) == NULL) | |
| if (X(WintunCreateAdapter) || X(WintunCloseAdapter) || X(WintunOpenAdapter) || X(WintunGetAdapterLUID) || | |
| X(WintunGetRunningDriverVersion) || X(WintunDeleteDriver) || X(WintunSetLogger) || X(WintunStartSession) || | |
| X(WintunEndSession) || X(WintunGetReadWaitEvent) || X(WintunReceivePacket) || X(WintunReleaseReceivePacket) || | |
| X(WintunAllocateSendPacket) || X(WintunSendPacket)) | |
| #undef X | |
| { | |
| DWORD LastError = GetLastError(); | |
| FreeLibrary(Wintun); | |
| SetLastError(LastError); | |
| return NULL; | |
| } | |
| return Wintun; | |
| } | |
| static void CALLBACK | |
| ConsoleLogger(_In_ WINTUN_LOGGER_LEVEL Level, _In_ DWORD64 Timestamp, _In_z_ const WCHAR *LogLine) | |
| { | |
| WCHAR LevelMarker; | |
| SYSTEMTIME SystemTime; | |
| FileTimeToSystemTime((FILETIME *)&Timestamp, &SystemTime); | |
| switch (Level) | |
| { | |
| case WINTUN_LOG_INFO: | |
| LevelMarker = L'+'; | |
| break; | |
| case WINTUN_LOG_WARN: | |
| LevelMarker = L'-'; | |
| break; | |
| case WINTUN_LOG_ERR: | |
| LevelMarker = L'!'; | |
| break; | |
| default: | |
| return; | |
| } | |
| fwprintf( | |
| stderr, | |
| L"%04u-%02u-%02u %02u:%02u:%02u.%04u [%c] %s\n", | |
| SystemTime.wYear, | |
| SystemTime.wMonth, | |
| SystemTime.wDay, | |
| SystemTime.wHour, | |
| SystemTime.wMinute, | |
| SystemTime.wSecond, | |
| SystemTime.wMilliseconds, | |
| LevelMarker, | |
| LogLine); | |
| } | |
| static DWORD64 Now(VOID) | |
| { | |
| HMODULE hNtDll = GetModuleHandleA("ntdll.dll"); | |
| NTSTATUS(WINAPI * NtQuerySystemTime)(PLARGE_INTEGER) = | |
| (NTSTATUS(WINAPI*)(PLARGE_INTEGER))GetProcAddress(hNtDll, "NtQuerySystemTime"); | |
| LARGE_INTEGER Timestamp; | |
| NtQuerySystemTime(&Timestamp); | |
| return Timestamp.QuadPart; | |
| } | |
| static DWORD | |
| LogError(_In_z_ const WCHAR *Prefix, _In_ DWORD Error) | |
| { | |
| WCHAR *SystemMessage = NULL, *FormattedMessage = NULL; | |
| FormatMessageW( | |
| FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_MAX_WIDTH_MASK, | |
| NULL, | |
| HRESULT_FROM_SETUPAPI(Error), | |
| MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), | |
| (LPWSTR)&SystemMessage, | |
| 0, | |
| NULL); | |
| { | |
| DWORD_PTR valist[] = { | |
| (DWORD_PTR)Prefix, (DWORD_PTR)Error, (DWORD_PTR)SystemMessage | |
| }; | |
| FormatMessageW( | |
| FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_ARGUMENT_ARRAY | | |
| FORMAT_MESSAGE_MAX_WIDTH_MASK, | |
| SystemMessage ? L"%1: %3(Code 0x%2!08X!)" : L"%1: Code 0x%2!08X!", | |
| 0, | |
| 0, | |
| (LPWSTR)&FormattedMessage, | |
| 0, | |
| (va_list*)valist); | |
| } | |
| if (FormattedMessage) | |
| ConsoleLogger(WINTUN_LOG_ERR, Now(), FormattedMessage); | |
| LocalFree(FormattedMessage); | |
| LocalFree(SystemMessage); | |
| return Error; | |
| } | |
| static DWORD | |
| LogLastError(_In_z_ const WCHAR *Prefix) | |
| { | |
| DWORD LastError = GetLastError(); | |
| LogError(Prefix, LastError); | |
| SetLastError(LastError); | |
| return LastError; | |
| } | |
| static void | |
| Log(_In_ WINTUN_LOGGER_LEVEL Level, _In_z_ const WCHAR *Format, ...) | |
| { | |
| WCHAR LogLine[0x200]; | |
| va_list args; | |
| va_start(args, Format); | |
| _vsnwprintf_s(LogLine, _countof(LogLine), _TRUNCATE, Format, args); | |
| va_end(args); | |
| ConsoleLogger(Level, Now(), LogLine); | |
| } | |
| static HANDLE QuitEvent; | |
| static volatile BOOL HaveQuit; | |
| static BOOL WINAPI | |
| CtrlHandler(_In_ DWORD CtrlType) | |
| { | |
| switch (CtrlType) | |
| { | |
| case CTRL_C_EVENT: | |
| case CTRL_BREAK_EVENT: | |
| case CTRL_CLOSE_EVENT: | |
| case CTRL_LOGOFF_EVENT: | |
| case CTRL_SHUTDOWN_EVENT: | |
| Log(WINTUN_LOG_INFO, L"Cleaning up and shutting down..."); | |
| HaveQuit = TRUE; | |
| SetEvent(QuitEvent); | |
| return TRUE; | |
| } | |
| return FALSE; | |
| } | |
| static void | |
| PrintPacket(_In_ const BYTE *Packet, _In_ DWORD PacketSize) | |
| { | |
| BYTE IpVersion, Proto; | |
| WCHAR Src[46], Dst[46]; | |
| if (PacketSize < 20) | |
| { | |
| Log(WINTUN_LOG_INFO, L"Received packet without room for an IP header"); | |
| return; | |
| } | |
| IpVersion = Packet[0] >> 4; | |
| if (IpVersion == 4) | |
| { | |
| HMODULE hNtDll = GetModuleHandleA("ntdll.dll"); | |
| PWSTR(WINAPI * RtlIpv4AddressToStringW)(const struct in_addr*, PWSTR) = | |
| (PWSTR(WINAPI*)(const struct in_addr*, PWSTR))GetProcAddress(hNtDll, "RtlIpv4AddressToStringW"); | |
| RtlIpv4AddressToStringW((struct in_addr *)&Packet[12], Src); | |
| RtlIpv4AddressToStringW((struct in_addr *)&Packet[16], Dst); | |
| Proto = Packet[9]; | |
| Packet += 20, PacketSize -= 20; | |
| } | |
| else if (IpVersion == 6 && PacketSize < 40) | |
| { | |
| Log(WINTUN_LOG_INFO, L"Received packet without room for an IP header"); | |
| return; | |
| } | |
| else if (IpVersion == 6) | |
| { | |
| HMODULE hNtDll = GetModuleHandleA("ntdll.dll"); | |
| PWSTR(WINAPI * RtlIpv6AddressToStringW)(const struct in6_addr*, PWSTR) = | |
| (PWSTR(WINAPI*)(const struct in6_addr*, PWSTR))GetProcAddress(hNtDll, "RtlIpv6AddressToStringW"); | |
| RtlIpv6AddressToStringW((struct in6_addr *)&Packet[8], Src); | |
| RtlIpv6AddressToStringW((struct in6_addr *)&Packet[24], Dst); | |
| Proto = Packet[6]; | |
| Packet += 40, PacketSize -= 40; | |
| } | |
| else | |
| { | |
| Log(WINTUN_LOG_INFO, L"Received packet that was not IP"); | |
| return; | |
| } | |
| if (Proto == 1 && PacketSize >= 8 && Packet[0] == 0) { | |
| Log(WINTUN_LOG_INFO, L"Received IPv%d ICMP echo reply from %s to %s", IpVersion, Src, Dst); | |
| } | |
| else { | |
| Log(WINTUN_LOG_INFO, L"Received IPv%d proto 0x%x packet from %s to %s", IpVersion, Proto, Src, Dst); | |
| } | |
| } | |
| static USHORT | |
| IPChecksum(_In_reads_bytes_(Len) BYTE *Buffer, _In_ DWORD Len) | |
| { | |
| ULONG Sum = 0; | |
| for (; Len > 1; Len -= 2, Buffer += 2) | |
| Sum += *(USHORT *)Buffer; | |
| if (Len) | |
| Sum += *Buffer; | |
| Sum = (Sum >> 16) + (Sum & 0xffff); | |
| Sum += (Sum >> 16); | |
| return (USHORT)(~Sum); | |
| } | |
| static void | |
| MakeICMP(_Out_writes_bytes_all_(28) BYTE Packet[28]) | |
| { | |
| memset(Packet, 0, 28); | |
| Packet[0] = 0x45; | |
| *(USHORT *)&Packet[2] = htons(28); | |
| Packet[8] = 255; | |
| Packet[9] = 1; | |
| *(ULONG *)&Packet[12] = htonl((10 << 24) | (6 << 16) | (7 << 8) | (8 << 0)); /* 10.6.7.8 */ | |
| *(ULONG *)&Packet[16] = htonl((10 << 24) | (6 << 16) | (7 << 8) | (7 << 0)); /* 10.6.7.7 */ | |
| *(USHORT *)&Packet[10] = IPChecksum(Packet, 20); | |
| Packet[20] = 8; | |
| *(USHORT *)&Packet[22] = IPChecksum(&Packet[20], 8); | |
| Log(WINTUN_LOG_INFO, L"Sending IPv4 ICMP echo request to 10.6.7.8 from 10.6.7.7"); | |
| } | |
| static DWORD WINAPI | |
| ReceivePackets(_Inout_ DWORD_PTR SessionPtr) | |
| { | |
| WINTUN_SESSION_HANDLE Session = (WINTUN_SESSION_HANDLE)SessionPtr; | |
| HANDLE WaitHandles[] = { WintunGetReadWaitEvent(Session), QuitEvent }; | |
| while (!HaveQuit) | |
| { | |
| DWORD PacketSize; | |
| BYTE *Packet = WintunReceivePacket(Session, &PacketSize); | |
| if (Packet) | |
| { | |
| PrintPacket(Packet, PacketSize); | |
| WintunReleaseReceivePacket(Session, Packet); | |
| } | |
| else | |
| { | |
| DWORD LastError = GetLastError(); | |
| switch (LastError) | |
| { | |
| case ERROR_NO_MORE_ITEMS: | |
| if (WaitForMultipleObjects(_countof(WaitHandles), WaitHandles, FALSE, INFINITE) == WAIT_OBJECT_0) | |
| continue; | |
| return ERROR_SUCCESS; | |
| default: | |
| LogError(L"Packet read failed", LastError); | |
| return LastError; | |
| } | |
| } | |
| } | |
| return ERROR_SUCCESS; | |
| } | |
| static DWORD WINAPI | |
| SendPackets(_Inout_ DWORD_PTR SessionPtr) | |
| { | |
| WINTUN_SESSION_HANDLE Session = (WINTUN_SESSION_HANDLE)SessionPtr; | |
| while (!HaveQuit) | |
| { | |
| BYTE *Packet = WintunAllocateSendPacket(Session, 28); | |
| if (Packet) | |
| { | |
| MakeICMP(Packet); | |
| WintunSendPacket(Session, Packet); | |
| } | |
| else if (GetLastError() != ERROR_BUFFER_OVERFLOW) | |
| return LogLastError(L"Packet write failed"); | |
| switch (WaitForSingleObject(QuitEvent, 1000 /* 1 second */)) | |
| { | |
| case WAIT_ABANDONED: | |
| case WAIT_OBJECT_0: | |
| return ERROR_SUCCESS; | |
| } | |
| } | |
| return ERROR_SUCCESS; | |
| } | |
| int __cdecl main(void) | |
| { | |
| DWORD LastError; | |
| GUID ExampleGuid = { 0xdeadbabe, 0xcafe, 0xbeef, { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef } }; | |
| WINTUN_ADAPTER_HANDLE Adapter; | |
| DWORD Version; | |
| MIB_UNICASTIPADDRESS_ROW AddressRow; | |
| WINTUN_SESSION_HANDLE Session; | |
| HMODULE Wintun = InitializeWintun(); | |
| if (!Wintun) | |
| return LogError(L"Failed to initialize Wintun", GetLastError()); | |
| WintunSetLogger(ConsoleLogger); | |
| Log(WINTUN_LOG_INFO, L"Wintun library loaded"); | |
| HaveQuit = FALSE; | |
| QuitEvent = CreateEventW(NULL, TRUE, FALSE, NULL); | |
| if (!QuitEvent) | |
| { | |
| LastError = LogError(L"Failed to create event", GetLastError()); | |
| goto cleanupWintun; | |
| } | |
| if (!SetConsoleCtrlHandler(CtrlHandler, TRUE)) | |
| { | |
| LastError = LogError(L"Failed to set console handler", GetLastError()); | |
| goto cleanupQuit; | |
| } | |
| Adapter = WintunCreateAdapter(L"Demo", L"Example", &ExampleGuid); | |
| if (!Adapter) | |
| { | |
| LastError = GetLastError(); | |
| LogError(L"Failed to create adapter", LastError); | |
| goto cleanupQuit; | |
| } | |
| Version = WintunGetRunningDriverVersion(); | |
| Log(WINTUN_LOG_INFO, L"Wintun v%u.%u loaded", (Version >> 16) & 0xff, (Version >> 0) & 0xff); | |
| InitializeUnicastIpAddressEntry(&AddressRow); | |
| WintunGetAdapterLUID(Adapter, &AddressRow.InterfaceLuid); | |
| AddressRow.Address.Ipv4.sin_family = AF_INET; | |
| AddressRow.Address.Ipv4.sin_addr.S_un.S_addr = htonl((10 << 24) | (6 << 16) | (7 << 8) | (7 << 0)); /* 10.6.7.7 */ | |
| AddressRow.OnLinkPrefixLength = 24; /* This is a /24 network */ | |
| AddressRow.DadState = IpDadStatePreferred; | |
| LastError = CreateUnicastIpAddressEntry(&AddressRow); | |
| if (LastError != ERROR_SUCCESS && LastError != ERROR_OBJECT_ALREADY_EXISTS) | |
| { | |
| LogError(L"Failed to set IP address", LastError); | |
| goto cleanupAdapter; | |
| } | |
| Session = WintunStartSession(Adapter, 0x400000); | |
| if (!Session) | |
| { | |
| LastError = LogLastError(L"Failed to create adapter"); | |
| goto cleanupAdapter; | |
| } | |
| Log(WINTUN_LOG_INFO, L"Launching threads and mangling packets..."); | |
| { | |
| size_t i; | |
| HANDLE Workers[] = { CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ReceivePackets, (LPVOID)Session, 0, NULL), | |
| CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)SendPackets, (LPVOID)Session, 0, NULL) }; | |
| if (!Workers[0] || !Workers[1]) | |
| { | |
| LastError = LogError(L"Failed to create threads", GetLastError()); | |
| goto cleanupWorkers; | |
| } | |
| WaitForMultipleObjectsEx(_countof(Workers), Workers, TRUE, INFINITE, TRUE); | |
| LastError = ERROR_SUCCESS; | |
| cleanupWorkers: | |
| HaveQuit = TRUE; | |
| SetEvent(QuitEvent); | |
| for (i = 0; i < _countof(Workers); ++i) | |
| { | |
| if (Workers[i]) | |
| { | |
| WaitForSingleObject(Workers[i], INFINITE); | |
| CloseHandle(Workers[i]); | |
| } | |
| } | |
| } | |
| WintunEndSession(Session); | |
| cleanupAdapter: | |
| WintunCloseAdapter(Adapter); | |
| cleanupQuit: | |
| SetConsoleCtrlHandler(CtrlHandler, FALSE); | |
| CloseHandle(QuitEvent); | |
| cleanupWintun: | |
| FreeLibrary(Wintun); | |
| return LastError; | |
| } |
meybe you can create adapter with WintunCreateAdapter in one process, and use WintunGetAdapterLUID to get adaper in anohter process. I have no experencies on it. just a advance.
meybe you can create adapter with
WintunCreateAdapterin one process, and useWintunGetAdapterLUIDto get adaper in anohter process. I have no experencies on it. just a advance.
Thank you for replying, I was able to get the adapter using a function from the Wintun library called WintunOpenAdapter, but when trying to start a new Wintun Session I end up getting error code 1247
An attempt was made to perform an initialization operation when initialization has already been performed
I think, there need not initialization before WintunOpenAdapter in another proess.
We need to initialize to use Wintun functions.
When I run this code, I get a slew of errors.
Thank you for the code! Is there any way to use multiple Wintun Sessions? I need to create a Wintun interface in one program and access the adapter's session from multiple programs. Is this possible?