api: upgrade

Signed-off-by: Simon Rozman <simon@rozman.si>
This commit is contained in:
Simon Rozman 2021-07-28 20:20:09 +02:00
parent d61007297d
commit d675646ab8
20 changed files with 1539 additions and 1383 deletions

File diff suppressed because it is too large Load Diff

View File

@ -13,58 +13,96 @@
#define MAX_INSTANCE_ID MAX_PATH /* TODO: Is MAX_PATH always enough? */
#define WINTUN_HWID L"Wintun"
void
AdapterInit(void);
/**
* Wintun adapter descriptor.
*/
typedef struct _WINTUN_ADAPTER
{
HDEVINFO DevInfo;
SP_DEVINFO_DATA DevInfoData;
GUID CfgInstanceID;
WCHAR DevInstanceID[MAX_INSTANCE_ID];
DWORD LuidIndex;
DWORD IfType;
DWORD IfIndex;
WCHAR Pool[WINTUN_MAX_POOL];
} WINTUN_ADAPTER;
/**
* @copydoc WINTUN_FREE_ADAPTER_FUNC
*/
void WINAPI
WintunFreeAdapter(_In_ WINTUN_ADAPTER *Adapter);
WINTUN_FREE_ADAPTER_FUNC_IMPL WintunFreeAdapter;
/**
* @copydoc WINTUN_CREATE_ADAPTER_FUNC
*/
_Return_type_success_(return != NULL) WINTUN_ADAPTER *WINAPI WintunCreateAdapter(
_In_z_ const WCHAR *Pool,
_In_z_ const WCHAR *Name,
_In_opt_ const GUID *RequestedGUID,
_Out_opt_ BOOL *RebootRequired);
WINTUN_CREATE_ADAPTER_FUNC_IMPL WintunCreateAdapter;
/**
* @copydoc WINTUN_OPEN_ADAPTER_FUNC
*/
WINTUN_OPEN_ADAPTER_FUNC_IMPL WintunOpenAdapter;
/**
* @copydoc WINTUN_DELETE_ADAPTER_FUNC
*/
_Return_type_success_(return != FALSE) BOOL WINAPI WintunDeleteAdapter(
_In_ const WINTUN_ADAPTER *Adapter,
_In_ BOOL ForceCloseSessions,
_Out_opt_ BOOL *RebootRequired);
WINTUN_DELETE_ADAPTER_FUNC_IMPL WintunDeleteAdapter;
/**
* @copydoc WINTUN_ENUM_ADAPTERS_FUNC
*/
WINTUN_ENUM_ADAPTERS_FUNC_IMPL WintunEnumAdapters;
/**
* @copydoc WINTUN_DELETE_POOL_DRIVER_FUNC
*/
_Return_type_success_(return != FALSE) BOOL WINAPI
WintunDeletePoolDriver(_In_z_ const WCHAR *Pool, _Out_opt_ BOOL *RebootRequired);
WINTUN_DELETE_POOL_DRIVER_FUNC_IMPL WintunDeletePoolDriver;
/**
* @copydoc WINTUN_GET_ADAPTER_LUID_FUNC
*/
WINTUN_GET_ADAPTER_LUID_FUNC_IMPL WintunGetAdapterLUID;
/**
* @copydoc WINTUN_GET_ADAPTER_NAME_FUNC
*/
WINTUN_GET_ADAPTER_NAME_FUNC_IMPL WintunGetAdapterName;
/**
* @copydoc WINTUN_SET_ADAPTER_NAME_FUNC
*/
WINTUN_SET_ADAPTER_NAME_FUNC_IMPL WintunSetAdapterName;
/**
* @copydoc WINTUN_GET_RUNNING_DRIVER_VERSION_FUNC
*/
WINTUN_GET_RUNNING_DRIVER_VERSION_FUNC_IMPL WintunGetRunningDriverVersion;
/**
* Returns a handle to the adapter device object.
*
* @param Adapter Adapter handle obtained with WintunOpenAdapter or WintunCreateAdapter.
*
* @return If the function succeeds, the return value is adapter device object handle. Must be released with
* CloseHandle. If the function fails, the return value is INVALID_HANDLE_VALUE. To get extended error
* @return If the function succeeds, the return value is adapter device object handle.
* If the function fails, the return value is INVALID_HANDLE_VALUE. To get extended error
* information, call GetLastError.
*/
_Return_type_success_(return != INVALID_HANDLE_VALUE) HANDLE WINAPI
AdapterOpenDeviceObject(_In_ const WINTUN_ADAPTER *Adapter);
_Return_type_success_(return != INVALID_HANDLE_VALUE)
HANDLE WINAPI
AdapterOpenDeviceObject(_In_ const WINTUN_ADAPTER *Adapter);
/**
* Returns an adapter object based on a devnode instance ID.
*
* @param Pool Pool name of adapter object to be opened.
*
* @param DevInstanceID Instance ID of devnode for opening adapter.
*
* @return If the function succeeds, the return value is adapter object..
* If the function fails, the return value is NULL. To get extended error
* information, call GetLastError.
*/
_Must_inspect_result_
_Return_type_success_(return != NULL)
_Post_maybenull_
WINTUN_ADAPTER *
AdapterOpenFromDevInstanceId(_In_z_ LPCWSTR Pool, _In_z_ LPCWSTR DevInstanceID);

View File

@ -53,15 +53,13 @@
<ItemGroup>
<ClInclude Include="main.h" />
<ClInclude Include="adapter.h" />
<ClInclude Include="rundll32_i.c">
<ExcludedFromBuild>true</ExcludedFromBuild>
</ClInclude>
<ClInclude Include="logger.h" />
<ClInclude Include="namespace.h" />
<ClInclude Include="nci.h" />
<ClInclude Include="ntdll.h" />
<ClInclude Include="registry.h" />
<ClInclude Include="resource.h" />
<ClInclude Include="rundll32.h" />
<ClInclude Include="wintun.h" />
</ItemGroup>
<ItemGroup>

View File

@ -4,6 +4,7 @@
*/
#include "logger.h"
#include "adapter.h"
#include "ntdll.h"
#include <Windows.h>
#include <winternl.h>
@ -11,17 +12,16 @@
#include <stdlib.h>
static BOOL CALLBACK
NopLogger(_In_ WINTUN_LOGGER_LEVEL Level, _In_z_ const WCHAR *LogLine)
NopLogger(_In_ WINTUN_LOGGER_LEVEL Level, _In_z_ LPCWSTR LogLine)
{
UNREFERENCED_PARAMETER(Level);
UNREFERENCED_PARAMETER(LogLine);
return TRUE;
}
WINTUN_LOGGER_CALLBACK Logger = NopLogger;
void CALLBACK
WintunSetLogger(_In_ WINTUN_LOGGER_CALLBACK NewLogger)
_Use_decl_annotations_
VOID WINAPI
WintunSetLogger(WINTUN_LOGGER_CALLBACK NewLogger)
{
if (!NewLogger)
NewLogger = NopLogger;
@ -29,14 +29,15 @@ WintunSetLogger(_In_ WINTUN_LOGGER_CALLBACK NewLogger)
}
static VOID
StrTruncate(_Inout_count_(StrChars) WCHAR *Str, _In_ SIZE_T StrChars)
StrTruncate(_Inout_count_(StrChars) LPWSTR Str, _In_ SIZE_T StrChars)
{
Str[StrChars - 2] = L'\u2026'; /* Horizontal Ellipsis */
Str[StrChars - 1] = 0;
}
_Post_equals_last_error_ DWORD
LoggerLog(_In_ WINTUN_LOGGER_LEVEL Level, _In_z_ const WCHAR *Function, _In_z_ const WCHAR *LogLine)
_Use_decl_annotations_
DWORD
LoggerLog(WINTUN_LOGGER_LEVEL Level, LPCWSTR Function, LPCWSTR LogLine)
{
DWORD LastError = GetLastError();
if (Function)
@ -52,12 +53,9 @@ LoggerLog(_In_ WINTUN_LOGGER_LEVEL Level, _In_z_ const WCHAR *Function, _In_z_ c
return LastError;
}
_Post_equals_last_error_ DWORD
LoggerLogV(
_In_ WINTUN_LOGGER_LEVEL Level,
_In_z_ const WCHAR *Function,
_In_z_ _Printf_format_string_ const WCHAR *Format,
_In_ va_list Args)
_Use_decl_annotations_
DWORD
LoggerLogV(WINTUN_LOGGER_LEVEL Level, LPCWSTR Function, LPCWSTR Format, va_list Args)
{
DWORD LastError = GetLastError();
WCHAR LogLine[0x400];
@ -71,16 +69,17 @@ LoggerLogV(
return LastError;
}
_Post_equals_last_error_ DWORD
LoggerError(_In_ DWORD Error, _In_z_ const WCHAR *Function, _In_z_ const WCHAR *Prefix)
_Use_decl_annotations_
DWORD
LoggerError(DWORD Error, LPCWSTR Function, LPCWSTR Prefix)
{
WCHAR *SystemMessage = NULL, *FormattedMessage = NULL;
LPWSTR 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),
(void *)&SystemMessage,
(VOID *)&SystemMessage,
0,
NULL);
FormatMessageW(
@ -89,7 +88,7 @@ LoggerError(_In_ DWORD Error, _In_z_ const WCHAR *Function, _In_z_ const WCHAR *
SystemMessage ? L"%4: %1: %3(Code 0x%2!08X!)" : L"%4: %1: Code 0x%2!08X!",
0,
0,
(void *)&FormattedMessage,
(VOID *)&FormattedMessage,
0,
(va_list *)(DWORD_PTR[]){ (DWORD_PTR)Prefix, (DWORD_PTR)Error, (DWORD_PTR)SystemMessage, (DWORD_PTR)Function });
if (FormattedMessage)
@ -99,12 +98,9 @@ LoggerError(_In_ DWORD Error, _In_z_ const WCHAR *Function, _In_z_ const WCHAR *
return Error;
}
_Post_equals_last_error_ DWORD
LoggerErrorV(
_In_ DWORD Error,
_In_z_ const WCHAR *Function,
_In_z_ _Printf_format_string_ const WCHAR *Format,
_In_ va_list Args)
_Use_decl_annotations_
DWORD
LoggerErrorV(DWORD Error, LPCWSTR Function, LPCWSTR Format, va_list Args)
{
WCHAR Prefix[0x400];
if (_vsnwprintf_s(Prefix, _countof(Prefix), _TRUNCATE, Format, Args) == -1)
@ -112,13 +108,14 @@ LoggerErrorV(
return LoggerError(Error, Function, Prefix);
}
_Use_decl_annotations_
VOID
LoggerGetRegistryKeyPath(_In_ HKEY Key, _Out_cap_c_(MAX_REG_PATH) WCHAR *Path)
LoggerGetRegistryKeyPath(HKEY Key, LPWSTR Path)
{
DWORD LastError = GetLastError();
if (Key == NULL)
{
wcscpy_s(Path, MAX_REG_PATH, L"<null>");
wcsncpy_s(Path, MAX_REG_PATH, L"<null>", _TRUNCATE);
goto out;
}
if (_snwprintf_s(Path, MAX_REG_PATH, _TRUNCATE, L"0x%p", Key) == -1)

View File

@ -9,6 +9,7 @@
#include "main.h"
#include "registry.h"
#include <Windows.h>
#include <intsafe.h>
#include <stdarg.h>
#include <wchar.h>
@ -17,25 +18,23 @@ extern WINTUN_LOGGER_CALLBACK Logger;
/**
* @copydoc WINTUN_SET_LOGGER_FUNC
*/
void WINAPI
WintunSetLogger(_In_ WINTUN_LOGGER_CALLBACK NewLogger);
WINTUN_SET_LOGGER_FUNC_IMPL WintunSetLogger;
_Post_equals_last_error_ DWORD
LoggerLog(_In_ WINTUN_LOGGER_LEVEL Level, _In_z_ const WCHAR *Function, _In_z_ const WCHAR *LogLine);
_Post_equals_last_error_
DWORD
LoggerLog(_In_ WINTUN_LOGGER_LEVEL Level, _In_z_ LPCWSTR Function, _In_z_ LPCWSTR LogLine);
_Post_equals_last_error_ DWORD
_Post_equals_last_error_
DWORD
LoggerLogV(
_In_ WINTUN_LOGGER_LEVEL Level,
_In_z_ const WCHAR *Function,
_In_z_ _Printf_format_string_ const WCHAR *Format,
_In_z_ LPCWSTR Function,
_In_z_ _Printf_format_string_ LPCWSTR Format,
_In_ va_list Args);
static inline _Post_equals_last_error_ DWORD
LoggerLogFmt(
_In_ WINTUN_LOGGER_LEVEL Level,
_In_z_ const WCHAR *Function,
_In_z_ _Printf_format_string_ const WCHAR *Format,
...)
_Post_equals_last_error_
static inline DWORD
LoggerLogFmt(_In_ WINTUN_LOGGER_LEVEL Level, _In_z_ LPCWSTR Function, _In_z_ _Printf_format_string_ LPCWSTR Format, ...)
{
va_list Args;
va_start(Args, Format);
@ -44,18 +43,21 @@ LoggerLogFmt(
return LastError;
}
_Post_equals_last_error_ DWORD
LoggerError(_In_ DWORD Error, _In_z_ const WCHAR *Function, _In_z_ const WCHAR *Prefix);
_Post_equals_last_error_
DWORD
LoggerError(_In_ DWORD Error, _In_z_ LPCWSTR Function, _In_z_ LPCWSTR Prefix);
_Post_equals_last_error_ DWORD
_Post_equals_last_error_
DWORD
LoggerErrorV(
_In_ DWORD Error,
_In_z_ const WCHAR *Function,
_In_z_ _Printf_format_string_ const WCHAR *Format,
_In_z_ LPCWSTR Function,
_In_z_ _Printf_format_string_ LPCWSTR Format,
_In_ va_list Args);
static inline _Post_equals_last_error_ DWORD
LoggerErrorFmt(_In_ DWORD Error, _In_z_ const WCHAR *Function, _In_z_ _Printf_format_string_ const WCHAR *Format, ...)
_Post_equals_last_error_
static inline DWORD
LoggerErrorFmt(_In_ DWORD Error, _In_z_ LPCWSTR Function, _In_z_ _Printf_format_string_ LPCWSTR Format, ...)
{
va_list Args;
va_start(Args, Format);
@ -64,8 +66,9 @@ LoggerErrorFmt(_In_ DWORD Error, _In_z_ const WCHAR *Function, _In_z_ _Printf_fo
return LastError;
}
static inline _Post_equals_last_error_ DWORD
LoggerLastErrorV(_In_z_ const WCHAR *Function, _In_z_ _Printf_format_string_ const WCHAR *Format, _In_ va_list Args)
_Post_equals_last_error_
static inline DWORD
LoggerLastErrorV(_In_z_ LPCWSTR Function, _In_z_ _Printf_format_string_ LPCWSTR Format, _In_ va_list Args)
{
DWORD LastError = GetLastError();
LoggerErrorV(LastError, Function, Format, Args);
@ -73,8 +76,9 @@ LoggerLastErrorV(_In_z_ const WCHAR *Function, _In_z_ _Printf_format_string_ con
return LastError;
}
static inline _Post_equals_last_error_ DWORD
LoggerLastErrorFmt(_In_z_ const WCHAR *Function, _In_z_ _Printf_format_string_ const WCHAR *Format, ...)
_Post_equals_last_error_
static inline DWORD
LoggerLastErrorFmt(_In_z_ LPCWSTR Function, _In_z_ _Printf_format_string_ LPCWSTR Format, ...)
{
va_list Args;
va_start(Args, Format);
@ -84,7 +88,7 @@ LoggerLastErrorFmt(_In_z_ const WCHAR *Function, _In_z_ _Printf_format_string_ c
}
VOID
LoggerGetRegistryKeyPath(_In_ HKEY Key, _Out_cap_c_(MAX_REG_PATH) WCHAR *Path);
LoggerGetRegistryKeyPath(_In_ HKEY Key, _Out_writes_z_(MAX_REG_PATH) LPWSTR Path);
#define __L(x) L##x
#define _L(x) __L(x)
@ -94,10 +98,31 @@ LoggerGetRegistryKeyPath(_In_ HKEY Key, _Out_cap_c_(MAX_REG_PATH) WCHAR *Path);
#define RET_ERROR(Ret, Error) ((Error) == ERROR_SUCCESS ? (Ret) : (SetLastError(Error), 0))
static inline _Return_type_success_(return != NULL) _Ret_maybenull_
_Post_writable_byte_size_(Size) void *LoggerAlloc(_In_z_ const WCHAR *Function, _In_ DWORD Flags, _In_ SIZE_T Size)
_Must_inspect_result_
DECLSPEC_ALLOCATOR
static inline _Return_type_success_(return != NULL)
_Post_maybenull_
_Post_writable_byte_size_(Size)
VOID *
LoggerAlloc(_In_z_ LPCWSTR Function, _In_ DWORD Flags, _In_ SIZE_T Size)
{
void *Data = HeapAlloc(ModuleHeap, Flags, Size);
VOID *Data = HeapAlloc(ModuleHeap, Flags, Size);
if (!Data)
{
LoggerLogFmt(WINTUN_LOG_ERR, Function, L"Out of memory (flags: 0x%x, requested size: 0x%zx)", Flags, Size);
SetLastError(ERROR_OUTOFMEMORY);
}
return Data;
}
_Must_inspect_result_
DECLSPEC_ALLOCATOR
static inline _Return_type_success_(return != NULL)
_Post_maybenull_
_Post_writable_byte_size_(Size)
VOID *
LoggerReAlloc(_In_z_ LPCWSTR Function, _In_ DWORD Flags, _Frees_ptr_opt_ LPVOID Mem, _In_ SIZE_T Size)
{
VOID *Data = Mem ? HeapReAlloc(ModuleHeap, Flags, Mem, Size) : HeapAlloc(ModuleHeap, Flags, Size);
if (!Data)
{
LoggerLogFmt(WINTUN_LOG_ERR, Function, L"Out of memory (flags: 0x%x, requested size: 0x%zx)", Flags, Size);
@ -106,10 +131,48 @@ static inline _Return_type_success_(return != NULL) _Ret_maybenull_
return Data;
}
#define Alloc(Size) LoggerAlloc(_L(__FUNCTION__), 0, Size)
#define ReAlloc(Mem, Size) LoggerReAlloc(_L(__FUNCTION__), 0, Mem, Size)
#define Zalloc(Size) LoggerAlloc(_L(__FUNCTION__), HEAP_ZERO_MEMORY, Size)
#define ReZalloc(Mem, Size) LoggerReAlloc(_L(__FUNCTION__), HEAP_ZERO_MEMORY, Mem, Size)
static inline void
Free(void *Ptr)
_Must_inspect_result_
DECLSPEC_ALLOCATOR
static inline _Return_type_success_(return != NULL)
_Post_maybenull_
_Post_writable_byte_size_((NumberOfElements) * (SizeOfOneElement))
VOID *
LoggerAllocArray(_In_z_ LPCWSTR Function, _In_ DWORD Flags, _In_ SIZE_T NumberOfElements, _In_ SIZE_T SizeOfOneElement)
{
SIZE_T Size;
if (FAILED(SIZETMult(NumberOfElements, SizeOfOneElement, &Size)))
return NULL;
return LoggerAlloc(Function, Flags, Size);
}
_Must_inspect_result_
DECLSPEC_ALLOCATOR
static inline _Return_type_success_(return != NULL)
_Post_maybenull_
_Post_writable_byte_size_((NumberOfElements) * (SizeOfOneElement))
VOID *
LoggerReAllocArray(
_In_z_ LPCWSTR Function,
_In_ DWORD Flags,
_Frees_ptr_opt_ LPVOID Mem,
_In_ SIZE_T NumberOfElements,
_In_ SIZE_T SizeOfOneElement)
{
SIZE_T Size;
if (FAILED(SIZETMult(NumberOfElements, SizeOfOneElement, &Size)))
return NULL;
return LoggerReAlloc(Function, Flags, Mem, Size);
}
#define AllocArray(Count, Size) LoggerAllocArray(_L(__FUNCTION__), 0, Count, Size)
#define ReAllocArray(Mem, Count, Size) LoggerReAllocArray(_L(__FUNCTION__), 0, Mem, Count, Size)
#define ZallocArray(Count, Size) LoggerAllocArray(_L(__FUNCTION__), HEAP_ZERO_MEMORY, Count, Size)
#define ReZallocArray(Mem, Count, Size) LoggerReAllocArray(_L(__FUNCTION__), HEAP_ZERO_MEMORY, Mem, Count, Size)
static inline VOID
Free(_Frees_ptr_opt_ VOID *Ptr)
{
if (!Ptr)
return;

View File

@ -3,18 +3,15 @@
* Copyright (C) 2018-2021 WireGuard LLC. All Rights Reserved.
*/
#include "adapter.h"
#include "logger.h"
#include "registry.h"
#include "adapter.h"
#include "main.h"
#include "namespace.h"
#include "wintun.h"
#include "registry.h"
#include "ntdll.h"
#include <Windows.h>
#pragma warning(push)
#pragma warning(disable : 4201)
/* nonstandard extension used: nameless struct/union */
#include <delayimp.h>
#pragma warning(pop)
#include <sddl.h>
#include <winefs.h>
#include <stdlib.h>
@ -23,6 +20,8 @@ HINSTANCE ResourceModule;
HANDLE ModuleHeap;
SECURITY_ATTRIBUTES SecurityAttributes = { .nLength = sizeof(SECURITY_ATTRIBUTES) };
BOOL IsLocalSystem;
USHORT NativeMachine = IMAGE_FILE_PROCESS;
BOOL IsWindows10;
static FARPROC WINAPI
DelayedLoadLibraryHook(unsigned dliNotify, PDelayLoadInfo pdli)
@ -37,8 +36,7 @@ DelayedLoadLibraryHook(unsigned dliNotify, PDelayLoadInfo pdli)
const PfnDliHook __pfnDliNotifyHook2 = DelayedLoadLibraryHook;
static BOOL
InitializeSecurityObjects(void)
static BOOL InitializeSecurityObjects(VOID)
{
BYTE LocalSystemSid[MAX_SID_SIZE];
DWORD RequiredBytes = sizeof(LocalSystemSid);
@ -72,11 +70,32 @@ cleanupProcessToken:
return Ret;
}
static VOID EnvInit(VOID)
{
DWORD MajorVersion;
RtlGetNtVersionNumbers(&MajorVersion, NULL, NULL);
IsWindows10 = MajorVersion >= 10;
#ifdef MAYBE_WOW64
typedef BOOL(WINAPI * IsWow64Process2_t)(
_In_ HANDLE hProcess, _Out_ USHORT * pProcessMachine, _Out_opt_ USHORT * pNativeMachine);
HANDLE Kernel32;
IsWow64Process2_t IsWow64Process2;
USHORT ProcessMachine;
if ((Kernel32 = GetModuleHandleW(L"kernel32.dll")) == NULL ||
(IsWow64Process2 = (IsWow64Process2_t)GetProcAddress(Kernel32, "IsWow64Process2")) == NULL ||
!IsWow64Process2(GetCurrentProcess(), &ProcessMachine, &NativeMachine))
{
BOOL IsWoW64;
NativeMachine =
IsWow64Process(GetCurrentProcess(), &IsWoW64) && IsWoW64 ? IMAGE_FILE_MACHINE_AMD64 : IMAGE_FILE_PROCESS;
}
#endif
}
BOOL APIENTRY
DllMain(_In_ HINSTANCE hinstDLL, _In_ DWORD fdwReason, _In_ LPVOID lpvReserved)
{
UNREFERENCED_PARAMETER(lpvReserved);
switch (fdwReason)
{
case DLL_PROCESS_ATTACH:
@ -89,7 +108,7 @@ DllMain(_In_ HINSTANCE hinstDLL, _In_ DWORD fdwReason, _In_ LPVOID lpvReserved)
HeapDestroy(ModuleHeap);
return FALSE;
}
AdapterInit();
EnvInit();
NamespaceInit();
break;

View File

@ -7,26 +7,21 @@
#include <Windows.h>
/* TODO: Replace with is_defined. MSVC has issues with the linux kernel varadic macro trick for this. */
#if defined(_M_IX86) || defined(_M_AMD64) || defined(_M_ARM)
# define MAYBE_WOW64 1
#if defined(_M_IX86)
# define IMAGE_FILE_PROCESS IMAGE_FILE_MACHINE_I386
#elif defined(_M_AMD64)
# define IMAGE_FILE_PROCESS IMAGE_FILE_MACHINE_AMD64
#elif defined(_M_ARM)
# define IMAGE_FILE_PROCESS IMAGE_FILE_MACHINE_ARMNT
#elif defined(_M_ARM64)
# define IMAGE_FILE_PROCESS IMAGE_FILE_MACHINE_ARM64
#else
# define MAYBE_WOW64 0
# error Unsupported architecture
#endif
#if defined(_M_AMD64) || defined(_M_ARM64)
# define ACCEPT_WOW64 1
#else
# define ACCEPT_WOW64 0
#endif
#ifdef HAVE_WHQL
# undef HAVE_WHQL
# define HAVE_WHQL 1
#else
# define HAVE_WHQL 0
#endif
#pragma warning(disable : 4127) /* conditional expression is constant */
extern HINSTANCE ResourceModule;
extern HANDLE ModuleHeap;
extern SECURITY_ATTRIBUTES SecurityAttributes;
extern BOOL IsLocalSystem;
extern USHORT NativeMachine;
extern BOOL IsWindows10;

View File

@ -19,13 +19,16 @@ static HANDLE BoundaryDescriptor = NULL;
static CRITICAL_SECTION Initializing;
static BCRYPT_ALG_HANDLE AlgProvider;
static _Return_type_success_(
return != NULL) WCHAR *NormalizeStringAlloc(_In_ NORM_FORM NormForm, _In_z_ const WCHAR *Source)
_Must_inspect_result_
static _Return_type_success_(return != NULL)
_Post_maybenull_
LPWSTR
NormalizeStringAlloc(_In_ NORM_FORM NormForm, _In_z_ LPCWSTR Source)
{
int Len = NormalizeString(NormForm, Source, -1, NULL, 0);
for (;;)
{
WCHAR *Str = Alloc(sizeof(WCHAR) * Len);
LPWSTR Str = AllocArray(Len, sizeof(*Str));
if (!Str)
return NULL;
Len = NormalizeString(NormForm, Source, -1, Str, Len);
@ -41,7 +44,8 @@ static _Return_type_success_(
}
}
static _Return_type_success_(return != FALSE) BOOL NamespaceRuntimeInit(void)
static _Return_type_success_(return != FALSE)
BOOL NamespaceRuntimeInit(VOID)
{
DWORD LastError;
@ -110,8 +114,9 @@ cleanupLeaveCriticalSection:
return FALSE;
}
_Check_return_
_Return_type_success_(return != NULL) HANDLE NamespaceTakePoolMutex(_In_z_ const WCHAR *Pool)
_Use_decl_annotations_
HANDLE
NamespaceTakePoolMutex(LPCWSTR Pool)
{
if (!NamespaceRuntimeInit())
return NULL;
@ -133,7 +138,7 @@ _Return_type_success_(return != NULL) HANDLE NamespaceTakePoolMutex(_In_z_ const
LastError = RtlNtStatusToDosError(Status);
goto cleanupSha256;
}
WCHAR *PoolNorm = NormalizeStringAlloc(NormalizationC, Pool);
LPWSTR PoolNorm = NormalizeStringAlloc(NormalizationC, Pool);
if (!PoolNorm)
{
LastError = GetLastError();
@ -184,8 +189,9 @@ cleanupSha256:
return NULL;
}
_Check_return_
_Return_type_success_(return != NULL) HANDLE NamespaceTakeDriverInstallationMutex(void)
_Use_decl_annotations_
HANDLE
NamespaceTakeDriverInstallationMutex(VOID)
{
if (!NamespaceRuntimeInit())
return NULL;
@ -208,21 +214,20 @@ _Return_type_success_(return != NULL) HANDLE NamespaceTakeDriverInstallationMute
return NULL;
}
void
NamespaceReleaseMutex(_In_ HANDLE Mutex)
_Use_decl_annotations_
VOID
NamespaceReleaseMutex(HANDLE Mutex)
{
ReleaseMutex(Mutex);
CloseHandle(Mutex);
}
void
NamespaceInit(void)
VOID NamespaceInit(VOID)
{
InitializeCriticalSection(&Initializing);
}
void
NamespaceDone(void)
VOID NamespaceDone(VOID)
{
EnterCriticalSection(&Initializing);
if (PrivateNamespace)

View File

@ -7,17 +7,24 @@
#include <Windows.h>
_Check_return_
_Return_type_success_(return != NULL) HANDLE NamespaceTakePoolMutex(_In_z_ const WCHAR *Pool);
_Must_inspect_result_
_Return_type_success_(return != NULL)
_Post_maybenull_
_Acquires_lock_(_Curr_)
HANDLE
NamespaceTakePoolMutex(_In_z_ LPCWSTR Pool);
_Check_return_
_Return_type_success_(return != NULL) HANDLE NamespaceTakeDriverInstallationMutex(void);
_Must_inspect_result_
_Return_type_success_(return != NULL)
_Post_maybenull_
_Acquires_lock_(_Curr_)
HANDLE
NamespaceTakeDriverInstallationMutex(VOID);
void
_Releases_lock_(Mutex)
VOID
NamespaceReleaseMutex(_In_ HANDLE Mutex);
void
NamespaceInit(void);
VOID NamespaceInit(VOID);
void
NamespaceDone(void);
VOID NamespaceDone(VOID);

View File

@ -9,19 +9,23 @@
#ifdef GENERATE_LIB
# define DECLSPEC __declspec(dllexport)
# define STUB { return 0; }
# define STUB \
{ \
return 0; \
}
#else
# define DECLSPEC __declspec(dllimport)
# define STUB ;
#endif
EXTERN_C
DECLSPEC DWORD WINAPI
NciSetConnectionName(_In_ const GUID *Guid, _In_z_ LPCWSTR NewName) STUB
EXTERN_C DECLSPEC DWORD WINAPI
NciSetConnectionName(_In_ const GUID *Guid, _In_z_ const WCHAR *NewName) STUB
EXTERN_C DECLSPEC DWORD WINAPI
EXTERN_C
DECLSPEC DWORD WINAPI
NciGetConnectionName(
_In_ const GUID *Guid,
_Out_z_bytecap_(InDestNameBytes) WCHAR *Name,
_Out_z_bytecap_(InDestNameBytes) LPWSTR Name,
_In_ DWORD InDestNameBytes,
_Out_opt_ DWORD *OutDestNameBytes) STUB

View File

@ -45,7 +45,7 @@ typedef struct _KEY_NAME_INFORMATION
* when run from legacy contexts. So, we instead use the undocumented RtlGetNtVersionNumbers.
*
* Another way would be reading from the PEB directly:
* ((DWORD *)NtCurrentTeb()->ProcessEnvironmentBlock)[sizeof(void *) == 8 ? 70 : 41]
* ((DWORD *)NtCurrentTeb()->ProcessEnvironmentBlock)[sizeof(VOID *) == 8 ? 70 : 41]
* Or just read from KUSER_SHARED_DATA the same way on 32-bit and 64-bit:
* *(DWORD *)0x7FFE026C
*/
@ -61,9 +61,3 @@ NtQueryKey(
_Out_bytecap_post_bytecount_(Length, *ResultLength) PVOID KeyInformation,
_In_ ULONG Length,
_Out_ PULONG ResultLength);
/* This is documented in NTSecAPI.h, which we can't include, due to header conflicts. It actually lives in advapi32.dll. */
#define RtlGenRandom SystemFunction036
BOOLEAN
NTAPI
RtlGenRandom(_Out_writes_bytes_all_(RandomBufferLength) PVOID RandomBuffer, _In_ ULONG RandomBufferLength);

View File

@ -10,11 +10,14 @@
#include <stdlib.h>
#include <strsafe.h>
static _Return_type_success_(return != NULL) HKEY
OpenKeyWait(_In_ HKEY Key, _Inout_z_ WCHAR *Path, _In_ DWORD Access, _In_ ULONGLONG Deadline)
_Must_inspect_result_
static _Return_type_success_(return != NULL)
_Post_maybenull_
HKEY
OpenKeyWait(_In_ HKEY Key, _Inout_z_ LPWSTR Path, _In_ DWORD Access, _In_ ULONGLONG Deadline)
{
DWORD LastError;
WCHAR *PathNext = wcschr(Path, L'\\');
LPWSTR PathNext = wcschr(Path, L'\\');
if (PathNext)
*PathNext = 0;
@ -87,8 +90,9 @@ static _Return_type_success_(return != NULL) HKEY
return NULL;
}
_Return_type_success_(return != NULL) HKEY
RegistryOpenKeyWait(_In_ HKEY Key, _In_z_ const WCHAR *Path, _In_ DWORD Access, _In_ DWORD Timeout)
_Use_decl_annotations_
HKEY
RegistryOpenKeyWait(HKEY Key, LPCWSTR Path, DWORD Access, DWORD Timeout)
{
WCHAR Buf[MAX_REG_PATH];
if (wcsncpy_s(Buf, _countof(Buf), Path, _TRUNCATE) == STRUNCATE)
@ -100,17 +104,17 @@ _Return_type_success_(return != NULL) HKEY
return OpenKeyWait(Key, Buf, Access, GetTickCount64() + Timeout);
}
_Return_type_success_(return != FALSE) BOOL RegistryGetString(_Inout_ WCHAR **Buf, _In_ DWORD Len, _In_ DWORD ValueType)
_Use_decl_annotations_
BOOL
RegistryGetString(LPWSTR *Buf, DWORD Len, DWORD ValueType)
{
if (wcsnlen(*Buf, Len) >= Len)
{
/* String is missing zero-terminator. */
WCHAR *BufZ = Alloc(((size_t)Len + 1) * sizeof(WCHAR));
LPWSTR BufZ = ReZallocArray(*Buf, (SIZE_T)Len + 1, sizeof(*BufZ));
if (!BufZ)
return FALSE;
wmemcpy(BufZ, *Buf, Len);
BufZ[Len] = 0;
Free(*Buf);
_Analysis_assume_((wmemset(BufZ, L'A', (SIZE_T)Len + 1), TRUE));
*Buf = BufZ;
}
@ -122,10 +126,9 @@ _Return_type_success_(return != FALSE) BOOL RegistryGetString(_Inout_ WCHAR **Bu
if (!(*Buf)[0])
return TRUE;
Len = Len * 2 + 64;
for (;;)
{
WCHAR *Expanded = Alloc(Len * sizeof(WCHAR));
LPWSTR Expanded = AllocArray(Len, sizeof(*Expanded));
if (!Expanded)
return FALSE;
DWORD Result = ExpandEnvironmentStringsW(*Buf, Expanded, Len);
@ -147,8 +150,9 @@ _Return_type_success_(return != FALSE) BOOL RegistryGetString(_Inout_ WCHAR **Bu
}
}
_Return_type_success_(return != FALSE) BOOL
RegistryGetMultiString(_Inout_ WCHAR **Buf, _In_ DWORD Len, _In_ DWORD ValueType)
_Use_decl_annotations_
BOOL
RegistryGetMultiString(PZZWSTR *Buf, DWORD Len, DWORD ValueType)
{
if (ValueType == REG_MULTI_SZ)
{
@ -157,25 +161,18 @@ _Return_type_success_(return != FALSE) BOOL
if (i > Len)
{
/* Missing string and list terminators. */
WCHAR *BufZ = Alloc(((size_t)Len + 2) * sizeof(WCHAR));
PZZWSTR BufZ = ReZallocArray(*Buf, (SIZE_T)Len + 2, sizeof(*BufZ));
if (!BufZ)
return FALSE;
wmemcpy(BufZ, *Buf, Len);
BufZ[Len] = 0;
BufZ[Len + 1] = 0;
Free(*Buf);
*Buf = BufZ;
return TRUE;
}
if (i == Len)
{
/* Missing list terminator. */
WCHAR *BufZ = Alloc(((size_t)Len + 1) * sizeof(WCHAR));
PZZWSTR BufZ = ReZallocArray(*Buf, (SIZE_T)Len + 1, sizeof(*BufZ));
if (!BufZ)
return FALSE;
wmemcpy(BufZ, *Buf, Len);
BufZ[Len] = 0;
Free(*Buf);
*Buf = BufZ;
return TRUE;
}
@ -188,22 +185,19 @@ _Return_type_success_(return != FALSE) BOOL
if (!RegistryGetString(Buf, Len, ValueType))
return FALSE;
Len = (DWORD)wcslen(*Buf) + 1;
WCHAR *BufZ = Alloc(((size_t)Len + 1) * sizeof(WCHAR));
PZZWSTR BufZ = ReZallocArray(*Buf, (SIZE_T)Len + 1, sizeof(WCHAR));
if (!BufZ)
return FALSE;
wmemcpy(BufZ, *Buf, Len);
BufZ[Len] = 0;
Free(*Buf);
*Buf = BufZ;
return TRUE;
}
static _Return_type_success_(return != NULL) void *RegistryQuery(
_In_ HKEY Key,
_In_opt_z_ const WCHAR *Name,
_Out_opt_ DWORD *ValueType,
_Inout_ DWORD *BufLen,
_In_ BOOL Log)
_Must_inspect_result_
static _Return_type_success_(return != NULL)
_Post_maybenull_
_Post_writable_byte_size_(*BufLen)
VOID *
RegistryQuery(_In_ HKEY Key, _In_opt_z_ LPCWSTR Name, _Out_opt_ DWORD *ValueType, _Inout_ DWORD *BufLen, _In_ BOOL Log)
{
for (;;)
{
@ -220,7 +214,7 @@ static _Return_type_success_(return != NULL) void *RegistryQuery(
{
WCHAR RegPath[MAX_REG_PATH];
LoggerGetRegistryKeyPath(Key, RegPath);
LOG_ERROR(LastError, L"Querying registry value %.*s\\%s failed", MAX_REG_PATH, RegPath, Name);
LOG_ERROR(LastError, L"Failed to query registry value %.*s\\%s", MAX_REG_PATH, RegPath, Name);
}
SetLastError(LastError);
return NULL;
@ -228,11 +222,12 @@ static _Return_type_success_(return != NULL) void *RegistryQuery(
}
}
_Return_type_success_(
return != NULL) WCHAR *RegistryQueryString(_In_ HKEY Key, _In_opt_z_ const WCHAR *Name, _In_ BOOL Log)
_Use_decl_annotations_
LPWSTR
RegistryQueryString(HKEY Key, LPCWSTR Name, BOOL Log)
{
DWORD LastError, ValueType, Size = 256 * sizeof(WCHAR);
WCHAR *Value = RegistryQuery(Key, Name, &ValueType, &Size, Log);
LPWSTR Value = RegistryQuery(Key, Name, &ValueType, &Size, Log);
if (!Value)
return NULL;
switch (ValueType)
@ -240,7 +235,7 @@ _Return_type_success_(
case REG_SZ:
case REG_EXPAND_SZ:
case REG_MULTI_SZ:
if (RegistryGetString(&Value, Size / sizeof(WCHAR), ValueType))
if (RegistryGetString(&Value, Size / sizeof(*Value), ValueType))
return Value;
LastError = GetLastError();
break;
@ -261,8 +256,9 @@ _Return_type_success_(
return NULL;
}
_Return_type_success_(
return != NULL) WCHAR *RegistryQueryStringWait(_In_ HKEY Key, _In_opt_z_ const WCHAR *Name, _In_ DWORD Timeout)
_Use_decl_annotations_
LPWSTR
RegistryQueryStringWait(HKEY Key, LPCWSTR Name, DWORD Timeout)
{
DWORD LastError;
ULONGLONG Deadline = GetTickCount64() + Timeout;
@ -282,7 +278,7 @@ _Return_type_success_(
LOG_ERROR(LastError, L"Failed to setup registry key %.*s notification", MAX_REG_PATH, RegPath);
break;
}
WCHAR *Value = RegistryQueryString(Key, Name, FALSE);
LPWSTR Value = RegistryQueryString(Key, Name, FALSE);
if (Value)
{
CloseHandle(Event);
@ -313,8 +309,9 @@ _Return_type_success_(
return NULL;
}
_Return_type_success_(return != FALSE) BOOL
RegistryQueryDWORD(_In_ HKEY Key, _In_opt_z_ const WCHAR *Name, _Out_ DWORD *Value, _In_ BOOL Log)
_Use_decl_annotations_
BOOL
RegistryQueryDWORD(HKEY Key, LPCWSTR Name, DWORD *Value, BOOL Log)
{
DWORD ValueType, Size = sizeof(DWORD);
DWORD LastError = RegQueryValueExW(Key, Name, NULL, &ValueType, (BYTE *)Value, &Size);
@ -324,7 +321,7 @@ _Return_type_success_(return != FALSE) BOOL
{
WCHAR RegPath[MAX_REG_PATH];
LoggerGetRegistryKeyPath(Key, RegPath);
LOG_ERROR(LastError, L"Querying registry value %.*s\\%s failed", MAX_REG_PATH, RegPath, Name);
LOG_ERROR(LastError, L"Failed to query registry value %.*s\\%s", MAX_REG_PATH, RegPath, Name);
}
SetLastError(LastError);
return FALSE;
@ -348,8 +345,9 @@ _Return_type_success_(return != FALSE) BOOL
return TRUE;
}
_Return_type_success_(return != FALSE) BOOL
RegistryQueryDWORDWait(_In_ HKEY Key, _In_opt_z_ const WCHAR *Name, _In_ DWORD Timeout, _Out_ DWORD *Value)
_Use_decl_annotations_
BOOL
RegistryQueryDWORDWait(HKEY Key, LPCWSTR Name, DWORD Timeout, DWORD *Value)
{
DWORD LastError;
ULONGLONG Deadline = GetTickCount64() + Timeout;
@ -398,73 +396,3 @@ _Return_type_success_(return != FALSE) BOOL
SetLastError(LastError);
return FALSE;
}
_Return_type_success_(return != FALSE) static BOOL
DeleteNodeRecurse(_In_ HKEY Key, _In_z_ WCHAR *Name)
{
LSTATUS Ret;
DWORD Size;
SIZE_T Len;
WCHAR SubName[MAX_REG_PATH], *End;
HKEY SubKey;
Len = wcslen(Name);
if (Len >= MAX_REG_PATH || !Len)
return TRUE;
if (RegDeleteKeyW(Key, Name) == ERROR_SUCCESS)
return TRUE;
Ret = RegOpenKeyEx(Key, Name, 0, KEY_READ, &SubKey);
if (Ret != ERROR_SUCCESS)
{
if (Ret == ERROR_FILE_NOT_FOUND)
return TRUE;
SetLastError(Ret);
return FALSE;
}
End = Name + Len;
if (End[-1] != L'\\')
{
*(End++) = L'\\';
*End = L'\0';
}
Size = MAX_REG_PATH;
Ret = RegEnumKeyEx(SubKey, 0, SubName, &Size, NULL, NULL, NULL, NULL);
if (Ret == ERROR_SUCCESS)
{
do
{
End[0] = L'\0';
StringCchCatW(Name, MAX_REG_PATH * 2, SubName);
if (!DeleteNodeRecurse(Key, Name))
break;
Size = MAX_REG_PATH;
Ret = RegEnumKeyEx(SubKey, 0, SubName, &Size, NULL, NULL, NULL, NULL);
} while (Ret == ERROR_SUCCESS);
}
else
{
SetLastError(Ret);
*(--End) = L'\0';
RegCloseKey(SubKey);
return FALSE;
}
*(--End) = L'\0';
RegCloseKey(SubKey);
Ret = RegDeleteKey(Key, Name);
if (Ret == ERROR_SUCCESS)
return TRUE;
SetLastError(Ret);
return FALSE;
}
_Return_type_success_(return != FALSE) BOOL
RegistryDeleteKeyRecursive(_In_ HKEY Key, _In_z_ const WCHAR *Name)
{
WCHAR NameBuf[(MAX_REG_PATH + 2) * 2] = { 0 };
StringCchCopyW(NameBuf, MAX_REG_PATH * 2, Name);
return DeleteNodeRecurse(Key, NameBuf);
}

View File

@ -26,8 +26,11 @@
* @return Key handle on success. If the function fails, the return value is zero. To get extended error information,
* call GetLastError.
*/
_Return_type_success_(return != NULL) HKEY
RegistryOpenKeyWait(_In_ HKEY Key, _In_z_ const WCHAR *Path, _In_ DWORD Access, _In_ DWORD Timeout);
_Must_inspect_result_
_Return_type_success_(return != NULL)
_Post_maybenull_
HKEY
RegistryOpenKeyWait(_In_ HKEY Key, _In_z_ LPCWSTR Path, _In_ DWORD Access, _In_ DWORD Timeout);
/**
* Validates and/or sanitizes string value read from registry.
@ -44,8 +47,10 @@ _Return_type_success_(return != NULL) HKEY
* @return If the function succeeds, the return value is nonzero. If the function fails, the return value is zero. To
* get extended error information, call GetLastError.
*/
_Return_type_success_(return != FALSE) BOOL
RegistryGetString(_Inout_ WCHAR **Buf, _In_ DWORD Len, _In_ DWORD ValueType);
_Must_inspect_result_
_Return_type_success_(return != FALSE)
BOOL
RegistryGetString(_Inout_ LPWSTR *Buf, _In_ DWORD Len, _In_ DWORD ValueType);
/**
* Validates and/or sanitizes multi-string value read from registry.
@ -61,8 +66,10 @@ _Return_type_success_(return != FALSE) BOOL
* @return If the function succeeds, the return value is nonzero. If the function fails, the return value is zero. To
* get extended error information, call GetLastError.
*/
_Return_type_success_(return != FALSE) BOOL
RegistryGetMultiString(_Inout_ WCHAR **Buf, _In_ DWORD Len, _In_ DWORD ValueType);
_Must_inspect_result_
_Return_type_success_(return != FALSE)
BOOL
RegistryGetMultiString(_Inout_ PZZWSTR *Buf, _In_ DWORD Len, _In_ DWORD ValueType);
/**
* Reads string value from registry key.
@ -83,8 +90,11 @@ _Return_type_success_(return != FALSE) BOOL
* @return String with registry value on success; If the function fails, the return value is zero. To get extended error
* information, call GetLastError.
*/
_Return_type_success_(
return != NULL) WCHAR *RegistryQueryString(_In_ HKEY Key, _In_opt_z_ const WCHAR *Name, _In_ BOOL Log);
_Must_inspect_result_
_Return_type_success_(return != NULL)
_Post_maybenull_
LPWSTR
RegistryQueryString(_In_ HKEY Key, _In_opt_z_ LPCWSTR Name, _In_ BOOL Log);
/**
* Reads string value from registry key. It waits for the registry value to become available.
@ -101,8 +111,11 @@ _Return_type_success_(
* get extended error information, call GetLastError. Possible errors include the following:
* ERROR_INVALID_DATATYPE when the registry value is not a string
*/
_Return_type_success_(
return != NULL) WCHAR *RegistryQueryStringWait(_In_ HKEY Key, _In_opt_z_ const WCHAR *Name, _In_ DWORD Timeout);
_Must_inspect_result_
_Return_type_success_(return != NULL)
_Post_maybenull_
LPWSTR
RegistryQueryStringWait(_In_ HKEY Key, _In_opt_z_ LPCWSTR Name, _In_ DWORD Timeout);
/**
* Reads a 32-bit DWORD value from registry key.
@ -120,8 +133,10 @@ _Return_type_success_(
* @return If the function succeeds, the return value is nonzero. If the function fails, the return value is zero. To
* get extended error information, call GetLastError.
*/
_Return_type_success_(return != FALSE) BOOL
RegistryQueryDWORD(_In_ HKEY Key, _In_opt_z_ const WCHAR *Name, _Out_ DWORD *Value, _In_ BOOL Log);
_Must_inspect_result_
_Return_type_success_(return != FALSE)
BOOL
RegistryQueryDWORD(_In_ HKEY Key, _In_opt_z_ LPCWSTR Name, _Out_ DWORD *Value, _In_ BOOL Log);
/**
* Reads a 32-bit DWORD value from registry key. It waits for the registry value to become available.
@ -139,17 +154,7 @@ _Return_type_success_(return != FALSE) BOOL
* ERROR_INVALID_DATATYPE when registry value exist but not REG_DWORD type;
* ERROR_INVALID_DATA when registry value size is not 4 bytes
*/
_Return_type_success_(return != FALSE) BOOL
RegistryQueryDWORDWait(_In_ HKEY Key, _In_opt_z_ const WCHAR *Name, _In_ DWORD Timeout, _Out_ DWORD *Value);
/**
* Deletes the entire registry key subtree recursively.
*
* @param Key Handle of the registry key to at which the subtree is rooted.
*
* @param Name Name of the subtree to delete.
*
* @return If the function succeeds, the return value is nonzero. If the function fails, the return value is zero. To
* get extended error information, call GetLastError.
*/
_Return_type_success_(return != FALSE) BOOL RegistryDeleteKeyRecursive(_In_ HKEY Key, _In_z_ const WCHAR *Name);
_Must_inspect_result_
_Return_type_success_(return != FALSE)
BOOL
RegistryQueryDWORDWait(_In_ HKEY Key, _In_opt_z_ LPCWSTR Name, _In_ DWORD Timeout, _Out_ DWORD *Value);

View File

@ -7,9 +7,12 @@
#include "main.h"
#include "resource.h"
#include <Windows.h>
#include <Shlwapi.h>
#include <NTSecAPI.h>
_Return_type_success_(return != NULL) _Ret_bytecount_(*Size) const
void *ResourceGetAddress(_In_z_ const WCHAR *ResourceName, _Out_ DWORD *Size)
_Use_decl_annotations_
const VOID *
ResourceGetAddress(LPCWSTR ResourceName, DWORD *Size)
{
HRSRC FoundResource = FindResourceW(ResourceModule, ResourceName, RT_RCDATA);
if (!FoundResource)
@ -39,11 +42,12 @@ _Return_type_success_(return != NULL) _Ret_bytecount_(*Size) const
return Address;
}
_Return_type_success_(return != FALSE) BOOL
ResourceCopyToFile(_In_z_ const WCHAR *DestinationPath, _In_z_ const WCHAR *ResourceName)
_Use_decl_annotations_
BOOL
ResourceCopyToFile(LPCWSTR DestinationPath, LPCWSTR ResourceName)
{
DWORD SizeResource;
const void *LockedResource = ResourceGetAddress(ResourceName, &SizeResource);
const VOID *LockedResource = ResourceGetAddress(ResourceName, &SizeResource);
if (!LockedResource)
{
LOG(WINTUN_LOG_ERR, L"Failed to locate resource %s", ResourceName);
@ -84,3 +88,42 @@ cleanupDestinationHandle:
CloseHandle(DestinationHandle);
return RET_ERROR(TRUE, LastError);
}
_Return_type_success_(return != FALSE)
BOOL
ResourceCreateTemporaryDirectory(_Out_writes_z_(MAX_PATH) LPWSTR RandomTempSubDirectory)
{
WCHAR WindowsDirectory[MAX_PATH];
if (!GetWindowsDirectoryW(WindowsDirectory, _countof(WindowsDirectory)))
{
LOG_LAST_ERROR(L"Failed to get Windows folder");
return FALSE;
}
WCHAR WindowsTempDirectory[MAX_PATH];
if (!PathCombineW(WindowsTempDirectory, WindowsDirectory, L"Temp"))
{
SetLastError(ERROR_BUFFER_OVERFLOW);
return FALSE;
}
UCHAR RandomBytes[32] = { 0 };
if (!RtlGenRandom(RandomBytes, sizeof(RandomBytes)))
{
LOG(WINTUN_LOG_ERR, L"Failed to generate random");
SetLastError(ERROR_GEN_FAILURE);
return FALSE;
}
WCHAR RandomSubDirectory[sizeof(RandomBytes) * 2 + 1];
for (int i = 0; i < sizeof(RandomBytes); ++i)
swprintf_s(&RandomSubDirectory[i * 2], 3, L"%02x", RandomBytes[i]);
if (!PathCombineW(RandomTempSubDirectory, WindowsTempDirectory, RandomSubDirectory))
{
SetLastError(ERROR_BUFFER_OVERFLOW);
return FALSE;
}
if (!CreateDirectoryW(RandomTempSubDirectory, &SecurityAttributes))
{
LOG_LAST_ERROR(L"Failed to create temporary folder %s", RandomTempSubDirectory);
return FALSE;
}
return TRUE;
}

View File

@ -11,25 +11,40 @@
/**
* Locates RT_RCDATA resource memory address and size.
*
* ResourceName Name of the RT_RCDATA resource. Use MAKEINTRESOURCEW to locate resource by ID.
* @param ResourceName Name of the RT_RCDATA resource. Use MAKEINTRESOURCEW to locate resource by ID.
*
* Size Pointer to a variable to receive resource size.
* @param Size Pointer to a variable to receive resource size.
*
* @return Resource address on success. If the function fails, the return value is NULL. To get extended error
* information, call GetLastError.
*/
_Return_type_success_(return != NULL) _Ret_bytecount_(*Size) const
void *ResourceGetAddress(_In_z_ const WCHAR *ResourceName, _Out_ DWORD *Size);
_Must_inspect_result_
_Return_type_success_(return != NULL)
_Post_maybenull_
_Post_readable_byte_size_(*Size) const VOID *ResourceGetAddress(_In_z_ LPCWSTR ResourceName, _Out_ DWORD *Size);
/**
* Copies resource to a file.
*
* DestinationPath File path
* @param DestinationPath File path
*
* ResourceName Name of the RT_RCDATA resource. Use MAKEINTRESOURCEW to locate resource by ID.
* @param ResourceName Name of the RT_RCDATA resource. Use MAKEINTRESOURCEW to locate resource by ID.
*
* @return If the function succeeds, the return value is nonzero. If the function fails, the return value is zero. To
* get extended error information, call GetLastError.
*/
_Return_type_success_(return != FALSE) BOOL
ResourceCopyToFile(_In_z_ const WCHAR *DestinationPath, _In_z_ const WCHAR *ResourceName);
_Return_type_success_(return != FALSE)
BOOL
ResourceCopyToFile(_In_z_ LPCWSTR DestinationPath, _In_z_ LPCWSTR ResourceName);
/**
* Creates a temporary directory.
*
* @param RandomTempSubDirectory Name of random temporary directory.
*
* @return If the function succeeds, the return value is nonzero. If the function fails, the return value is zero. To
* get extended error information, call GetLastError.
*/
_Return_type_success_(return != FALSE)
BOOL
ResourceCreateTemporaryDirectory(_Out_writes_z_(MAX_PATH) LPWSTR RandomTempSubDirectory);

View File

@ -3,12 +3,14 @@
* Copyright (C) 2018-2021 WireGuard LLC. All Rights Reserved.
*/
#include "rundll32.h"
#include "adapter.h"
#include "main.h"
#include "logger.h"
#include "wintun.h"
#include "resource.h"
#include <Windows.h>
#include <shellapi.h>
#include <Shlwapi.h>
#include <cfgmgr32.h>
#include <objbase.h>
#include <assert.h>
@ -18,10 +20,10 @@
# define EXPORT comment(linker, "/EXPORT:" __FUNCTION__ "=" __FUNCDNAME__)
static DWORD
WriteFormatted(_In_ DWORD StdHandle, _In_z_ const WCHAR *Template, ...)
WriteFormatted(_In_ DWORD StdHandle, _In_z_ LPCWSTR Template, ...)
{
WCHAR *FormattedMessage = NULL;
DWORD SizeWritten;
LPWSTR FormattedMessage = NULL;
DWORD Size;
va_list Arguments;
va_start(Arguments, Template);
DWORD Len = FormatMessageW(
@ -29,19 +31,22 @@ WriteFormatted(_In_ DWORD StdHandle, _In_z_ const WCHAR *Template, ...)
Template,
0,
0,
(void *)&FormattedMessage,
(VOID *)&FormattedMessage,
0,
&Arguments);
WriteFile(GetStdHandle(StdHandle), FormattedMessage, Len * sizeof(WCHAR), &SizeWritten, NULL);
if (SUCCEEDED(DWordMult(Len, sizeof(*FormattedMessage), &Size)))
WriteFile(GetStdHandle(StdHandle), FormattedMessage, Size, &Size, NULL);
else
Size = 0;
LocalFree(FormattedMessage);
va_end(Arguments);
return SizeWritten / sizeof(WCHAR);
return Size / sizeof(*FormattedMessage);
}
static void CALLBACK
ConsoleLogger(_In_ WINTUN_LOGGER_LEVEL Level, _In_z_ const WCHAR *LogLine)
static VOID CALLBACK
ConsoleLogger(_In_ WINTUN_LOGGER_LEVEL Level, _In_z_ LPCWSTR LogLine)
{
const WCHAR *Template;
LPCWSTR Template;
switch (Level)
{
case WINTUN_LOG_INFO:
@ -59,29 +64,14 @@ ConsoleLogger(_In_ WINTUN_LOGGER_LEVEL Level, _In_z_ const WCHAR *LogLine)
WriteFormatted(STD_ERROR_HANDLE, Template, LogLine);
}
static int Argc;
static WCHAR **Argv;
static void
Init(void)
{
WintunSetLogger(ConsoleLogger);
Argv = CommandLineToArgvW(GetCommandLineW(), &Argc);
}
static void
Done(void)
{
LocalFree(Argv);
}
# pragma warning(disable : 4100) /* unreferenced formal parameter */
VOID __stdcall CreateAdapter(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow)
{
# pragma EXPORT
Init();
int Argc;
LPWSTR *Argv = CommandLineToArgvW(GetCommandLineW(), &Argc);
WintunSetLogger(ConsoleLogger);
if (Argc < 4)
goto cleanup;
if (wcslen(Argv[2]) >= WINTUN_MAX_POOL)
@ -95,47 +85,52 @@ VOID __stdcall CreateAdapter(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int
BOOL RebootRequired;
WINTUN_ADAPTER *Adapter = WintunCreateAdapter(Argv[2], Argv[3], Argc > 4 ? &RequestedGUID : NULL, &RebootRequired);
DWORD LastError = Adapter ? ERROR_SUCCESS : GetLastError();
WCHAR GuidStr[MAX_GUID_STRING_LEN];
WriteFormatted(
STD_OUTPUT_HANDLE,
L"%1!X! %2!.*s! %3!X!",
LastError,
StringFromGUID2(Adapter ? &Adapter->CfgInstanceID : &GUID_NULL, GuidStr, _countof(GuidStr)),
GuidStr,
RebootRequired);
STD_OUTPUT_HANDLE, L"%1!X! %2!s! %3!X!", LastError, Adapter ? Adapter->DevInstanceID : L"", RebootRequired);
if (Adapter)
WintunFreeAdapter(Adapter);
cleanup:
Done();
LocalFree(Argv);
}
VOID __stdcall DeleteAdapter(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow)
{
# pragma EXPORT
Init();
if (Argc < 3)
int Argc;
LPWSTR *Argv = CommandLineToArgvW(GetCommandLineW(), &Argc);
WintunSetLogger(ConsoleLogger);
if (Argc < 4)
goto cleanup;
WINTUN_ADAPTER Adapter = { 0 };
BOOL ForceCloseSessions = wcstoul(Argv[2], NULL, 10);
if (FAILED(CLSIDFromString(Argv[3], &Adapter.CfgInstanceID)))
goto cleanup;
BOOL RebootRequired;
DWORD LastError =
WintunDeleteAdapter(&Adapter, ForceCloseSessions, &RebootRequired) ? ERROR_SUCCESS : GetLastError();
DWORD LastError;
BOOL RebootRequired = FALSE;
WINTUN_ADAPTER *Adapter = AdapterOpenFromDevInstanceId(Argv[2], Argv[3]);
if (!Adapter)
{
LastError = GetLastError();
goto write;
}
BOOL ForceCloseSessions = wcstoul(Argv[4], NULL, 10);
LastError = WintunDeleteAdapter(Adapter, ForceCloseSessions, &RebootRequired) ? ERROR_SUCCESS : GetLastError();
WintunFreeAdapter(Adapter);
write:
WriteFormatted(STD_OUTPUT_HANDLE, L"%1!X! %2!X!", LastError, RebootRequired);
cleanup:
Done();
LocalFree(Argv);
}
VOID __stdcall DeletePoolDriver(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow)
{
# pragma EXPORT
Init();
int Argc;
LPWSTR *Argv = CommandLineToArgvW(GetCommandLineW(), &Argc);
WintunSetLogger(ConsoleLogger);
if (Argc < 2)
goto cleanup;
@ -144,6 +139,455 @@ VOID __stdcall DeletePoolDriver(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, i
WriteFormatted(STD_OUTPUT_HANDLE, L"%1!X! %2!X!", LastError, RebootRequired);
cleanup:
Done();
LocalFree(Argv);
}
#endif
#ifdef MAYBE_WOW64
_Return_type_success_(return != FALSE)
static BOOL
AppendToBuffer(_Inout_ LPWSTR *Buffer, _In_ CONST WCHAR Addition, _Inout_ SIZE_T *BufferPos, _Inout_ SIZE_T *BufferLen)
{
SIZE_T NewPos;
if (FAILED(SIZETAdd(*BufferPos, sizeof(Addition), &NewPos)))
return FALSE;
if (NewPos >= *BufferLen)
{
SIZE_T NewLen;
if (FAILED(SIZETMult(NewPos, 3, &NewLen)))
return FALSE;
LPWSTR NewBuffer = ReZalloc(*Buffer, NewLen);
if (!NewBuffer)
return FALSE;
*Buffer = NewBuffer;
*BufferLen = NewLen;
}
SIZE_T NewIndex = *BufferPos / sizeof(**Buffer);
if (*Buffer + NewIndex < *Buffer)
return FALSE;
(*Buffer)[NewIndex] = Addition;
*BufferPos = NewPos;
return TRUE;
}
_Must_inspect_result_
static _Return_type_success_(return != NULL)
_Post_maybenull_
LPWSTR
ArgvToCommandLineW(_In_ SIZE_T ArgCount, ...)
{
LPWSTR Output = NULL;
SIZE_T BufferPos = 0, BufferLen = 0;
# define Append(Char) \
do \
{ \
if (!AppendToBuffer(&Output, Char, &BufferPos, &BufferLen)) \
goto cleanupBuffer; \
} while (0)
va_list Args;
va_start(Args, ArgCount);
for (SIZE_T i = 0; i < ArgCount; ++i)
{
LPCWSTR Arg = va_arg(Args, LPCWSTR);
SIZE_T ArgLen = wcslen(Arg);
if (ArgLen >= DWORD_MAX >> 3)
goto cleanupBuffer;
if (i)
Append(L' ');
Append(L'"');
for (SIZE_T j = 0;; ++j)
{
SIZE_T NumberBackslashes = 0;
while (j < ArgLen && Arg[j] == L'\\')
{
++j;
++NumberBackslashes;
}
if (j >= ArgLen)
{
for (SIZE_T k = 0; k < NumberBackslashes * 2; ++k)
Append(L'\\');
break;
}
else if (Arg[j] == L'"')
{
for (SIZE_T k = 0; k < NumberBackslashes * 2 + 1; ++k)
Append(L'\\');
Append(Arg[j]);
}
else
{
for (SIZE_T k = 0; k < NumberBackslashes; ++k)
Append(L'\\');
Append(Arg[j]);
}
}
Append(L'"');
}
va_end(Args);
return Output;
cleanupBuffer:
Free(Output);
return NULL;
# undef Append
}
typedef struct _PROCESS_STDOUT_STATE
{
HANDLE Stdout;
LPWSTR Response;
DWORD ResponseCapacity;
} PROCESS_STDOUT_STATE;
_Return_type_success_(return != ERROR_SUCCESS)
static DWORD WINAPI
ProcessStdout(_Inout_ PROCESS_STDOUT_STATE *State)
{
for (DWORD Offset = 0, MaxLen = State->ResponseCapacity - 1; Offset < MaxLen;)
{
DWORD Size;
if (FAILED(DWordMult(MaxLen - Offset, sizeof(WCHAR), &Size)))
return ERROR_BUFFER_OVERFLOW;
if (!ReadFile(State->Stdout, State->Response + Offset, Size, &Size, NULL))
return ERROR_SUCCESS;
if (Size % sizeof(WCHAR))
return ERROR_INVALID_DATA;
Offset += Size / sizeof(WCHAR);
State->Response[Offset] = 0;
}
return ERROR_BUFFER_OVERFLOW;
}
static DWORD WINAPI
ProcessStderr(_In_ HANDLE Stderr)
{
enum
{
OnNone,
OnLevelStart,
OnLevel,
OnLevelEnd,
OnSpace,
OnMsg
} State = OnNone;
WCHAR Msg[0x200];
DWORD Count = 0;
WINTUN_LOGGER_LEVEL Level = WINTUN_LOG_INFO;
for (;;)
{
WCHAR Buf[0x200];
DWORD SizeRead;
if (!ReadFile(Stderr, Buf, sizeof(Buf), &SizeRead, NULL))
return ERROR_SUCCESS;
if (SizeRead % sizeof(*Buf))
return ERROR_INVALID_DATA;
SizeRead /= sizeof(*Buf);
for (DWORD i = 0; i < SizeRead; ++i)
{
WCHAR c = Buf[i];
if (State == OnNone && c == L'[')
State = OnLevelStart;
else if (
State == OnLevelStart && ((Level = WINTUN_LOG_INFO, c == L'+') ||
(Level = WINTUN_LOG_WARN, c == L'-') || (Level = WINTUN_LOG_ERR, c == L'!')))
State = OnLevelEnd;
else if (State == OnLevelEnd && c == L']')
State = OnSpace;
else if (State == OnSpace && !iswspace(c) || State == OnMsg && c != L'\r' && c != L'\n')
{
if (Count < _countof(Msg) - 1)
Msg[Count++] = c;
State = OnMsg;
}
else if (State == OnMsg && c == L'\n')
{
Msg[Count] = 0;
LoggerLog(Level, NULL, Msg);
State = OnNone;
Count = 0;
}
}
}
}
static _Return_type_success_(return != FALSE)
BOOL
ExecuteRunDll32(
_In_z_ LPCWSTR Function,
_In_z_ LPCWSTR Arguments,
_Out_z_cap_c_(ResponseCapacity) LPWSTR Response,
_In_ DWORD ResponseCapacity)
{
WCHAR WindowsDirectory[MAX_PATH];
if (!GetWindowsDirectoryW(WindowsDirectory, _countof(WindowsDirectory)))
{
LOG_LAST_ERROR(L"Failed to get Windows folder");
return FALSE;
}
WCHAR RunDll32Path[MAX_PATH];
if (!PathCombineW(RunDll32Path, WindowsDirectory, L"Sysnative\\rundll32.exe"))
{
SetLastError(ERROR_BUFFER_OVERFLOW);
return FALSE;
}
DWORD LastError;
WCHAR RandomTempSubDirectory[MAX_PATH];
if (!ResourceCreateTemporaryDirectory(RandomTempSubDirectory))
{
LOG(WINTUN_LOG_ERR, L"Failed to create temporary folder");
return FALSE;
}
WCHAR DllPath[MAX_PATH] = { 0 };
if (!PathCombineW(DllPath, RandomTempSubDirectory, L"wintun.dll"))
{
LastError = ERROR_BUFFER_OVERFLOW;
goto cleanupDirectory;
}
LPCWSTR WintunDllResourceName;
switch (NativeMachine)
{
case IMAGE_FILE_MACHINE_AMD64:
WintunDllResourceName = L"wintun-amd64.dll";
break;
case IMAGE_FILE_MACHINE_ARM64:
WintunDllResourceName = L"wintun-arm64.dll";
break;
default:
LOG(WINTUN_LOG_ERR, L"Unsupported platform 0x%x", NativeMachine);
LastError = ERROR_NOT_SUPPORTED;
goto cleanupDirectory;
}
if (!ResourceCopyToFile(DllPath, WintunDllResourceName))
{
LastError = LOG(WINTUN_LOG_ERR, L"Failed to copy resource %s to %s", WintunDllResourceName, DllPath);
goto cleanupDelete;
}
size_t CommandLineLen = 10 + MAX_PATH + 2 + wcslen(Arguments) + 1 + wcslen(Function) + 1;
LPWSTR CommandLine = AllocArray(CommandLineLen, sizeof(*CommandLine));
if (!CommandLine)
{
LastError = GetLastError();
goto cleanupDelete;
}
if (_snwprintf_s(
CommandLine,
CommandLineLen,
_TRUNCATE,
L"rundll32 \"%.*s\",%s %s",
MAX_PATH,
DllPath,
Function,
Arguments) == -1)
{
LOG(WINTUN_LOG_ERR, L"Command line too long");
LastError = ERROR_INVALID_PARAMETER;
goto cleanupDelete;
}
HANDLE StreamRStdout = INVALID_HANDLE_VALUE, StreamRStderr = INVALID_HANDLE_VALUE,
StreamWStdout = INVALID_HANDLE_VALUE, StreamWStderr = INVALID_HANDLE_VALUE;
if (!CreatePipe(&StreamRStdout, &StreamWStdout, &SecurityAttributes, 0) ||
!CreatePipe(&StreamRStderr, &StreamWStderr, &SecurityAttributes, 0))
{
LastError = LOG_LAST_ERROR(L"Failed to create pipes");
goto cleanupPipes;
}
if (!SetHandleInformation(StreamWStdout, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT) ||
!SetHandleInformation(StreamWStderr, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT))
{
LastError = LOG_LAST_ERROR(L"Failed to set handle info");
goto cleanupPipes;
}
if (ResponseCapacity)
Response[0] = 0;
PROCESS_STDOUT_STATE ProcessStdoutState = { .Stdout = StreamRStdout,
.Response = Response,
.ResponseCapacity = ResponseCapacity };
HANDLE ThreadStdout = NULL, ThreadStderr = NULL;
if ((ThreadStdout = CreateThread(NULL, 0, ProcessStdout, &ProcessStdoutState, 0, NULL)) == NULL ||
(ThreadStderr = CreateThread(NULL, 0, ProcessStderr, StreamRStderr, 0, NULL)) == NULL)
{
LastError = LOG_LAST_ERROR(L"Failed to spawn readers");
goto cleanupThreads;
}
STARTUPINFOW si = { .cb = sizeof(STARTUPINFO),
.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES,
.wShowWindow = SW_HIDE,
.hStdOutput = StreamWStdout,
.hStdError = StreamWStderr };
PROCESS_INFORMATION pi;
if (!CreateProcessW(RunDll32Path, CommandLine, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi))
{
LastError = LOG_LAST_ERROR(L"Failed to create process: %s", CommandLine);
goto cleanupThreads;
}
LastError = ERROR_SUCCESS;
WaitForSingleObject(pi.hProcess, INFINITE);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
cleanupThreads:
if (ThreadStderr)
{
CloseHandle(StreamWStderr);
StreamWStderr = INVALID_HANDLE_VALUE;
WaitForSingleObject(ThreadStderr, INFINITE);
CloseHandle(ThreadStderr);
}
if (ThreadStdout)
{
CloseHandle(StreamWStdout);
StreamWStdout = INVALID_HANDLE_VALUE;
WaitForSingleObject(ThreadStdout, INFINITE);
DWORD ThreadResult;
if (!GetExitCodeThread(ThreadStdout, &ThreadResult))
LOG_LAST_ERROR(L"Failed to retrieve stdout reader result");
else if (ThreadResult != ERROR_SUCCESS)
LOG_ERROR(LastError, L"Failed to read process output");
CloseHandle(ThreadStdout);
}
cleanupPipes:
CloseHandle(StreamRStderr);
CloseHandle(StreamWStderr);
CloseHandle(StreamRStdout);
CloseHandle(StreamWStdout);
Free(CommandLine);
cleanupDelete:
DeleteFileW(DllPath);
cleanupDirectory:
RemoveDirectoryW(RandomTempSubDirectory);
return RET_ERROR(TRUE, LastError);
}
_Use_decl_annotations_
WINTUN_ADAPTER *
CreateAdapterViaRundll32(LPCWSTR Pool, LPCWSTR Name, const GUID *RequestedGUID, BOOL *RebootRequired)
{
LOG(WINTUN_LOG_INFO, L"Spawning native process");
LPWSTR Arguments = NULL;
if (RequestedGUID)
{
WCHAR RequestedGUIDStr[MAX_GUID_STRING_LEN];
if (StringFromGUID2(RequestedGUID, RequestedGUIDStr, _countof(RequestedGUIDStr)))
Arguments = ArgvToCommandLineW(3, Pool, Name, RequestedGUIDStr);
}
else
Arguments = ArgvToCommandLineW(2, Pool, Name);
if (!Arguments)
{
LOG(WINTUN_LOG_ERR, L"Command line too long");
SetLastError(ERROR_INVALID_PARAMETER);
return NULL;
}
WINTUN_ADAPTER *Adapter = NULL;
DWORD LastError;
WCHAR Response[8 + 1 + MAX_GUID_STRING_LEN + 1 + 8 + 1];
if (!ExecuteRunDll32(L"CreateAdapter", Arguments, Response, _countof(Response)))
{
LastError = GetLastError();
LOG(WINTUN_LOG_ERR, L"Error executing worker process: %s", Arguments);
goto cleanupArguments;
}
int Argc;
LPWSTR *Argv = CommandLineToArgvW(Response, &Argc);
if (Argc < 3)
{
LOG(WINTUN_LOG_ERR, L"Incomplete response: %s", Response);
LastError = ERROR_INVALID_PARAMETER;
goto cleanupArgv;
}
LastError = wcstoul(Argv[0], NULL, 16);
if (LastError == ERROR_SUCCESS && (Adapter = AdapterOpenFromDevInstanceId(Pool, Argv[1])) == NULL)
{
LOG(WINTUN_LOG_ERR, L"Failed to get adapter %s", Argv[1]);
LastError = ERROR_FILE_NOT_FOUND;
}
if (wcstoul(Argv[2], NULL, 16))
*RebootRequired = TRUE;
cleanupArgv:
LocalFree(Argv);
cleanupArguments:
Free(Arguments);
SetLastError(LastError);
return Adapter;
}
_Use_decl_annotations_
BOOL
DeleteAdapterViaRundll32(const WINTUN_ADAPTER *Adapter, BOOL ForceCloseSessions, BOOL *RebootRequired)
{
LOG(WINTUN_LOG_INFO, L"Spawning native process");
LPWSTR Arguments = ArgvToCommandLineW(3, Adapter->Pool, Adapter->DevInstanceID, ForceCloseSessions ? L"1" : L"0");
if (!Arguments)
{
LOG(WINTUN_LOG_ERR, L"Command line too long");
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
WCHAR Response[8 + 1 + 8 + 1];
DWORD LastError;
if (!ExecuteRunDll32(L"DeleteAdapter", Arguments, Response, _countof(Response)))
{
LastError = GetLastError();
LOG(WINTUN_LOG_ERR, L"Error executing worker process: %s", Arguments);
goto cleanupArguments;
}
int Argc;
LPWSTR *Argv = CommandLineToArgvW(Response, &Argc);
if (Argc < 2)
{
LOG(WINTUN_LOG_ERR, L"Incomplete response: %s", Response);
LastError = ERROR_INVALID_PARAMETER;
goto cleanupArgv;
}
LastError = wcstoul(Argv[0], NULL, 16);
if (wcstoul(Argv[1], NULL, 16))
*RebootRequired = TRUE;
cleanupArgv:
LocalFree(Argv);
cleanupArguments:
Free(Arguments);
return RET_ERROR(TRUE, LastError);
}
_Use_decl_annotations_
BOOL
DeletePoolDriverViaRundll32(LPCWSTR Pool, BOOL *RebootRequired)
{
LOG(WINTUN_LOG_INFO, L"Spawning native process");
LPWSTR Arguments = ArgvToCommandLineW(1, Pool);
if (!Arguments)
{
LOG(WINTUN_LOG_ERR, L"Command line too long");
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
WCHAR Response[8 + 1 + 8 + 1];
DWORD LastError;
if (!ExecuteRunDll32(L"DeletePoolDriver", Arguments, Response, _countof(Response)))
{
LastError = GetLastError();
LOG(WINTUN_LOG_ERR, L"Error executing worker process: %s", Arguments);
goto cleanupArguments;
}
int Argc;
LPWSTR *Argv = CommandLineToArgvW(Response, &Argc);
if (Argc < 2)
{
LOG(WINTUN_LOG_ERR, L"Incomplete response: %s", Response);
LastError = ERROR_INVALID_PARAMETER;
goto cleanupArgv;
}
LastError = wcstoul(Argv[0], NULL, 16);
if (wcstoul(Argv[1], NULL, 16))
*RebootRequired = TRUE;
cleanupArgv:
LocalFree(Argv);
cleanupArguments:
Free(Arguments);
return RET_ERROR(TRUE, LastError);
}
#endif

29
api/rundll32.h Normal file
View File

@ -0,0 +1,29 @@
/* SPDX-License-Identifier: GPL-2.0
*
* Copyright (C) 2018-2021 WireGuard LLC. All Rights Reserved.
*/
#pragma once
#include "adapter.h"
_Must_inspect_result_
_Return_type_success_(return != NULL)
_Post_maybenull_
WINTUN_ADAPTER *
CreateAdapterViaRundll32(
_In_z_ LPCWSTR Pool,
_In_z_ LPCWSTR Name,
_In_opt_ const GUID *RequestedGUID,
_Inout_ BOOL *RebootRequired);
_Return_type_success_(return != FALSE)
BOOL
DeleteAdapterViaRundll32(
_In_ const WINTUN_ADAPTER *Adapter,
_In_ BOOL ForceCloseSessions,
_Inout_ BOOL *RebootRequired);
_Return_type_success_(return != FALSE)
BOOL
DeletePoolDriverViaRundll32(_In_z_ LPCWSTR Pool, _Inout_ BOOL *RebootRequired);

View File

@ -1,352 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0
*
* Copyright (C) 2018-2021 WireGuard LLC. All Rights Reserved.
*/
/* TODO: This is currently #include'd in adapter.c. Move into rundll32.c properly. */
typedef struct _PROCESS_STDOUT_STATE
{
HANDLE Stdout;
WCHAR *Response;
DWORD ResponseCapacity;
} PROCESS_STDOUT_STATE;
static DWORD WINAPI
ProcessStdout(_Inout_ PROCESS_STDOUT_STATE *State)
{
for (DWORD Offset = 0, MaxLen = State->ResponseCapacity - 1; Offset < MaxLen;)
{
DWORD SizeRead;
if (!ReadFile(State->Stdout, State->Response + Offset, sizeof(WCHAR) * (MaxLen - Offset), &SizeRead, NULL))
return ERROR_SUCCESS;
if (SizeRead % sizeof(WCHAR))
return ERROR_INVALID_DATA;
Offset += SizeRead / sizeof(WCHAR);
State->Response[Offset] = 0;
}
return ERROR_BUFFER_OVERFLOW;
}
static DWORD WINAPI
ProcessStderr(_In_ HANDLE Stderr)
{
enum
{
OnNone,
OnLevelStart,
OnLevel,
OnLevelEnd,
OnSpace,
OnMsg
} State = OnNone;
WCHAR Msg[0x200];
DWORD Count = 0;
WINTUN_LOGGER_LEVEL Level = WINTUN_LOG_INFO;
for (;;)
{
WCHAR Buf[0x200];
DWORD SizeRead;
if (!ReadFile(Stderr, Buf, sizeof(Buf), &SizeRead, NULL))
return ERROR_SUCCESS;
if (SizeRead % sizeof(WCHAR))
return ERROR_INVALID_DATA;
SizeRead /= sizeof(WCHAR);
for (DWORD i = 0; i < SizeRead; ++i)
{
WCHAR c = Buf[i];
if (State == OnNone && c == L'[')
State = OnLevelStart;
else if (
State == OnLevelStart && ((Level = WINTUN_LOG_INFO, c == L'+') ||
(Level = WINTUN_LOG_WARN, c == L'-') || (Level = WINTUN_LOG_ERR, c == L'!')))
State = OnLevelEnd;
else if (State == OnLevelEnd && c == L']')
State = OnSpace;
else if (State == OnSpace && !iswspace(c) || State == OnMsg && c != L'\r' && c != L'\n')
{
if (Count < _countof(Msg) - 1)
Msg[Count++] = c;
State = OnMsg;
}
else if (State == OnMsg && c == L'\n')
{
Msg[Count] = 0;
LoggerLog(Level, NULL, Msg);
State = OnNone;
Count = 0;
}
}
}
}
static _Return_type_success_(return != FALSE) BOOL ExecuteRunDll32(
_In_z_ const WCHAR *Arguments,
_Out_z_cap_c_(ResponseCapacity) WCHAR *Response,
_In_ DWORD ResponseCapacity)
{
WCHAR WindowsDirectory[MAX_PATH];
if (!GetWindowsDirectoryW(WindowsDirectory, _countof(WindowsDirectory)))
{
LOG_LAST_ERROR(L"Failed to get Windows folder");
return FALSE;
}
WCHAR RunDll32Path[MAX_PATH];
if (!PathCombineW(RunDll32Path, WindowsDirectory, L"Sysnative\\rundll32.exe"))
{
SetLastError(ERROR_BUFFER_OVERFLOW);
return FALSE;
}
DWORD LastError;
WCHAR RandomTempSubDirectory[MAX_PATH];
if (!CreateTemporaryDirectory(RandomTempSubDirectory))
{
LOG(WINTUN_LOG_ERR, L"Failed to create temporary folder %s", RandomTempSubDirectory);
return FALSE;
}
WCHAR DllPath[MAX_PATH] = { 0 };
if (!PathCombineW(DllPath, RandomTempSubDirectory, L"wintun.dll"))
{
LastError = ERROR_BUFFER_OVERFLOW;
goto cleanupDirectory;
}
const WCHAR *WintunDllResourceName;
switch (NativeMachine)
{
case IMAGE_FILE_MACHINE_AMD64:
WintunDllResourceName = L"wintun-amd64.dll";
break;
case IMAGE_FILE_MACHINE_ARM64:
WintunDllResourceName = L"wintun-arm64.dll";
break;
default:
LOG(WINTUN_LOG_ERR, L"Unsupported platform 0x%x", NativeMachine);
LastError = ERROR_NOT_SUPPORTED;
goto cleanupDirectory;
}
if (!ResourceCopyToFile(DllPath, WintunDllResourceName))
{
LastError = LOG(WINTUN_LOG_ERR, L"Failed to copy resource %s to %s", WintunDllResourceName, DllPath);
goto cleanupDelete;
}
size_t CommandLineLen = 10 + MAX_PATH + 2 + wcslen(Arguments) + 1;
WCHAR *CommandLine = Alloc(CommandLineLen * sizeof(WCHAR));
if (!CommandLine)
{
LastError = GetLastError();
goto cleanupDelete;
}
if (_snwprintf_s(CommandLine, CommandLineLen, _TRUNCATE, L"rundll32 \"%.*s\",%s", MAX_PATH, DllPath, Arguments) ==
-1)
{
LOG(WINTUN_LOG_ERR, L"Command line too long");
LastError = ERROR_INVALID_PARAMETER;
goto cleanupDelete;
}
HANDLE StreamRStdout = INVALID_HANDLE_VALUE, StreamRStderr = INVALID_HANDLE_VALUE,
StreamWStdout = INVALID_HANDLE_VALUE, StreamWStderr = INVALID_HANDLE_VALUE;
if (!CreatePipe(&StreamRStdout, &StreamWStdout, &SecurityAttributes, 0) ||
!CreatePipe(&StreamRStderr, &StreamWStderr, &SecurityAttributes, 0))
{
LastError = LOG_LAST_ERROR(L"Failed to create pipes");
goto cleanupPipes;
}
if (!SetHandleInformation(StreamWStdout, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT) ||
!SetHandleInformation(StreamWStderr, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT))
{
LastError = LOG_LAST_ERROR(L"Failed to set handle info");
goto cleanupPipes;
}
if (ResponseCapacity)
Response[0] = 0;
PROCESS_STDOUT_STATE ProcessStdoutState = { .Stdout = StreamRStdout,
.Response = Response,
.ResponseCapacity = ResponseCapacity };
HANDLE ThreadStdout = NULL, ThreadStderr = NULL;
if ((ThreadStdout = CreateThread(NULL, 0, ProcessStdout, &ProcessStdoutState, 0, NULL)) == NULL ||
(ThreadStderr = CreateThread(NULL, 0, ProcessStderr, StreamRStderr, 0, NULL)) == NULL)
{
LastError = LOG_LAST_ERROR(L"Failed to spawn readers");
goto cleanupThreads;
}
STARTUPINFOW si = { .cb = sizeof(STARTUPINFO),
.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES,
.wShowWindow = SW_HIDE,
.hStdOutput = StreamWStdout,
.hStdError = StreamWStderr };
PROCESS_INFORMATION pi;
if (!CreateProcessW(RunDll32Path, CommandLine, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi))
{
LastError = LOG_LAST_ERROR(L"Failed to create process: %s", CommandLine);
goto cleanupThreads;
}
LastError = ERROR_SUCCESS;
WaitForSingleObject(pi.hProcess, INFINITE);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
cleanupThreads:
if (ThreadStderr)
{
CloseHandle(StreamWStderr);
StreamWStderr = INVALID_HANDLE_VALUE;
WaitForSingleObject(ThreadStderr, INFINITE);
CloseHandle(ThreadStderr);
}
if (ThreadStdout)
{
CloseHandle(StreamWStdout);
StreamWStdout = INVALID_HANDLE_VALUE;
WaitForSingleObject(ThreadStdout, INFINITE);
DWORD ThreadResult;
if (!GetExitCodeThread(ThreadStdout, &ThreadResult))
LOG_LAST_ERROR(L"Failed to retrieve stdout reader result");
else if (ThreadResult != ERROR_SUCCESS)
LOG_ERROR(LastError, L"Failed to read process output");
CloseHandle(ThreadStdout);
}
cleanupPipes:
CloseHandle(StreamRStderr);
CloseHandle(StreamWStderr);
CloseHandle(StreamRStdout);
CloseHandle(StreamWStdout);
Free(CommandLine);
cleanupDelete:
DeleteFileW(DllPath);
cleanupDirectory:
RemoveDirectoryW(RandomTempSubDirectory);
return RET_ERROR(TRUE, LastError);
}
static _Return_type_success_(return != NULL) WINTUN_ADAPTER *CreateAdapterViaRundll32(
_In_z_ const WCHAR *Pool,
_In_z_ const WCHAR *Name,
_In_opt_ const GUID *RequestedGUID,
_Inout_ BOOL *RebootRequired)
{
LOG(WINTUN_LOG_INFO, L"Spawning native process");
WCHAR RequestedGUIDStr[MAX_GUID_STRING_LEN];
WCHAR Arguments[15 + WINTUN_MAX_POOL + 3 + MAX_ADAPTER_NAME + 2 + MAX_GUID_STRING_LEN + 1];
if (_snwprintf_s(
Arguments,
_countof(Arguments),
_TRUNCATE,
RequestedGUID ? L"CreateAdapter \"%s\" \"%s\" %.*s" : L"CreateAdapter \"%s\" \"%s\"",
Pool,
Name,
RequestedGUID ? StringFromGUID2(RequestedGUID, RequestedGUIDStr, _countof(RequestedGUIDStr)) : 0,
RequestedGUIDStr) == -1)
{
LOG(WINTUN_LOG_ERR, L"Command line too long");
SetLastError(ERROR_INVALID_PARAMETER);
return NULL;
}
WCHAR Response[8 + 1 + MAX_GUID_STRING_LEN + 1 + 8 + 1];
if (!ExecuteRunDll32(Arguments, Response, _countof(Response)))
{
LOG(WINTUN_LOG_ERR, L"Error executing worker process: %s", Arguments);
return NULL;
}
DWORD LastError;
WINTUN_ADAPTER *Adapter = NULL;
int Argc;
WCHAR **Argv = CommandLineToArgvW(Response, &Argc);
GUID CfgInstanceID;
if (Argc < 3 || FAILED(CLSIDFromString(Argv[1], &CfgInstanceID)))
{
LOG(WINTUN_LOG_ERR, L"Incomplete or invalid response: %s", Response);
LastError = ERROR_INVALID_PARAMETER;
goto cleanupArgv;
}
LastError = wcstoul(Argv[0], NULL, 16);
if (LastError == ERROR_SUCCESS && (Adapter = GetAdapter(Pool, &CfgInstanceID)) == NULL)
{
LOG(WINTUN_LOG_ERR, L"Failed to get adapter %s", Argv[1]);
LastError = ERROR_FILE_NOT_FOUND;
}
if (wcstoul(Argv[2], NULL, 16))
*RebootRequired = TRUE;
cleanupArgv:
LocalFree(Argv);
SetLastError(LastError);
return Adapter;
}
static _Return_type_success_(return != FALSE) BOOL DeleteAdapterViaRundll32(
_In_ const WINTUN_ADAPTER *Adapter,
_In_ BOOL ForceCloseSessions,
_Inout_ BOOL *RebootRequired)
{
LOG(WINTUN_LOG_INFO, L"Spawning native process");
WCHAR GuidStr[MAX_GUID_STRING_LEN];
WCHAR Arguments[16 + MAX_GUID_STRING_LEN + 1];
if (_snwprintf_s(
Arguments,
_countof(Arguments),
_TRUNCATE,
L"DeleteAdapter %d %.*s",
ForceCloseSessions ? 1 : 0,
StringFromGUID2(&Adapter->CfgInstanceID, GuidStr, _countof(GuidStr)),
GuidStr) == -1)
{
LOG(WINTUN_LOG_ERR, L"Command line too long");
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
WCHAR Response[8 + 1 + 8 + 1];
DWORD LastError;
if (!ExecuteRunDll32(Arguments, Response, _countof(Response)))
{
LOG(WINTUN_LOG_ERR, L"Error executing worker process: %s", Arguments);
return FALSE;
}
int Argc;
WCHAR **Argv = CommandLineToArgvW(Response, &Argc);
if (Argc < 2)
{
LOG(WINTUN_LOG_ERR, L"Incomplete or invalid response: %s", Response);
LastError = ERROR_INVALID_PARAMETER;
goto cleanupArgv;
}
LastError = wcstoul(Argv[0], NULL, 16);
if (wcstoul(Argv[1], NULL, 16))
*RebootRequired = TRUE;
cleanupArgv:
LocalFree(Argv);
return RET_ERROR(TRUE, LastError);
}
static _Return_type_success_(return != FALSE) BOOL
DeletePoolDriverViaRundll32(_In_z_ const WCHAR Pool[WINTUN_MAX_POOL], _Inout_ BOOL *RebootRequired)
{
LOG(WINTUN_LOG_INFO, L"Spawning native process");
WCHAR Arguments[17 + WINTUN_MAX_POOL + 1];
if (_snwprintf_s(Arguments, _countof(Arguments), _TRUNCATE, L"DeletePoolDriver %s", Pool) == -1)
{
LOG(WINTUN_LOG_ERR, L"Command line too long");
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
WCHAR Response[8 + 1 + 8 + 1];
DWORD LastError;
if (!ExecuteRunDll32(Arguments, Response, _countof(Response)))
{
LOG(WINTUN_LOG_ERR, L"Error executing worker process: %s", Arguments);
return FALSE;
}
int Argc;
WCHAR **Argv = CommandLineToArgvW(Response, &Argc);
if (Argc < 2)
{
LOG(WINTUN_LOG_ERR, L"Incomplete or invalid response: %s", Response);
LastError = ERROR_INVALID_PARAMETER;
goto cleanupArgv;
}
LastError = wcstoul(Argv[0], NULL, 16);
if (wcstoul(Argv[1], NULL, 16))
*RebootRequired = TRUE;
cleanupArgv:
LocalFree(Argv);
return RET_ERROR(TRUE, LastError);
}

View File

@ -70,8 +70,10 @@ typedef struct _TUN_SESSION
HANDLE Handle;
} TUN_SESSION;
_Return_type_success_(return != NULL) TUN_SESSION *WINAPI
WintunStartSession(_In_ const WINTUN_ADAPTER *Adapter, _In_ DWORD Capacity)
WINTUN_START_SESSION_FUNC_IMPL WintunStartSession;
_Use_decl_annotations_
TUN_SESSION *WINAPI
WintunStartSession(WINTUN_ADAPTER *Adapter, DWORD Capacity)
{
DWORD LastError;
TUN_SESSION *Session = Zalloc(sizeof(TUN_SESSION));
@ -126,8 +128,8 @@ _Return_type_success_(return != NULL) TUN_SESSION *WINAPI
goto cleanupHandle;
}
Session->Capacity = Capacity;
(void)InitializeCriticalSectionAndSpinCount(&Session->Receive.Lock, LOCK_SPIN_COUNT);
(void)InitializeCriticalSectionAndSpinCount(&Session->Send.Lock, LOCK_SPIN_COUNT);
(VOID) InitializeCriticalSectionAndSpinCount(&Session->Receive.Lock, LOCK_SPIN_COUNT);
(VOID) InitializeCriticalSectionAndSpinCount(&Session->Send.Lock, LOCK_SPIN_COUNT);
return Session;
cleanupHandle:
CloseHandle(Session->Handle);
@ -144,8 +146,10 @@ cleanup:
return NULL;
}
void WINAPI
WintunEndSession(_In_ TUN_SESSION *Session)
WINTUN_END_SESSION_FUNC_IMPL WintunEndSession;
_Use_decl_annotations_
VOID WINAPI
WintunEndSession(TUN_SESSION *Session)
{
DeleteCriticalSection(&Session->Send.Lock);
DeleteCriticalSection(&Session->Receive.Lock);
@ -156,14 +160,18 @@ WintunEndSession(_In_ TUN_SESSION *Session)
Free(Session);
}
WINTUN_GET_READ_WAIT_EVENT_FUNC_IMPL WintunGetReadWaitEvent;
_Use_decl_annotations_
HANDLE WINAPI
WintunGetReadWaitEvent(_In_ TUN_SESSION *Session)
WintunGetReadWaitEvent(TUN_SESSION *Session)
{
return Session->Descriptor.Send.TailMoved;
}
_Return_type_success_(return != NULL) _Ret_bytecount_(*PacketSize) BYTE *WINAPI
WintunReceivePacket(_In_ TUN_SESSION *Session, _Out_ DWORD *PacketSize)
WINTUN_RECEIVE_PACKET_FUNC_IMPL WintunReceivePacket;
_Use_decl_annotations_
BYTE *WINAPI
WintunReceivePacket(TUN_SESSION *Session, DWORD *PacketSize)
{
DWORD LastError;
EnterCriticalSection(&Session->Send.Lock);
@ -213,8 +221,10 @@ cleanup:
return NULL;
}
void WINAPI
WintunReleaseReceivePacket(_In_ TUN_SESSION *Session, _In_ const BYTE *Packet)
WINTUN_RELEASE_RECEIVE_PACKET_FUNC_IMPL WintunReleaseReceivePacket;
_Use_decl_annotations_
VOID WINAPI
WintunReleaseReceivePacket(TUN_SESSION *Session, const BYTE *Packet)
{
EnterCriticalSection(&Session->Send.Lock);
TUN_PACKET *ReleasedBuffPacket = (TUN_PACKET *)(Packet - offsetof(TUN_PACKET, Data));
@ -232,8 +242,10 @@ WintunReleaseReceivePacket(_In_ TUN_SESSION *Session, _In_ const BYTE *Packet)
LeaveCriticalSection(&Session->Send.Lock);
}
_Return_type_success_(return != NULL) _Ret_bytecount_(PacketSize) BYTE *WINAPI
WintunAllocateSendPacket(_In_ TUN_SESSION *Session, _In_ DWORD PacketSize)
WINTUN_ALLOCATE_SEND_PACKET_FUNC_IMPL WintunAllocateSendPacket;
_Use_decl_annotations_
BYTE *WINAPI
WintunAllocateSendPacket(TUN_SESSION *Session, DWORD PacketSize)
{
DWORD LastError;
EnterCriticalSection(&Session->Receive.Lock);
@ -268,8 +280,10 @@ cleanup:
return NULL;
}
void WINAPI
WintunSendPacket(_In_ TUN_SESSION *Session, _In_ const BYTE *Packet)
WINTUN_SEND_PACKET_FUNC_IMPL WintunSendPacket;
_Use_decl_annotations_
VOID WINAPI
WintunSendPacket(TUN_SESSION *Session, const BYTE *Packet)
{
EnterCriticalSection(&Session->Receive.Lock);
TUN_PACKET *ReleasedBuffPacket = (TUN_PACKET *)(Packet - offsetof(TUN_PACKET, Data));
@ -285,7 +299,8 @@ WintunSendPacket(_In_ TUN_SESSION *Session, _In_ const BYTE *Packet)
TUN_RING_WRAP(Session->Receive.TailRelease + AlignedPacketSize, Session->Capacity);
Session->Receive.PacketsToRelease--;
}
if (Session->Descriptor.Receive.Ring->Tail != Session->Receive.TailRelease) {
if (Session->Descriptor.Receive.Ring->Tail != Session->Receive.TailRelease)
{
WriteULongRelease(&Session->Descriptor.Receive.Ring->Tail, Session->Receive.TailRelease);
if (ReadAcquire(&Session->Descriptor.Receive.Ring->Alertable))
SetEvent(Session->Descriptor.Receive.TailMoved);

View File

@ -16,7 +16,7 @@ extern "C" {
/**
* A handle representing Wintun adapter
*/
typedef void *WINTUN_ADAPTER_HANDLE;
typedef struct _WINTUN_ADAPTER *WINTUN_ADAPTER_HANDLE;
/**
* Maximum pool name length including zero terminator
@ -41,11 +41,12 @@ typedef void *WINTUN_ADAPTER_HANDLE;
* @return If the function succeeds, the return value is the adapter handle. Must be released with WintunFreeAdapter. If
* the function fails, the return value is NULL. To get extended error information, call GetLastError.
*/
typedef _Return_type_success_(return != NULL) WINTUN_ADAPTER_HANDLE(WINAPI *WINTUN_CREATE_ADAPTER_FUNC)(
_In_z_ const WCHAR *Pool,
_In_z_ const WCHAR *Name,
_In_opt_ const GUID *RequestedGUID,
_Out_opt_ BOOL *RebootRequired);
typedef _Must_inspect_result_
_Return_type_success_(return != NULL)
_Post_maybenull_
WINTUN_ADAPTER_HANDLE(WINAPI WINTUN_CREATE_ADAPTER_FUNC_IMPL)
(_In_z_ LPCWSTR Pool, _In_z_ LPCWSTR Name, _In_opt_ const GUID *RequestedGUID, _Out_opt_ BOOL *RebootRequired);
typedef WINTUN_CREATE_ADAPTER_FUNC_IMPL *WINTUN_CREATE_ADAPTER_FUNC;
/**
* Opens an existing Wintun adapter.
@ -55,14 +56,15 @@ typedef _Return_type_success_(return != NULL) WINTUN_ADAPTER_HANDLE(WINAPI *WINT
* @param Name Adapter name. Zero-terminated string of up to MAX_ADAPTER_NAME-1 characters.
*
* @return If the function succeeds, the return value is adapter handle. Must be released with WintunFreeAdapter. If the
* function fails, the return value is NULL. To get extended error information, call GetLastError. Possible
* errors include the following:
* ERROR_FILE_NOT_FOUND if adapter with given name is not found;
* ERROR_ALREADY_EXISTS if adapter is found but not a Wintun-class or not a member of the pool
* function fails, the return value is NULL. To get extended error information, call GetLastError. Possible errors
* include the following: ERROR_FILE_NOT_FOUND if adapter with given name is not found; ERROR_ALREADY_EXISTS if adapter
* is found but not a Wintun-class or not a member of the pool
*/
typedef _Return_type_success_(return != NULL)
WINTUN_ADAPTER_HANDLE(WINAPI *WINTUN_OPEN_ADAPTER_FUNC)(_In_z_ const WCHAR *Pool, _In_z_ const WCHAR *Name);
typedef _Must_inspect_result_
_Return_type_success_(return != NULL)
_Post_maybenull_
WINTUN_ADAPTER_HANDLE(WINAPI WINTUN_OPEN_ADAPTER_FUNC_IMPL)(_In_z_ LPCWSTR Pool, _In_z_ LPCWSTR Name);
typedef WINTUN_OPEN_ADAPTER_FUNC_IMPL *WINTUN_OPEN_ADAPTER_FUNC;
/**
* Deletes a Wintun adapter.
@ -78,10 +80,10 @@ typedef _Return_type_success_(return != NULL)
* @return If the function succeeds, the return value is nonzero. If the function fails, the return value is zero. To
* get extended error information, call GetLastError.
*/
typedef _Return_type_success_(return != FALSE) BOOL(WINAPI *WINTUN_DELETE_ADAPTER_FUNC)(
_In_ WINTUN_ADAPTER_HANDLE Adapter,
_In_ BOOL ForceCloseSessions,
_Out_opt_ BOOL *RebootRequired);
typedef _Return_type_success_(return != FALSE)
BOOL(WINAPI WINTUN_DELETE_ADAPTER_FUNC_IMPL)
(_In_ WINTUN_ADAPTER_HANDLE Adapter, _In_ BOOL ForceCloseSessions, _Out_opt_ BOOL *RebootRequired);
typedef WINTUN_DELETE_ADAPTER_FUNC_IMPL *WINTUN_DELETE_ADAPTER_FUNC;
/**
* Called by WintunEnumAdapters for each adapter in the pool.
@ -107,15 +109,17 @@ typedef BOOL(CALLBACK *WINTUN_ENUM_CALLBACK)(_In_ WINTUN_ADAPTER_HANDLE Adapter,
* @return If the function succeeds, the return value is nonzero. If the function fails, the return value is zero. To
* get extended error information, call GetLastError.
*/
typedef _Return_type_success_(return != FALSE) BOOL(
WINAPI *WINTUN_ENUM_ADAPTERS_FUNC)(_In_z_ const WCHAR *Pool, _In_ WINTUN_ENUM_CALLBACK Callback, _In_ LPARAM Param);
typedef _Return_type_success_(return != FALSE)
BOOL(WINAPI WINTUN_ENUM_ADAPTERS_FUNC_IMPL)(_In_z_ LPCWSTR Pool, _In_ WINTUN_ENUM_CALLBACK Callback, _In_ LPARAM Param);
typedef WINTUN_ENUM_ADAPTERS_FUNC_IMPL *WINTUN_ENUM_ADAPTERS_FUNC;
/**
* Releases Wintun adapter resources.
*
* @param Adapter Adapter handle obtained with WintunOpenAdapter or WintunCreateAdapter.
*/
typedef void(WINAPI *WINTUN_FREE_ADAPTER_FUNC)(_In_ WINTUN_ADAPTER_HANDLE Adapter);
typedef VOID(WINAPI WINTUN_FREE_ADAPTER_FUNC_IMPL)(_In_ WINTUN_ADAPTER_HANDLE Adapter);
typedef WINTUN_FREE_ADAPTER_FUNC_IMPL *WINTUN_FREE_ADAPTER_FUNC;
/**
* Deletes all Wintun adapters in a pool and if there are no more adapters in any other pools, also removes Wintun
@ -129,7 +133,8 @@ typedef void(WINAPI *WINTUN_FREE_ADAPTER_FUNC)(_In_ WINTUN_ADAPTER_HANDLE Adapte
* get extended error information, call GetLastError.
*/
typedef _Return_type_success_(return != FALSE)
BOOL(WINAPI *WINTUN_DELETE_POOL_DRIVER_FUNC)(_In_z_ const WCHAR *Pool, _Out_opt_ BOOL *RebootRequired);
BOOL(WINAPI WINTUN_DELETE_POOL_DRIVER_FUNC_IMPL)(_In_z_ LPCWSTR Pool, _Out_opt_ BOOL *RebootRequired);
typedef WINTUN_DELETE_POOL_DRIVER_FUNC_IMPL *WINTUN_DELETE_POOL_DRIVER_FUNC;
/**
* Returns the LUID of the adapter.
@ -138,7 +143,8 @@ typedef _Return_type_success_(return != FALSE)
*
* @param Luid Pointer to LUID to receive adapter LUID.
*/
typedef void(WINAPI *WINTUN_GET_ADAPTER_LUID_FUNC)(_In_ WINTUN_ADAPTER_HANDLE Adapter, _Out_ NET_LUID *Luid);
typedef VOID(WINAPI WINTUN_GET_ADAPTER_LUID_FUNC_IMPL)(_In_ WINTUN_ADAPTER_HANDLE Adapter, _Out_ NET_LUID *Luid);
typedef WINTUN_GET_ADAPTER_LUID_FUNC_IMPL *WINTUN_GET_ADAPTER_LUID_FUNC;
/**
* Returns the name of the Wintun adapter.
@ -150,9 +156,11 @@ typedef void(WINAPI *WINTUN_GET_ADAPTER_LUID_FUNC)(_In_ WINTUN_ADAPTER_HANDLE Ad
* @return If the function succeeds, the return value is nonzero. If the function fails, the return value is zero. To
* get extended error information, call GetLastError.
*/
typedef _Return_type_success_(return != FALSE) BOOL(WINAPI *WINTUN_GET_ADAPTER_NAME_FUNC)(
_In_ WINTUN_ADAPTER_HANDLE Adapter,
_Out_cap_c_(MAX_ADAPTER_NAME) WCHAR *Name);
typedef _Must_inspect_result_
_Return_type_success_(return != FALSE)
BOOL(WINAPI WINTUN_GET_ADAPTER_NAME_FUNC_IMPL)
(_In_ WINTUN_ADAPTER_HANDLE Adapter, _Out_writes_z_(MAX_ADAPTER_NAME) LPWSTR Name);
typedef WINTUN_GET_ADAPTER_NAME_FUNC_IMPL *WINTUN_GET_ADAPTER_NAME_FUNC;
/**
* Sets name of the Wintun adapter.
@ -165,7 +173,8 @@ typedef _Return_type_success_(return != FALSE) BOOL(WINAPI *WINTUN_GET_ADAPTER_N
* get extended error information, call GetLastError.
*/
typedef _Return_type_success_(return != FALSE)
BOOL(WINAPI *WINTUN_SET_ADAPTER_NAME_FUNC)(_In_ WINTUN_ADAPTER_HANDLE Adapter, _In_z_ const WCHAR *Name);
BOOL(WINAPI WINTUN_SET_ADAPTER_NAME_FUNC_IMPL)(_In_ WINTUN_ADAPTER_HANDLE Adapter, _In_z_ LPCWSTR Name);
typedef WINTUN_SET_ADAPTER_NAME_FUNC_IMPL *WINTUN_SET_ADAPTER_NAME_FUNC;
/**
* Determines the version of the Wintun driver currently loaded.
@ -174,7 +183,9 @@ typedef _Return_type_success_(return != FALSE)
* zero. To get extended error information, call GetLastError. Possible errors include the following:
* ERROR_FILE_NOT_FOUND Wintun not loaded
*/
typedef DWORD(WINAPI *WINTUN_GET_RUNNING_DRIVER_VERSION_FUNC)(void);
typedef _Return_type_success_(return != 0)
DWORD(WINAPI WINTUN_GET_RUNNING_DRIVER_VERSION_FUNC_IMPL)(VOID);
typedef WINTUN_GET_RUNNING_DRIVER_VERSION_FUNC_IMPL *WINTUN_GET_RUNNING_DRIVER_VERSION_FUNC;
/**
* Determines the level of logging, passed to WINTUN_LOGGER_CALLBACK.
@ -193,7 +204,7 @@ typedef enum
*
* @param Message Message text.
*/
typedef void(CALLBACK *WINTUN_LOGGER_CALLBACK)(_In_ WINTUN_LOGGER_LEVEL Level, _In_z_ const WCHAR *Message);
typedef VOID(CALLBACK *WINTUN_LOGGER_CALLBACK)(_In_ WINTUN_LOGGER_LEVEL Level, _In_z_ LPCWSTR Message);
/**
* Sets logger callback function.
@ -202,7 +213,8 @@ typedef void(CALLBACK *WINTUN_LOGGER_CALLBACK)(_In_ WINTUN_LOGGER_LEVEL Level, _
* threads concurrently. Should the logging require serialization, you must handle serialization in
* NewLogger. Set to NULL to disable.
*/
typedef void(WINAPI *WINTUN_SET_LOGGER_FUNC)(_In_ WINTUN_LOGGER_CALLBACK NewLogger);
typedef VOID(WINAPI WINTUN_SET_LOGGER_FUNC_IMPL)(_In_ WINTUN_LOGGER_CALLBACK NewLogger);
typedef WINTUN_SET_LOGGER_FUNC_IMPL *WINTUN_SET_LOGGER_FUNC;
/**
* Minimum ring capacity.
@ -217,7 +229,7 @@ typedef void(WINAPI *WINTUN_SET_LOGGER_FUNC)(_In_ WINTUN_LOGGER_CALLBACK NewLogg
/**
* A handle representing Wintun session
*/
typedef void *WINTUN_SESSION_HANDLE;
typedef struct _TUN_SESSION *WINTUN_SESSION_HANDLE;
/**
* Starts Wintun session.
@ -230,15 +242,19 @@ typedef void *WINTUN_SESSION_HANDLE;
* @return Wintun session handle. Must be released with WintunEndSession. If the function fails, the return value is
* NULL. To get extended error information, call GetLastError.
*/
typedef _Return_type_success_(return != NULL)
WINTUN_SESSION_HANDLE(WINAPI *WINTUN_START_SESSION_FUNC)(_In_ WINTUN_ADAPTER_HANDLE Adapter, _In_ DWORD Capacity);
typedef _Must_inspect_result_
_Return_type_success_(return != NULL)
_Post_maybenull_
WINTUN_SESSION_HANDLE(WINAPI WINTUN_START_SESSION_FUNC_IMPL)(_In_ WINTUN_ADAPTER_HANDLE Adapter, _In_ DWORD Capacity);
typedef WINTUN_START_SESSION_FUNC_IMPL *WINTUN_START_SESSION_FUNC;
/**
* Ends Wintun session.
*
* @param Session Wintun session handle obtained with WintunStartSession
*/
typedef void(WINAPI *WINTUN_END_SESSION_FUNC)(_In_ WINTUN_SESSION_HANDLE Session);
typedef VOID(WINAPI WINTUN_END_SESSION_FUNC_IMPL)(_In_ WINTUN_SESSION_HANDLE Session);
typedef WINTUN_END_SESSION_FUNC_IMPL *WINTUN_END_SESSION_FUNC;
/**
* Gets Wintun session's read-wait event handle.
@ -250,7 +266,8 @@ typedef void(WINAPI *WINTUN_END_SESSION_FUNC)(_In_ WINTUN_SESSION_HANDLE Session
* load), wait for this event to become signaled before retrying WintunReceivePackets. Do not call
* CloseHandle on this event - it is managed by the session.
*/
typedef HANDLE(WINAPI *WINTUN_GET_READ_WAIT_EVENT_FUNC)(_In_ WINTUN_SESSION_HANDLE Session);
typedef HANDLE(WINAPI WINTUN_GET_READ_WAIT_EVENT_FUNC_IMPL)(_In_ WINTUN_SESSION_HANDLE Session);
typedef WINTUN_GET_READ_WAIT_EVENT_FUNC_IMPL *WINTUN_GET_READ_WAIT_EVENT_FUNC;
/**
* Maximum IP packet size
@ -272,8 +289,12 @@ typedef HANDLE(WINAPI *WINTUN_GET_READ_WAIT_EVENT_FUNC)(_In_ WINTUN_SESSION_HAND
* ERROR_NO_MORE_ITEMS Wintun buffer is exhausted;
* ERROR_INVALID_DATA Wintun buffer is corrupt
*/
typedef _Return_type_success_(return != NULL) _Ret_bytecount_(*PacketSize) BYTE *(
WINAPI *WINTUN_RECEIVE_PACKET_FUNC)(_In_ WINTUN_SESSION_HANDLE Session, _Out_ DWORD *PacketSize);
typedef _Must_inspect_result_
_Return_type_success_(return != NULL)
_Post_maybenull_
_Post_writable_byte_size_(*PacketSize)
BYTE *(WINAPI WINTUN_RECEIVE_PACKET_FUNC_IMPL)(_In_ WINTUN_SESSION_HANDLE Session, _Out_ DWORD *PacketSize);
typedef WINTUN_RECEIVE_PACKET_FUNC_IMPL *WINTUN_RECEIVE_PACKET_FUNC;
/**
* Releases internal buffer after the received packet has been processed by the client. This function is thread-safe.
@ -282,7 +303,9 @@ typedef _Return_type_success_(return != NULL) _Ret_bytecount_(*PacketSize) BYTE
*
* @param Packet Packet obtained with WintunReceivePacket
*/
typedef void(WINAPI *WINTUN_RELEASE_RECEIVE_PACKET_FUNC)(_In_ WINTUN_SESSION_HANDLE Session, _In_ const BYTE *Packet);
typedef VOID(
WINAPI WINTUN_RELEASE_RECEIVE_PACKET_FUNC_IMPL)(_In_ WINTUN_SESSION_HANDLE Session, _In_ const BYTE *Packet);
typedef WINTUN_RELEASE_RECEIVE_PACKET_FUNC_IMPL *WINTUN_RELEASE_RECEIVE_PACKET_FUNC;
/**
* Allocates memory for a packet to send. After the memory is filled with packet data, call WintunSendPacket to send
@ -299,8 +322,12 @@ typedef void(WINAPI *WINTUN_RELEASE_RECEIVE_PACKET_FUNC)(_In_ WINTUN_SESSION_HAN
* ERROR_HANDLE_EOF Wintun adapter is terminating;
* ERROR_BUFFER_OVERFLOW Wintun buffer is full;
*/
typedef _Return_type_success_(return != NULL) _Ret_bytecount_(PacketSize) BYTE *(
WINAPI *WINTUN_ALLOCATE_SEND_PACKET_FUNC)(_In_ WINTUN_SESSION_HANDLE Session, _In_ DWORD PacketSize);
typedef _Must_inspect_result_
_Return_type_success_(return != NULL)
_Post_maybenull_
_Post_writable_byte_size_(PacketSize)
BYTE *(WINAPI WINTUN_ALLOCATE_SEND_PACKET_FUNC_IMPL)(_In_ WINTUN_SESSION_HANDLE Session, _In_ DWORD PacketSize);
typedef WINTUN_ALLOCATE_SEND_PACKET_FUNC_IMPL *WINTUN_ALLOCATE_SEND_PACKET_FUNC;
/**
* Sends the packet and releases internal buffer. WintunSendPacket is thread-safe, but the WintunAllocateSendPacket
@ -311,7 +338,8 @@ typedef _Return_type_success_(return != NULL) _Ret_bytecount_(PacketSize) BYTE *
*
* @param Packet Packet obtained with WintunAllocateSendPacket
*/
typedef void(WINAPI *WINTUN_SEND_PACKET_FUNC)(_In_ WINTUN_SESSION_HANDLE Session, _In_ const BYTE *Packet);
typedef VOID(WINAPI WINTUN_SEND_PACKET_FUNC_IMPL)(_In_ WINTUN_SESSION_HANDLE Session, _In_ const BYTE *Packet);
typedef WINTUN_SEND_PACKET_FUNC_IMPL *WINTUN_SEND_PACKET_FUNC;
#ifdef __cplusplus
}