api: rewrite based on SwDevice

Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
This commit is contained in:
Jason A. Donenfeld 2021-10-11 23:21:31 -06:00
parent c69ec758d1
commit 544fdaaf8f
30 changed files with 2554 additions and 2836 deletions

112
README.md
View File

@ -11,12 +11,12 @@ Wintun is deployed as a platform-specific `wintun.dll` file. Install the `wintun
Include the [`wintun.h` file](https://git.zx2c4.com/wintun/tree/api/wintun.h) in your project simply by copying it there and dynamically load the `wintun.dll` using [`LoadLibraryEx()`](https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexa) and [`GetProcAddress()`](https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-getprocaddress) to resolve each function, using the typedefs provided in the header file. The [`InitializeWintun` function in the example.c code](https://git.zx2c4.com/wintun/tree/example/example.c) provides this in a function that you can simply copy and paste.
With the library setup, Wintun can then be used by first creating an adapter, and then starting a tunnel session on that adapter. Adapters have names (e.g. "OfficeNet"), and each one belongs to a _pool_ (e.g. "WireGuard"). So, for example, the WireGuard application app creates multiple tunnels all inside of its "WireGuard" _pool_:
With the library setup, Wintun can then be used by first creating an adapter, configuring it, and then setting its status to "up". Adapters have names (e.g. "OfficeNet") and types (e.g. "Wintun").
```C
WINTUN_ADAPTER_HANDLE Adapter1 = WintunCreateAdapter(L"WireGuard", L"OfficeNet", &SomeFixedGUID1, NULL);
WINTUN_ADAPTER_HANDLE Adapter2 = WintunCreateAdapter(L"WireGuard", L"HomeNet", &SomeFixedGUID2, NULL);
WINTUN_ADAPTER_HANDLE Adapter3 = WintunCreateAdapter(L"WireGuard", L"Data Center", &SomeFixedGUID3, NULL);
WINTUN_ADAPTER_HANDLE Adapter1 = WintunCreateAdapter(L"OfficeNet", L"Wintun", &SomeFixedGUID1);
WINTUN_ADAPTER_HANDLE Adapter2 = WintunCreateAdapter(L"HomeNet", L"Wintun", &SomeFixedGUID2);
WINTUN_ADAPTER_HANDLE Adapter3 = WintunCreateAdapter(L"Data Center", L"Wintun", &SomeFixedGUID3);
```
After creating an adapter, we can use it by starting a session:
@ -119,13 +119,14 @@ Non-zero to continue iterating adapters; zero to stop.
#### WINTUN\_LOGGER\_CALLBACK
`typedef void(* WINTUN_LOGGER_CALLBACK) (WINTUN_LOGGER_LEVEL Level, const WCHAR *Message)`
`typedef void(* WINTUN_LOGGER_CALLBACK) (WINTUN_LOGGER_LEVEL Level, DWORD64 Timestamp, const WCHAR *Message)`
Called by internal logger to report diagnostic messages
**Parameters**
- *Level*: Message level.
- *Timestamp*: Message timestamp in in 100ns intervals since 1601-01-01 UTC.
- *Message*: Message text.
#### WINTUN\_SESSION\_HANDLE
@ -152,88 +153,49 @@ Enumerator
#### WintunCreateAdapter()
`WINTUN_ADAPTER_HANDLE WintunCreateAdapter (const WCHAR * Pool, const WCHAR * Name, const GUID * RequestedGUID, BOOL * RebootRequired)`
`WINTUN_ADAPTER_HANDLE WintunCreateAdapter (const WCHAR * Name, const WCHAR * TunnelType, const GUID * RequestedGUID)`
Creates a new Wintun adapter.
**Parameters**
- *Pool*: Name of the adapter pool. Zero-terminated string of up to WINTUN\_MAX\_POOL-1 characters.
- *Name*: The requested name of the adapter. Zero-terminated string of up to MAX\_ADAPTER\_NAME-1 characters.
- *Name*: Name of the adapter tunnel type. Zero-terminated string of up to MAX\_ADAPTER\_NAME-1 characters.
- *RequestedGUID*: The GUID of the created network adapter, which then influences NLA generation deterministically. If it is set to NULL, the GUID is chosen by the system at random, and hence a new NLA entry is created for each new adapter. It is called "requested" GUID because the API it uses is completely undocumented, and so there could be minor interesting complications with its usage.
- *RebootRequired*: Optional pointer to a boolean flag to be set to TRUE in case SetupAPI suggests a reboot.
**Returns**
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.
If the function succeeds, the return value is the adapter handle. Must be released with WintunCloseAdapter. If the function fails, the return value is NULL. To get extended error information, call GetLastError.
#### WintunOpenAdapter()
`WINTUN_ADAPTER_HANDLE WintunOpenAdapter (const WCHAR * Pool, const WCHAR * Name)`
`WINTUN_ADAPTER_HANDLE WintunOpenAdapter (const WCHAR * Name)`
Opens an existing Wintun adapter.
**Parameters**
- *Pool*: Name of the adapter pool. Zero-terminated string of up to WINTUN\_MAX\_POOL-1 characters.
- *Name*: Adapter name. Zero-terminated string of up to MAX\_ADAPTER\_NAME-1 characters.
- *Name*: The requested name of the adapter. Zero-terminated string of up to MAX\_ADAPTER\_NAME-1 characters.
**Returns**
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
If the function succeeds, the return value is adapter handle. Must be released with WintunCloseAdapter. If the function fails, the return value is NULL. To get extended error information, call GetLastError.
#### WintunDeleteAdapter()
#### WintunCloseAdapter()
`BOOL WintunDeleteAdapter (WINTUN_ADAPTER_HANDLE Adapter, BOOL ForceCloseSessions, BOOL * RebootRequired)`
`void WintunCloseAdapter (WINTUN_ADAPTER_HANDLE Adapter)`
Deletes a Wintun adapter.
Releases Wintun adapter resources and, if adapter was created with WintunCreateAdapter, removes adapter.
**Parameters**
- *Adapter*: Adapter handle obtained with WintunOpenAdapter or WintunCreateAdapter.
- *ForceCloseSessions*: Force close adapter handles that may be in use by other processes. Only set this to TRUE with extreme care, as this is resource intensive and may put processes into an undefined or unpredictable state. Most users should set this to FALSE.
- *RebootRequired*: Optional pointer to a boolean flag to be set to TRUE in case SetupAPI suggests a reboot.
- *Adapter*: Adapter handle obtained with WintunCreateAdapter or WintunOpenAdapter.
**Returns**
#### WintunDeleteDriver()
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.
`BOOL WintunDeleteDriver ()`
#### WintunEnumAdapters()
`BOOL WintunEnumAdapters (const WCHAR * Pool, WINTUN_ENUM_CALLBACK Callback, LPARAM Param)`
Enumerates all Wintun adapters.
**Parameters**
- *Pool*: Name of the adapter pool. Zero-terminated string of up to WINTUN\_MAX\_POOL-1 characters.
- *Callback*: Callback function. To continue enumeration, the callback function must return TRUE; to stop enumeration, it must return FALSE.
- *Param*: An application-defined value to be passed to the callback function.
**Returns**
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.
#### WintunFreeAdapter()
`void WintunFreeAdapter (WINTUN_ADAPTER_HANDLE Adapter)`
Releases Wintun adapter resources.
**Parameters**
- *Adapter*: Adapter handle obtained with WintunOpenAdapter or WintunCreateAdapter.
#### WintunDeletePoolDriver()
`BOOL WintunDeletePoolDriver (const WCHAR * Pool, BOOL * RebootRequired)`
Deletes all Wintun adapters in a pool and if there are no more adapters in any other pools, also removes Wintun from the driver store, usually called by uninstallers.
**Parameters**
- *Pool*: Name of the adapter pool. Zero-terminated string of up to WINTUN\_MAX\_POOL-1 characters.
- *RebootRequired*: Optional pointer to a boolean flag to be set to TRUE in case SetupAPI suggests a reboot.
Deletes the Wintun driver if there are no more adapters in use.
**Returns**
@ -250,36 +212,6 @@ Returns the LUID of the adapter.
- *Adapter*: Adapter handle obtained with WintunOpenAdapter or WintunCreateAdapter
- *Luid*: Pointer to LUID to receive adapter LUID.
#### WintunGetAdapterName()
`BOOL WintunGetAdapterName (WINTUN_ADAPTER_HANDLE Adapter, WCHAR * Name)`
Returns the name of the Wintun adapter.
**Parameters**
- *Adapter*: Adapter handle obtained with WintunOpenAdapter or WintunCreateAdapter
- *Name*: Pointer to a string to receive adapter name
**Returns**
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.
#### WintunSetAdapterName()
`BOOL WintunSetAdapterName (WINTUN_ADAPTER_HANDLE Adapter, const WCHAR * Name)`
Sets name of the Wintun adapter.
**Parameters**
- *Adapter*: Adapter handle obtained with WintunOpenAdapter or WintunCreateAdapter
- *Name*: Adapter name. Zero-terminated string of up to MAX\_ADAPTER\_NAME-1 characters.
**Returns**
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.
#### WintunGetRunningDriverVersion()
`DWORD WintunGetRunningDriverVersion (void )`
@ -397,10 +329,10 @@ Sends the packet and releases internal buffer. WintunSendPacket is thread-safe,
General requirements:
- [Visual Studio 2019](https://visualstudio.microsoft.com/downloads/) with Windows SDK 10.0.18362.0
- [Windows Driver Kit for Windows 10, version 1903](https://docs.microsoft.com/en-us/windows-hardware/drivers/download-the-wdk)
- [Visual Studio 2019](https://visualstudio.microsoft.com/downloads/) with Windows SDK
- [Windows Driver Kit](https://docs.microsoft.com/en-us/windows-hardware/drivers/download-the-wdk)
`wintun.sln` may be opened in Visual Studio for development and building. Be sure to run `bcdedit /set testsigning on` before to enable unsigned driver loading. The default run sequence (F5) in Visual Studio will build the example project.
`wireguard.sln` may be opened in Visual Studio for development and building. Be sure to run `bcdedit /set testsigning on` and then reboot before to enable unsigned driver loading. The default run sequence (F5) in Visual Studio will build the example project and its dependencies.
## License

File diff suppressed because it is too large Load Diff

View File

@ -12,71 +12,46 @@
#define MAX_INSTANCE_ID MAX_PATH /* TODO: Is MAX_PATH always enough? */
#define WINTUN_HWID L"Wintun"
#define WINTUN_ENUMERATOR (IsWindows7 ? L"ROOT\\" WINTUN_HWID : L"SWD\\" WINTUN_HWID)
extern const DEVPROPKEY DEVPKEY_Wintun_Name;
typedef struct HSWDEVICE__ *HSWDEVICE;
/**
* Wintun adapter descriptor.
*/
typedef struct _WINTUN_ADAPTER
{
HSWDEVICE SwDevice;
HDEVINFO DevInfo;
SP_DEVINFO_DATA DevInfoData;
WCHAR *InterfaceFilename;
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
*/
WINTUN_FREE_ADAPTER_FUNC_IMPL WintunFreeAdapter;
/**
* @copydoc WINTUN_CREATE_ADAPTER_FUNC
*/
WINTUN_CREATE_ADAPTER_FUNC_IMPL WintunCreateAdapter;
WINTUN_CREATE_ADAPTER_FUNC WintunCreateAdapter;
/**
* @copydoc WINTUN_OPEN_ADAPTER_FUNC
*/
WINTUN_OPEN_ADAPTER_FUNC_IMPL WintunOpenAdapter;
WINTUN_OPEN_ADAPTER_FUNC WintunOpenAdapter;
/**
* @copydoc WINTUN_DELETE_ADAPTER_FUNC
* @copydoc WINTUN_CLOSE_ADAPTER_FUNC
*/
WINTUN_DELETE_ADAPTER_FUNC_IMPL WintunDeleteAdapter;
/**
* @copydoc WINTUN_ENUM_ADAPTERS_FUNC
*/
WINTUN_ENUM_ADAPTERS_FUNC_IMPL WintunEnumAdapters;
/**
* @copydoc WINTUN_DELETE_POOL_DRIVER_FUNC
*/
WINTUN_DELETE_POOL_DRIVER_FUNC_IMPL WintunDeletePoolDriver;
WINTUN_CLOSE_ADAPTER_FUNC WintunCloseAdapter;
/**
* @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;
WINTUN_GET_ADAPTER_LUID_FUNC WintunGetAdapterLUID;
/**
* Returns a handle to the adapter device object.
@ -90,19 +65,88 @@ WINTUN_GET_RUNNING_DRIVER_VERSION_FUNC_IMPL WintunGetRunningDriverVersion;
_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.
* Returns the device object file name for an adapter instance ID.
*
* @param Pool Pool name of adapter object to be opened.
* @param InstanceID The device instance ID of the adapter.
*
* @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.
* @return If the function succeeds, the return value is the filename of the device object, which
* must be freed with Free(). If the function fails, the return value is INVALID_HANDLE_VALUE.
* 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);
LPWSTR
AdapterGetDeviceObjectFileName(_In_z_ LPCWSTR InstanceId);
/**
* Cleans up adapters with no attached process.
*/
VOID AdapterCleanupOrphanedDevices(VOID);
/**
* Cleans up adapters that use the old enumerator.
*/
VOID AdapterCleanupLegacyDevices(VOID);
/**
* Removes the specified device instance.
*
* @param DevInfo Device info handle from SetupAPI.
* @param DevInfoData Device info data specifying which device.
*
* @return If the function succeeds, the return value is TRUE. If the
* function fails, the return value is FALSE. To get extended
* error information, call GetLastError.
*/
_Return_type_success_(return != FALSE)
BOOL
AdapterRemoveInstance(_In_ HDEVINFO DevInfo, _In_ SP_DEVINFO_DATA *DevInfoData);
/**
* Enables the specified device instance.
*
* @param DevInfo Device info handle from SetupAPI.
* @param DevInfoData Device info data specifying which device.
*
* @return If the function succeeds, the return value is TRUE. If the
* function fails, the return value is FALSE. To get extended
* error information, call GetLastError.
*/
_Return_type_success_(return != FALSE)
BOOL
AdapterEnableInstance(_In_ HDEVINFO DevInfo, _In_ SP_DEVINFO_DATA *DevInfoData);
/**
* Disables the specified device instance.
*
* @param DevInfo Device info handle from SetupAPI.
* @param DevInfoData Device info data specifying which device.
*
* @return If the function succeeds, the return value is TRUE. If the
* function fails, the return value is FALSE. To get extended
* error information, call GetLastError.
*/
_Return_type_success_(return != FALSE)
BOOL
AdapterDisableInstance(_In_ HDEVINFO DevInfo, _In_ SP_DEVINFO_DATA *DevInfoData);
/**
* Force closes all device handles of the specified device instance.
*
* @param DevInfo Device info handle from SetupAPI.
* @param DevInfoData Device info data specifying which device.
*
* @return If the function succeeds, the return value is TRUE. If the
* function fails, the return value is FALSE. To get extended
* error information, call GetLastError.
*/
_Return_type_success_(return != FALSE)
BOOL
AdapterForceCloseHandles(_In_ HDEVINFO DevInfo, _In_ SP_DEVINFO_DATA *DevInfoData);

351
api/adapter_win7.h Normal file
View File

@ -0,0 +1,351 @@
/* SPDX-License-Identifier: GPL-2.0
*
* Copyright (C) 2018-2021 WireGuard LLC. All Rights Reserved.
*/
static const DEVPROPKEY DEVPKEY_Wintun_OwningProcess = {
{ 0x3361c968, 0x2f2e, 0x4660, { 0xb4, 0x7e, 0x69, 0x9c, 0xdc, 0x4c, 0x32, 0xb9 } },
DEVPROPID_FIRST_USABLE + 3
};
typedef struct _OWNING_PROCESS
{
DWORD ProcessId;
FILETIME CreationTime;
} OWNING_PROCESS;
_Must_inspect_result_
static _Return_type_success_(return != FALSE)
BOOL
WaitForInterfaceWin7(_In_ HDEVINFO DevInfo, _In_ SP_DEVINFO_DATA *DevInfoData, _In_ LPCWSTR DevInstanceId)
{
ULONG Status, Number;
DWORD ValType, Zero;
WCHAR *FileName = NULL;
HKEY Key = INVALID_HANDLE_VALUE;
HANDLE FileHandle = INVALID_HANDLE_VALUE;
BOOLEAN Ret = FALSE;
for (DWORD Tries = 0; Tries < 1500; ++Tries)
{
if (Tries)
Sleep(10);
if (Key == INVALID_HANDLE_VALUE)
Key = SetupDiOpenDevRegKey(DevInfo, DevInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DRV, KEY_QUERY_VALUE);
if (!FileName)
FileName = AdapterGetDeviceObjectFileName(DevInstanceId);
if (FileName && FileHandle == INVALID_HANDLE_VALUE)
FileHandle = CreateFileW(
FileName,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
NULL,
OPEN_EXISTING,
0,
NULL);
Zero = 0;
if (FileName && FileHandle != INVALID_HANDLE_VALUE && Key != INVALID_HANDLE_VALUE && Key &&
RegQueryValueExW(Key, L"NetCfgInstanceId", NULL, &ValType, NULL, &Zero) != ERROR_MORE_DATA &&
CM_Get_DevNode_Status(&Status, &Number, DevInfoData->DevInst, 0) == CR_SUCCESS &&
!(Status & DN_HAS_PROBLEM) && !Number)
{
Ret = TRUE;
break;
}
}
if (Key != INVALID_HANDLE_VALUE && Key)
RegCloseKey(Key);
if (FileHandle != INVALID_HANDLE_VALUE)
CloseHandle(FileHandle);
Free(FileName);
return Ret;
}
_Must_inspect_result_
static _Return_type_success_(return != FALSE)
BOOL
CreateAdapterWin7(_Inout_ WINTUN_ADAPTER *Adapter, _In_z_ LPCWSTR Name, _In_z_ LPCWSTR TunnelTypeName)
{
DWORD LastError = ERROR_SUCCESS;
HDEVINFO DevInfo = SetupDiCreateDeviceInfoListExW(&GUID_DEVCLASS_NET, NULL, NULL, NULL);
if (DevInfo == INVALID_HANDLE_VALUE)
{
LastError = LOG_LAST_ERROR(L"Failed to create empty device information set");
goto cleanup;
}
SP_DEVINFO_DATA DevInfoData = { .cbSize = sizeof(DevInfoData) };
#ifdef MAYBE_WOW64
if (NativeMachine != IMAGE_FILE_PROCESS)
{
if (!CreateInstanceWin7ViaRundll32(Adapter->DevInstanceID))
{
LastError = LOG_LAST_ERROR(L"Failed to create device instance");
goto cleanup;
}
if (!SetupDiOpenDeviceInfoW(DevInfo, Adapter->DevInstanceID, NULL, DIOD_INHERIT_CLASSDRVS, &DevInfoData))
{
LastError = GetLastError();
goto cleanupDevInfo;
}
goto resumeAfterInstance;
}
#endif
if (!SetupDiCreateDeviceInfoW(
DevInfo, WINTUN_HWID, &GUID_DEVCLASS_NET, TunnelTypeName, NULL, DICD_GENERATE_ID, &DevInfoData))
{
LastError = LOG_LAST_ERROR(L"Failed to create new device information element");
goto cleanupDevInfo;
}
SP_DEVINSTALL_PARAMS_W DevInstallParams = { .cbSize = sizeof(DevInstallParams) };
if (!SetupDiGetDeviceInstallParamsW(DevInfo, &DevInfoData, &DevInstallParams))
{
LastError = LOG_LAST_ERROR(L"Failed to retrieve adapter device installation parameters");
goto cleanupDevInfo;
}
DevInstallParams.Flags |= DI_QUIETINSTALL;
if (!SetupDiSetDeviceInstallParamsW(DevInfo, &DevInfoData, &DevInstallParams))
{
LastError = LOG_LAST_ERROR(L"Failed to set adapter device installation parameters");
goto cleanupDevInfo;
}
if (!SetupDiSetSelectedDevice(DevInfo, &DevInfoData))
{
LastError = LOG_LAST_ERROR(L"Failed to select adapter device");
goto cleanupDevInfo;
}
static const WCHAR Hwids[_countof(WINTUN_HWID) + 1 /*Multi-string terminator*/] = WINTUN_HWID;
if (!SetupDiSetDeviceRegistryPropertyW(DevInfo, &DevInfoData, SPDRP_HARDWAREID, (const BYTE *)Hwids, sizeof(Hwids)))
{
LastError = LOG_LAST_ERROR(L"Failed to set adapter hardware ID");
goto cleanupDevInfo;
}
if (!SetupDiBuildDriverInfoList(DevInfo, &DevInfoData, SPDIT_COMPATDRIVER))
{
LastError = LOG_LAST_ERROR(L"Failed building adapter driver info list");
goto cleanupDevInfo;
}
SP_DRVINFO_DATA_W DrvInfoData = { .cbSize = sizeof(SP_DRVINFO_DATA_W) };
if (!SetupDiEnumDriverInfoW(DevInfo, &DevInfoData, SPDIT_COMPATDRIVER, 0, &DrvInfoData) ||
!SetupDiSetSelectedDriverW(DevInfo, &DevInfoData, &DrvInfoData))
{
LastError = LOG_ERROR(ERROR_DRIVER_INSTALL_BLOCKED, L"Failed to select a driver");
goto cleanupDriverInfo;
}
if (!SetupDiCallClassInstaller(DIF_REGISTERDEVICE, DevInfo, &DevInfoData))
{
LastError = LOG_LAST_ERROR(L"Failed to register adapter device");
goto cleanupDevInfo;
}
if (!SetupDiCallClassInstaller(DIF_REGISTER_COINSTALLERS, DevInfo, &DevInfoData))
LOG_LAST_ERROR(L"Failed to register adapter coinstallers");
if (!SetupDiCallClassInstaller(DIF_INSTALLINTERFACES, DevInfo, &DevInfoData))
LOG_LAST_ERROR(L"Failed to install adapter interfaces");
if (!SetupDiCallClassInstaller(DIF_INSTALLDEVICE, DevInfo, &DevInfoData))
{
LastError = LOG_LAST_ERROR(L"Failed to install adapter device");
goto cleanupDevice;
}
#ifdef MAYBE_WOW64
resumeAfterInstance:;
#endif
OWNING_PROCESS OwningProcess = { .ProcessId = GetCurrentProcessId() };
FILETIME Unused;
if (!GetProcessTimes(GetCurrentProcess(), &OwningProcess.CreationTime, &Unused, &Unused, &Unused))
{
LastError = LOG_LAST_ERROR(L"Failed to get process creation time");
goto cleanupDevice;
}
if (!SetupDiSetDeviceRegistryPropertyW(
DevInfo,
&DevInfoData,
SPDRP_FRIENDLYNAME,
(PBYTE)TunnelTypeName,
(DWORD)((wcslen(TunnelTypeName) + 1) * sizeof(TunnelTypeName[0]))) ||
!SetupDiSetDeviceRegistryPropertyW(
DevInfo,
&DevInfoData,
SPDRP_DEVICEDESC,
(PBYTE)TunnelTypeName,
(DWORD)((wcslen(TunnelTypeName) + 1) * sizeof(TunnelTypeName[0]))) ||
!SetupDiSetDevicePropertyW(
DevInfo,
&DevInfoData,
&DEVPKEY_Wintun_Name,
DEVPROP_TYPE_STRING,
(PBYTE)Name,
(DWORD)((wcslen(Name) + 1) * sizeof(Name[0])),
0) ||
!SetupDiSetDevicePropertyW(
DevInfo,
&DevInfoData,
&DEVPKEY_Wintun_OwningProcess,
DEVPROP_TYPE_BINARY,
(PBYTE)&OwningProcess,
sizeof(OwningProcess),
0))
{
LastError = LOG_LAST_ERROR(L"Failed to set device properties");
goto cleanupDevice;
}
DWORD RequiredChars = _countof(Adapter->DevInstanceID);
if (!SetupDiGetDeviceInstanceIdW(DevInfo, &DevInfoData, Adapter->DevInstanceID, RequiredChars, &RequiredChars))
{
LastError = LOG_LAST_ERROR(L"Failed to get adapter instance ID");
goto cleanupDevice;
}
if (!WaitForInterfaceWin7(DevInfo, &DevInfoData, Adapter->DevInstanceID))
{
DEVPROPTYPE PropertyType = 0;
INT32 ProblemCode = 0;
if (!SetupDiGetDevicePropertyW(
DevInfo,
&DevInfoData,
&DEVPKEY_Device_ProblemCode,
&PropertyType,
(PBYTE)&ProblemCode,
sizeof(ProblemCode),
NULL,
0) ||
(PropertyType != DEVPROP_TYPE_INT32 && PropertyType != DEVPROP_TYPE_UINT32))
ProblemCode = 0;
LastError = LOG_ERROR(
ERROR_DEVICE_REINITIALIZATION_NEEDED, L"Failed to setup adapter (problem code: 0x%x)", ProblemCode);
goto cleanupDevice;
}
cleanupDevice:
if (LastError != ERROR_SUCCESS)
AdapterRemoveInstance(DevInfo, &DevInfoData);
cleanupDriverInfo:
SetupDiDestroyDriverInfoList(DevInfo, &DevInfoData, SPDIT_COMPATDRIVER);
cleanupDevInfo:
SetupDiDestroyDeviceInfoList(DevInfo);
cleanup:
return RET_ERROR(TRUE, LastError);
}
static VOID
CreateAdapterPostWin7(_Inout_ WINTUN_ADAPTER *Adapter, _In_z_ LPCWSTR TunnelTypeName)
{
SetupDiSetDeviceRegistryPropertyW(
Adapter->DevInfo,
&Adapter->DevInfoData,
SPDRP_FRIENDLYNAME,
(PBYTE)TunnelTypeName,
(DWORD)((wcslen(TunnelTypeName) + 1) * sizeof(TunnelTypeName[0])));
SetupDiSetDeviceRegistryPropertyW(
Adapter->DevInfo,
&Adapter->DevInfoData,
SPDRP_DEVICEDESC,
(PBYTE)TunnelTypeName,
(DWORD)((wcslen(TunnelTypeName) + 1) * sizeof(TunnelTypeName[0])));
}
static BOOL
ProcessIsStale(_In_ OWNING_PROCESS *OwningProcess)
{
HANDLE Process = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, OwningProcess->ProcessId);
if (!Process)
return TRUE;
FILETIME CreationTime, Unused;
BOOL Ret = GetProcessTimes(Process, &CreationTime, &Unused, &Unused, &Unused);
CloseHandle(Process);
if (!Ret)
return FALSE;
return !!memcmp(&CreationTime, &OwningProcess->CreationTime, sizeof(CreationTime));
}
VOID AdapterCleanupOrphanedDevicesWin7(VOID)
{
HDEVINFO DevInfo = SetupDiGetClassDevsExW(&GUID_DEVCLASS_NET, WINTUN_ENUMERATOR, NULL, 0, NULL, NULL, NULL);
if (DevInfo == INVALID_HANDLE_VALUE)
{
if (GetLastError() != ERROR_INVALID_DATA)
LOG_LAST_ERROR(L"Failed to get adapters");
return;
}
SP_DEVINFO_DATA DevInfoData = { .cbSize = sizeof(DevInfoData) };
for (DWORD EnumIndex = 0;; ++EnumIndex)
{
if (!SetupDiEnumDeviceInfo(DevInfo, EnumIndex, &DevInfoData))
{
if (GetLastError() == ERROR_NO_MORE_ITEMS)
break;
continue;
}
OWNING_PROCESS OwningProcess;
DEVPROPTYPE PropType;
if (SetupDiGetDevicePropertyW(
DevInfo,
&DevInfoData,
&DEVPKEY_Wintun_OwningProcess,
&PropType,
(PBYTE)&OwningProcess,
sizeof(OwningProcess),
NULL,
0) &&
PropType == DEVPROP_TYPE_BINARY && !ProcessIsStale(&OwningProcess))
continue;
WCHAR Name[MAX_ADAPTER_NAME] = L"<unknown>";
SetupDiGetDevicePropertyW(
DevInfo,
&DevInfoData,
&DEVPKEY_Wintun_Name,
&PropType,
(PBYTE)Name,
MAX_ADAPTER_NAME * sizeof(Name[0]),
NULL,
0);
if (!AdapterRemoveInstance(DevInfo, &DevInfoData))
{
LOG_LAST_ERROR(L"Failed to remove orphaned adapter \"%s\"", Name);
continue;
}
LOG(WINTUN_LOG_INFO, L"Removed orphaned adapter \"%s\"", Name);
}
SetupDiDestroyDeviceInfoList(DevInfo);
}
VOID AdapterCleanupLegacyDevices(VOID)
{
HDEVINFO DevInfo = SetupDiGetClassDevsExW(&GUID_DEVCLASS_NET, L"ROOT\\NET", NULL, 0, NULL, NULL, NULL);
if (DevInfo == INVALID_HANDLE_VALUE)
return;
SP_DEVINFO_DATA DevInfoData = { .cbSize = sizeof(DevInfoData) };
for (DWORD EnumIndex = 0;; ++EnumIndex)
{
if (!SetupDiEnumDeviceInfo(DevInfo, EnumIndex, &DevInfoData))
{
if (GetLastError() == ERROR_NO_MORE_ITEMS)
break;
continue;
}
WCHAR HardwareIDs[0x400] = { 0 };
DWORD ValueType, Size = sizeof(HardwareIDs) - sizeof(HardwareIDs[0]);
if (!SetupDiGetDeviceRegistryPropertyW(
DevInfo, &DevInfoData, SPDRP_HARDWAREID, &ValueType, (PBYTE)HardwareIDs, Size, &Size) ||
Size > sizeof(HardwareIDs) - sizeof(HardwareIDs[0]))
continue;
Size /= sizeof(HardwareIDs[0]);
for (WCHAR *P = HardwareIDs; P < HardwareIDs + Size; P += wcslen(P) + 1)
{
if (!_wcsicmp(P, WINTUN_HWID))
{
AdapterRemoveInstance(DevInfo, &DevInfoData);
break;
}
}
}
SetupDiDestroyDeviceInfoList(DevInfo);
}

View File

@ -18,24 +18,25 @@
<ClCompile>
<PreprocessorDefinitions>_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="'$(Platform)'=='Win32'">MAYBE_WOW64;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="'$(Platform)'=='x64'">ACCEPT_WOW64;MAYBE_WOW64;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="'$(Platform)'=='x64'">MAYBE_WOW64;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="'$(Platform)'=='ARM'">MAYBE_WOW64;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="'$(Platform)'=='ARM64'">ACCEPT_WOW64;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="'$(Platform)'=='ARM64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalOptions>/volatile:iso %(AdditionalOptions)</AdditionalOptions>
<DisableSpecificWarnings>4100;4201;$(DisableSpecificWarnings)</DisableSpecificWarnings>
<AdditionalIncludeDirectories>$(IntDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<ResourceCompile>
<AdditionalIncludeDirectories>..\$(Configuration)\$(WintunPlatform);..\$(Configuration);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions Condition="Exists('..\$(Configuration)\arm64\wintun.dll')">BUILT_ARM64_WOW64;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="Exists('..\$(Configuration)\amd64\wintun.dll')">BUILT_AMD64_WOW64;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="Exists('..\$(Configuration)\arm64\driver\wintun.sys') And Exists('..\$(Configuration)\arm64\setupapihost.dll')">BUILT_ARM64_WOW64;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="Exists('..\$(Configuration)\amd64\driver\wintun.sys') And Exists('..\$(Configuration)\amd64\setupapihost.dll')">BUILT_AMD64_WOW64;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="'$(Platform)'=='Win32'">WANT_ARM64_WOW64;WANT_AMD64_WOW64;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="'$(Platform)'=='x64'">WANT_ARM64_WOW64;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="'$(Platform)'=='ARM'">WANT_ARM64_WOW64;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ResourceCompile>
<Link>
<DelayLoadDLLs>advapi32.dll;bcrypt.dll;cfgmgr32.dll;iphlpapi.dll;ole32.dll;nci.dll;setupapi.dll;shell32.dll;shlwapi.dll;version.dll</DelayLoadDLLs>
<AdditionalDependencies>Bcrypt.lib;Cfgmgr32.lib;Iphlpapi.lib;$(IntDir)nci.lib;ntdll.lib;Setupapi.lib;shlwapi.lib;version.lib;%(AdditionalDependencies)</AdditionalDependencies>
<DelayLoadDLLs>advapi32.dll;api-ms-win-devices-query-l1-1-0.dll;api-ms-win-devices-swdevice-l1-1-0.dll;cfgmgr32.dll;iphlpapi.dll;ole32.dll;nci.dll;setupapi.dll;shlwapi.dll;version.dll</DelayLoadDLLs>
<DelayLoadDLLs Condition="'$(Platform)'!='ARM64'">shell32.dll;%(DelayLoadDLLs)</DelayLoadDLLs>
<AdditionalDependencies>Cfgmgr32.lib;Iphlpapi.lib;onecore.lib;$(IntDir)nci.lib;ntdll.lib;Setupapi.lib;shlwapi.lib;swdevice.lib;version.lib;%(AdditionalDependencies)</AdditionalDependencies>
<ModuleDefinitionFile>exports.def</ModuleDefinitionFile>
<SubSystem>Windows</SubSystem>
</Link>
@ -48,8 +49,10 @@
<None Include="nci.def" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="adapter_win7.h" />
<ClInclude Include="main.h" />
<ClInclude Include="adapter.h" />
<ClInclude Include="driver.h" />
<ClInclude Include="logger.h" />
<ClInclude Include="namespace.h" />
<ClInclude Include="nci.h" />
@ -62,6 +65,7 @@
<ItemGroup>
<ClCompile Include="main.c" />
<ClCompile Include="adapter.c" />
<ClCompile Include="driver.c" />
<ClCompile Include="logger.c" />
<ClCompile Include="namespace.c" />
<ClCompile Include="registry.c" />

View File

@ -58,6 +58,12 @@
<ClInclude Include="rundll32.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="driver.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="adapter_win7.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="namespace.c">
@ -66,9 +72,6 @@
<ClCompile Include="rundll32.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="registry.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="logger.c">
<Filter>Source Files</Filter>
</ClCompile>
@ -84,5 +87,11 @@
<ClCompile Include="main.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="driver.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="registry.c">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
</Project>

587
api/driver.c Normal file
View File

@ -0,0 +1,587 @@
/* SPDX-License-Identifier: GPL-2.0
*
* Copyright (C) 2018-2021 WireGuard LLC. All Rights Reserved.
*/
#include <Windows.h>
#include <winternl.h>
#include <cfgmgr32.h>
#include <SetupAPI.h>
#include <devguid.h>
#include <ndisguid.h>
#include <Shlwapi.h>
#include <shellapi.h>
#include <wchar.h>
#include "driver.h"
#include "adapter.h"
#include "logger.h"
#include "namespace.h"
#include "resource.h"
#include "registry.h"
#include "ntdll.h"
#include "rundll32.h"
#include "wintun-inf.h"
#pragma warning(disable : 4221) /* nonstandard: address of automatic in initializer */
struct _SP_DEVINFO_DATA_LIST
{
SP_DEVINFO_DATA Data;
struct _SP_DEVINFO_DATA_LIST *Next;
};
static _Return_type_success_(return != FALSE)
BOOL
DisableAllOurAdapters(_In_ HDEVINFO DevInfo, _Inout_ SP_DEVINFO_DATA_LIST **DisabledAdapters)
{
DWORD LastError = ERROR_SUCCESS;
for (DWORD EnumIndex = 0;; ++EnumIndex)
{
SP_DEVINFO_DATA_LIST *DeviceNode = Zalloc(sizeof(*DeviceNode));
if (!DeviceNode)
return FALSE;
DeviceNode->Data.cbSize = sizeof(SP_DEVINFO_DATA);
if (!SetupDiEnumDeviceInfo(DevInfo, EnumIndex, &DeviceNode->Data))
{
if (GetLastError() == ERROR_NO_MORE_ITEMS)
{
Free(DeviceNode);
break;
}
goto cleanupDeviceNode;
}
DEVPROPTYPE PropType;
WCHAR Name[MAX_ADAPTER_NAME] = L"<unknown>";
SetupDiGetDevicePropertyW(
DevInfo,
&DeviceNode->Data,
&DEVPKEY_Wintun_Name,
&PropType,
(PBYTE)Name,
MAX_ADAPTER_NAME * sizeof(Name[0]),
NULL,
0);
ULONG Status, ProblemCode;
if (CM_Get_DevNode_Status(&Status, &ProblemCode, DeviceNode->Data.DevInst, 0) != CR_SUCCESS ||
((Status & DN_HAS_PROBLEM) && ProblemCode == CM_PROB_DISABLED))
goto cleanupDeviceNode;
LOG(WINTUN_LOG_INFO, L"Force closing adapter \"%s\" open handles", Name);
if (!AdapterForceCloseHandles(DevInfo, &DeviceNode->Data))
LOG(WINTUN_LOG_WARN, L"Failed to force close adapter \"%s\" open handles", Name);
LOG(WINTUN_LOG_INFO, L"Disabling adapter \"%s\"", Name);
if (!AdapterDisableInstance(DevInfo, &DeviceNode->Data))
{
LOG_LAST_ERROR(L"Failed to disable adapter \"%s\"", Name);
LastError = LastError != ERROR_SUCCESS ? LastError : GetLastError();
goto cleanupDeviceNode;
}
DeviceNode->Next = *DisabledAdapters;
*DisabledAdapters = DeviceNode;
continue;
cleanupDeviceNode:
Free(DeviceNode);
}
return RET_ERROR(TRUE, LastError);
}
static _Return_type_success_(return != FALSE)
BOOL
EnableAllOurAdapters(_In_ HDEVINFO DevInfo, _In_ SP_DEVINFO_DATA_LIST *AdaptersToEnable)
{
DWORD LastError = ERROR_SUCCESS;
for (SP_DEVINFO_DATA_LIST *DeviceNode = AdaptersToEnable; DeviceNode; DeviceNode = DeviceNode->Next)
{
DEVPROPTYPE PropType;
WCHAR Name[MAX_ADAPTER_NAME] = L"<unknown>";
SetupDiGetDevicePropertyW(
DevInfo,
&DeviceNode->Data,
&DEVPKEY_Wintun_Name,
&PropType,
(PBYTE)Name,
MAX_ADAPTER_NAME * sizeof(Name[0]),
NULL,
0);
LOG(WINTUN_LOG_INFO, L"Enabling adapter \"%s\"", Name);
if (!AdapterEnableInstance(DevInfo, &DeviceNode->Data))
{
LOG_LAST_ERROR(L"Failed to enable adapter \"%s\"", Name);
LastError = LastError != ERROR_SUCCESS ? LastError : GetLastError();
}
}
return RET_ERROR(TRUE, LastError);
}
static BOOL
IsNewer(
_In_ const FILETIME *DriverDate1,
_In_ DWORDLONG DriverVersion1,
_In_ const FILETIME *DriverDate2,
_In_ DWORDLONG DriverVersion2)
{
if (DriverDate1->dwHighDateTime > DriverDate2->dwHighDateTime)
return TRUE;
if (DriverDate1->dwHighDateTime < DriverDate2->dwHighDateTime)
return FALSE;
if (DriverDate1->dwLowDateTime > DriverDate2->dwLowDateTime)
return TRUE;
if (DriverDate1->dwLowDateTime < DriverDate2->dwLowDateTime)
return FALSE;
if (DriverVersion1 > DriverVersion2)
return TRUE;
if (DriverVersion1 < DriverVersion2)
return FALSE;
return FALSE;
}
static _Return_type_success_(return != 0)
DWORD
VersionOfFile(_In_z_ LPCWSTR Filename)
{
DWORD Zero;
DWORD Len = GetFileVersionInfoSizeW(Filename, &Zero);
if (!Len)
{
LOG_LAST_ERROR(L"Failed to query %s version info size", Filename);
return 0;
}
VOID *VersionInfo = Alloc(Len);
if (!VersionInfo)
return 0;
DWORD LastError = ERROR_SUCCESS, Version = 0;
VS_FIXEDFILEINFO *FixedInfo;
UINT FixedInfoLen = sizeof(*FixedInfo);
if (!GetFileVersionInfoW(Filename, 0, Len, VersionInfo))
{
LastError = LOG_LAST_ERROR(L"Failed to get %s version info", Filename);
goto out;
}
if (!VerQueryValueW(VersionInfo, L"\\", &FixedInfo, &FixedInfoLen))
{
LastError = LOG_LAST_ERROR(L"Failed to get %s version info root", Filename);
goto out;
}
Version = FixedInfo->dwFileVersionMS;
if (!Version)
{
LOG(WINTUN_LOG_WARN, L"Determined version of %s, but was v0.0, so returning failure", Filename);
LastError = ERROR_VERSION_PARSE_ERROR;
}
out:
Free(VersionInfo);
return RET_ERROR(Version, LastError);
}
static DWORD WINAPI
MaybeGetRunningDriverVersion(BOOL ReturnOneIfRunningInsteadOfVersion)
{
PRTL_PROCESS_MODULES Modules;
ULONG BufferSize = 128 * 1024;
for (;;)
{
Modules = Alloc(BufferSize);
if (!Modules)
return 0;
NTSTATUS Status = NtQuerySystemInformation(SystemModuleInformation, Modules, BufferSize, &BufferSize);
if (NT_SUCCESS(Status))
break;
Free(Modules);
if (Status == STATUS_INFO_LENGTH_MISMATCH)
continue;
LOG(WINTUN_LOG_ERR, L"Failed to enumerate drivers (status: 0x%x)", Status);
SetLastError(RtlNtStatusToDosError(Status));
return 0;
}
DWORD LastError = ERROR_SUCCESS, Version = 0;
for (ULONG i = Modules->NumberOfModules; i-- > 0;)
{
LPCSTR NtPath = (LPCSTR)Modules->Modules[i].FullPathName;
if (!_stricmp(&NtPath[Modules->Modules[i].OffsetToFileName], "wintun.sys"))
{
if (ReturnOneIfRunningInsteadOfVersion)
{
Version = 1;
goto cleanupModules;
}
WCHAR FilePath[MAX_PATH * 3 + 15];
if (_snwprintf_s(FilePath, _countof(FilePath), _TRUNCATE, L"\\\\?\\GLOBALROOT%S", NtPath) == -1)
continue;
Version = VersionOfFile(FilePath);
if (!Version)
LastError = GetLastError();
goto cleanupModules;
}
}
LastError = ERROR_FILE_NOT_FOUND;
cleanupModules:
Free(Modules);
return RET_ERROR(Version, LastError);
}
_Use_decl_annotations_
DWORD WINAPI WintunGetRunningDriverVersion(VOID)
{
return MaybeGetRunningDriverVersion(FALSE);
}
static BOOL EnsureWintunUnloaded(VOID)
{
BOOL Loaded;
for (DWORD Tries = 0; Tries < 1500; ++Tries)
{
if (Tries)
Sleep(50);
Loaded = MaybeGetRunningDriverVersion(TRUE) != 0;
if (!Loaded)
break;
}
return !Loaded;
}
_Use_decl_annotations_
VOID
DriverInstallDeferredCleanup(HDEVINFO DevInfoExistingAdapters, SP_DEVINFO_DATA_LIST *ExistingAdapters)
{
if (ExistingAdapters)
{
EnableAllOurAdapters(DevInfoExistingAdapters, ExistingAdapters);
while (ExistingAdapters)
{
SP_DEVINFO_DATA_LIST *Next = ExistingAdapters->Next;
Free(ExistingAdapters);
ExistingAdapters = Next;
}
}
if (DevInfoExistingAdapters != INVALID_HANDLE_VALUE)
SetupDiDestroyDeviceInfoList(DevInfoExistingAdapters);
}
_Use_decl_annotations_
BOOL
DriverInstall(HDEVINFO *DevInfoExistingAdaptersForCleanup, SP_DEVINFO_DATA_LIST **ExistingAdaptersForCleanup)
{
static const FILETIME OurDriverDate = WINTUN_INF_FILETIME;
static const DWORDLONG OurDriverVersion = WINTUN_INF_VERSION;
HANDLE DriverInstallationLock = NamespaceTakeDriverInstallationMutex();
if (!DriverInstallationLock)
{
LOG(WINTUN_LOG_ERR, L"Failed to take driver installation mutex");
return FALSE;
}
DWORD LastError = ERROR_SUCCESS;
HDEVINFO DevInfo = SetupDiCreateDeviceInfoListExW(&GUID_DEVCLASS_NET, NULL, NULL, NULL);
if (DevInfo == INVALID_HANDLE_VALUE)
{
LastError = LOG_LAST_ERROR(L"Failed to create empty device information set");
goto cleanupDriverInstallationLock;
}
SP_DEVINFO_DATA DevInfoData = { .cbSize = sizeof(DevInfoData) };
if (!SetupDiCreateDeviceInfoW(DevInfo, WINTUN_HWID, &GUID_DEVCLASS_NET, NULL, NULL, DICD_GENERATE_ID, &DevInfoData))
{
LastError = LOG_LAST_ERROR(L"Failed to create new device information element");
goto cleanupDevInfo;
}
static const WCHAR Hwids[_countof(WINTUN_HWID) + 1 /*Multi-string terminator*/] = WINTUN_HWID;
if (!SetupDiSetDeviceRegistryPropertyW(DevInfo, &DevInfoData, SPDRP_HARDWAREID, (const BYTE *)Hwids, sizeof(Hwids)))
{
LastError = LOG_LAST_ERROR(L"Failed to set adapter hardware ID");
goto cleanupDevInfo;
}
if (!SetupDiBuildDriverInfoList(DevInfo, &DevInfoData, SPDIT_COMPATDRIVER))
{
LastError = LOG_LAST_ERROR(L"Failed building adapter driver info list");
goto cleanupDevInfo;
}
FILETIME DriverDate = { 0 };
DWORDLONG DriverVersion = 0;
HDEVINFO DevInfoExistingAdapters = INVALID_HANDLE_VALUE;
SP_DEVINFO_DATA_LIST *ExistingAdapters = NULL;
for (DWORD EnumIndex = 0;; ++EnumIndex)
{
SP_DRVINFO_DATA_W DrvInfoData = { .cbSize = sizeof(SP_DRVINFO_DATA_W) };
if (!SetupDiEnumDriverInfoW(DevInfo, &DevInfoData, SPDIT_COMPATDRIVER, EnumIndex, &DrvInfoData))
{
if (GetLastError() == ERROR_NO_MORE_ITEMS)
break;
continue;
}
if (IsNewer(&OurDriverDate, OurDriverVersion, &DrvInfoData.DriverDate, DrvInfoData.DriverVersion))
{
if (DevInfoExistingAdapters == INVALID_HANDLE_VALUE)
{
DevInfoExistingAdapters = SetupDiGetClassDevsExW(
&GUID_DEVCLASS_NET, WINTUN_ENUMERATOR, NULL, DIGCF_PRESENT, NULL, NULL, NULL);
if (DevInfoExistingAdapters == INVALID_HANDLE_VALUE)
{
LastError = LOG_LAST_ERROR(L"Failed to get present adapters");
SetupDiDestroyDriverInfoList(DevInfo, &DevInfoData, SPDIT_COMPATDRIVER);
goto cleanupExistingAdapters;
}
_Analysis_assume_(DevInfoExistingAdapters != NULL);
DisableAllOurAdapters(DevInfoExistingAdapters, &ExistingAdapters);
LOG(WINTUN_LOG_INFO, L"Waiting for existing driver to unload from kernel");
if (!EnsureWintunUnloaded())
LOG(WINTUN_LOG_WARN,
L"Failed to unload existing driver, which means a reboot will likely be required");
}
LOG(WINTUN_LOG_INFO,
L"Removing existing driver %u.%u",
(DWORD)((DrvInfoData.DriverVersion & 0xffff000000000000) >> 48),
(DWORD)((DrvInfoData.DriverVersion & 0x0000ffff00000000) >> 32));
BYTE LargeBuffer[0x2000];
DWORD Size = sizeof(LargeBuffer);
SP_DRVINFO_DETAIL_DATA_W *DrvInfoDetailData = (SP_DRVINFO_DETAIL_DATA_W *)LargeBuffer;
DrvInfoDetailData->cbSize = sizeof(SP_DRVINFO_DETAIL_DATA_W);
if (!SetupDiGetDriverInfoDetailW(DevInfo, &DevInfoData, &DrvInfoData, DrvInfoDetailData, Size, &Size))
{
LOG(WINTUN_LOG_WARN, L"Failed getting adapter driver info detail");
continue;
}
LPWSTR InfFileName = PathFindFileNameW(DrvInfoDetailData->InfFileName);
if (!SetupUninstallOEMInfW(InfFileName, SUOI_FORCEDELETE, NULL))
LOG_LAST_ERROR(L"Unable to remove existing driver %s", InfFileName);
continue;
}
if (!IsNewer(&DrvInfoData.DriverDate, DrvInfoData.DriverVersion, &DriverDate, DriverVersion))
continue;
DriverDate = DrvInfoData.DriverDate;
DriverVersion = DrvInfoData.DriverVersion;
}
SetupDiDestroyDriverInfoList(DevInfo, &DevInfoData, SPDIT_COMPATDRIVER);
if (DriverVersion)
{
LOG(WINTUN_LOG_INFO,
L"Using existing driver %u.%u",
(DWORD)((DriverVersion & 0xffff000000000000) >> 48),
(DWORD)((DriverVersion & 0x0000ffff00000000) >> 32));
LastError = ERROR_SUCCESS;
goto cleanupExistingAdapters;
}
LOG(WINTUN_LOG_INFO,
L"Installing driver %u.%u",
(DWORD)((OurDriverVersion & 0xffff000000000000) >> 48),
(DWORD)((OurDriverVersion & 0x0000ffff00000000) >> 32));
WCHAR RandomTempSubDirectory[MAX_PATH];
if (!ResourceCreateTemporaryDirectory(RandomTempSubDirectory))
{
LastError = LOG_LAST_ERROR(L"Failed to create temporary folder %s", RandomTempSubDirectory);
goto cleanupExistingAdapters;
}
WCHAR CatPath[MAX_PATH] = { 0 };
WCHAR SysPath[MAX_PATH] = { 0 };
WCHAR InfPath[MAX_PATH] = { 0 };
WCHAR DownlevelShimPath[MAX_PATH] = { 0 };
if (!PathCombineW(CatPath, RandomTempSubDirectory, L"wintun.cat") ||
!PathCombineW(SysPath, RandomTempSubDirectory, L"wintun.sys") ||
!PathCombineW(InfPath, RandomTempSubDirectory, L"wintun.inf"))
{
LastError = ERROR_BUFFER_OVERFLOW;
goto cleanupDirectory;
}
WCHAR *CatSource, *SysSource, *InfSource;
if (NativeMachine == IMAGE_FILE_PROCESS)
{
CatSource = L"wintun.cat";
SysSource = L"wintun.sys";
InfSource = L"wintun.inf";
}
else if (NativeMachine == IMAGE_FILE_MACHINE_AMD64)
{
CatSource = L"wintun-amd64.cat";
SysSource = L"wintun-amd64.sys";
InfSource = L"wintun-amd64.inf";
}
else if (NativeMachine == IMAGE_FILE_MACHINE_ARM64)
{
CatSource = L"wintun-arm64.cat";
SysSource = L"wintun-arm64.sys";
InfSource = L"wintun-arm64.inf";
}
else
{
LastError = LOG_ERROR(ERROR_NOT_SUPPORTED, L"Unsupported platform 0x%x", NativeMachine);
goto cleanupDirectory;
}
LOG(WINTUN_LOG_INFO, L"Extracting driver");
if (!ResourceCopyToFile(CatPath, CatSource) || !ResourceCopyToFile(SysPath, SysSource) ||
!ResourceCopyToFile(InfPath, InfSource))
{
LastError = LOG_LAST_ERROR(L"Failed to extract driver");
goto cleanupDelete;
}
WCHAR *WintrustKeyOriginalValue = NULL;
HKEY WintrustKey = NULL;
if (!IsWindows10)
{
LOG(WINTUN_LOG_INFO, L"Shimming downlevel driver loader");
if (!PathCombineW(DownlevelShimPath, RandomTempSubDirectory, L"downlevelshim.dll"))
{
DownlevelShimPath[0] = L'\0';
LastError = ERROR_BUFFER_OVERFLOW;
goto cleanupDelete;
}
if (!ResourceCopyToFile(DownlevelShimPath, L"downlevelshim.dll"))
{
LastError = LOG_LAST_ERROR(L"Failed to extract downlevel shim");
goto cleanupDelete;
}
LastError = RegOpenKeyExW(
HKEY_LOCAL_MACHINE,
L"SOFTWARE\\Microsoft\\Cryptography\\Providers\\Trust\\FinalPolicy\\{F750E6C3-38EE-11D1-85E5-00C04FC295EE}",
0,
KEY_QUERY_VALUE | KEY_SET_VALUE,
&WintrustKey);
if (LastError != ERROR_SUCCESS)
{
LOG_ERROR(LastError, L"Failed to open Wintrust FinalPolicy key");
goto cleanupDelete;
}
WintrustKeyOriginalValue = RegistryQueryString(WintrustKey, L"$DLL", TRUE);
if (!WintrustKeyOriginalValue)
{
LastError = LOG_LAST_ERROR(L"Failed to read current Wintrust FinalPolicy key");
goto cleanupWintrustKey;
}
LastError = RegSetValueExW(
WintrustKey,
L"$DLL",
0,
REG_SZ,
(BYTE *)DownlevelShimPath,
(DWORD)((wcslen(DownlevelShimPath) + 1) * sizeof(DownlevelShimPath[0])));
if (LastError != ERROR_SUCCESS)
{
LOG_ERROR(LastError, L"Failed to set Wintrust FinalPolicy key");
goto cleanupWintrustChangedKey;
}
}
LOG(WINTUN_LOG_INFO, L"Installing driver");
if (!SetupCopyOEMInfW(InfPath, NULL, SPOST_NONE, 0, NULL, 0, NULL, NULL))
LastError = LOG_LAST_ERROR(L"Could not install driver %s to store", InfPath);
cleanupWintrustChangedKey:
if (WintrustKeyOriginalValue)
RegSetValueExW(
WintrustKey,
L"$DLL",
0,
REG_SZ,
(BYTE *)WintrustKeyOriginalValue,
(DWORD)((wcslen(WintrustKeyOriginalValue) + 1) * sizeof(WintrustKeyOriginalValue[0])));
cleanupWintrustKey:
if (WintrustKey)
RegCloseKey(WintrustKey);
if (WintrustKeyOriginalValue)
Free(WintrustKeyOriginalValue);
cleanupDelete:
DeleteFileW(CatPath);
DeleteFileW(SysPath);
DeleteFileW(InfPath);
if (DownlevelShimPath[0])
DeleteFileW(DownlevelShimPath);
cleanupDirectory:
RemoveDirectoryW(RandomTempSubDirectory);
cleanupExistingAdapters:
if (LastError == ERROR_SUCCESS)
{
*DevInfoExistingAdaptersForCleanup = DevInfoExistingAdapters;
*ExistingAdaptersForCleanup = ExistingAdapters;
}
else
DriverInstallDeferredCleanup(DevInfoExistingAdapters, ExistingAdapters);
cleanupDevInfo:
SetupDiDestroyDeviceInfoList(DevInfo);
cleanupDriverInstallationLock:
NamespaceReleaseMutex(DriverInstallationLock);
return RET_ERROR(TRUE, LastError);
}
_Use_decl_annotations_
BOOL WINAPI WintunDeleteDriver(VOID)
{
DWORD LastError = ERROR_SUCCESS;
AdapterCleanupOrphanedDevices();
HANDLE DriverInstallationLock = NamespaceTakeDriverInstallationMutex();
if (!DriverInstallationLock)
{
LastError = LOG(WINTUN_LOG_ERR, L"Failed to take driver installation mutex");
goto cleanup;
}
HDEVINFO DevInfo = SetupDiCreateDeviceInfoListExW(&GUID_DEVCLASS_NET, NULL, NULL, NULL);
if (DevInfo == INVALID_HANDLE_VALUE)
{
LastError = LOG_LAST_ERROR(L"Failed to create empty device information set");
goto cleanupDriverInstallationLock;
}
SP_DEVINFO_DATA DevInfoData = { .cbSize = sizeof(DevInfoData) };
if (!SetupDiCreateDeviceInfoW(DevInfo, WINTUN_HWID, &GUID_DEVCLASS_NET, NULL, NULL, DICD_GENERATE_ID, &DevInfoData))
{
LastError = LOG_LAST_ERROR(L"Failed to create new device information element");
goto cleanupDevInfo;
}
static const WCHAR Hwids[_countof(WINTUN_HWID) + 1 /*Multi-string terminator*/] = WINTUN_HWID;
if (!SetupDiSetDeviceRegistryPropertyW(DevInfo, &DevInfoData, SPDRP_HARDWAREID, (const BYTE *)Hwids, sizeof(Hwids)))
{
LastError = LOG_LAST_ERROR(L"Failed to set adapter hardware ID");
goto cleanupDevInfo;
}
if (!SetupDiBuildDriverInfoList(DevInfo, &DevInfoData, SPDIT_COMPATDRIVER))
{
LastError = LOG_LAST_ERROR(L"Failed building adapter driver info list");
goto cleanupDevInfo;
}
for (DWORD EnumIndex = 0;; ++EnumIndex)
{
SP_DRVINFO_DATA_W DrvInfoData = { .cbSize = sizeof(SP_DRVINFO_DATA_W) };
if (!SetupDiEnumDriverInfoW(DevInfo, &DevInfoData, SPDIT_COMPATDRIVER, EnumIndex, &DrvInfoData))
{
if (GetLastError() == ERROR_NO_MORE_ITEMS)
break;
continue;
}
BYTE LargeBuffer[0x2000];
DWORD Size = sizeof(LargeBuffer);
SP_DRVINFO_DETAIL_DATA_W *DrvInfoDetailData = (SP_DRVINFO_DETAIL_DATA_W *)LargeBuffer;
DrvInfoDetailData->cbSize = sizeof(SP_DRVINFO_DETAIL_DATA_W);
if (!SetupDiGetDriverInfoDetailW(DevInfo, &DevInfoData, &DrvInfoData, DrvInfoDetailData, Size, &Size))
{
LOG(WINTUN_LOG_WARN, L"Failed getting adapter driver info detail");
continue;
}
LPCWSTR Path = PathFindFileNameW(DrvInfoDetailData->InfFileName);
LOG(WINTUN_LOG_INFO, L"Removing driver %s", Path);
if (!SetupUninstallOEMInfW(Path, 0, NULL))
{
LOG_LAST_ERROR(L"Unable to remove driver %s", Path);
LastError = LastError != ERROR_SUCCESS ? LastError : GetLastError();
}
}
SetupDiDestroyDriverInfoList(DevInfo, &DevInfoData, SPDIT_COMPATDRIVER);
cleanupDevInfo:
SetupDiDestroyDeviceInfoList(DevInfo);
cleanupDriverInstallationLock:
NamespaceReleaseMutex(DriverInstallationLock);
cleanup:
return RET_ERROR(TRUE, LastError);
}

34
api/driver.h Normal file
View File

@ -0,0 +1,34 @@
/* SPDX-License-Identifier: GPL-2.0
*
* Copyright (C) 2018-2021 WireGuard LLC. All Rights Reserved.
*/
#pragma once
#include "wintun.h"
#include <Windows.h>
#include <SetupAPI.h>
#define WINTUN_HWID L"Wintun"
typedef struct _SP_DEVINFO_DATA_LIST SP_DEVINFO_DATA_LIST;
VOID
DriverInstallDeferredCleanup(_In_ HDEVINFO DevInfoExistingAdapters, _In_opt_ SP_DEVINFO_DATA_LIST *ExistingAdapters);
_Must_inspect_result_
_Return_type_success_(return != FALSE)
BOOL
DriverInstall(
_Out_ HDEVINFO *DevInfoExistingAdaptersForCleanup,
_Out_ SP_DEVINFO_DATA_LIST **ExistingAdaptersForCleanup);
/**
* @copydoc WINTUN_DELETE_DRIVER_FUNC
*/
WINTUN_DELETE_DRIVER_FUNC WintunDeleteDriver;
/**
* @copydoc WINTUN_GET_RUNNING_DRIVER_VERSION_FUNC
*/
WINTUN_GET_RUNNING_DRIVER_VERSION_FUNC WintunGetRunningDriverVersion;

View File

@ -2,19 +2,15 @@ LIBRARY wintun.dll
EXPORTS
WintunAllocateSendPacket
WintunCreateAdapter
WintunDeleteAdapter
WintunDeletePoolDriver
WintunEndSession
WintunEnumAdapters
WintunFreeAdapter
WintunOpenAdapter
WintunCloseAdapter
WintunGetAdapterLUID
WintunGetAdapterName
WintunGetReadWaitEvent
WintunGetRunningDriverVersion
WintunReceivePacket
WintunReleaseReceivePacket
WintunSendPacket
WintunSetAdapterName
WintunDeleteDriver
WintunSetLogger
WintunStartSession

View File

@ -7,18 +7,26 @@
#include "adapter.h"
#include "ntdll.h"
#include <Windows.h>
#include <iphlpapi.h>
#include <winternl.h>
#include <wchar.h>
#include <stdlib.h>
static BOOL CALLBACK
NopLogger(_In_ WINTUN_LOGGER_LEVEL Level, _In_z_ LPCWSTR LogLine)
NopLogger(_In_ WINTUN_LOGGER_LEVEL Level, _In_ DWORD64 Timestamp, _In_z_ LPCWSTR LogLine)
{
return TRUE;
}
WINTUN_LOGGER_CALLBACK Logger = NopLogger;
static DWORD64 Now(VOID)
{
LARGE_INTEGER Timestamp;
NtQuerySystemTime(&Timestamp);
return Timestamp.QuadPart;
}
_Use_decl_annotations_
VOID WINAPI
WintunSetLogger(WINTUN_LOGGER_CALLBACK NewLogger)
@ -37,41 +45,30 @@ StrTruncate(_Inout_count_(StrChars) LPWSTR Str, _In_ SIZE_T StrChars)
_Use_decl_annotations_
DWORD
LoggerLog(WINTUN_LOGGER_LEVEL Level, LPCWSTR Function, LPCWSTR LogLine)
LoggerLog(WINTUN_LOGGER_LEVEL Level, LPCWSTR LogLine)
{
DWORD LastError = GetLastError();
if (Function)
{
WCHAR Combined[0x400];
if (_snwprintf_s(Combined, _countof(Combined), _TRUNCATE, L"%s: %s", Function, LogLine) == -1)
StrTruncate(Combined, _countof(Combined));
Logger(Level, Combined);
}
else
Logger(Level, LogLine);
Logger(Level, Now(), LogLine);
SetLastError(LastError);
return LastError;
}
_Use_decl_annotations_
DWORD
LoggerLogV(WINTUN_LOGGER_LEVEL Level, LPCWSTR Function, LPCWSTR Format, va_list Args)
LoggerLogV(WINTUN_LOGGER_LEVEL Level, LPCWSTR Format, va_list Args)
{
DWORD LastError = GetLastError();
WCHAR LogLine[0x400];
if (_vsnwprintf_s(LogLine, _countof(LogLine), _TRUNCATE, Format, Args) == -1)
StrTruncate(LogLine, _countof(LogLine));
if (Function)
LoggerLog(Level, Function, LogLine);
else
Logger(Level, LogLine);
Logger(Level, Now(), LogLine);
SetLastError(LastError);
return LastError;
}
_Use_decl_annotations_
DWORD
LoggerError(DWORD Error, LPCWSTR Function, LPCWSTR Prefix)
LoggerError(DWORD Error, LPCWSTR Prefix)
{
LPWSTR SystemMessage = NULL, FormattedMessage = NULL;
FormatMessageW(
@ -85,14 +82,14 @@ LoggerError(DWORD Error, LPCWSTR Function, LPCWSTR Prefix)
FormatMessageW(
FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_ARGUMENT_ARRAY |
FORMAT_MESSAGE_MAX_WIDTH_MASK,
SystemMessage ? L"%4: %1: %3(Code 0x%2!08X!)" : L"%4: %1: Code 0x%2!08X!",
SystemMessage ? L"%1: %3(Code 0x%2!08X!)" : L"%1: Code 0x%2!08X!",
0,
0,
(VOID *)&FormattedMessage,
0,
(va_list *)(DWORD_PTR[]){ (DWORD_PTR)Prefix, (DWORD_PTR)Error, (DWORD_PTR)SystemMessage, (DWORD_PTR)Function });
(va_list *)(DWORD_PTR[]){ (DWORD_PTR)Prefix, (DWORD_PTR)Error, (DWORD_PTR)SystemMessage });
if (FormattedMessage)
Logger(WINTUN_LOG_ERR, FormattedMessage);
Logger(WINTUN_LOG_ERR, Now(), FormattedMessage);
LocalFree(FormattedMessage);
LocalFree(SystemMessage);
return Error;
@ -100,12 +97,12 @@ LoggerError(DWORD Error, LPCWSTR Function, LPCWSTR Prefix)
_Use_decl_annotations_
DWORD
LoggerErrorV(DWORD Error, LPCWSTR Function, LPCWSTR Format, va_list Args)
LoggerErrorV(DWORD Error, LPCWSTR Format, va_list Args)
{
WCHAR Prefix[0x400];
if (_vsnwprintf_s(Prefix, _countof(Prefix), _TRUNCATE, Format, Args) == -1)
StrTruncate(Prefix, _countof(Prefix));
return LoggerError(Error, Function, Prefix);
WCHAR LogLine[0x400];
if (_vsnwprintf_s(LogLine, _countof(LogLine), _TRUNCATE, Format, Args) == -1)
StrTruncate(LogLine, _countof(LogLine));
return LoggerError(Error, LogLine);
}
_Use_decl_annotations_

View File

@ -18,71 +18,63 @@ extern WINTUN_LOGGER_CALLBACK Logger;
/**
* @copydoc WINTUN_SET_LOGGER_FUNC
*/
WINTUN_SET_LOGGER_FUNC_IMPL WintunSetLogger;
WINTUN_SET_LOGGER_FUNC WintunSetLogger;
_Post_equals_last_error_
DWORD
LoggerLog(_In_ WINTUN_LOGGER_LEVEL Level, _In_z_ LPCWSTR Function, _In_z_ LPCWSTR LogLine);
LoggerLog(_In_ WINTUN_LOGGER_LEVEL Level, _In_z_ LPCWSTR LogLine);
_Post_equals_last_error_
DWORD
LoggerLogV(
_In_ WINTUN_LOGGER_LEVEL Level,
_In_z_ LPCWSTR Function,
_In_z_ _Printf_format_string_ LPCWSTR Format,
_In_ va_list Args);
LoggerLogV(_In_ WINTUN_LOGGER_LEVEL Level, _In_z_ _Printf_format_string_ LPCWSTR Format, _In_ va_list Args);
_Post_equals_last_error_
static inline DWORD
LoggerLogFmt(_In_ WINTUN_LOGGER_LEVEL Level, _In_z_ LPCWSTR Function, _In_z_ _Printf_format_string_ LPCWSTR Format, ...)
LoggerLogFmt(_In_ WINTUN_LOGGER_LEVEL Level, _In_z_ _Printf_format_string_ LPCWSTR Format, ...)
{
va_list Args;
va_start(Args, Format);
DWORD LastError = LoggerLogV(Level, Function, Format, Args);
DWORD LastError = LoggerLogV(Level, Format, Args);
va_end(Args);
return LastError;
}
_Post_equals_last_error_
DWORD
LoggerError(_In_ DWORD Error, _In_z_ LPCWSTR Function, _In_z_ LPCWSTR Prefix);
LoggerError(_In_ DWORD Error, _In_z_ LPCWSTR Prefix);
_Post_equals_last_error_
DWORD
LoggerErrorV(
_In_ DWORD Error,
_In_z_ LPCWSTR Function,
_In_z_ _Printf_format_string_ LPCWSTR Format,
_In_ va_list Args);
LoggerErrorV(_In_ DWORD Error, _In_z_ _Printf_format_string_ LPCWSTR Format, _In_ va_list Args);
_Post_equals_last_error_
static inline DWORD
LoggerErrorFmt(_In_ DWORD Error, _In_z_ LPCWSTR Function, _In_z_ _Printf_format_string_ LPCWSTR Format, ...)
LoggerErrorFmt(_In_ DWORD Error, _In_z_ _Printf_format_string_ LPCWSTR Format, ...)
{
va_list Args;
va_start(Args, Format);
DWORD LastError = LoggerErrorV(Error, Function, Format, Args);
DWORD LastError = LoggerErrorV(Error, Format, Args);
va_end(Args);
return LastError;
}
_Post_equals_last_error_
static inline DWORD
LoggerLastErrorV(_In_z_ LPCWSTR Function, _In_z_ _Printf_format_string_ LPCWSTR Format, _In_ va_list Args)
LoggerLastErrorV(_In_z_ _Printf_format_string_ LPCWSTR Format, _In_ va_list Args)
{
DWORD LastError = GetLastError();
LoggerErrorV(LastError, Function, Format, Args);
LoggerErrorV(LastError, Format, Args);
SetLastError(LastError);
return LastError;
}
_Post_equals_last_error_
static inline DWORD
LoggerLastErrorFmt(_In_z_ LPCWSTR Function, _In_z_ _Printf_format_string_ LPCWSTR Format, ...)
LoggerLastErrorFmt(_In_z_ _Printf_format_string_ LPCWSTR Format, ...)
{
va_list Args;
va_start(Args, Format);
DWORD LastError = LoggerLastErrorV(Function, Format, Args);
DWORD LastError = LoggerLastErrorV(Format, Args);
va_end(Args);
return LastError;
}
@ -90,11 +82,9 @@ LoggerLastErrorFmt(_In_z_ LPCWSTR Function, _In_z_ _Printf_format_string_ LPCWST
VOID
LoggerGetRegistryKeyPath(_In_ HKEY Key, _Out_writes_z_(MAX_REG_PATH) LPWSTR Path);
#define __L(x) L##x
#define _L(x) __L(x)
#define LOG(lvl, msg, ...) (LoggerLogFmt((lvl), _L(__FUNCTION__), msg, __VA_ARGS__))
#define LOG_ERROR(err, msg, ...) (LoggerErrorFmt((err), _L(__FUNCTION__), msg, __VA_ARGS__))
#define LOG_LAST_ERROR(msg, ...) (LoggerLastErrorFmt(_L(__FUNCTION__), msg, __VA_ARGS__))
#define LOG(lvl, msg, ...) (LoggerLogFmt((lvl), msg, __VA_ARGS__))
#define LOG_ERROR(err, msg, ...) (LoggerErrorFmt((err), msg, __VA_ARGS__))
#define LOG_LAST_ERROR(msg, ...) (LoggerLastErrorFmt(msg, __VA_ARGS__))
#define RET_ERROR(Ret, Error) ((Error) == ERROR_SUCCESS ? (Ret) : (SetLastError(Error), 0))
@ -130,6 +120,9 @@ LoggerReAlloc(_In_z_ LPCWSTR Function, _In_ DWORD Flags, _Frees_ptr_opt_ LPVOID
}
return Data;
}
#define __L(x) L##x
#define _L(x) __L(x)
#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)

View File

@ -21,7 +21,13 @@ HANDLE ModuleHeap;
SECURITY_ATTRIBUTES SecurityAttributes = { .nLength = sizeof(SECURITY_ATTRIBUTES) };
BOOL IsLocalSystem;
USHORT NativeMachine = IMAGE_FILE_PROCESS;
#if NTDDI_VERSION == NTDDI_WIN7
BOOL IsWindows7;
#endif
#if NTDDI_VERSION < NTDDI_WIN10
BOOL IsWindows10;
#endif
static FARPROC WINAPI
DelayedLoadLibraryHook(unsigned dliNotify, PDelayLoadInfo pdli)
@ -70,11 +76,17 @@ cleanupProcessToken:
return Ret;
}
static VOID EnvInit(VOID)
static void EnvInit(VOID)
{
DWORD MajorVersion;
RtlGetNtVersionNumbers(&MajorVersion, NULL, NULL);
DWORD MajorVersion, MinorVersion;
RtlGetNtVersionNumbers(&MajorVersion, &MinorVersion, NULL);
#if NTDDI_VERSION == NTDDI_WIN7
IsWindows7 = MajorVersion == 6 && MinorVersion == 1;
#endif
#if NTDDI_VERSION < NTDDI_WIN10
IsWindows10 = MajorVersion >= 10;
#endif
#ifdef MAYBE_WOW64
typedef BOOL(WINAPI * IsWow64Process2_t)(
@ -110,6 +122,7 @@ DllMain(_In_ HINSTANCE hinstDLL, _In_ DWORD fdwReason, _In_ LPVOID lpvReserved)
}
EnvInit();
NamespaceInit();
AdapterCleanupLegacyDevices();
break;
case DLL_PROCESS_DETACH:

View File

@ -24,4 +24,15 @@ extern HANDLE ModuleHeap;
extern SECURITY_ATTRIBUTES SecurityAttributes;
extern BOOL IsLocalSystem;
extern USHORT NativeMachine;
#if NTDDI_VERSION > NTDDI_WIN7
# define IsWindows7 FALSE
#else
extern BOOL IsWindows7;
#endif
#if NTDDI_VERSION >= NTDDI_WIN10
# define IsWindows10 TRUE
#else
extern BOOL IsWindows10;
#endif

View File

@ -9,7 +9,6 @@
#include <Windows.h>
#include <winternl.h>
#include <bcrypt.h>
#include <winefs.h>
#include <wchar.h>
#include <stdlib.h>
@ -17,32 +16,6 @@
static HANDLE PrivateNamespace = NULL;
static HANDLE BoundaryDescriptor = NULL;
static CRITICAL_SECTION Initializing;
static BCRYPT_ALG_HANDLE AlgProvider;
_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 (;;)
{
LPWSTR Str = AllocArray(Len, sizeof(*Str));
if (!Str)
return NULL;
Len = NormalizeString(NormForm, Source, -1, Str, Len);
if (Len > 0)
return Str;
Free(Str);
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
{
LOG_LAST_ERROR(L"Failed: %s", Source);
return NULL;
}
Len = -Len;
}
}
static _Return_type_success_(return != FALSE)
BOOL NamespaceRuntimeInit(VOID)
@ -56,27 +29,19 @@ BOOL NamespaceRuntimeInit(VOID)
return TRUE;
}
NTSTATUS Status;
if (!BCRYPT_SUCCESS(Status = BCryptOpenAlgorithmProvider(&AlgProvider, BCRYPT_SHA256_ALGORITHM, NULL, 0)))
{
LOG(WINTUN_LOG_ERR, L"Failed to open algorithm provider (status: 0x%x)", Status);
LastError = RtlNtStatusToDosError(Status);
goto cleanupLeaveCriticalSection;
}
BYTE Sid[MAX_SID_SIZE];
DWORD SidSize = sizeof(Sid);
if (!CreateWellKnownSid(IsLocalSystem ? WinLocalSystemSid : WinBuiltinAdministratorsSid, NULL, Sid, &SidSize))
{
LastError = LOG_LAST_ERROR(L"Failed to create SID");
goto cleanupBCryptCloseAlgorithmProvider;
goto cleanupLeaveCriticalSection;
}
BoundaryDescriptor = CreateBoundaryDescriptorW(L"Wintun", 0);
if (!BoundaryDescriptor)
{
LastError = LOG_LAST_ERROR(L"Failed to create boundary descriptor");
goto cleanupBCryptCloseAlgorithmProvider;
goto cleanupLeaveCriticalSection;
}
if (!AddSIDToBoundaryDescriptor(&BoundaryDescriptor, Sid))
{
@ -106,89 +71,12 @@ BOOL NamespaceRuntimeInit(VOID)
cleanupBoundaryDescriptor:
DeleteBoundaryDescriptor(BoundaryDescriptor);
cleanupBCryptCloseAlgorithmProvider:
BCryptCloseAlgorithmProvider(AlgProvider, 0);
cleanupLeaveCriticalSection:
LeaveCriticalSection(&Initializing);
SetLastError(LastError);
return FALSE;
}
_Use_decl_annotations_
HANDLE
NamespaceTakePoolMutex(LPCWSTR Pool)
{
if (!NamespaceRuntimeInit())
return NULL;
BCRYPT_HASH_HANDLE Sha256 = NULL;
NTSTATUS Status;
if (!BCRYPT_SUCCESS(Status = BCryptCreateHash(AlgProvider, &Sha256, NULL, 0, NULL, 0, 0)))
{
LOG(WINTUN_LOG_ERR, L"Failed to create hash (status: 0x%x)", Status);
SetLastError(RtlNtStatusToDosError(Status));
return NULL;
}
DWORD LastError;
static const WCHAR mutex_label[] = L"Wintun Adapter Name Mutex Stable Suffix v1 jason@zx2c4.com";
if (!BCRYPT_SUCCESS(
Status = BCryptHashData(Sha256, (PUCHAR)mutex_label, sizeof(mutex_label) /* Including NULL 2 bytes */, 0)))
{
LOG(WINTUN_LOG_ERR, L"Failed to hash data (status: 0x%x)", Status);
LastError = RtlNtStatusToDosError(Status);
goto cleanupSha256;
}
LPWSTR PoolNorm = NormalizeStringAlloc(NormalizationC, Pool);
if (!PoolNorm)
{
LastError = GetLastError();
goto cleanupSha256;
}
if (!BCRYPT_SUCCESS(
Status = BCryptHashData(Sha256, (PUCHAR)PoolNorm, (int)wcslen(PoolNorm) + 2 /* Add in NULL 2 bytes */, 0)))
{
LOG(WINTUN_LOG_ERR, L"Failed to hash data (status: 0x%x)", Status);
LastError = RtlNtStatusToDosError(Status);
goto cleanupPoolNorm;
}
BYTE Hash[32];
if (!BCRYPT_SUCCESS(Status = BCryptFinishHash(Sha256, Hash, sizeof(Hash), 0)))
{
LOG(WINTUN_LOG_ERR, L"Failed to calculate hash (status: 0x%x)", Status);
LastError = RtlNtStatusToDosError(Status);
goto cleanupPoolNorm;
}
static const WCHAR MutexNamePrefix[] = L"Wintun\\Wintun-Name-Mutex-";
WCHAR MutexName[_countof(MutexNamePrefix) + sizeof(Hash) * 2];
memcpy(MutexName, MutexNamePrefix, sizeof(MutexNamePrefix));
for (size_t i = 0; i < sizeof(Hash); ++i)
swprintf_s(&MutexName[_countof(MutexNamePrefix) - 1 + i * 2], 3, L"%02x", Hash[i]);
HANDLE Mutex = CreateMutexW(&SecurityAttributes, FALSE, MutexName);
if (!Mutex)
{
LastError = LOG_LAST_ERROR(L"Failed to create mutex %s", MutexName);
goto cleanupPoolNorm;
}
DWORD Result = WaitForSingleObject(Mutex, INFINITE);
switch (Result)
{
case WAIT_OBJECT_0:
case WAIT_ABANDONED:
Free(PoolNorm);
BCryptDestroyHash(Sha256);
return Mutex;
}
LOG(WINTUN_LOG_ERR, L"Failed to get mutex %s (status: 0x%x)", MutexName, Result);
LastError = ERROR_GEN_FAILURE;
CloseHandle(Mutex);
cleanupPoolNorm:
Free(PoolNorm);
cleanupSha256:
BCryptDestroyHash(Sha256);
SetLastError(LastError);
return NULL;
}
_Use_decl_annotations_
HANDLE
NamespaceTakeDriverInstallationMutex(VOID)
@ -214,6 +102,31 @@ NamespaceTakeDriverInstallationMutex(VOID)
return NULL;
}
_Use_decl_annotations_
HANDLE
NamespaceTakeDeviceInstallationMutex(VOID)
{
if (!NamespaceRuntimeInit())
return NULL;
HANDLE Mutex = CreateMutexW(&SecurityAttributes, FALSE, L"Wintun\\Wintun-Device-Installation-Mutex");
if (!Mutex)
{
LOG_LAST_ERROR(L"Failed to create mutex");
return NULL;
}
DWORD Result = WaitForSingleObject(Mutex, INFINITE);
switch (Result)
{
case WAIT_OBJECT_0:
case WAIT_ABANDONED:
return Mutex;
}
LOG(WINTUN_LOG_ERR, L"Failed to get mutex (status: 0x%x)", Result);
CloseHandle(Mutex);
SetLastError(ERROR_GEN_FAILURE);
return NULL;
}
_Use_decl_annotations_
VOID
NamespaceReleaseMutex(HANDLE Mutex)
@ -232,7 +145,6 @@ VOID NamespaceDone(VOID)
EnterCriticalSection(&Initializing);
if (PrivateNamespace)
{
BCryptCloseAlgorithmProvider(AlgProvider, 0);
ClosePrivateNamespace(PrivateNamespace, 0);
DeleteBoundaryDescriptor(BoundaryDescriptor);
PrivateNamespace = NULL;

View File

@ -12,14 +12,14 @@ _Return_type_success_(return != NULL)
_Post_maybenull_
_Acquires_lock_(_Curr_)
HANDLE
NamespaceTakePoolMutex(_In_z_ LPCWSTR Pool);
NamespaceTakeDriverInstallationMutex(VOID);
_Must_inspect_result_
_Return_type_success_(return != NULL)
_Post_maybenull_
_Acquires_lock_(_Curr_)
HANDLE
NamespaceTakeDriverInstallationMutex(VOID);
NamespaceTakeDeviceInstallationMutex(VOID);
_Releases_lock_(Mutex)
VOID

View File

@ -39,7 +39,6 @@ typedef struct _KEY_NAME_INFORMATION
} KEY_NAME_INFORMATION, *PKEY_NAME_INFORMATION;
#define STATUS_INFO_LENGTH_MISMATCH ((NTSTATUS)0xC0000004L) // TODO: #include <ntstatus.h> instead of this
#define STATUS_PNP_DEVICE_CONFIGURATION_PENDING ((NTSTATUS)0xC0000495L)
/* We can't use RtlGetVersion, because appcompat's aclayers.dll shims it to report Vista
* when run from legacy contexts. So, we instead use the undocumented RtlGetNtVersionNumbers.

View File

@ -10,100 +10,6 @@
#include <stdlib.h>
#include <strsafe.h>
_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;
LPWSTR PathNext = wcschr(Path, L'\\');
if (PathNext)
*PathNext = 0;
HANDLE Event = CreateEventW(NULL, FALSE, FALSE, NULL);
if (!Event)
{
LOG_LAST_ERROR(L"Failed to create event");
return NULL;
}
for (;;)
{
LastError = RegNotifyChangeKeyValue(Key, FALSE, REG_NOTIFY_CHANGE_NAME, Event, TRUE);
if (LastError != ERROR_SUCCESS)
{
WCHAR RegPath[MAX_REG_PATH];
LoggerGetRegistryKeyPath(Key, RegPath);
LOG_ERROR(LastError, L"Failed to setup registry key %.*s notification", MAX_REG_PATH, RegPath);
break;
}
HKEY Subkey;
LastError = RegOpenKeyExW(Key, Path, 0, PathNext ? KEY_NOTIFY : Access, &Subkey);
if (LastError == ERROR_SUCCESS)
{
if (PathNext)
{
HKEY KeyOut = OpenKeyWait(Subkey, PathNext + 1, Access, Deadline);
if (KeyOut)
{
RegCloseKey(Subkey);
CloseHandle(Event);
return KeyOut;
}
LastError = GetLastError();
break;
}
else
{
CloseHandle(Event);
return Subkey;
}
}
if (LastError != ERROR_FILE_NOT_FOUND && LastError != ERROR_PATH_NOT_FOUND)
{
WCHAR RegPath[MAX_REG_PATH];
LoggerGetRegistryKeyPath(Key, RegPath);
LOG_ERROR(LastError, L"Failed to open registry key %.*s\\%s", MAX_REG_PATH, RegPath, Path);
break;
}
LONGLONG TimeLeft = Deadline - GetTickCount64();
if (TimeLeft < 0)
TimeLeft = 0;
DWORD Result = WaitForSingleObject(Event, (DWORD)TimeLeft);
if (Result != WAIT_OBJECT_0)
{
WCHAR RegPath[MAX_REG_PATH];
LoggerGetRegistryKeyPath(Key, RegPath);
LOG(WINTUN_LOG_ERR,
L"Timeout waiting for registry key %.*s\\%s (status: 0x%x)",
MAX_REG_PATH,
RegPath,
Path,
Result);
break;
}
}
CloseHandle(Event);
SetLastError(LastError);
return NULL;
}
_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)
{
LOG(WINTUN_LOG_ERR, L"Registry path too long: %s", Path);
SetLastError(ERROR_INVALID_PARAMETER);
return NULL;
}
return OpenKeyWait(Key, Buf, Access, GetTickCount64() + Timeout);
}
_Use_decl_annotations_
BOOL
RegistryGetString(LPWSTR *Buf, DWORD Len, DWORD ValueType)
@ -150,48 +56,6 @@ RegistryGetString(LPWSTR *Buf, DWORD Len, DWORD ValueType)
}
}
_Use_decl_annotations_
BOOL
RegistryGetMultiString(PZZWSTR *Buf, DWORD Len, DWORD ValueType)
{
if (ValueType == REG_MULTI_SZ)
{
for (size_t i = 0;; i += wcsnlen(*Buf + i, Len - i) + 1)
{
if (i > Len)
{
/* Missing string and list terminators. */
PZZWSTR BufZ = ReZallocArray(*Buf, (SIZE_T)Len + 2, sizeof(*BufZ));
if (!BufZ)
return FALSE;
*Buf = BufZ;
return TRUE;
}
if (i == Len)
{
/* Missing list terminator. */
PZZWSTR BufZ = ReZallocArray(*Buf, (SIZE_T)Len + 1, sizeof(*BufZ));
if (!BufZ)
return FALSE;
*Buf = BufZ;
return TRUE;
}
if (!(*Buf)[i])
return TRUE;
}
}
/* Sanitize REG_SZ/REG_EXPAND_SZ and append a list terminator to make a multi-string. */
if (!RegistryGetString(Buf, Len, ValueType))
return FALSE;
Len = (DWORD)wcslen(*Buf) + 1;
PZZWSTR BufZ = ReZallocArray(*Buf, (SIZE_T)Len + 1, sizeof(WCHAR));
if (!BufZ)
return FALSE;
*Buf = BufZ;
return TRUE;
}
_Must_inspect_result_
static _Return_type_success_(return != NULL)
_Post_maybenull_
@ -256,59 +120,6 @@ RegistryQueryString(HKEY Key, LPCWSTR Name, BOOL Log)
return NULL;
}
_Use_decl_annotations_
LPWSTR
RegistryQueryStringWait(HKEY Key, LPCWSTR Name, DWORD Timeout)
{
DWORD LastError;
ULONGLONG Deadline = GetTickCount64() + Timeout;
HANDLE Event = CreateEventW(NULL, FALSE, FALSE, NULL);
if (!Event)
{
LOG_LAST_ERROR(L"Failed to create event");
return NULL;
}
for (;;)
{
LastError = RegNotifyChangeKeyValue(Key, FALSE, REG_NOTIFY_CHANGE_LAST_SET, Event, TRUE);
if (LastError != ERROR_SUCCESS)
{
WCHAR RegPath[MAX_REG_PATH];
LoggerGetRegistryKeyPath(Key, RegPath);
LOG_ERROR(LastError, L"Failed to setup registry key %.*s notification", MAX_REG_PATH, RegPath);
break;
}
LPWSTR Value = RegistryQueryString(Key, Name, FALSE);
if (Value)
{
CloseHandle(Event);
return Value;
}
LastError = GetLastError();
if (LastError != ERROR_FILE_NOT_FOUND && LastError != ERROR_PATH_NOT_FOUND)
break;
LONGLONG TimeLeft = Deadline - GetTickCount64();
if (TimeLeft < 0)
TimeLeft = 0;
DWORD Result = WaitForSingleObject(Event, (DWORD)TimeLeft);
if (Result != WAIT_OBJECT_0)
{
WCHAR RegPath[MAX_REG_PATH];
LoggerGetRegistryKeyPath(Key, RegPath);
LOG(WINTUN_LOG_ERR,
L"Timeout waiting for registry value %.*s\\%s (status: 0x%x)",
MAX_REG_PATH,
RegPath,
Name,
Result);
break;
}
}
CloseHandle(Event);
SetLastError(LastError);
return NULL;
}
_Use_decl_annotations_
BOOL
RegistryQueryDWORD(HKEY Key, LPCWSTR Name, DWORD *Value, BOOL Log)
@ -344,55 +155,3 @@ RegistryQueryDWORD(HKEY Key, LPCWSTR Name, DWORD *Value, BOOL Log)
}
return TRUE;
}
_Use_decl_annotations_
BOOL
RegistryQueryDWORDWait(HKEY Key, LPCWSTR Name, DWORD Timeout, DWORD *Value)
{
DWORD LastError;
ULONGLONG Deadline = GetTickCount64() + Timeout;
HANDLE Event = CreateEventW(NULL, FALSE, FALSE, NULL);
if (!Event)
{
LOG_LAST_ERROR(L"Failed to create event");
return FALSE;
}
for (;;)
{
LastError = RegNotifyChangeKeyValue(Key, FALSE, REG_NOTIFY_CHANGE_LAST_SET, Event, TRUE);
if (LastError != ERROR_SUCCESS)
{
WCHAR RegPath[MAX_REG_PATH];
LoggerGetRegistryKeyPath(Key, RegPath);
LOG_ERROR(LastError, L"Failed to setup registry key %.*s notification", MAX_REG_PATH, RegPath);
break;
}
if (RegistryQueryDWORD(Key, Name, Value, FALSE))
{
CloseHandle(Event);
return TRUE;
}
LastError = GetLastError();
if (LastError != ERROR_FILE_NOT_FOUND && LastError != ERROR_PATH_NOT_FOUND)
break;
LONGLONG TimeLeft = Deadline - GetTickCount64();
if (TimeLeft < 0)
TimeLeft = 0;
DWORD Result = WaitForSingleObject(Event, (DWORD)TimeLeft);
if (Result != WAIT_OBJECT_0)
{
WCHAR RegPath[MAX_REG_PATH];
LoggerGetRegistryKeyPath(Key, RegPath);
LOG(WINTUN_LOG_ERR,
L"Timeout waiting registry value %.*s\\%s (status: 0x%x)",
MAX_REG_PATH,
RegPath,
Name,
Result);
break;
}
}
CloseHandle(Event);
SetLastError(LastError);
return FALSE;
}

View File

@ -12,26 +12,6 @@
256 /* Maximum registry path length \
https://support.microsoft.com/en-us/help/256986/windows-registry-information-for-advanced-users */
/**
* Opens the specified registry key. It waits for the registry key to become available.
*
* @param Key Handle of the parent registry key. Must be opened with notify access.
*
* @param Path Subpath of the registry key to open. Zero-terminated string of up to MAX_REG_PATH-1 characters.
*
* @param Access A mask that specifies the desired access rights to the key to be opened.
*
* @param Timeout Timeout to wait for the value in milliseconds.
*
* @return Key handle on success. If the function fails, the return value is zero. To get extended error information,
* call GetLastError.
*/
_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.
*
@ -52,25 +32,6 @@ _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.
*
* @param Buf On input, it contains a pointer to pointer where the data is stored. The data must be allocated
* using HeapAlloc(ModuleHeap, 0). On output, it contains a pointer to pointer where the sanitized
* data is stored. It must be released with HeapFree(ModuleHeap, 0, *Buf) after use.
*
* @param Len Length of data string in wide characters.
*
* @param ValueType Type of data. Must be one of REG_MULTI_SZ, REG_SZ or REG_EXPAND_SZ.
*
* @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.
*/
_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.
*
@ -96,27 +57,6 @@ _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.
*
* @param Key Handle of the registry key to read from. Must be opened with read and notify access.
*
* @param Name Name of the value to read.
*
* @param Timeout Timeout to wait for the value in milliseconds.
*
* @return Registry value. If the value type is REG_EXPAND_SZ the value is expanded using ExpandEnvironmentStrings(). If
* the value type is REG_MULTI_SZ, only the first string from the multi-string is returned. The string must be
* released with HeapFree(ModuleHeap, 0, Value) after use. If the function fails, the return value is zero. To
* get extended error information, call GetLastError. Possible errors include the following:
* ERROR_INVALID_DATATYPE when the registry value is not a string
*/
_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.
*
@ -137,24 +77,3 @@ _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.
*
* @param Key Handle of the registry key to read from. Must be opened with read access.
*
* @param Name Name of the value to read.
*
* @param Timeout Timeout to wait for the value in milliseconds.
*
* @param Value Pointer to DWORD to retrieve registry value.
*
* @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. Possible errors include the following:
* ERROR_INVALID_DATATYPE when registry value exist but not REG_DWORD type;
* ERROR_INVALID_DATA when registry value size is not 4 bytes
*/
_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

@ -16,16 +16,22 @@ downlevelshim.dll RCDATA "downlevelshim.dll"
#if defined(WANT_AMD64_WOW64)
# if defined(BUILT_AMD64_WOW64)
wintun-amd64.dll RCDATA "amd64\\wintun.dll"
wintun-amd64.cat RCDATA "amd64\\driver\\wintun.cat"
wintun-amd64.inf RCDATA "amd64\\driver\\wintun.inf"
wintun-amd64.sys RCDATA "amd64\\driver\\wintun.sys"
setupapihost-amd64.dll RCDATA "amd64\\setupapihost.dll"
# else
# pragma message("AMD64 wintun.dll was not built, so this will not work from WOW64")
# pragma message("AMD64 wintun.sys was not built, so this will not work from WOW64")
# endif
#endif
#if defined(WANT_ARM64_WOW64)
# if defined(BUILT_ARM64_WOW64)
wintun-arm64.dll RCDATA "arm64\\wintun.dll"
wintun-arm64.cat RCDATA "arm64\\driver\\wintun.cat"
wintun-arm64.inf RCDATA "arm64\\driver\\wintun.inf"
wintun-arm64.sys RCDATA "arm64\\driver\\wintun.sys"
setupapihost-arm64.dll RCDATA "arm64\\setupapihost.dll"
# else
# pragma message("ARM64 wintun.dll was not built, so this will not work from WOW64")
# pragma message("ARM64 wintun.sys was not built, so this will not work from WOW64")
# endif
#endif

View File

@ -15,134 +15,6 @@
#include <objbase.h>
#include <assert.h>
#ifdef ACCEPT_WOW64
# define EXPORT comment(linker, "/EXPORT:" __FUNCTION__ "=" __FUNCDNAME__)
static DWORD
WriteFormatted(_In_ DWORD StdHandle, _In_z_ LPCWSTR Template, ...)
{
LPWSTR FormattedMessage = NULL;
DWORD Size;
va_list Arguments;
va_start(Arguments, Template);
DWORD Len = FormatMessageW(
FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ALLOCATE_BUFFER,
Template,
0,
0,
(VOID *)&FormattedMessage,
0,
&Arguments);
if (SUCCEEDED(DWordMult(Len, sizeof(*FormattedMessage), &Size)))
WriteFile(GetStdHandle(StdHandle), FormattedMessage, Size, &Size, NULL);
else
Size = 0;
LocalFree(FormattedMessage);
va_end(Arguments);
return Size / sizeof(*FormattedMessage);
}
static VOID CALLBACK
ConsoleLogger(_In_ WINTUN_LOGGER_LEVEL Level, _In_z_ LPCWSTR LogLine)
{
LPCWSTR Template;
switch (Level)
{
case WINTUN_LOG_INFO:
Template = L"[+] %1\n";
break;
case WINTUN_LOG_WARN:
Template = L"[-] %1\n";
break;
case WINTUN_LOG_ERR:
Template = L"[!] %1\n";
break;
default:
return;
}
WriteFormatted(STD_ERROR_HANDLE, Template, LogLine);
}
VOID __stdcall CreateAdapter(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow)
{
# pragma EXPORT
int Argc;
LPWSTR *Argv = CommandLineToArgvW(GetCommandLineW(), &Argc);
WintunSetLogger(ConsoleLogger);
if (Argc < 4)
goto cleanup;
if (wcslen(Argv[2]) >= WINTUN_MAX_POOL)
goto cleanup;
if (wcslen(Argv[3]) >= MAX_ADAPTER_NAME)
goto cleanup;
GUID RequestedGUID;
if (Argc > 4 && FAILED(CLSIDFromString(Argv[4], &RequestedGUID)))
goto cleanup;
BOOL RebootRequired;
WINTUN_ADAPTER *Adapter = WintunCreateAdapter(Argv[2], Argv[3], Argc > 4 ? &RequestedGUID : NULL, &RebootRequired);
DWORD LastError = Adapter ? ERROR_SUCCESS : GetLastError();
WriteFormatted(
STD_OUTPUT_HANDLE, L"%1!X! %2!s! %3!X!", LastError, Adapter ? Adapter->DevInstanceID : L"\"\"", RebootRequired);
if (Adapter)
WintunFreeAdapter(Adapter);
cleanup:
LocalFree(Argv);
}
VOID __stdcall DeleteAdapter(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow)
{
# pragma EXPORT
int Argc;
LPWSTR *Argv = CommandLineToArgvW(GetCommandLineW(), &Argc);
WintunSetLogger(ConsoleLogger);
if (Argc < 4)
goto cleanup;
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:
LocalFree(Argv);
}
VOID __stdcall DeletePoolDriver(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow)
{
# pragma EXPORT
int Argc;
LPWSTR *Argv = CommandLineToArgvW(GetCommandLineW(), &Argc);
WintunSetLogger(ConsoleLogger);
if (Argc < 2)
goto cleanup;
BOOL RebootRequired;
DWORD LastError = WintunDeletePoolDriver(Argv[2], &RebootRequired) ? ERROR_SUCCESS : GetLastError();
WriteFormatted(STD_OUTPUT_HANDLE, L"%1!X! %2!X!", LastError, RebootRequired);
cleanup:
LocalFree(Argv);
}
#endif
#ifdef MAYBE_WOW64
_Return_type_success_(return != FALSE)
@ -265,52 +137,23 @@ ProcessStdout(_Inout_ PROCESS_STDOUT_STATE *State)
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;
WCHAR Msg[0x200], Buf[0x220], LevelRune;
DWORD64 Timestamp;
DWORD SizeRead;
WINTUN_LOGGER_LEVEL Level;
for (;;)
{
WCHAR Buf[0x200];
DWORD SizeRead;
if (!ReadFile(Stderr, Buf, sizeof(Buf), &SizeRead, NULL))
if (!ReadFile(Stderr, Buf, sizeof(Buf), &SizeRead, NULL) || !SizeRead)
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;
}
}
Msg[0] = Buf[SizeRead / sizeof(*Buf) - 1] = L'\0';
if (swscanf_s(Buf, L"[%c %I64u] %[^\n]", &LevelRune, 1, &Timestamp, Msg, (DWORD)_countof(Msg)) != 3 || !Msg[0])
return ERROR_INVALID_DATA;
if (!((Level = WINTUN_LOG_INFO, LevelRune == L'+') || (Level = WINTUN_LOG_WARN, LevelRune == L'-') ||
(Level = WINTUN_LOG_ERR, LevelRune == L'!')))
return ERROR_INVALID_DATA;
Logger(Level, Timestamp, Msg);
}
}
@ -343,7 +186,7 @@ ExecuteRunDll32(
return FALSE;
}
WCHAR DllPath[MAX_PATH] = { 0 };
if (!PathCombineW(DllPath, RandomTempSubDirectory, L"wintun.dll"))
if (!PathCombineW(DllPath, RandomTempSubDirectory, L"setupapihost.dll"))
{
LastError = ERROR_BUFFER_OVERFLOW;
goto cleanupDirectory;
@ -352,10 +195,10 @@ ExecuteRunDll32(
switch (NativeMachine)
{
case IMAGE_FILE_MACHINE_AMD64:
WintunDllResourceName = L"wintun-amd64.dll";
WintunDllResourceName = L"setupapihost-amd64.dll";
break;
case IMAGE_FILE_MACHINE_ARM64:
WintunDllResourceName = L"wintun-arm64.dll";
WintunDllResourceName = L"setupapihost-arm64.dll";
break;
default:
LOG(WINTUN_LOG_ERR, L"Unsupported platform 0x%x", NativeMachine);
@ -444,9 +287,9 @@ cleanupThreads:
WaitForSingleObject(ThreadStdout, INFINITE);
DWORD ThreadResult;
if (!GetExitCodeThread(ThreadStdout, &ThreadResult))
LOG_LAST_ERROR(L"Failed to retrieve stdout reader result");
LastError = LOG_LAST_ERROR(L"Failed to retrieve stdout reader result");
else if (ThreadResult != ERROR_SUCCESS)
LOG_ERROR(LastError, L"Failed to read process output");
LastError = LOG_ERROR(ThreadResult, L"Failed to read process output");
CloseHandle(ThreadStdout);
}
cleanupPipes:
@ -462,90 +305,40 @@ cleanupDirectory:
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_
static _Return_type_success_(return != FALSE)
BOOL
DeleteAdapterViaRundll32(const WINTUN_ADAPTER *Adapter, BOOL ForceCloseSessions, BOOL *RebootRequired)
InvokeClassInstaller(_In_ LPCWSTR Action, _In_ LPCWSTR Function, _In_ HDEVINFO DevInfo, _In_ SP_DEVINFO_DATA *DevInfoData)
{
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_INFO, L"Spawning native process to %s instance", Action);
WCHAR InstanceId[MAX_INSTANCE_ID];
DWORD RequiredChars = _countof(InstanceId);
if (!SetupDiGetDeviceInstanceIdW(DevInfo, DevInfoData, InstanceId, RequiredChars, &RequiredChars))
{
LOG(WINTUN_LOG_ERR, L"Command line too long");
SetLastError(ERROR_INVALID_PARAMETER);
LOG_LAST_ERROR(L"Failed to get adapter instance ID");
return FALSE;
}
WCHAR Response[8 + 1 + 8 + 1];
DWORD LastError;
if (!ExecuteRunDll32(L"DeleteAdapter", Arguments, Response, _countof(Response)))
LPWSTR Arguments = ArgvToCommandLineW(1, InstanceId);
if (!Arguments)
{
LastError = GetLastError();
LOG(WINTUN_LOG_ERR, L"Error executing worker process: %s", Arguments);
SetLastError(LOG_ERROR(ERROR_INVALID_PARAMETER, L"Command line too long"));
return FALSE;
}
DWORD LastError;
WCHAR Response[8 + 1];
if (!ExecuteRunDll32(Function, Arguments, Response, _countof(Response)))
{
LastError = LOG_LAST_ERROR(L"Error executing worker process: %s", Arguments);
goto cleanupArguments;
}
int Argc;
LPWSTR *Argv = CommandLineToArgvW(Response, &Argc);
if (Argc < 2)
if (Argc < 1)
{
LOG(WINTUN_LOG_ERR, L"Incomplete response: %s", Response);
LastError = ERROR_INVALID_PARAMETER;
LastError = LOG_ERROR(ERROR_INVALID_PARAMETER, L"Incomplete response: %s", Response);
goto cleanupArgv;
}
LastError = wcstoul(Argv[0], NULL, 16);
if (wcstoul(Argv[1], NULL, 16))
*RebootRequired = TRUE;
cleanupArgv:
LocalFree(Argv);
cleanupArguments:
@ -555,39 +348,51 @@ cleanupArguments:
_Use_decl_annotations_
BOOL
DeletePoolDriverViaRundll32(LPCWSTR Pool, BOOL *RebootRequired)
RemoveInstanceViaRundll32(HDEVINFO DevInfo, SP_DEVINFO_DATA *DevInfoData)
{
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;
return InvokeClassInstaller(L"remove", L"RemoveInstance", DevInfo, DevInfoData);
}
WCHAR Response[8 + 1 + 8 + 1];
DWORD LastError;
if (!ExecuteRunDll32(L"DeletePoolDriver", Arguments, Response, _countof(Response)))
_Use_decl_annotations_
BOOL
EnableInstanceViaRundll32(HDEVINFO DevInfo, SP_DEVINFO_DATA *DevInfoData)
{
LastError = GetLastError();
LOG(WINTUN_LOG_ERR, L"Error executing worker process: %s", Arguments);
goto cleanupArguments;
return InvokeClassInstaller(L"enable", L"EnableInstance", DevInfo, DevInfoData);
}
_Use_decl_annotations_
BOOL
DisableInstanceViaRundll32(HDEVINFO DevInfo, SP_DEVINFO_DATA *DevInfoData)
{
return InvokeClassInstaller(L"disable", L"DisableInstance", DevInfo, DevInfoData);
}
_Use_decl_annotations_
BOOL
CreateInstanceWin7ViaRundll32(LPWSTR InstanceId)
{
LOG(WINTUN_LOG_INFO, L"Spawning native process to create instance");
DWORD LastError;
WCHAR Response[MAX_INSTANCE_ID + 1];
if (!ExecuteRunDll32(L"CreateInstanceWin7", L"", Response, _countof(Response)))
{
LastError = LOG_LAST_ERROR(L"Error executing worker process");
goto cleanup;
}
int Argc;
LPWSTR *Argv = CommandLineToArgvW(Response, &Argc);
if (Argc < 2)
{
LOG(WINTUN_LOG_ERR, L"Incomplete response: %s", Response);
LastError = ERROR_INVALID_PARAMETER;
LastError = LOG_ERROR(ERROR_INVALID_PARAMETER, L"Incomplete response: %s", Response);
goto cleanupArgv;
}
LastError = wcstoul(Argv[0], NULL, 16);
if (wcstoul(Argv[1], NULL, 16))
*RebootRequired = TRUE;
if (LastError == ERROR_SUCCESS)
wcsncpy_s(InstanceId, MAX_INSTANCE_ID, Argv[1], _TRUNCATE);
cleanupArgv:
LocalFree(Argv);
cleanupArguments:
Free(Arguments);
cleanup:
return RET_ERROR(TRUE, LastError);
}
#endif

View File

@ -5,25 +5,22 @@
#pragma once
#include <Windows.h>
#include <SetupAPI.h>
#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
RemoveInstanceViaRundll32(_In_ HDEVINFO DevInfo, _In_ SP_DEVINFO_DATA *DevInfoData);
_Return_type_success_(return != FALSE)
BOOL
DeleteAdapterViaRundll32(
_In_ const WINTUN_ADAPTER *Adapter,
_In_ BOOL ForceCloseSessions,
_Inout_ BOOL *RebootRequired);
EnableInstanceViaRundll32(_In_ HDEVINFO DevInfo, _In_ SP_DEVINFO_DATA *DevInfoData);
_Return_type_success_(return != FALSE)
BOOL
DeletePoolDriverViaRundll32(_In_z_ LPCWSTR Pool, _Inout_ BOOL *RebootRequired);
DisableInstanceViaRundll32(_In_ HDEVINFO DevInfo, _In_ SP_DEVINFO_DATA *DevInfoData);
_Return_type_success_(return != FALSE)
BOOL
CreateInstanceWin7ViaRundll32(_Out_writes_z_(MAX_INSTANCE_ID) LPWSTR InstanceId);

View File

@ -70,7 +70,7 @@ typedef struct _TUN_SESSION
HANDLE Handle;
} TUN_SESSION;
WINTUN_START_SESSION_FUNC_IMPL WintunStartSession;
WINTUN_START_SESSION_FUNC WintunStartSession;
_Use_decl_annotations_
TUN_SESSION *WINAPI
WintunStartSession(WINTUN_ADAPTER *Adapter, DWORD Capacity)
@ -146,7 +146,7 @@ cleanup:
return NULL;
}
WINTUN_END_SESSION_FUNC_IMPL WintunEndSession;
WINTUN_END_SESSION_FUNC WintunEndSession;
_Use_decl_annotations_
VOID WINAPI
WintunEndSession(TUN_SESSION *Session)
@ -160,7 +160,7 @@ WintunEndSession(TUN_SESSION *Session)
Free(Session);
}
WINTUN_GET_READ_WAIT_EVENT_FUNC_IMPL WintunGetReadWaitEvent;
WINTUN_GET_READ_WAIT_EVENT_FUNC WintunGetReadWaitEvent;
_Use_decl_annotations_
HANDLE WINAPI
WintunGetReadWaitEvent(TUN_SESSION *Session)
@ -168,7 +168,7 @@ WintunGetReadWaitEvent(TUN_SESSION *Session)
return Session->Descriptor.Send.TailMoved;
}
WINTUN_RECEIVE_PACKET_FUNC_IMPL WintunReceivePacket;
WINTUN_RECEIVE_PACKET_FUNC WintunReceivePacket;
_Use_decl_annotations_
BYTE *WINAPI
WintunReceivePacket(TUN_SESSION *Session, DWORD *PacketSize)
@ -221,7 +221,7 @@ cleanup:
return NULL;
}
WINTUN_RELEASE_RECEIVE_PACKET_FUNC_IMPL WintunReleaseReceivePacket;
WINTUN_RELEASE_RECEIVE_PACKET_FUNC WintunReleaseReceivePacket;
_Use_decl_annotations_
VOID WINAPI
WintunReleaseReceivePacket(TUN_SESSION *Session, const BYTE *Packet)
@ -242,7 +242,7 @@ WintunReleaseReceivePacket(TUN_SESSION *Session, const BYTE *Packet)
LeaveCriticalSection(&Session->Send.Lock);
}
WINTUN_ALLOCATE_SEND_PACKET_FUNC_IMPL WintunAllocateSendPacket;
WINTUN_ALLOCATE_SEND_PACKET_FUNC WintunAllocateSendPacket;
_Use_decl_annotations_
BYTE *WINAPI
WintunAllocateSendPacket(TUN_SESSION *Session, DWORD PacketSize)
@ -280,7 +280,7 @@ cleanup:
return NULL;
}
WINTUN_SEND_PACKET_FUNC_IMPL WintunSendPacket;
WINTUN_SEND_PACKET_FUNC WintunSendPacket;
_Use_decl_annotations_
VOID WINAPI
WintunSendPacket(TUN_SESSION *Session, const BYTE *Packet)

View File

@ -5,176 +5,102 @@
#pragma once
#include <winsock2.h>
#include <windows.h>
#include <ipexport.h>
#include <ifdef.h>
#include <ws2ipdef.h>
#ifdef __cplusplus
extern "C" {
#endif
#ifndef ALIGNED
# if defined(_MSC_VER)
# define ALIGNED(n) __declspec(align(n))
# elif defined(__GNUC__)
# define ALIGNED(n) __attribute__((aligned(n)))
# else
# error "Unable to define ALIGNED"
# endif
#endif
/* MinGW is missing this one, unfortunately. */
#ifndef _Post_maybenull_
# define _Post_maybenull_
#endif
#pragma warning(push)
#pragma warning(disable : 4324) /* structure was padded due to alignment specifier */
/**
* A handle representing Wintun adapter
*/
typedef struct _WINTUN_ADAPTER *WINTUN_ADAPTER_HANDLE;
/**
* Maximum pool name length including zero terminator
*/
#define WINTUN_MAX_POOL 256
/**
* Creates a new Wintun adapter.
*
* @param Pool Name of the adapter pool. Zero-terminated string of up to WINTUN_MAX_POOL-1 characters.
*
* @param Name The requested name of the adapter. Zero-terminated string of up to MAX_ADAPTER_NAME-1
* characters.
*
* @param TunelType Name of the adapter tunnel type. Zero-terminated string of up to MAX_ADAPTER_NAME-1
* characters.
*
* @param RequestedGUID The GUID of the created network adapter, which then influences NLA generation deterministically.
* If it is set to NULL, the GUID is chosen by the system at random, and hence a new NLA entry is
* created for each new adapter. It is called "requested" GUID because the API it uses is
* completely undocumented, and so there could be minor interesting complications with its usage.
*
* @param RebootRequired Optional pointer to a boolean flag to be set to TRUE in case SetupAPI suggests a reboot.
*
* @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.
* @return If the function succeeds, the return value is the adapter handle. Must be released with
* WintunCloseAdapter. If the function fails, the return value is NULL. To get extended error information, call
* GetLastError.
*/
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;
WINTUN_ADAPTER_HANDLE(WINAPI WINTUN_CREATE_ADAPTER_FUNC)
(_In_z_ LPCWSTR Name, _In_z_ LPCWSTR TunnelType, _In_opt_ const GUID *RequestedGUID);
/**
* Opens an existing Wintun adapter.
*
* @param Pool Name of the adapter pool. Zero-terminated string of up to WINTUN_MAX_POOL-1 characters.
* @param Name The requested name of the adapter. Zero-terminated string of up to MAX_ADAPTER_NAME-1
* characters.
*
* @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
* @return If the function succeeds, the return value is the adapter handle. Must be released with
* WintunCloseAdapter. If the function fails, the return value is NULL. To get extended error information, call
* GetLastError.
*/
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;
WINTUN_ADAPTER_HANDLE(WINAPI WINTUN_OPEN_ADAPTER_FUNC)(_In_z_ LPCWSTR Name);
/**
* Deletes a Wintun adapter.
* Releases Wintun adapter resources and, if adapter was created with WintunCreateAdapter, removes adapter.
*
* @param Adapter Adapter handle obtained with WintunOpenAdapter or WintunCreateAdapter.
*
* @param ForceCloseSessions Force close adapter handles that may be in use by other processes. Only set this to TRUE
* with extreme care, as this is resource intensive and may put processes into an undefined
* or unpredictable state. Most users should set this to FALSE.
*
* @param RebootRequired Optional pointer to a boolean flag to be set to TRUE in case SetupAPI suggests a reboot.
* @param Adapter Adapter handle obtained with WintunCreateAdapter or WintunOpenAdapter.
*/
typedef VOID(WINAPI WINTUN_CLOSE_ADAPTER_FUNC)(_In_opt_ WINTUN_ADAPTER_HANDLE Adapter);
/**
* Deletes the Wintun driver if there are no more adapters in use.
*
* @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_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.
*
* @param Adapter Adapter handle, which will be freed when this function returns.
*
* @param Param An application-defined value passed to the WintunEnumAdapters.
*
* @return Non-zero to continue iterating adapters; zero to stop.
*/
typedef BOOL(CALLBACK *WINTUN_ENUM_CALLBACK)(_In_ WINTUN_ADAPTER_HANDLE Adapter, _In_ LPARAM Param);
/**
* Enumerates all Wintun adapters.
*
* @param Pool Name of the adapter pool. Zero-terminated string of up to WINTUN_MAX_POOL-1 characters.
*
* @param Callback Callback function. To continue enumeration, the callback function must return TRUE; to stop
* enumeration, it must return FALSE.
*
* @param Param An application-defined value to be passed to the callback function.
*
* @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_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_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
* from the driver store, usually called by uninstallers.
*
* @param Pool Name of the adapter pool. Zero-terminated string of up to WINTUN_MAX_POOL-1 characters.
*
* @param RebootRequired Optional pointer to a boolean flag to be set to TRUE in case SetupAPI suggests a reboot.
*
* @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_POOL_DRIVER_FUNC_IMPL)(_In_z_ LPCWSTR Pool, _Out_opt_ BOOL *RebootRequired);
typedef WINTUN_DELETE_POOL_DRIVER_FUNC_IMPL *WINTUN_DELETE_POOL_DRIVER_FUNC;
BOOL(WINAPI WINTUN_DELETE_DRIVER_FUNC)(VOID);
/**
* Returns the LUID of the adapter.
*
* @param Adapter Adapter handle obtained with WintunOpenAdapter or WintunCreateAdapter
* @param Adapter Adapter handle obtained with WintunCreateAdapter or WintunOpenAdapter
*
* @param Luid Pointer to LUID to receive adapter 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.
*
* @param Adapter Adapter handle obtained with WintunOpenAdapter or WintunCreateAdapter
*
* @param Name Pointer to a string to receive adapter name
*
* @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 _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.
*
* @param Adapter Adapter handle obtained with WintunOpenAdapter or WintunCreateAdapter
*
* @param Name Adapter name. Zero-terminated string of up to MAX_ADAPTER_NAME-1 characters.
*
* @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_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;
typedef VOID(WINAPI WINTUN_GET_ADAPTER_LUID_FUNC)(_In_ WINTUN_ADAPTER_HANDLE Adapter, _Out_ NET_LUID *Luid);
/**
* Determines the version of the Wintun driver currently loaded.
@ -184,8 +110,7 @@ typedef WINTUN_SET_ADAPTER_NAME_FUNC_IMPL *WINTUN_SET_ADAPTER_NAME_FUNC;
* ERROR_FILE_NOT_FOUND Wintun not loaded
*/
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;
DWORD(WINAPI WINTUN_GET_RUNNING_DRIVER_VERSION_FUNC)(VOID);
/**
* Determines the level of logging, passed to WINTUN_LOGGER_CALLBACK.
@ -202,9 +127,14 @@ typedef enum
*
* @param Level Message level.
*
* @param Timestamp Message timestamp in in 100ns intervals since 1601-01-01 UTC.
*
* @param Message Message text.
*/
typedef VOID(CALLBACK *WINTUN_LOGGER_CALLBACK)(_In_ WINTUN_LOGGER_LEVEL Level, _In_z_ LPCWSTR Message);
typedef VOID(CALLBACK *WINTUN_LOGGER_CALLBACK)(
_In_ WINTUN_LOGGER_LEVEL Level,
_In_ DWORD64 Timestamp,
_In_z_ LPCWSTR Message);
/**
* Sets logger callback function.
@ -213,8 +143,7 @@ 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_IMPL)(_In_ WINTUN_LOGGER_CALLBACK NewLogger);
typedef WINTUN_SET_LOGGER_FUNC_IMPL *WINTUN_SET_LOGGER_FUNC;
typedef VOID(WINAPI WINTUN_SET_LOGGER_FUNC)(_In_ WINTUN_LOGGER_CALLBACK NewLogger);
/**
* Minimum ring capacity.
@ -245,16 +174,14 @@ typedef struct _TUN_SESSION *WINTUN_SESSION_HANDLE;
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;
WINTUN_SESSION_HANDLE(WINAPI WINTUN_START_SESSION_FUNC)(_In_ WINTUN_ADAPTER_HANDLE Adapter, _In_ DWORD Capacity);
/**
* Ends Wintun session.
*
* @param Session Wintun session handle obtained with WintunStartSession
*/
typedef VOID(WINAPI WINTUN_END_SESSION_FUNC_IMPL)(_In_ WINTUN_SESSION_HANDLE Session);
typedef WINTUN_END_SESSION_FUNC_IMPL *WINTUN_END_SESSION_FUNC;
typedef VOID(WINAPI WINTUN_END_SESSION_FUNC)(_In_ WINTUN_SESSION_HANDLE Session);
/**
* Gets Wintun session's read-wait event handle.
@ -266,8 +193,7 @@ typedef WINTUN_END_SESSION_FUNC_IMPL *WINTUN_END_SESSION_FUNC;
* 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_IMPL)(_In_ WINTUN_SESSION_HANDLE Session);
typedef WINTUN_GET_READ_WAIT_EVENT_FUNC_IMPL *WINTUN_GET_READ_WAIT_EVENT_FUNC;
typedef HANDLE(WINAPI WINTUN_GET_READ_WAIT_EVENT_FUNC)(_In_ WINTUN_SESSION_HANDLE Session);
/**
* Maximum IP packet size
@ -293,8 +219,7 @@ 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;
BYTE *(WINAPI WINTUN_RECEIVE_PACKET_FUNC)(_In_ WINTUN_SESSION_HANDLE Session, _Out_ DWORD *PacketSize);
/**
* Releases internal buffer after the received packet has been processed by the client. This function is thread-safe.
@ -304,8 +229,7 @@ typedef WINTUN_RECEIVE_PACKET_FUNC_IMPL *WINTUN_RECEIVE_PACKET_FUNC;
* @param Packet Packet obtained with WintunReceivePacket
*/
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;
WINAPI WINTUN_RELEASE_RECEIVE_PACKET_FUNC)(_In_ WINTUN_SESSION_HANDLE Session, _In_ const BYTE *Packet);
/**
* Allocates memory for a packet to send. After the memory is filled with packet data, call WintunSendPacket to send
@ -326,8 +250,7 @@ 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;
BYTE *(WINAPI WINTUN_ALLOCATE_SEND_PACKET_FUNC)(_In_ WINTUN_SESSION_HANDLE Session, _In_ DWORD PacketSize);
/**
* Sends the packet and releases internal buffer. WintunSendPacket is thread-safe, but the WintunAllocateSendPacket
@ -338,8 +261,9 @@ typedef WINTUN_ALLOCATE_SEND_PACKET_FUNC_IMPL *WINTUN_ALLOCATE_SEND_PACKET_FUNC;
*
* @param Packet Packet obtained with WintunAllocateSendPacket
*/
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;
typedef VOID(WINAPI WINTUN_SEND_PACKET_FUNC)(_In_ WINTUN_SESSION_HANDLE Session, _In_ const BYTE *Packet);
#pragma warning(pop)
#ifdef __cplusplus
}

View File

@ -32,17 +32,20 @@ wintun.sys, , , 0x00004002 ; COPYFLG_IN_USE_RENAME | COPYFLG_NOSKIP
[Wintun.Install]
Characteristics = 0x1 ; NCF_VIRTUAL
AddReg = Wintun.Ndi
AddProperty = Wintun.Properties
CopyFiles = Wintun.CopyFiles.Sys
*IfType = 53 ; IF_TYPE_PROP_VIRTUAL
*MediaType = 19 ; NdisMediumIP
*PhysicalMediaType = 0 ; NdisPhysicalMediumUnspecified
EnableDhcp = 0 ; Disable DHCP
[Wintun.Properties]
DeviceVendorWebsite,,,,"https://www.wintun.net/"
[Wintun.Install.Services]
AddService = wintun, 2, Wintun.Service, Wintun.EventLog ; 2=SPSVCINST_ASSOCSERVICE
[Wintun.Ndi]
HKR, , DeviceVxDs, , wintun.sys
HKR, Ndi, Service, 0, wintun
HKR, Ndi\Interfaces, UpperRange, , "ndis5"
HKR, Ndi\Interfaces, LowerRange, , "nolower"

View File

@ -9,29 +9,26 @@
#include <iphlpapi.h>
#include <mstcpip.h>
#include <ip2string.h>
#include <winternl.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include "wintun.h"
static WINTUN_CREATE_ADAPTER_FUNC WintunCreateAdapter;
static WINTUN_DELETE_ADAPTER_FUNC WintunDeleteAdapter;
static WINTUN_DELETE_POOL_DRIVER_FUNC WintunDeletePoolDriver;
static WINTUN_ENUM_ADAPTERS_FUNC WintunEnumAdapters;
static WINTUN_FREE_ADAPTER_FUNC WintunFreeAdapter;
static WINTUN_OPEN_ADAPTER_FUNC WintunOpenAdapter;
static WINTUN_GET_ADAPTER_LUID_FUNC WintunGetAdapterLUID;
static WINTUN_GET_ADAPTER_NAME_FUNC WintunGetAdapterName;
static WINTUN_SET_ADAPTER_NAME_FUNC WintunSetAdapterName;
static WINTUN_GET_RUNNING_DRIVER_VERSION_FUNC WintunGetRunningDriverVersion;
static WINTUN_SET_LOGGER_FUNC WintunSetLogger;
static WINTUN_START_SESSION_FUNC WintunStartSession;
static WINTUN_END_SESSION_FUNC WintunEndSession;
static WINTUN_GET_READ_WAIT_EVENT_FUNC WintunGetReadWaitEvent;
static WINTUN_RECEIVE_PACKET_FUNC WintunReceivePacket;
static WINTUN_RELEASE_RECEIVE_PACKET_FUNC WintunReleaseReceivePacket;
static WINTUN_ALLOCATE_SEND_PACKET_FUNC WintunAllocateSendPacket;
static WINTUN_SEND_PACKET_FUNC WintunSendPacket;
static WINTUN_CREATE_ADAPTER_FUNC *WintunCreateAdapter;
static WINTUN_CLOSE_ADAPTER_FUNC *WintunCloseAdapter;
static WINTUN_OPEN_ADAPTER_FUNC *WintunOpenAdapter;
static WINTUN_GET_ADAPTER_LUID_FUNC *WintunGetAdapterLUID;
static WINTUN_GET_RUNNING_DRIVER_VERSION_FUNC *WintunGetRunningDriverVersion;
static WINTUN_DELETE_DRIVER_FUNC *WintunDeleteDriver;
static WINTUN_SET_LOGGER_FUNC *WintunSetLogger;
static WINTUN_START_SESSION_FUNC *WintunStartSession;
static WINTUN_END_SESSION_FUNC *WintunEndSession;
static WINTUN_GET_READ_WAIT_EVENT_FUNC *WintunGetReadWaitEvent;
static WINTUN_RECEIVE_PACKET_FUNC *WintunReceivePacket;
static WINTUN_RELEASE_RECEIVE_PACKET_FUNC *WintunReleaseReceivePacket;
static WINTUN_ALLOCATE_SEND_PACKET_FUNC *WintunAllocateSendPacket;
static WINTUN_SEND_PACKET_FUNC *WintunSendPacket;
static HMODULE
InitializeWintun(void)
@ -40,16 +37,13 @@ InitializeWintun(void)
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(WintunDeletePoolDriver, WINTUN_DELETE_POOL_DRIVER_FUNC) || X(WintunEnumAdapters, WINTUN_ENUM_ADAPTERS_FUNC) ||
X(WintunFreeAdapter, WINTUN_FREE_ADAPTER_FUNC) || X(WintunOpenAdapter, WINTUN_OPEN_ADAPTER_FUNC) ||
X(WintunGetAdapterLUID, WINTUN_GET_ADAPTER_LUID_FUNC) ||
X(WintunGetAdapterName, WINTUN_GET_ADAPTER_NAME_FUNC) ||
X(WintunSetAdapterName, WINTUN_SET_ADAPTER_NAME_FUNC) ||
#define X(Name, Type) ((Name = (Type *)GetProcAddress(Wintun, #Name)) == NULL)
if (X(WintunCreateAdapter, WINTUN_CREATE_ADAPTER_FUNC) || X(WintunCloseAdapter, WINTUN_CLOSE_ADAPTER_FUNC) ||
X(WintunOpenAdapter, WINTUN_OPEN_ADAPTER_FUNC) || X(WintunGetAdapterLUID, WINTUN_GET_ADAPTER_LUID_FUNC) ||
X(WintunGetRunningDriverVersion, WINTUN_GET_RUNNING_DRIVER_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(WintunDeleteDriver, WINTUN_DELETE_DRIVER_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(WintunReleaseReceivePacket, WINTUN_RELEASE_RECEIVE_PACKET_FUNC) ||
X(WintunAllocateSendPacket, WINTUN_ALLOCATE_SEND_PACKET_FUNC) || X(WintunSendPacket, WINTUN_SEND_PACKET_FUNC))
@ -64,12 +58,10 @@ InitializeWintun(void)
}
static void CALLBACK
ConsoleLogger(_In_ WINTUN_LOGGER_LEVEL Level, _In_z_ const WCHAR *LogLine)
ConsoleLogger(_In_ WINTUN_LOGGER_LEVEL Level, _In_ DWORD64 Timestamp, _In_z_ const WCHAR *LogLine)
{
FILETIME Timestamp;
GetSystemTimePreciseAsFileTime(&Timestamp);
SYSTEMTIME SystemTime;
FileTimeToSystemTime(&Timestamp, &SystemTime);
FileTimeToSystemTime((FILETIME *)&Timestamp, &SystemTime);
WCHAR LevelMarker;
switch (Level)
{
@ -99,6 +91,13 @@ ConsoleLogger(_In_ WINTUN_LOGGER_LEVEL Level, _In_z_ const WCHAR *LogLine)
LogLine);
}
static DWORD64 Now(VOID)
{
LARGE_INTEGER Timestamp;
NtQuerySystemTime(&Timestamp);
return Timestamp.QuadPart;
}
static DWORD
LogError(_In_z_ const WCHAR *Prefix, _In_ DWORD Error)
{
@ -121,7 +120,7 @@ LogError(_In_z_ const WCHAR *Prefix, _In_ DWORD Error)
0,
(va_list *)(DWORD_PTR[]){ (DWORD_PTR)Prefix, (DWORD_PTR)Error, (DWORD_PTR)SystemMessage });
if (FormattedMessage)
ConsoleLogger(WINTUN_LOG_ERR, FormattedMessage);
ConsoleLogger(WINTUN_LOG_ERR, Now(), FormattedMessage);
LocalFree(FormattedMessage);
LocalFree(SystemMessage);
return Error;
@ -144,7 +143,7 @@ Log(_In_ WINTUN_LOGGER_LEVEL Level, _In_z_ const WCHAR *Format, ...)
va_start(args, Format);
_vsnwprintf_s(LogLine, _countof(LogLine), _TRUNCATE, Format, args);
va_end(args);
ConsoleLogger(Level, LogLine);
ConsoleLogger(Level, Now(), LogLine);
}
static HANDLE QuitEvent;
@ -295,25 +294,13 @@ SendPackets(_Inout_ DWORD_PTR SessionPtr)
return ERROR_SUCCESS;
}
static BOOL CALLBACK
PrintAdapter(_In_ WINTUN_ADAPTER_HANDLE Adapter, _In_ LPARAM Param)
{
UNREFERENCED_PARAMETER(Param);
WCHAR szAdapterName[MAX_ADAPTER_NAME];
if (WintunGetAdapterName(Adapter, szAdapterName))
Log(WINTUN_LOG_INFO, L"Existing Wintun adapter: %s", szAdapterName);
return TRUE;
}
int
main(void)
int __cdecl main(void)
{
HMODULE Wintun = InitializeWintun();
if (!Wintun)
return LogError(L"Failed to initialize Wintun", GetLastError());
WintunSetLogger(ConsoleLogger);
Log(WINTUN_LOG_INFO, L"Wintun library loaded");
WintunEnumAdapters(L"Example", PrintAdapter, 0);
DWORD LastError;
HaveQuit = FALSE;
@ -330,17 +317,13 @@ main(void)
}
GUID ExampleGuid = { 0xdeadbabe, 0xcafe, 0xbeef, { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef } };
WINTUN_ADAPTER_HANDLE Adapter = WintunOpenAdapter(L"Example", L"Demo");
if (!Adapter)
{
Adapter = WintunCreateAdapter(L"Example", L"Demo", &ExampleGuid, NULL);
WINTUN_ADAPTER_HANDLE Adapter = WintunCreateAdapter(L"Demo", L"Example", &ExampleGuid);
if (!Adapter)
{
LastError = GetLastError();
LogError(L"Failed to create adapter", LastError);
goto cleanupQuit;
}
}
DWORD Version = WintunGetRunningDriverVersion();
Log(WINTUN_LOG_INFO, L"Wintun v%u.%u loaded", (Version >> 16) & 0xff, (Version >> 0) & 0xff);
@ -391,8 +374,7 @@ cleanupWorkers:
}
WintunEndSession(Session);
cleanupAdapter:
WintunDeleteAdapter(Adapter, FALSE, NULL);
WintunFreeAdapter(Adapter);
WintunCloseAdapter(Adapter);
cleanupQuit:
SetConsoleCtrlHandler(CtrlHandler, FALSE);
CloseHandle(QuitEvent);

184
setupapihost/host.c Normal file
View File

@ -0,0 +1,184 @@
/* SPDX-License-Identifier: GPL-2.0
*
* Copyright (C) 2018-2021 WireGuard LLC. All Rights Reserved.
*/
#include <windows.h>
#include <delayimp.h>
#include <setupapi.h>
#include <devguid.h>
#include <shellapi.h>
#include <intsafe.h>
#include <stdlib.h>
#define EXPORT comment(linker, "/EXPORT:" __FUNCTION__ "=" __FUNCDNAME__)
static FARPROC WINAPI
DelayedLoadLibraryHook(unsigned dliNotify, PDelayLoadInfo pdli)
{
if (dliNotify != dliNotePreLoadLibrary)
return NULL;
HMODULE Library = LoadLibraryExA(pdli->szDll, NULL, LOAD_LIBRARY_SEARCH_SYSTEM32);
if (!Library)
abort();
return (FARPROC)Library;
}
const PfnDliHook __pfnDliNotifyHook2 = DelayedLoadLibraryHook;
static DWORD
WriteFormatted(_In_ DWORD StdHandle, _In_z_ LPCWSTR Template, ...)
{
LPWSTR FormattedMessage = NULL;
DWORD Size;
va_list Arguments;
va_start(Arguments, Template);
DWORD Len = FormatMessageW(
FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ALLOCATE_BUFFER,
Template,
0,
0,
(VOID *)&FormattedMessage,
0,
&Arguments);
if (SUCCEEDED(DWordMult(Len, sizeof(*FormattedMessage), &Size)))
WriteFile(GetStdHandle(StdHandle), FormattedMessage, Size, &Size, NULL);
else
Size = 0;
LocalFree(FormattedMessage);
va_end(Arguments);
return Size / sizeof(*FormattedMessage);
}
VOID __stdcall RemoveInstance(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow)
{
#pragma EXPORT
DWORD LastError = ERROR_SUCCESS;
int Argc;
LPWSTR *Argv = CommandLineToArgvW(GetCommandLineW(), &Argc);
if (Argc < 3)
goto cleanup;
WCHAR *InstanceId = Argv[2];
HDEVINFO DevInfo = SetupDiCreateDeviceInfoListExW(&GUID_DEVCLASS_NET, NULL, NULL, NULL);
if (DevInfo == INVALID_HANDLE_VALUE)
{
LastError = GetLastError();
goto cleanup;
}
SP_DEVINFO_DATA DevInfoData = { .cbSize = sizeof(DevInfoData) };
if (!SetupDiOpenDeviceInfoW(DevInfo, InstanceId, NULL, DIOD_INHERIT_CLASSDRVS, &DevInfoData))
{
LastError = GetLastError();
goto cleanupDevInfo;
}
SP_REMOVEDEVICE_PARAMS RemoveDeviceParams = { .ClassInstallHeader = { .cbSize = sizeof(SP_CLASSINSTALL_HEADER),
.InstallFunction = DIF_REMOVE },
.Scope = DI_REMOVEDEVICE_GLOBAL };
if (!SetupDiSetClassInstallParamsW(
DevInfo, &DevInfoData, &RemoveDeviceParams.ClassInstallHeader, sizeof(RemoveDeviceParams)) ||
!SetupDiCallClassInstaller(DIF_REMOVE, DevInfo, &DevInfoData))
{
LastError = GetLastError();
goto cleanupDevInfo;
}
cleanupDevInfo:
SetupDiDestroyDeviceInfoList(DevInfo);
cleanup:
LocalFree(Argv);
WriteFormatted(STD_OUTPUT_HANDLE, L"%1!X!", LastError);
}
VOID __stdcall EnableInstance(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow)
{
#pragma EXPORT
DWORD LastError = ERROR_SUCCESS;
int Argc;
LPWSTR *Argv = CommandLineToArgvW(GetCommandLineW(), &Argc);
if (Argc < 3)
goto cleanup;
WCHAR *InstanceId = Argv[2];
HDEVINFO DevInfo = SetupDiCreateDeviceInfoListExW(&GUID_DEVCLASS_NET, NULL, NULL, NULL);
if (DevInfo == INVALID_HANDLE_VALUE)
{
LastError = GetLastError();
goto cleanup;
}
SP_DEVINFO_DATA DevInfoData = { .cbSize = sizeof(DevInfoData) };
if (!SetupDiOpenDeviceInfoW(DevInfo, InstanceId, NULL, DIOD_INHERIT_CLASSDRVS, &DevInfoData))
{
LastError = GetLastError();
goto cleanupDevInfo;
}
SP_PROPCHANGE_PARAMS Params = { .ClassInstallHeader = { .cbSize = sizeof(SP_CLASSINSTALL_HEADER),
.InstallFunction = DIF_PROPERTYCHANGE },
.StateChange = DICS_ENABLE,
.Scope = DICS_FLAG_GLOBAL };
if (!SetupDiSetClassInstallParamsW(DevInfo, &DevInfoData, &Params.ClassInstallHeader, sizeof(Params)) ||
!SetupDiCallClassInstaller(DIF_PROPERTYCHANGE, DevInfo, &DevInfoData))
{
LastError = GetLastError();
goto cleanupDevInfo;
}
cleanupDevInfo:
SetupDiDestroyDeviceInfoList(DevInfo);
cleanup:
LocalFree(Argv);
WriteFormatted(STD_OUTPUT_HANDLE, L"%1!X!", LastError);
}
VOID __stdcall DisableInstance(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow)
{
#pragma EXPORT
DWORD LastError = ERROR_SUCCESS;
int Argc;
LPWSTR *Argv = CommandLineToArgvW(GetCommandLineW(), &Argc);
if (Argc < 3)
goto cleanup;
WCHAR *InstanceId = Argv[2];
HDEVINFO DevInfo = SetupDiCreateDeviceInfoListExW(&GUID_DEVCLASS_NET, NULL, NULL, NULL);
if (DevInfo == INVALID_HANDLE_VALUE)
{
LastError = GetLastError();
goto cleanup;
}
SP_DEVINFO_DATA DevInfoData = { .cbSize = sizeof(DevInfoData) };
if (!SetupDiOpenDeviceInfoW(DevInfo, InstanceId, NULL, DIOD_INHERIT_CLASSDRVS, &DevInfoData))
{
LastError = GetLastError();
goto cleanupDevInfo;
}
SP_PROPCHANGE_PARAMS Params = { .ClassInstallHeader = { .cbSize = sizeof(SP_CLASSINSTALL_HEADER),
.InstallFunction = DIF_PROPERTYCHANGE },
.StateChange = DICS_DISABLE,
.Scope = DICS_FLAG_GLOBAL };
if (!SetupDiSetClassInstallParamsW(DevInfo, &DevInfoData, &Params.ClassInstallHeader, sizeof(Params)) ||
!SetupDiCallClassInstaller(DIF_PROPERTYCHANGE, DevInfo, &DevInfoData))
{
LastError = GetLastError();
goto cleanupDevInfo;
}
cleanupDevInfo:
SetupDiDestroyDeviceInfoList(DevInfo);
cleanup:
LocalFree(Argv);
WriteFormatted(STD_OUTPUT_HANDLE, L"%1!X!", LastError);
}
#if NTDDI_VERSION == NTDDI_WIN7
#include "host_win7.h"
#endif

102
setupapihost/host_win7.h Normal file
View File

@ -0,0 +1,102 @@
/* SPDX-License-Identifier: GPL-2.0
*
* Copyright (C) 2018-2021 WireGuard LLC. All Rights Reserved.
*/
#include <devguid.h>
#define MAX_INSTANCE_ID MAX_PATH /* TODO: Is MAX_PATH always enough? */
#define WINTUN_HWID L"Wintun"
VOID __stdcall CreateInstanceWin7(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow)
{
#pragma EXPORT
DWORD LastError = ERROR_SUCCESS;
WCHAR InstanceId[MAX_INSTANCE_ID] = { 0 };
HDEVINFO DevInfo = SetupDiCreateDeviceInfoListExW(&GUID_DEVCLASS_NET, NULL, NULL, NULL);
if (DevInfo == INVALID_HANDLE_VALUE)
{
LastError = GetLastError();
goto cleanup;
}
SP_DEVINFO_DATA DevInfoData = { .cbSize = sizeof(DevInfoData) };
if (!SetupDiCreateDeviceInfoW(
DevInfo, WINTUN_HWID, &GUID_DEVCLASS_NET, NULL, NULL, DICD_GENERATE_ID, &DevInfoData))
{
LastError = GetLastError();
goto cleanupDevInfo;
}
SP_DEVINSTALL_PARAMS_W DevInstallParams = { .cbSize = sizeof(DevInstallParams) };
if (!SetupDiGetDeviceInstallParamsW(DevInfo, &DevInfoData, &DevInstallParams))
{
LastError = GetLastError();
goto cleanupDevInfo;
}
DevInstallParams.Flags |= DI_QUIETINSTALL;
if (!SetupDiSetDeviceInstallParamsW(DevInfo, &DevInfoData, &DevInstallParams))
{
LastError = GetLastError();
goto cleanupDevInfo;
}
if (!SetupDiSetSelectedDevice(DevInfo, &DevInfoData))
{
LastError = GetLastError();
goto cleanupDevInfo;
}
static const WCHAR Hwids[_countof(WINTUN_HWID) + 1 /*Multi-string terminator*/] = WINTUN_HWID;
if (!SetupDiSetDeviceRegistryPropertyW(DevInfo, &DevInfoData, SPDRP_HARDWAREID, (const BYTE *)Hwids, sizeof(Hwids)))
{
LastError = GetLastError();
goto cleanupDevInfo;
}
if (!SetupDiBuildDriverInfoList(DevInfo, &DevInfoData, SPDIT_COMPATDRIVER))
{
LastError = GetLastError();
goto cleanupDevInfo;
}
SP_DRVINFO_DATA_W DrvInfoData = { .cbSize = sizeof(SP_DRVINFO_DATA_W) };
if (!SetupDiEnumDriverInfoW(DevInfo, &DevInfoData, SPDIT_COMPATDRIVER, 0, &DrvInfoData) ||
!SetupDiSetSelectedDriverW(DevInfo, &DevInfoData, &DrvInfoData))
{
LastError = GetLastError();
goto cleanupDriverInfo;
}
if (!SetupDiCallClassInstaller(DIF_REGISTERDEVICE, DevInfo, &DevInfoData))
{
LastError = GetLastError();
goto cleanupDevInfo;
}
SetupDiCallClassInstaller(DIF_REGISTER_COINSTALLERS, DevInfo, &DevInfoData);
SetupDiCallClassInstaller(DIF_INSTALLINTERFACES, DevInfo, &DevInfoData);
if (!SetupDiCallClassInstaller(DIF_INSTALLDEVICE, DevInfo, &DevInfoData))
{
LastError = GetLastError();
goto cleanupDevice;
}
DWORD RequiredChars = _countof(InstanceId);
if (!SetupDiGetDeviceInstanceIdW(DevInfo, &DevInfoData, InstanceId, RequiredChars, &RequiredChars))
{
LastError = GetLastError();
goto cleanupDevice;
}
cleanupDevice:
if (LastError != ERROR_SUCCESS)
{
SP_REMOVEDEVICE_PARAMS RemoveDeviceParams = { .ClassInstallHeader = { .cbSize = sizeof(SP_CLASSINSTALL_HEADER),
.InstallFunction = DIF_REMOVE },
.Scope = DI_REMOVEDEVICE_GLOBAL };
if (SetupDiSetClassInstallParamsW(
DevInfo, &DevInfoData, &RemoveDeviceParams.ClassInstallHeader, sizeof(RemoveDeviceParams)))
SetupDiCallClassInstaller(DIF_REMOVE, DevInfo, &DevInfoData);
}
cleanupDriverInfo:
SetupDiDestroyDriverInfoList(DevInfo, &DevInfoData, SPDIT_COMPATDRIVER);
cleanupDevInfo:
SetupDiDestroyDeviceInfoList(DevInfo);
cleanup:
WriteFormatted(STD_OUTPUT_HANDLE, L"%1!X! %2!s!", LastError, LastError == ERROR_SUCCESS ? InstanceId : L"\"\"");
}

View File

@ -0,0 +1,37 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Label="Globals">
<ProjectGuid>{9911D673-CF5F-4B41-B190-807AA1BE445B}</ProjectGuid>
<RootNamespace>setupapihost</RootNamespace>
<ProjectName>setupapihost</ProjectName>
</PropertyGroup>
<PropertyGroup Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset>
</PropertyGroup>
<Import Project="..\wintun.props" />
<PropertyGroup>
<TargetName>setupapihost</TargetName>
</PropertyGroup>
<ItemDefinitionGroup>
<ClCompile>
<PreprocessorDefinitions>_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalOptions>/volatile:iso %(AdditionalOptions)</AdditionalOptions>
<DisableSpecificWarnings>4100;4201;$(DisableSpecificWarnings)</DisableSpecificWarnings>
</ClCompile>
<Link>
<DelayLoadDLLs>setupapi.dll;shell32.dll</DelayLoadDLLs>
<AdditionalDependencies>Setupapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
<SubSystem>Windows</SubSystem>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="host.c" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="host_win7.h" />
</ItemGroup>
<Import Project="..\wintun.props.user" Condition="exists('..\wintun.props.user')" />
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets" />
</Project>

View File

@ -59,21 +59,21 @@
<Target Name="Dll-x86"
Outputs="$(Configuration)\x86\wintun.dll"
DependsOnTargets="Dll-amd64;Dll-arm64">
<MSBuild Projects="downlevelshim\downlevelshim.vcxproj;api\api.vcxproj" Targets="Build" Properties="Configuration=$(Configuration);Platform=Win32" />
<MSBuild Projects="setupapihost\setupapihost.vcxproj;downlevelshim\downlevelshim.vcxproj;api\api.vcxproj" Targets="Build" Properties="Configuration=$(Configuration);Platform=Win32" />
</Target>
<Target Name="Dll-amd64"
Outputs="$(Configuration)\amd64\wintun.dll"
DependsOnTargets="Dll-arm64">
<MSBuild Projects="downlevelshim\downlevelshim.vcxproj;api\api.vcxproj" Targets="Build" Properties="Configuration=$(Configuration);Platform=x64" />
<MSBuild Projects="setupapihost\setupapihost.vcxproj;downlevelshim\downlevelshim.vcxproj;api\api.vcxproj" Targets="Build" Properties="Configuration=$(Configuration);Platform=x64" />
</Target>
<Target Name="Dll-arm"
Outputs="$(Configuration)\arm\wintun.dll"
DependsOnTargets="Dll-arm64">
<MSBuild Projects="downlevelshim\downlevelshim.vcxproj;api\api.vcxproj" Targets="Build" Properties="Configuration=$(Configuration);Platform=ARM" />
<MSBuild Projects="setupapihost\setupapihost.vcxproj;downlevelshim\downlevelshim.vcxproj;api\api.vcxproj" Targets="Build" Properties="Configuration=$(Configuration);Platform=ARM" />
</Target>
<Target Name="Dll-arm64"
Outputs="$(Configuration)\arm64\wintun.dll">
<MSBuild Projects="downlevelshim\downlevelshim.vcxproj;api\api.vcxproj" Targets="Build" Properties="Configuration=$(Configuration);Platform=ARM64" />
<MSBuild Projects="setupapihost\setupapihost.vcxproj;downlevelshim\downlevelshim.vcxproj;api\api.vcxproj" Targets="Build" Properties="Configuration=$(Configuration);Platform=ARM64" />
</Target>
<!--

View File

@ -8,10 +8,13 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "api", "api\api.vcxproj", "{
ProjectSection(ProjectDependencies) = postProject
{F7679B65-2FEC-469A-8BAC-B07BF4439422} = {F7679B65-2FEC-469A-8BAC-B07BF4439422}
{6E8213E6-5046-4DE8-A760-0932C7D6E33E} = {6E8213E6-5046-4DE8-A760-0932C7D6E33E}
{9911D673-CF5F-4B41-B190-807AA1BE445B} = {9911D673-CF5F-4B41-B190-807AA1BE445B}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "driver", "driver\driver.vcxproj", "{F7679B65-2FEC-469A-8BAC-B07BF4439422}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "setupapihost", "setupapihost\setupapihost.vcxproj", "{9911D673-CF5F-4B41-B190-807AA1BE445B}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "downlevelshim", "downlevelshim\downlevelshim.vcxproj", "{6E8213E6-5046-4DE8-A760-0932C7D6E33E}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{3A98F138-EE02-4488-B856-B3C48500BEA8}"
@ -81,6 +84,22 @@ Global
{F7679B65-2FEC-469A-8BAC-B07BF4439422}.Release|arm64.Build.0 = Release|ARM64
{F7679B65-2FEC-469A-8BAC-B07BF4439422}.Release|x86.ActiveCfg = Release|Win32
{F7679B65-2FEC-469A-8BAC-B07BF4439422}.Release|x86.Build.0 = Release|Win32
{9911D673-CF5F-4B41-B190-807AA1BE445B}.Debug|amd64.ActiveCfg = Debug|x64
{9911D673-CF5F-4B41-B190-807AA1BE445B}.Debug|amd64.Build.0 = Debug|x64
{9911D673-CF5F-4B41-B190-807AA1BE445B}.Debug|arm.ActiveCfg = Debug|ARM
{9911D673-CF5F-4B41-B190-807AA1BE445B}.Debug|arm.Build.0 = Debug|ARM
{9911D673-CF5F-4B41-B190-807AA1BE445B}.Debug|arm64.ActiveCfg = Debug|ARM64
{9911D673-CF5F-4B41-B190-807AA1BE445B}.Debug|arm64.Build.0 = Debug|ARM64
{9911D673-CF5F-4B41-B190-807AA1BE445B}.Debug|x86.ActiveCfg = Debug|Win32
{9911D673-CF5F-4B41-B190-807AA1BE445B}.Debug|x86.Build.0 = Debug|Win32
{9911D673-CF5F-4B41-B190-807AA1BE445B}.Release|amd64.ActiveCfg = Release|x64
{9911D673-CF5F-4B41-B190-807AA1BE445B}.Release|amd64.Build.0 = Release|x64
{9911D673-CF5F-4B41-B190-807AA1BE445B}.Release|arm.ActiveCfg = Release|ARM
{9911D673-CF5F-4B41-B190-807AA1BE445B}.Release|arm.Build.0 = Release|ARM
{9911D673-CF5F-4B41-B190-807AA1BE445B}.Release|arm64.ActiveCfg = Release|ARM64
{9911D673-CF5F-4B41-B190-807AA1BE445B}.Release|arm64.Build.0 = Release|ARM64
{9911D673-CF5F-4B41-B190-807AA1BE445B}.Release|x86.ActiveCfg = Release|Win32
{9911D673-CF5F-4B41-B190-807AA1BE445B}.Release|x86.Build.0 = Release|Win32
{6E8213E6-5046-4DE8-A760-0932C7D6E33E}.Debug|amd64.ActiveCfg = Debug|x64
{6E8213E6-5046-4DE8-A760-0932C7D6E33E}.Debug|amd64.Build.0 = Debug|x64
{6E8213E6-5046-4DE8-A760-0932C7D6E33E}.Debug|arm.ActiveCfg = Debug|ARM