api: rewrite based on SwDevice
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
This commit is contained in:
parent
c69ec758d1
commit
544fdaaf8f
112
README.md
112
README.md
@ -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
|
||||
|
||||
|
2427
api/adapter.c
2427
api/adapter.c
File diff suppressed because it is too large
Load Diff
136
api/adapter.h
136
api/adapter.h
@ -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
351
api/adapter_win7.h
Normal 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);
|
||||
}
|
@ -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" />
|
||||
|
@ -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
587
api/driver.c
Normal 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
34
api/driver.h
Normal 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;
|
@ -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
|
||||
|
47
api/logger.c
47
api/logger.c
@ -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_
|
||||
|
45
api/logger.h
45
api/logger.h
@ -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)
|
||||
|
19
api/main.c
19
api/main.c
@ -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:
|
||||
|
11
api/main.h
11
api/main.h
@ -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
|
142
api/namespace.c
142
api/namespace.c
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
241
api/registry.c
241
api/registry.c
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
||||
|
333
api/rundll32.c
333
api/rundll32.c
@ -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;
|
||||
}
|
||||
WCHAR Response[8 + 1 + 8 + 1];
|
||||
return InvokeClassInstaller(L"remove", L"RemoveInstance", DevInfo, DevInfoData);
|
||||
}
|
||||
|
||||
_Use_decl_annotations_
|
||||
BOOL
|
||||
EnableInstanceViaRundll32(HDEVINFO DevInfo, SP_DEVINFO_DATA *DevInfoData)
|
||||
{
|
||||
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;
|
||||
if (!ExecuteRunDll32(L"DeletePoolDriver", Arguments, Response, _countof(Response)))
|
||||
WCHAR Response[MAX_INSTANCE_ID + 1];
|
||||
if (!ExecuteRunDll32(L"CreateInstanceWin7", L"", Response, _countof(Response)))
|
||||
{
|
||||
LastError = GetLastError();
|
||||
LOG(WINTUN_LOG_ERR, L"Error executing worker process: %s", Arguments);
|
||||
goto cleanupArguments;
|
||||
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
|
||||
|
@ -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);
|
@ -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)
|
||||
|
198
api/wintun.h
198
api/wintun.h
@ -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
|
||||
}
|
||||
|
@ -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"
|
||||
|
@ -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
184
setupapihost/host.c
Normal 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
102
setupapihost/host_win7.h
Normal 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"\"\"");
|
||||
}
|
37
setupapihost/setupapihost.vcxproj
Normal file
37
setupapihost/setupapihost.vcxproj
Normal 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>
|
@ -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>
|
||||
|
||||
<!--
|
||||
|
19
wintun.sln
19
wintun.sln
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user