example: rewrite and replace api's debug rundll32 functionality
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
This commit is contained in:
		
							parent
							
								
									0d7b9c7319
								
							
						
					
					
						commit
						9a937c7a49
					
				| @ -101,11 +101,6 @@ | |||||||
|     <RunCodeAnalysis>true</RunCodeAnalysis> |     <RunCodeAnalysis>true</RunCodeAnalysis> | ||||||
|     <IgnoreImportLibrary>true</IgnoreImportLibrary> |     <IgnoreImportLibrary>true</IgnoreImportLibrary> | ||||||
|   </PropertyGroup> |   </PropertyGroup> | ||||||
|   <PropertyGroup Condition="'$(Configuration)'=='Debug'" Label="Configuration"> |  | ||||||
|     <LocalDebuggerCommand>rundll32.exe</LocalDebuggerCommand> |  | ||||||
|     <LocalDebuggerCommandArguments>$(OutDir)$(TargetName)$(TargetExt),DoThingsForDebugging</LocalDebuggerCommandArguments> |  | ||||||
|     <DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor> |  | ||||||
|   </PropertyGroup> |  | ||||||
|   <ItemDefinitionGroup> |   <ItemDefinitionGroup> | ||||||
|     <ClCompile> |     <ClCompile> | ||||||
|       <PreprocessorDefinitions>_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions> |       <PreprocessorDefinitions>_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions> | ||||||
| @ -171,7 +166,6 @@ lib.exe /def:nci.def /out:"$(IntDir)nci.lib" /machine:$(PlatformTarget) /nologo | |||||||
|     <ClInclude Include="ntldr.h" /> |     <ClInclude Include="ntldr.h" /> | ||||||
|     <ClInclude Include="registry.h" /> |     <ClInclude Include="registry.h" /> | ||||||
|     <ClInclude Include="resource.h" /> |     <ClInclude Include="resource.h" /> | ||||||
|     <ClInclude Include="session.h" /> |  | ||||||
|     <ClInclude Include="wintun.h" /> |     <ClInclude Include="wintun.h" /> | ||||||
|   </ItemGroup> |   </ItemGroup> | ||||||
|   <ItemGroup> |   <ItemGroup> | ||||||
|  | |||||||
| @ -58,9 +58,6 @@ | |||||||
|     <ClInclude Include="entry.h"> |     <ClInclude Include="entry.h"> | ||||||
|       <Filter>Header Files</Filter> |       <Filter>Header Files</Filter> | ||||||
|     </ClInclude> |     </ClInclude> | ||||||
|     <ClInclude Include="session.h"> |  | ||||||
|       <Filter>Header Files</Filter> |  | ||||||
|     </ClInclude> |  | ||||||
|   </ItemGroup> |   </ItemGroup> | ||||||
|   <ItemGroup> |   <ItemGroup> | ||||||
|     <ClCompile Include="namespace.c"> |     <ClCompile Include="namespace.c"> | ||||||
|  | |||||||
| @ -5,7 +5,6 @@ | |||||||
| 
 | 
 | ||||||
| #include "adapter.h" | #include "adapter.h" | ||||||
| #include "logger.h" | #include "logger.h" | ||||||
| #include "session.h" |  | ||||||
| #include "wintun.h" | #include "wintun.h" | ||||||
| 
 | 
 | ||||||
| #include <Windows.h> | #include <Windows.h> | ||||||
| @ -17,12 +16,6 @@ | |||||||
| 
 | 
 | ||||||
| #if defined(ACCEPT_WOW64) || defined(_DEBUG) | #if defined(ACCEPT_WOW64) || defined(_DEBUG) | ||||||
| 
 | 
 | ||||||
| static |  | ||||||
| #ifndef _DEBUG |  | ||||||
| const |  | ||||||
| #endif |  | ||||||
| BOOL WriteToConsole = FALSE; |  | ||||||
| 
 |  | ||||||
| static DWORD | static DWORD | ||||||
| WriteFormatted(_In_ DWORD StdHandle, _In_z_ const WCHAR *Template, ...) | WriteFormatted(_In_ DWORD StdHandle, _In_z_ const WCHAR *Template, ...) | ||||||
| { | { | ||||||
| @ -38,10 +31,7 @@ WriteFormatted(_In_ DWORD StdHandle, _In_z_ const WCHAR *Template, ...) | |||||||
|         (void *)&FormattedMessage, |         (void *)&FormattedMessage, | ||||||
|         0, |         0, | ||||||
|         &Arguments); |         &Arguments); | ||||||
|     if (WriteToConsole) |     WriteFile(GetStdHandle(StdHandle), FormattedMessage, Len * sizeof(WCHAR), &SizeWritten, NULL); | ||||||
|         WriteConsoleW(GetStdHandle(StdHandle), FormattedMessage, Len, &SizeWritten, NULL); |  | ||||||
|     else |  | ||||||
|         WriteFile(GetStdHandle(StdHandle), FormattedMessage, Len * sizeof(WCHAR), &SizeWritten, NULL); |  | ||||||
|     LocalFree(FormattedMessage); |     LocalFree(FormattedMessage); | ||||||
|     va_end(Arguments); |     va_end(Arguments); | ||||||
|     return SizeWritten / sizeof(WCHAR); |     return SizeWritten / sizeof(WCHAR); | ||||||
| @ -158,30 +148,4 @@ VOID __stdcall DeleteDriver(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int n | |||||||
|     Done(); |     Done(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #ifdef _DEBUG |  | ||||||
| VOID __stdcall DoThingsForDebugging(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow) |  | ||||||
| { |  | ||||||
| #    pragma EXPORT |  | ||||||
|     UNREFERENCED_PARAMETER(hwnd); |  | ||||||
|     UNREFERENCED_PARAMETER(hinst); |  | ||||||
|     UNREFERENCED_PARAMETER(lpszCmdLine); |  | ||||||
|     UNREFERENCED_PARAMETER(nCmdShow); |  | ||||||
| 
 |  | ||||||
|     AllocConsole(); |  | ||||||
|     WriteToConsole = TRUE; |  | ||||||
|     Init(); |  | ||||||
|     GUID TestGuid = { 0xdeadbabe, 0xcafe, 0xbeef, { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef } }; |  | ||||||
|     WINTUN_ADAPTER *Adapter; |  | ||||||
|     BOOL RebootRequired; |  | ||||||
|     assert(WintunCreateAdapter(L"Wintun", L"Test", &TestGuid, &Adapter, &RebootRequired) == ERROR_SUCCESS); |  | ||||||
|     assert(!RebootRequired); |  | ||||||
|     TUN_SESSION *Session; |  | ||||||
|     assert(WintunStartSession(Adapter, WINTUN_MIN_RING_CAPACITY, &Session) == ERROR_SUCCESS); |  | ||||||
|     WintunEndSession(Session); |  | ||||||
|     assert(WintunDeleteAdapter(Adapter, TRUE, &RebootRequired) == ERROR_SUCCESS); |  | ||||||
|     assert(!RebootRequired); |  | ||||||
|     system("pause"); |  | ||||||
| } |  | ||||||
| #endif |  | ||||||
| 
 |  | ||||||
| #endif | #endif | ||||||
|  | |||||||
| @ -7,7 +7,6 @@ | |||||||
| #include "elevate.h" | #include "elevate.h" | ||||||
| #include "entry.h" | #include "entry.h" | ||||||
| #include "logger.h" | #include "logger.h" | ||||||
| #include "session.h" |  | ||||||
| #include "wintun.h" | #include "wintun.h" | ||||||
| #include <Windows.h> | #include <Windows.h> | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -1,59 +0,0 @@ | |||||||
| /* SPDX-License-Identifier: GPL-2.0
 |  | ||||||
|  * |  | ||||||
|  * Copyright (C) 2018-2020 WireGuard LLC. All Rights Reserved. |  | ||||||
|  */ |  | ||||||
| 
 |  | ||||||
| #pragma once |  | ||||||
| 
 |  | ||||||
| #include "wintun.h" |  | ||||||
| #include <Windows.h> |  | ||||||
| 
 |  | ||||||
| typedef struct _TUN_SESSION TUN_SESSION; |  | ||||||
| 
 |  | ||||||
| /**
 |  | ||||||
|  * @copydoc WINTUN_START_SESSION_FUNC |  | ||||||
|  */ |  | ||||||
| WINTUN_STATUS WINAPI |  | ||||||
| WintunStartSession( |  | ||||||
|     _In_ const WINTUN_ADAPTER *Adapter, |  | ||||||
|     _In_ DWORD Capacity, |  | ||||||
|     _Out_ TUN_SESSION **Session); |  | ||||||
| 
 |  | ||||||
| /**
 |  | ||||||
|  * @copydoc WINTUN_END_SESSION_FUNC |  | ||||||
|  */ |  | ||||||
| void WINAPI |  | ||||||
| WintunEndSession(_In_ TUN_SESSION *Session); |  | ||||||
| 
 |  | ||||||
| /**
 |  | ||||||
|  * @copydoc WINTUN_GET_READ_WAIT_EVENT_FUNC |  | ||||||
|  */ |  | ||||||
| HANDLE WINAPI |  | ||||||
| WintunGetReadWaitEvent(_In_ TUN_SESSION *Session); |  | ||||||
| 
 |  | ||||||
| /**
 |  | ||||||
|  * @copydoc WINTUN_RECEIVE_PACKET_FUNC |  | ||||||
|  */ |  | ||||||
| WINTUN_STATUS WINAPI |  | ||||||
| WintunReceivePacket(_In_ TUN_SESSION *Session, _Out_bytecapcount_(*PacketSize) BYTE **Packet, _Out_ DWORD *PacketSize); |  | ||||||
| 
 |  | ||||||
| /**
 |  | ||||||
|  * @copydoc WINTUN_RECEIVE_RELEASE_FUNC |  | ||||||
|  */ |  | ||||||
| void WINAPI |  | ||||||
| WintunReceiveRelease(_In_ TUN_SESSION *Session, _In_ const BYTE *Packet); |  | ||||||
| 
 |  | ||||||
| /**
 |  | ||||||
|  * @copydoc WINTUN_ALLOCATE_SEND_PACKET |  | ||||||
|  */ |  | ||||||
| WINTUN_STATUS WINAPI |  | ||||||
| WintunAllocateSendPacket( |  | ||||||
|     _In_ TUN_SESSION *Session, |  | ||||||
|     _In_ DWORD PacketSize, |  | ||||||
|     _Out_bytecapcount_(PacketSize) BYTE **Packet); |  | ||||||
| 
 |  | ||||||
| /**
 |  | ||||||
|  * @copydoc WINTUN_SEND_PACKET |  | ||||||
|  */ |  | ||||||
| void WINAPI |  | ||||||
| WintunSendPacket(_In_ TUN_SESSION *Session, _In_ const BYTE *Packet); |  | ||||||
| @ -3,16 +3,31 @@ | |||||||
|  * Copyright (C) 2018-2020 WireGuard LLC. All Rights Reserved. |  * Copyright (C) 2018-2020 WireGuard LLC. All Rights Reserved. | ||||||
|  */ |  */ | ||||||
| 
 | 
 | ||||||
| #include "../api/wintun.h" | #include <winsock2.h> | ||||||
|  | #include <Windows.h> | ||||||
|  | #include <ws2ipdef.h> | ||||||
|  | #include <iphlpapi.h> | ||||||
|  | #include <ip2string.h> | ||||||
| #include <stdarg.h> | #include <stdarg.h> | ||||||
| #include <stdio.h> | #include <stdio.h> | ||||||
|  | #include "wintun.h" | ||||||
| 
 | 
 | ||||||
| static WINTUN_GET_VERSION_FUNC WintunGetVersion; |  | ||||||
| static WINTUN_SET_LOGGER_FUNC WintunSetLogger; |  | ||||||
| static WINTUN_CREATE_ADAPTER_FUNC WintunCreateAdapter; | static WINTUN_CREATE_ADAPTER_FUNC WintunCreateAdapter; | ||||||
| static WINTUN_DELETE_ADAPTER_FUNC WintunDeleteAdapter; | static WINTUN_DELETE_ADAPTER_FUNC WintunDeleteAdapter; | ||||||
|  | static WINTUN_DELETE_DRIVER_FUNC WintunDeleteDriver; | ||||||
|  | static WINTUN_ENUM_ADAPTERS_FUNC WintunEnumAdapters; | ||||||
|  | static WINTUN_FREE_ADAPTER_FUNC WintunFreeAdapter; | ||||||
|  | static WINTUN_GET_ADAPTER_FUNC WintunGetAdapter; | ||||||
|  | static WINTUN_GET_ADAPTER_DEVICE_OBJECT_FUNC WintunGetAdapterDeviceObject; | ||||||
|  | static WINTUN_GET_ADAPTER_GUID_FUNC WintunGetAdapterGUID; | ||||||
|  | static WINTUN_GET_ADAPTER_LUID_FUNC WintunGetAdapterLUID; | ||||||
|  | static WINTUN_GET_ADAPTER_NAME_FUNC WintunGetAdapterName; | ||||||
|  | static WINTUN_SET_ADAPTER_NAME_FUNC WintunSetAdapterName; | ||||||
|  | static WINTUN_GET_VERSION_FUNC WintunGetVersion; | ||||||
|  | static WINTUN_SET_LOGGER_FUNC WintunSetLogger; | ||||||
| static WINTUN_START_SESSION_FUNC WintunStartSession; | static WINTUN_START_SESSION_FUNC WintunStartSession; | ||||||
| static WINTUN_END_SESSION_FUNC WintunEndSession; | static WINTUN_END_SESSION_FUNC WintunEndSession; | ||||||
|  | static WINTUN_GET_READ_WAIT_EVENT_FUNC WintunGetReadWaitEvent; | ||||||
| static WINTUN_RECEIVE_PACKET_FUNC WintunReceivePacket; | static WINTUN_RECEIVE_PACKET_FUNC WintunReceivePacket; | ||||||
| static WINTUN_RECEIVE_RELEASE_FUNC WintunReceiveRelease; | static WINTUN_RECEIVE_RELEASE_FUNC WintunReceiveRelease; | ||||||
| static WINTUN_ALLOCATE_SEND_PACKET_FUNC WintunAllocateSendPacket; | static WINTUN_ALLOCATE_SEND_PACKET_FUNC WintunAllocateSendPacket; | ||||||
| @ -59,9 +74,8 @@ ConsoleLogger(_In_ WINTUN_LOGGER_LEVEL Level, _In_z_ const WCHAR *LogLine) | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static DWORD | static DWORD | ||||||
| LogLastError(_In_z_ const WCHAR *Prefix) | LogError(_In_z_ const WCHAR *Prefix, _In_ DWORD Error) | ||||||
| { | { | ||||||
|     DWORD Error = GetLastError(); |  | ||||||
|     WCHAR *SystemMessage = NULL, *FormattedMessage = NULL; |     WCHAR *SystemMessage = NULL, *FormattedMessage = NULL; | ||||||
|     FormatMessageW( |     FormatMessageW( | ||||||
|         FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_MAX_WIDTH_MASK, |         FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_MAX_WIDTH_MASK, | ||||||
| @ -84,7 +98,6 @@ LogLastError(_In_z_ const WCHAR *Prefix) | |||||||
|         ConsoleLogger(WINTUN_LOG_ERR, FormattedMessage); |         ConsoleLogger(WINTUN_LOG_ERR, FormattedMessage); | ||||||
|     LocalFree(FormattedMessage); |     LocalFree(FormattedMessage); | ||||||
|     LocalFree(SystemMessage); |     LocalFree(SystemMessage); | ||||||
|     SetLastError(Error); |  | ||||||
|     return Error; |     return Error; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -100,7 +113,7 @@ Log(_In_ WINTUN_LOGGER_LEVEL Level, _In_z_ const WCHAR *Format, ...) | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static BOOL WINAPI | static BOOL WINAPI | ||||||
| CtrlHandler(DWORD CtrlType) | CtrlHandler(_In_ DWORD CtrlType) | ||||||
| { | { | ||||||
|     switch (CtrlType) |     switch (CtrlType) | ||||||
|     { |     { | ||||||
| @ -109,6 +122,7 @@ CtrlHandler(DWORD CtrlType) | |||||||
|     case CTRL_CLOSE_EVENT: |     case CTRL_CLOSE_EVENT: | ||||||
|     case CTRL_LOGOFF_EVENT: |     case CTRL_LOGOFF_EVENT: | ||||||
|     case CTRL_SHUTDOWN_EVENT: |     case CTRL_SHUTDOWN_EVENT: | ||||||
|  |         Log(WINTUN_LOG_INFO, L"Cleaning up and shutting down..."); | ||||||
|         HaveQuit = TRUE; |         HaveQuit = TRUE; | ||||||
|         SetEvent(QuitEvent); |         SetEvent(QuitEvent); | ||||||
|         return TRUE; |         return TRUE; | ||||||
| @ -116,143 +130,249 @@ CtrlHandler(DWORD CtrlType) | |||||||
|     return FALSE; |     return FALSE; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static DWORD WINAPI | static void | ||||||
| TestAdapter(_Inout_ DWORD_PTR Index) | PrintPacket(_In_ const BYTE *Packet, _In_ DWORD PacketSize) | ||||||
| { | { | ||||||
|     /* Create adapter. */ |     if (PacketSize < 20) | ||||||
|     WCHAR AdapterName[MAX_ADAPTER_NAME]; |     { | ||||||
|     _snwprintf_s( |         Log(WINTUN_LOG_INFO, L"Received packet without room for an IP header"); | ||||||
|         AdapterName, |         return; | ||||||
|         _countof(AdapterName), |     } | ||||||
|         _TRUNCATE, |     BYTE IpVersion = Packet[0] >> 4, Proto; | ||||||
|         L"test-%d.%d-%zu", |     WCHAR Src[46], Dst[46]; | ||||||
|         WINTUN_VERSION_MAJ, |     if (IpVersion == 4) | ||||||
|         WINTUN_VERSION_MIN, |     { | ||||||
|         Index); |         RtlIpv4AddressToStringW((struct in_addr *)&Packet[12], Src); | ||||||
|     const GUID AdapterGuid = { 0xeef7ebf, |         RtlIpv4AddressToStringW((struct in_addr *)&Packet[16], Dst); | ||||||
|                                WINTUN_VERSION_MAJ, |         Proto = Packet[9]; | ||||||
|                                WINTUN_VERSION_MIN, |         Packet += 20, PacketSize -= 20; | ||||||
|                                { (BYTE)Index & 0xff, 0xa, 0x33, 0xbf, 0x5c, 0x8, 0x4a, 0xc6 } }; |     } | ||||||
|  |     else if (IpVersion == 6 && PacketSize < 40) | ||||||
|  |     { | ||||||
|  |         Log(WINTUN_LOG_INFO, L"Received packet without room for an IP header"); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |     else if (IpVersion == 6) | ||||||
|  |     { | ||||||
|  |         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(BYTE *Buffer, 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(_Inout_ 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) |     while (!HaveQuit) | ||||||
|     { |     { | ||||||
|         WINTUN_ADAPTER_HANDLE Adapter; |         BYTE *Packet; | ||||||
|         BOOL RebootRequired = FALSE; |         DWORD PacketSize; | ||||||
|         DWORD Result = WintunCreateAdapter(L"Example", AdapterName, &AdapterGuid, &Adapter, &RebootRequired); |         DWORD Result = WintunReceivePacket(Session, &Packet, &PacketSize); | ||||||
|         if (Result != ERROR_SUCCESS) |         switch (Result) | ||||||
|         { |         { | ||||||
|             Log(WINTUN_LOG_ERR, L"%s adapter creation failed.\n", AdapterName); |         case ERROR_SUCCESS: | ||||||
|  |             PrintPacket(Packet, PacketSize); | ||||||
|  |             WintunReceiveRelease(Session, Packet); | ||||||
|  |             continue; | ||||||
|  |         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", Result); | ||||||
|             return Result; |             return Result; | ||||||
|         } |         } | ||||||
| 
 |  | ||||||
|         DWORDLONG WintunVersion = WintunGetVersion(); |  | ||||||
|         Log(WINTUN_LOG_INFO, |  | ||||||
|             L"%s adapter created (Wintun %d.%d.%d.%d, reboot: %d).\n", |  | ||||||
|             AdapterName, |  | ||||||
|             (WintunVersion >> 48) & 0xffff, |  | ||||||
|             (WintunVersion >> 32) & 0xffff, |  | ||||||
|             (WintunVersion >> 16) & 0xffff, |  | ||||||
|             (WintunVersion >> 0) & 0xffff, |  | ||||||
|             RebootRequired ? 1 : 0); |  | ||||||
| 
 |  | ||||||
|         WINTUN_SESSION_HANDLE Session; |  | ||||||
|         HANDLE WaitHandles[2] = { NULL, QuitEvent }; |  | ||||||
|         Result = WintunStartSession(Adapter, 0x100000, &Session, &WaitHandles[0]); |  | ||||||
|         if (Result != ERROR_SUCCESS) |  | ||||||
|         { |  | ||||||
|             Log(WINTUN_LOG_ERR, L"%s session creation failed.\n", AdapterName); |  | ||||||
|             goto cleanupAdapter; |  | ||||||
|         } |  | ||||||
|         while (!HaveQuit) |  | ||||||
|         { |  | ||||||
|             BYTE *Packet; |  | ||||||
|             DWORD PacketSize; |  | ||||||
|             Result = WintunReceivePacket(Session, &Packet, &PacketSize); |  | ||||||
|             switch (Result) |  | ||||||
|             { |  | ||||||
|             case ERROR_SUCCESS: |  | ||||||
|                 // TODO: Process packet.
 |  | ||||||
|                 WintunReceiveRelease(Session, Packet); |  | ||||||
|                 continue; |  | ||||||
|             case ERROR_NO_MORE_ITEMS: |  | ||||||
|                 if (WaitForMultipleObjects(_countof(WaitHandles), WaitHandles, FALSE, INFINITE) == WAIT_OBJECT_0) |  | ||||||
|                     continue; |  | ||||||
|                 goto cleanupSession; |  | ||||||
|             } |  | ||||||
|             Log(WINTUN_LOG_ERR, L"%s packet read failed (Code 0x%08X).\n", AdapterName, Result); |  | ||||||
|             goto cleanupSession; |  | ||||||
|         } |  | ||||||
|     cleanupSession: |  | ||||||
|         WintunEndSession(Session); |  | ||||||
|     cleanupAdapter: |  | ||||||
|         WintunDeleteAdapter(Adapter, TRUE, &RebootRequired); |  | ||||||
|     } |     } | ||||||
|     return ERROR_SUCCESS; |     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, &Packet); | ||||||
|  |         MakeICMP(Packet); | ||||||
|  |         WintunSendPacket(Session, Packet); | ||||||
|  | 
 | ||||||
|  |         switch (WaitForSingleObject(QuitEvent, 1000 /* 1 second */)) | ||||||
|  |         { | ||||||
|  |         case WAIT_ABANDONED: | ||||||
|  |         case WAIT_OBJECT_0: | ||||||
|  |             return ERROR_SUCCESS; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     return ERROR_SUCCESS; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 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, Type) ((Name = (Type)GetProcAddress(Wintun, #Name)) == NULL) | ||||||
|  |     if (X(WintunCreateAdapter, WINTUN_CREATE_ADAPTER_FUNC) || X(WintunDeleteAdapter, WINTUN_DELETE_ADAPTER_FUNC) || | ||||||
|  |         X(WintunDeleteDriver, WINTUN_DELETE_DRIVER_FUNC) || X(WintunEnumAdapters, WINTUN_ENUM_ADAPTERS_FUNC) || | ||||||
|  |         X(WintunFreeAdapter, WINTUN_FREE_ADAPTER_FUNC) || X(WintunGetAdapter, WINTUN_GET_ADAPTER_FUNC) || | ||||||
|  |         X(WintunGetAdapterDeviceObject, WINTUN_GET_ADAPTER_DEVICE_OBJECT_FUNC) || | ||||||
|  |         X(WintunGetAdapterGUID, WINTUN_GET_ADAPTER_GUID_FUNC) || | ||||||
|  |         X(WintunGetAdapterLUID, WINTUN_GET_ADAPTER_LUID_FUNC) || | ||||||
|  |         X(WintunGetAdapterName, WINTUN_GET_ADAPTER_NAME_FUNC) || | ||||||
|  |         X(WintunSetAdapterName, WINTUN_SET_ADAPTER_NAME_FUNC) || X(WintunGetVersion, WINTUN_GET_VERSION_FUNC) || | ||||||
|  |         X(WintunSetLogger, WINTUN_SET_LOGGER_FUNC) || X(WintunStartSession, WINTUN_START_SESSION_FUNC) || | ||||||
|  |         X(WintunEndSession, WINTUN_END_SESSION_FUNC) || X(WintunGetReadWaitEvent, WINTUN_GET_READ_WAIT_EVENT_FUNC) || | ||||||
|  |         X(WintunReceivePacket, WINTUN_RECEIVE_PACKET_FUNC) || X(WintunReceiveRelease, WINTUN_RECEIVE_RELEASE_FUNC) || | ||||||
|  |         X(WintunAllocateSendPacket, WINTUN_ALLOCATE_SEND_PACKET_FUNC) || X(WintunSendPacket, WINTUN_SEND_PACKET_FUNC)) | ||||||
|  | #undef X | ||||||
|  |     { | ||||||
|  |         DWORD Result = GetLastError(); | ||||||
|  |         FreeLibrary(Wintun); | ||||||
|  |         SetLastError(Result); | ||||||
|  |         return NULL; | ||||||
|  |     } | ||||||
|  |     SetLastError(ERROR_SUCCESS); | ||||||
|  |     return Wintun; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| int | int | ||||||
| main(void) | main(void) | ||||||
| { | { | ||||||
|     Log(WINTUN_LOG_INFO, L"Wintun Test v%d.%d\n", WINTUN_VERSION_MAJ, WINTUN_VERSION_MIN); |     HMODULE Wintun = InitializeWintun(); | ||||||
| 
 |  | ||||||
|     HMODULE Wintun = |  | ||||||
|         LoadLibraryExW(L"wintun.dll", NULL, LOAD_LIBRARY_SEARCH_APPLICATION_DIR | LOAD_LIBRARY_SEARCH_SYSTEM32); |  | ||||||
|     if (!Wintun) |     if (!Wintun) | ||||||
|         return LogLastError(L"Failed to load wintun.dll"); |         return LogError(L"Failed to initialize Wintun", GetLastError()); | ||||||
|     DWORD Result; |     WintunSetLogger(ConsoleLogger); | ||||||
|     if ((WintunGetVersion = (WINTUN_GET_VERSION_FUNC)GetProcAddress(Wintun, "WintunGetVersion")) == NULL || |     Log(WINTUN_LOG_INFO, L"Wintun library loaded"); | ||||||
|         (WintunSetLogger = (WINTUN_SET_LOGGER_FUNC)GetProcAddress(Wintun, "WintunSetLogger")) == NULL || |  | ||||||
|         (WintunCreateAdapter = (WINTUN_CREATE_ADAPTER_FUNC)GetProcAddress(Wintun, "WintunCreateAdapter")) == NULL || |  | ||||||
|         (WintunDeleteAdapter = (WINTUN_DELETE_ADAPTER_FUNC)GetProcAddress(Wintun, "WintunDeleteAdapter")) == NULL || |  | ||||||
|         (WintunStartSession = (WINTUN_START_SESSION_FUNC)GetProcAddress(Wintun, "WintunStartSession")) == NULL || |  | ||||||
|         (WintunEndSession = (WINTUN_END_SESSION_FUNC)GetProcAddress(Wintun, "WintunEndSession")) == NULL || |  | ||||||
|         (WintunReceivePacket = (WINTUN_RECEIVE_PACKET_FUNC)GetProcAddress(Wintun, "WintunReceivePacket")) == NULL || |  | ||||||
|         (WintunReceiveRelease = (WINTUN_RECEIVE_RELEASE_FUNC)GetProcAddress(Wintun, "WintunReceiveRelease")) == NULL || |  | ||||||
|         (WintunAllocateSendPacket = |  | ||||||
|              (WINTUN_ALLOCATE_SEND_PACKET_FUNC)GetProcAddress(Wintun, "WintunAllocateSendPacket")) == NULL || |  | ||||||
|         (WintunSendPacket = (WINTUN_SEND_PACKET_FUNC)GetProcAddress(Wintun, "WintunSendPacket")) == NULL) |  | ||||||
|     { |  | ||||||
|         Result = LogLastError(L"Failed to get wintun.dll entries"); |  | ||||||
|         goto cleanupWintun; |  | ||||||
|     } |  | ||||||
| 
 | 
 | ||||||
|  |     DWORD Result; | ||||||
|     HaveQuit = FALSE; |     HaveQuit = FALSE; | ||||||
|     QuitEvent = CreateEventW(NULL, TRUE, FALSE, NULL); |     QuitEvent = CreateEventW(NULL, TRUE, FALSE, NULL); | ||||||
|     if (!QuitEvent) |     if (!QuitEvent) | ||||||
|     { |     { | ||||||
|         Result = LogLastError(L"Failed to create event"); |         Result = LogError(L"Failed to create event", GetLastError()); | ||||||
|         goto cleanupWintun; |         goto cleanupWintun; | ||||||
|     } |     } | ||||||
|     WintunSetLogger(ConsoleLogger); |  | ||||||
|     if (!SetConsoleCtrlHandler(CtrlHandler, TRUE)) |     if (!SetConsoleCtrlHandler(CtrlHandler, TRUE)) | ||||||
|     { |     { | ||||||
|         Result = LogLastError(L"Failed to set console handler"); |         Result = LogError(L"Failed to set console handler", GetLastError()); | ||||||
|         goto cleanupQuit; |         goto cleanupQuit; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     HANDLE Workers[MAXIMUM_WAIT_OBJECTS] = { 0 }; |     GUID ExampleGuid = { 0xdeadbabe, 0xcafe, 0xbeef, { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef } }; | ||||||
|     for (size_t i = 0; i < _countof(Workers); ++i) |     WINTUN_ADAPTER_HANDLE Adapter; | ||||||
|         if (!Workers[i]) |     Result = WintunGetAdapter(L"Example", L"Demo", &Adapter); | ||||||
|         { |     if (Result != ERROR_SUCCESS) | ||||||
|             Workers[i] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)TestAdapter, (LPVOID)i, 0, NULL); |         Result = WintunCreateAdapter(L"Example", L"Demo", &ExampleGuid, &Adapter, NULL); | ||||||
|             if (!Workers[i]) |     if (Result != ERROR_SUCCESS) | ||||||
|             { |     { | ||||||
|                 Result = LogLastError(L"Failed to create thread"); |         LogError(L"Failed to create adapter", Result); | ||||||
|                 goto cleanupWorkers; |         goto cleanupQuit; | ||||||
|             } |     } | ||||||
|         } | 
 | ||||||
|  |     DWORDLONG Version = WintunGetVersion(); | ||||||
|  |     Log(WINTUN_LOG_INFO, | ||||||
|  |         L"Wintun v%d.%d.%d.%d loaded", | ||||||
|  |         (Version >> 48) & 0xff, | ||||||
|  |         (Version >> 32) & 0xff, | ||||||
|  |         (Version >> 16) & 0xff, | ||||||
|  |         (Version >> 0) & 0xff, | ||||||
|  |         WINTUN_VERSION_MIN); | ||||||
|  | 
 | ||||||
|  |     MIB_UNICASTIPADDRESS_ROW AddressRow; | ||||||
|  |     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 */ | ||||||
|  |     Result = CreateUnicastIpAddressEntry(&AddressRow); | ||||||
|  |     if (Result != ERROR_SUCCESS) | ||||||
|  |     { | ||||||
|  |         LogError(L"Failed to set IP address", Result); | ||||||
|  |         goto cleanupAdapter; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     WINTUN_SESSION_HANDLE Session; | ||||||
|  |     Result = WintunStartSession(Adapter, 0x40000, &Session); | ||||||
|  |     if (Result != ERROR_SUCCESS) | ||||||
|  |     { | ||||||
|  |         LogError(L"Failed to create adapter", Result); | ||||||
|  |         goto cleanupAdapter; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     Log(WINTUN_LOG_INFO, L"Launching threads and mangling packets..."); | ||||||
|  | 
 | ||||||
|  |     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]) | ||||||
|  |     { | ||||||
|  |         Result = LogError(L"Failed to create threads", GetLastError()); | ||||||
|  |         goto cleanupWorkers; | ||||||
|  |     } | ||||||
|     WaitForMultipleObjectsEx(_countof(Workers), Workers, TRUE, INFINITE, TRUE); |     WaitForMultipleObjectsEx(_countof(Workers), Workers, TRUE, INFINITE, TRUE); | ||||||
|     Result = ERROR_SUCCESS; |     Result = ERROR_SUCCESS; | ||||||
|  | 
 | ||||||
| cleanupWorkers: | cleanupWorkers: | ||||||
|     HaveQuit = TRUE; |     HaveQuit = TRUE; | ||||||
|     SetEvent(QuitEvent); |     SetEvent(QuitEvent); | ||||||
|     for (size_t i = 0; i < _countof(Workers); ++i) |     for (size_t i = 0; i < _countof(Workers); ++i) | ||||||
|  |     { | ||||||
|         if (Workers[i]) |         if (Workers[i]) | ||||||
|         { |         { | ||||||
|             WaitForSingleObject(Workers[i], INFINITE); |             WaitForSingleObject(Workers[i], INFINITE); | ||||||
|             CloseHandle(Workers[i]); |             CloseHandle(Workers[i]); | ||||||
|         } |         } | ||||||
|     SetConsoleCtrlHandler(CtrlHandler, FALSE); |     } | ||||||
|  |     WintunEndSession(Session); | ||||||
|  | cleanupAdapter: | ||||||
|  |     WintunDeleteAdapter(Adapter, FALSE, NULL); | ||||||
|  |     WintunFreeAdapter(Adapter); | ||||||
| cleanupQuit: | cleanupQuit: | ||||||
|  |     SetConsoleCtrlHandler(CtrlHandler, FALSE); | ||||||
|     CloseHandle(QuitEvent); |     CloseHandle(QuitEvent); | ||||||
| cleanupWintun: | cleanupWintun: | ||||||
|     FreeLibrary(Wintun); |     FreeLibrary(Wintun); | ||||||
|  | |||||||
| @ -52,17 +52,14 @@ | |||||||
|   </PropertyGroup> |   </PropertyGroup> | ||||||
|   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> |   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> | ||||||
|   <PropertyGroup Condition="'$(Configuration)'=='Debug'" Label="Configuration"> |   <PropertyGroup Condition="'$(Configuration)'=='Debug'" Label="Configuration"> | ||||||
|     <ConfigurationType>Application</ConfigurationType> |  | ||||||
|     <UseDebugLibraries>true</UseDebugLibraries> |     <UseDebugLibraries>true</UseDebugLibraries> | ||||||
|     <PlatformToolset>v142</PlatformToolset> |  | ||||||
|     <CharacterSet>Unicode</CharacterSet> |  | ||||||
|     <SpectreMitigation>false</SpectreMitigation> |  | ||||||
|   </PropertyGroup> |   </PropertyGroup> | ||||||
|   <PropertyGroup Condition="'$(Configuration)'=='Release'" Label="Configuration"> |   <PropertyGroup Condition="'$(Configuration)'=='Release'" Label="Configuration"> | ||||||
|     <ConfigurationType>Application</ConfigurationType> |  | ||||||
|     <UseDebugLibraries>false</UseDebugLibraries> |  | ||||||
|     <PlatformToolset>v142</PlatformToolset> |  | ||||||
|     <WholeProgramOptimization>true</WholeProgramOptimization> |     <WholeProgramOptimization>true</WholeProgramOptimization> | ||||||
|  |   </PropertyGroup> | ||||||
|  |   <PropertyGroup Label="Configuration"> | ||||||
|  |     <ConfigurationType>Application</ConfigurationType> | ||||||
|  |     <PlatformToolset>v142</PlatformToolset> | ||||||
|     <CharacterSet>Unicode</CharacterSet> |     <CharacterSet>Unicode</CharacterSet> | ||||||
|     <SpectreMitigation>false</SpectreMitigation> |     <SpectreMitigation>false</SpectreMitigation> | ||||||
|   </PropertyGroup> |   </PropertyGroup> | ||||||
| @ -107,7 +104,15 @@ | |||||||
|       <LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration> |       <LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration> | ||||||
|     </Link> |     </Link> | ||||||
|   </ItemDefinitionGroup> |   </ItemDefinitionGroup> | ||||||
|  |   <ItemDefinitionGroup> | ||||||
|  |     <Link> | ||||||
|  |       <AdditionalDependencies>iphlpapi.lib;kernel32.lib;ntdll.lib;ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies> | ||||||
|  |     </Link> | ||||||
|  |     <ClCompile> | ||||||
|  |       <AdditionalIncludeDirectories>..\api</AdditionalIncludeDirectories> | ||||||
|  |     </ClCompile> | ||||||
|  |   </ItemDefinitionGroup> | ||||||
|   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> |   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> | ||||||
|   <ImportGroup Label="ExtensionTargets"> |   <ImportGroup Label="ExtensionTargets"> | ||||||
|   </ImportGroup> |   </ImportGroup> | ||||||
| </Project> | </Project> | ||||||
| @ -5,14 +5,6 @@ | |||||||
|       <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier> |       <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier> | ||||||
|       <Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions> |       <Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions> | ||||||
|     </Filter> |     </Filter> | ||||||
|     <Filter Include="Header Files"> |  | ||||||
|       <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier> |  | ||||||
|       <Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions> |  | ||||||
|     </Filter> |  | ||||||
|     <Filter Include="Resource Files"> |  | ||||||
|       <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier> |  | ||||||
|       <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions> |  | ||||||
|     </Filter> |  | ||||||
|   </ItemGroup> |   </ItemGroup> | ||||||
|   <ItemGroup> |   <ItemGroup> | ||||||
|     <ClCompile Include="example.c"> |     <ClCompile Include="example.c"> | ||||||
|  | |||||||
| @ -64,13 +64,21 @@ Global | |||||||
| 		{F7679B65-2FEC-469A-8BAC-B07BF4439422}.Release|x86.ActiveCfg = Release|Win32 | 		{F7679B65-2FEC-469A-8BAC-B07BF4439422}.Release|x86.ActiveCfg = Release|Win32 | ||||||
| 		{F7679B65-2FEC-469A-8BAC-B07BF4439422}.Release|x86.Build.0 = Release|Win32 | 		{F7679B65-2FEC-469A-8BAC-B07BF4439422}.Release|x86.Build.0 = Release|Win32 | ||||||
| 		{2ABAC503-245D-4F53-85C5-0F844DEF738B}.Debug|amd64.ActiveCfg = Debug|x64 | 		{2ABAC503-245D-4F53-85C5-0F844DEF738B}.Debug|amd64.ActiveCfg = Debug|x64 | ||||||
|  | 		{2ABAC503-245D-4F53-85C5-0F844DEF738B}.Debug|amd64.Build.0 = Debug|x64 | ||||||
| 		{2ABAC503-245D-4F53-85C5-0F844DEF738B}.Debug|arm.ActiveCfg = Debug|ARM | 		{2ABAC503-245D-4F53-85C5-0F844DEF738B}.Debug|arm.ActiveCfg = Debug|ARM | ||||||
|  | 		{2ABAC503-245D-4F53-85C5-0F844DEF738B}.Debug|arm.Build.0 = Debug|ARM | ||||||
| 		{2ABAC503-245D-4F53-85C5-0F844DEF738B}.Debug|arm64.ActiveCfg = Debug|ARM64 | 		{2ABAC503-245D-4F53-85C5-0F844DEF738B}.Debug|arm64.ActiveCfg = Debug|ARM64 | ||||||
|  | 		{2ABAC503-245D-4F53-85C5-0F844DEF738B}.Debug|arm64.Build.0 = Debug|ARM64 | ||||||
| 		{2ABAC503-245D-4F53-85C5-0F844DEF738B}.Debug|x86.ActiveCfg = Debug|Win32 | 		{2ABAC503-245D-4F53-85C5-0F844DEF738B}.Debug|x86.ActiveCfg = Debug|Win32 | ||||||
|  | 		{2ABAC503-245D-4F53-85C5-0F844DEF738B}.Debug|x86.Build.0 = Debug|Win32 | ||||||
| 		{2ABAC503-245D-4F53-85C5-0F844DEF738B}.Release|amd64.ActiveCfg = Release|x64 | 		{2ABAC503-245D-4F53-85C5-0F844DEF738B}.Release|amd64.ActiveCfg = Release|x64 | ||||||
|  | 		{2ABAC503-245D-4F53-85C5-0F844DEF738B}.Release|amd64.Build.0 = Release|x64 | ||||||
| 		{2ABAC503-245D-4F53-85C5-0F844DEF738B}.Release|arm.ActiveCfg = Release|ARM | 		{2ABAC503-245D-4F53-85C5-0F844DEF738B}.Release|arm.ActiveCfg = Release|ARM | ||||||
|  | 		{2ABAC503-245D-4F53-85C5-0F844DEF738B}.Release|arm.Build.0 = Release|ARM | ||||||
| 		{2ABAC503-245D-4F53-85C5-0F844DEF738B}.Release|arm64.ActiveCfg = Release|ARM64 | 		{2ABAC503-245D-4F53-85C5-0F844DEF738B}.Release|arm64.ActiveCfg = Release|ARM64 | ||||||
|  | 		{2ABAC503-245D-4F53-85C5-0F844DEF738B}.Release|arm64.Build.0 = Release|ARM64 | ||||||
| 		{2ABAC503-245D-4F53-85C5-0F844DEF738B}.Release|x86.ActiveCfg = Release|Win32 | 		{2ABAC503-245D-4F53-85C5-0F844DEF738B}.Release|x86.ActiveCfg = Release|Win32 | ||||||
|  | 		{2ABAC503-245D-4F53-85C5-0F844DEF738B}.Release|x86.Build.0 = Release|Win32 | ||||||
| 	EndGlobalSection | 	EndGlobalSection | ||||||
| 	GlobalSection(SolutionProperties) = preSolution | 	GlobalSection(SolutionProperties) = preSolution | ||||||
| 		HideSolutionNode = FALSE | 		HideSolutionNode = FALSE | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user