• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 The Khronos Group Inc.
3  * Copyright (c) 2021 Valve Corporation
4  * Copyright (c) 2021 LunarG, Inc.
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and/or associated documentation files (the "Materials"), to
8  * deal in the Materials without restriction, including without limitation the
9  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10  * sell copies of the Materials, and to permit persons to whom the Materials are
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice(s) and this permission notice shall be included in
14  * all copies or substantial portions of the Materials.
15  *
16  * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19  *
20  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
21  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
22  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE MATERIALS OR THE
23  * USE OR OTHER DEALINGS IN THE MATERIALS.
24  *
25  * Author: Charles Giessen <charles@lunarg.com>
26  */
27 
28 // This needs to be defined first, or else we'll get redefinitions on NTSTATUS values
29 #if defined(_WIN32)
30 #define UMDF_USING_NTSTATUS
31 #include <ntstatus.h>
32 #endif
33 
34 #include <windows.h>
35 #include <debugapi.h>
36 
37 #include "shim.h"
38 
39 #include "detours.h"
40 
41 static PlatformShim platform_shim;
42 
43 extern "C" {
44 
45 static LibraryWrapper gdi32_dll;
46 
47 using PFN_GetSidSubAuthority = PDWORD(__stdcall *)(PSID pSid, DWORD nSubAuthority);
48 static PFN_GetSidSubAuthority fpGetSidSubAuthority = GetSidSubAuthority;
49 
ShimGetSidSubAuthority(PSID,DWORD)50 PDWORD __stdcall ShimGetSidSubAuthority(PSID, DWORD) { return &platform_shim.elevation_level; }
51 
52 static PFN_LoaderEnumAdapters2 fpEnumAdapters2 = nullptr;
53 static PFN_LoaderQueryAdapterInfo fpQueryAdapterInfo = nullptr;
54 
ShimEnumAdapters2(LoaderEnumAdapters2 * adapters)55 NTSTATUS APIENTRY ShimEnumAdapters2(LoaderEnumAdapters2 *adapters) {
56     if (adapters == nullptr) {
57         return STATUS_INVALID_PARAMETER;
58     }
59     if (platform_shim.d3dkmt_adapters.size() == 0) {
60         if (adapters->adapters != nullptr) adapters->adapter_count = 0;
61         return STATUS_SUCCESS;
62     }
63     if (adapters->adapters != nullptr) {
64         for (size_t i = 0; i < platform_shim.d3dkmt_adapters.size(); i++) {
65             adapters->adapters[i].handle = platform_shim.d3dkmt_adapters[i].hAdapter;
66             adapters->adapters[i].luid = platform_shim.d3dkmt_adapters[i].adapter_luid;
67         }
68         adapters->adapter_count = static_cast<ULONG>(platform_shim.d3dkmt_adapters.size());
69     } else {
70         adapters->adapter_count = static_cast<ULONG>(platform_shim.d3dkmt_adapters.size());
71     }
72     return STATUS_SUCCESS;
73 }
ShimQueryAdapterInfo(const LoaderQueryAdapterInfo * query_info)74 NTSTATUS APIENTRY ShimQueryAdapterInfo(const LoaderQueryAdapterInfo *query_info) {
75     if (query_info == nullptr || query_info->private_data == nullptr) {
76         return STATUS_INVALID_PARAMETER;
77     }
78     auto handle = query_info->handle;
79     auto it = std::find_if(platform_shim.d3dkmt_adapters.begin(), platform_shim.d3dkmt_adapters.end(),
80                            [handle](D3DKMT_Adapter const &adapter) { return handle == adapter.hAdapter; });
81     if (it == platform_shim.d3dkmt_adapters.end()) {
82         return STATUS_INVALID_PARAMETER;
83     }
84     auto &adapter = *it;
85     auto *reg_info = reinterpret_cast<LoaderQueryRegistryInfo *>(query_info->private_data);
86 
87     std::vector<std::wstring> *paths = nullptr;
88     if (wcsstr(reg_info->value_name, L"DriverName") != nullptr) {  // looking for drivers
89         paths = &adapter.driver_paths;
90     } else if (wcsstr(reg_info->value_name, L"ImplicitLayers") != nullptr) {  // looking for implicit layers
91         paths = &adapter.implicit_layer_paths;
92     } else if (wcsstr(reg_info->value_name, L"ExplicitLayers") != nullptr) {  // looking for explicit layers
93         paths = &adapter.explicit_layer_paths;
94     }
95 
96     reg_info->status = LOADER_QUERY_REGISTRY_STATUS_SUCCESS;
97     if (reg_info->output_value_size == 0) {
98         // final null terminator size
99         ULONG size = 2;
100 
101         // size is in bytes, so multiply path size + 1 (for null terminator) by size of wchar (basically, 2).
102         for (auto const &path : *paths) size += static_cast<ULONG>((path.length() + 1) * sizeof(wchar_t));
103         reg_info->output_value_size = size;
104         if (size != 2) {
105             // only want to write data if there is path data to write
106             reg_info->status = LOADER_QUERY_REGISTRY_STATUS_BUFFER_OVERFLOW;
107         }
108     } else if (reg_info->output_value_size > 2) {
109         size_t index = 0;
110         for (auto const &path : *paths) {
111             for (auto w : path) {
112                 reg_info->output_string[index++] = w;
113             }
114             reg_info->output_string[index++] = L'\0';
115         }
116         // make sure there is a null terminator
117         reg_info->output_string[index++] = L'\0';
118 
119         reg_info->status = LOADER_QUERY_REGISTRY_STATUS_SUCCESS;
120     }
121 
122     return STATUS_SUCCESS;
123 }
124 
125 // clang-format off
126 static CONFIGRET(WINAPI *REAL_CM_Get_Device_ID_List_SizeW)(PULONG pulLen, PCWSTR pszFilter, ULONG ulFlags) = CM_Get_Device_ID_List_SizeW;
127 static CONFIGRET(WINAPI *REAL_CM_Get_Device_ID_ListW)(PCWSTR pszFilter, PZZWSTR Buffer, ULONG BufferLen, ULONG ulFlags) = CM_Get_Device_ID_ListW;
128 static CONFIGRET(WINAPI *REAL_CM_Locate_DevNodeW)(PDEVINST pdnDevInst, DEVINSTID_W pDeviceID, ULONG ulFlags) =  CM_Locate_DevNodeW;
129 static CONFIGRET(WINAPI *REAL_CM_Get_DevNode_Status)(PULONG pulStatus, PULONG pulProblemNumber, DEVINST dnDevInst, ULONG ulFlags) =  CM_Get_DevNode_Status;
130 static CONFIGRET(WINAPI *REAL_CM_Get_Device_IDW)(DEVINST dnDevInst, PWSTR Buffer, ULONG BufferLen, ULONG ulFlags) =  CM_Get_Device_IDW;
131 static CONFIGRET(WINAPI *REAL_CM_Get_Child)(PDEVINST pdnDevInst, DEVINST dnDevInst, ULONG ulFlags) =  CM_Get_Child;
132 static CONFIGRET(WINAPI *REAL_CM_Get_DevNode_Registry_PropertyW)(DEVINST dnDevInst, ULONG ulProperty, PULONG pulRegDataType, PVOID Buffer, PULONG pulLength, ULONG ulFlags) =  CM_Get_DevNode_Registry_PropertyW;
133 static CONFIGRET(WINAPI *REAL_CM_Get_Sibling)(PDEVINST pdnDevInst, DEVINST dnDevInst, ULONG ulFlags) = CM_Get_Sibling;
134 // clang-format on
135 
SHIM_CM_Get_Device_ID_List_SizeW(PULONG pulLen,PCWSTR pszFilter,ULONG ulFlags)136 CONFIGRET WINAPI SHIM_CM_Get_Device_ID_List_SizeW(PULONG pulLen, [[maybe_unused]] PCWSTR pszFilter,
137                                                   [[maybe_unused]] ULONG ulFlags) {
138     if (pulLen == nullptr) {
139         return CR_INVALID_POINTER;
140     }
141     *pulLen = static_cast<ULONG>(platform_shim.CM_device_ID_list.size());
142     return CR_SUCCESS;
143 }
SHIM_CM_Get_Device_ID_ListW(PCWSTR pszFilter,PZZWSTR Buffer,ULONG BufferLen,ULONG ulFlags)144 CONFIGRET WINAPI SHIM_CM_Get_Device_ID_ListW([[maybe_unused]] PCWSTR pszFilter, PZZWSTR Buffer, ULONG BufferLen,
145                                              [[maybe_unused]] ULONG ulFlags) {
146     if (Buffer != NULL) {
147         if (BufferLen < platform_shim.CM_device_ID_list.size()) return CR_BUFFER_SMALL;
148         for (size_t i = 0; i < BufferLen; i++) {
149             Buffer[i] = platform_shim.CM_device_ID_list[i];
150         }
151     }
152     return CR_SUCCESS;
153 }
154 // TODO
SHIM_CM_Locate_DevNodeW(PDEVINST,DEVINSTID_W,ULONG)155 CONFIGRET WINAPI SHIM_CM_Locate_DevNodeW(PDEVINST, DEVINSTID_W, ULONG) { return CR_FAILURE; }
156 // TODO
SHIM_CM_Get_DevNode_Status(PULONG,PULONG,DEVINST,ULONG)157 CONFIGRET WINAPI SHIM_CM_Get_DevNode_Status(PULONG, PULONG, DEVINST, ULONG) { return CR_FAILURE; }
158 // TODO
SHIM_CM_Get_Device_IDW(DEVINST,PWSTR,ULONG,ULONG)159 CONFIGRET WINAPI SHIM_CM_Get_Device_IDW(DEVINST, PWSTR, ULONG, ULONG) { return CR_FAILURE; }
160 // TODO
SHIM_CM_Get_Child(PDEVINST,DEVINST,ULONG)161 CONFIGRET WINAPI SHIM_CM_Get_Child(PDEVINST, DEVINST, ULONG) { return CR_FAILURE; }
162 // TODO
SHIM_CM_Get_DevNode_Registry_PropertyW(DEVINST,ULONG,PULONG,PVOID,PULONG,ULONG)163 CONFIGRET WINAPI SHIM_CM_Get_DevNode_Registry_PropertyW(DEVINST, ULONG, PULONG, PVOID, PULONG, ULONG) { return CR_FAILURE; }
164 // TODO
SHIM_CM_Get_Sibling(PDEVINST,DEVINST,ULONG)165 CONFIGRET WINAPI SHIM_CM_Get_Sibling(PDEVINST, DEVINST, ULONG) { return CR_FAILURE; }
166 
167 static LibraryWrapper dxgi_module;
168 typedef HRESULT(APIENTRY *PFN_CreateDXGIFactory1)(REFIID riid, void **ppFactory);
169 
170 PFN_CreateDXGIFactory1 RealCreateDXGIFactory1;
171 
ShimGetDesc1(IDXGIAdapter1 * pAdapter,_Out_ DXGI_ADAPTER_DESC1 * pDesc)172 HRESULT __stdcall ShimGetDesc1(IDXGIAdapter1 *pAdapter,
173                                /* [annotation][out] */
174                                _Out_ DXGI_ADAPTER_DESC1 *pDesc) {
175     if (pAdapter == nullptr || pDesc == nullptr) return DXGI_ERROR_INVALID_CALL;
176 
177     for (const auto &[index, adapter] : platform_shim.dxgi_adapters) {
178         if (&adapter.adapter_instance == pAdapter) {
179             *pDesc = adapter.desc1;
180             return S_OK;
181         }
182     }
183     return DXGI_ERROR_INVALID_CALL;
184 }
ShimIDXGIFactory1Release(IDXGIFactory1 *)185 ULONG __stdcall ShimIDXGIFactory1Release(IDXGIFactory1 *) { return S_OK; }
ShimIDXGIFactory6Release(IDXGIFactory6 *)186 ULONG __stdcall ShimIDXGIFactory6Release(IDXGIFactory6 *) { return S_OK; }
ShimRelease(IDXGIAdapter1 *)187 ULONG __stdcall ShimRelease(IDXGIAdapter1 *) { return S_OK; }
188 
setup_and_get_IDXGIAdapter1(DXGIAdapter & adapter)189 IDXGIAdapter1 *setup_and_get_IDXGIAdapter1(DXGIAdapter &adapter) {
190     adapter.adapter_vtbl_instance.GetDesc1 = ShimGetDesc1;
191     adapter.adapter_vtbl_instance.Release = ShimRelease;
192     adapter.adapter_instance.lpVtbl = &adapter.adapter_vtbl_instance;
193     return &adapter.adapter_instance;
194 }
195 
ShimEnumAdapters1_1(IDXGIFactory1 * This,UINT Adapter,_COM_Outptr_ IDXGIAdapter1 ** ppAdapter)196 HRESULT __stdcall ShimEnumAdapters1_1([[maybe_unused]] IDXGIFactory1 *This,
197                                       /* [in] */ UINT Adapter,
198                                       /* [annotation][out] */
199                                       _COM_Outptr_ IDXGIAdapter1 **ppAdapter) {
200     if (Adapter >= platform_shim.dxgi_adapters.size()) {
201         return DXGI_ERROR_INVALID_CALL;
202     }
203     if (ppAdapter != nullptr) {
204         *ppAdapter = setup_and_get_IDXGIAdapter1(platform_shim.dxgi_adapters.at(Adapter));
205     }
206     return S_OK;
207 }
208 
ShimEnumAdapters1_6(IDXGIFactory6 * This,UINT Adapter,_COM_Outptr_ IDXGIAdapter1 ** ppAdapter)209 HRESULT __stdcall ShimEnumAdapters1_6([[maybe_unused]] IDXGIFactory6 *This,
210                                       /* [in] */ UINT Adapter,
211                                       /* [annotation][out] */
212                                       _COM_Outptr_ IDXGIAdapter1 **ppAdapter) {
213     if (Adapter >= platform_shim.dxgi_adapters.size()) {
214         return DXGI_ERROR_INVALID_CALL;
215     }
216     if (ppAdapter != nullptr) {
217         *ppAdapter = setup_and_get_IDXGIAdapter1(platform_shim.dxgi_adapters.at(Adapter));
218     }
219     return S_OK;
220 }
221 
ShimEnumAdapterByGpuPreference(IDXGIFactory6 * This,_In_ UINT Adapter,_In_ DXGI_GPU_PREFERENCE GpuPreference,_In_ REFIID riid,_COM_Outptr_ void ** ppvAdapter)222 HRESULT __stdcall ShimEnumAdapterByGpuPreference([[maybe_unused]] IDXGIFactory6 *This, _In_ UINT Adapter,
223                                                  [[maybe_unused]] _In_ DXGI_GPU_PREFERENCE GpuPreference,
224                                                  [[maybe_unused]] _In_ REFIID riid, _COM_Outptr_ void **ppvAdapter) {
225     if (Adapter >= platform_shim.dxgi_adapters.size()) {
226         return DXGI_ERROR_NOT_FOUND;
227     }
228     // loader always uses DXGI_GPU_PREFERENCE_UNSPECIFIED
229     // Update the shim if this isn't the case
230     assert(GpuPreference == DXGI_GPU_PREFERENCE::DXGI_GPU_PREFERENCE_UNSPECIFIED &&
231            "Test shim assumes the GpuPreference is unspecified.");
232     if (ppvAdapter != nullptr) {
233         *ppvAdapter = setup_and_get_IDXGIAdapter1(platform_shim.dxgi_adapters.at(Adapter));
234     }
235     return S_OK;
236 }
237 
get_IDXGIFactory1()238 static IDXGIFactory1 *get_IDXGIFactory1() {
239     static IDXGIFactory1Vtbl vtbl{};
240     vtbl.EnumAdapters1 = ShimEnumAdapters1_1;
241     vtbl.Release = ShimIDXGIFactory1Release;
242     static IDXGIFactory1 factory{};
243     factory.lpVtbl = &vtbl;
244     return &factory;
245 }
246 
get_IDXGIFactory6()247 static IDXGIFactory6 *get_IDXGIFactory6() {
248     static IDXGIFactory6Vtbl vtbl{};
249     vtbl.EnumAdapters1 = ShimEnumAdapters1_6;
250     vtbl.EnumAdapterByGpuPreference = ShimEnumAdapterByGpuPreference;
251     vtbl.Release = ShimIDXGIFactory6Release;
252     static IDXGIFactory6 factory{};
253     factory.lpVtbl = &vtbl;
254     return &factory;
255 }
256 
ShimCreateDXGIFactory1(REFIID riid,void ** ppFactory)257 HRESULT __stdcall ShimCreateDXGIFactory1(REFIID riid, void **ppFactory) {
258     if (riid == IID_IDXGIFactory1) {
259         auto *factory = get_IDXGIFactory1();
260         *ppFactory = factory;
261         return S_OK;
262     }
263     if (riid == IID_IDXGIFactory6) {
264         auto *factory = get_IDXGIFactory6();
265         *ppFactory = factory;
266         return S_OK;
267     }
268     assert(false && "new riid, update shim code to handle");
269     return S_FALSE;
270 }
271 
272 // Windows Registry shims
273 using PFN_RegOpenKeyExA = LSTATUS(__stdcall *)(HKEY hKey, LPCSTR lpSubKey, DWORD ulOptions, REGSAM samDesired, PHKEY phkResult);
274 static PFN_RegOpenKeyExA fpRegOpenKeyExA = RegOpenKeyExA;
275 using PFN_RegQueryValueExA = LSTATUS(__stdcall *)(HKEY hKey, LPCSTR lpValueName, LPDWORD lpReserved, LPDWORD lpType, LPBYTE lpData,
276                                                   LPDWORD lpcbData);
277 static PFN_RegQueryValueExA fpRegQueryValueExA = RegQueryValueExA;
278 using PFN_RegEnumValueA = LSTATUS(__stdcall *)(HKEY hKey, DWORD dwIndex, LPSTR lpValueName, LPDWORD lpcchValueName,
279                                                LPDWORD lpReserved, LPDWORD lpType, LPBYTE lpData, LPDWORD lpcbData);
280 static PFN_RegEnumValueA fpRegEnumValueA = RegEnumValueA;
281 
282 using PFN_RegCloseKey = LSTATUS(__stdcall *)(HKEY hKey);
283 static PFN_RegCloseKey fpRegCloseKey = RegCloseKey;
284 
ShimRegOpenKeyExA(HKEY hKey,LPCSTR lpSubKey,DWORD ulOptions,REGSAM samDesired,PHKEY phkResult)285 LSTATUS __stdcall ShimRegOpenKeyExA(HKEY hKey, LPCSTR lpSubKey, [[maybe_unused]] DWORD ulOptions,
286                                     [[maybe_unused]] REGSAM samDesired, PHKEY phkResult) {
287     if (HKEY_LOCAL_MACHINE != hKey && HKEY_CURRENT_USER != hKey) return ERROR_BADKEY;
288     std::string hive = "";
289     if (HKEY_LOCAL_MACHINE == hKey)
290         hive = "HKEY_LOCAL_MACHINE";
291     else if (HKEY_CURRENT_USER == hKey)
292         hive = "HKEY_CURRENT_USER";
293     if (hive == "") return ERROR_ACCESS_DENIED;
294 
295     platform_shim.created_keys.emplace_back(platform_shim.created_key_count++, hive + "\\" + lpSubKey);
296     *phkResult = platform_shim.created_keys.back().get();
297     return 0;
298 }
get_path_of_created_key(HKEY hKey)299 const std::string *get_path_of_created_key(HKEY hKey) {
300     for (const auto &key : platform_shim.created_keys) {
301         if (key.key == hKey) {
302             return &key.path;
303         }
304     }
305     return nullptr;
306 }
get_registry_vector(std::string const & path)307 std::vector<RegistryEntry> *get_registry_vector(std::string const &path) {
308     if (path == "HKEY_LOCAL_MACHINE\\" VK_DRIVERS_INFO_REGISTRY_LOC) return &platform_shim.hkey_local_machine_drivers;
309     if (path == "HKEY_LOCAL_MACHINE\\" VK_ELAYERS_INFO_REGISTRY_LOC) return &platform_shim.hkey_local_machine_explicit_layers;
310     if (path == "HKEY_LOCAL_MACHINE\\" VK_ILAYERS_INFO_REGISTRY_LOC) return &platform_shim.hkey_local_machine_implicit_layers;
311     if (path == "HKEY_CURRENT_USER\\" VK_ELAYERS_INFO_REGISTRY_LOC) return &platform_shim.hkey_current_user_explicit_layers;
312     if (path == "HKEY_CURRENT_USER\\" VK_ILAYERS_INFO_REGISTRY_LOC) return &platform_shim.hkey_current_user_implicit_layers;
313     if (path == "HKEY_LOCAL_MACHINE\\" VK_SETTINGS_INFO_REGISTRY_LOC) return &platform_shim.hkey_local_machine_settings;
314     if (path == "HKEY_CURRENT_USER\\" VK_SETTINGS_INFO_REGISTRY_LOC) return &platform_shim.hkey_current_user_settings;
315     return nullptr;
316 }
ShimRegQueryValueExA(HKEY,LPCSTR,LPDWORD,LPDWORD,LPBYTE,LPDWORD)317 LSTATUS __stdcall ShimRegQueryValueExA(HKEY, LPCSTR, LPDWORD, LPDWORD, LPBYTE, LPDWORD) {
318     // TODO:
319     return ERROR_SUCCESS;
320 }
ShimRegEnumValueA(HKEY hKey,DWORD dwIndex,LPSTR lpValueName,LPDWORD lpcchValueName,LPDWORD lpReserved,LPDWORD lpType,LPBYTE lpData,LPDWORD lpcbData)321 LSTATUS __stdcall ShimRegEnumValueA(HKEY hKey, DWORD dwIndex, LPSTR lpValueName, LPDWORD lpcchValueName,
322                                     [[maybe_unused]] LPDWORD lpReserved, [[maybe_unused]] LPDWORD lpType, LPBYTE lpData,
323                                     LPDWORD lpcbData) {
324     const std::string *path = get_path_of_created_key(hKey);
325     if (path == nullptr) return ERROR_NO_MORE_ITEMS;
326 
327     const auto *location_ptr = get_registry_vector(*path);
328     if (location_ptr == nullptr) return ERROR_NO_MORE_ITEMS;
329     const auto &location = *location_ptr;
330     if (dwIndex >= location.size()) return ERROR_NO_MORE_ITEMS;
331 
332     std::string name = narrow(location[dwIndex].name);
333     if (*lpcchValueName < name.size()) return ERROR_NO_MORE_ITEMS;
334     for (size_t i = 0; i < name.size(); i++) {
335         lpValueName[i] = name[i];
336     }
337     lpValueName[name.size()] = '\0';
338     *lpcchValueName = static_cast<DWORD>(name.size() + 1);
339     if (*lpcbData < sizeof(DWORD)) return ERROR_NO_MORE_ITEMS;
340     DWORD *lpcbData_dword = reinterpret_cast<DWORD *>(lpData);
341     *lpcbData_dword = location[dwIndex].value;
342     *lpcbData = sizeof(DWORD);
343     return ERROR_SUCCESS;
344 }
ShimRegCloseKey(HKEY hKey)345 LSTATUS __stdcall ShimRegCloseKey(HKEY hKey) {
346     for (size_t i = 0; i < platform_shim.created_keys.size(); i++) {
347         if (platform_shim.created_keys[i].get() == hKey) {
348             platform_shim.created_keys.erase(platform_shim.created_keys.begin() + i);
349             return ERROR_SUCCESS;
350         }
351     }
352     // means that RegCloseKey was called with an invalid key value (one that doesn't exist or has already been closed)
353     exit(-1);
354 }
355 
356 // Windows app package shims
357 using PFN_GetPackagesByPackageFamily = LONG(WINAPI *)(PCWSTR, UINT32 *, PWSTR *, UINT32 *, WCHAR *);
358 static PFN_GetPackagesByPackageFamily fpGetPackagesByPackageFamily = GetPackagesByPackageFamily;
359 using PFN_GetPackagePathByFullName = LONG(WINAPI *)(PCWSTR, UINT32 *, PWSTR);
360 static PFN_GetPackagePathByFullName fpGetPackagePathByFullName = GetPackagePathByFullName;
361 
362 static constexpr wchar_t package_full_name[] = L"ThisIsARandomStringSinceTheNameDoesn'tMatter";
ShimGetPackagesByPackageFamily(_In_ PCWSTR packageFamilyName,_Inout_ UINT32 * count,_Out_writes_opt_ (* count)PWSTR * packageFullNames,_Inout_ UINT32 * bufferLength,_Out_writes_opt_ (* bufferLength)WCHAR * buffer)363 LONG WINAPI ShimGetPackagesByPackageFamily(_In_ PCWSTR packageFamilyName, _Inout_ UINT32 *count,
364                                            _Out_writes_opt_(*count) PWSTR *packageFullNames, _Inout_ UINT32 *bufferLength,
365                                            _Out_writes_opt_(*bufferLength) WCHAR *buffer) {
366     if (!packageFamilyName || !count || !bufferLength) return ERROR_INVALID_PARAMETER;
367     if (!platform_shim.app_package_path.empty() && wcscmp(packageFamilyName, L"Microsoft.D3DMappingLayers_8wekyb3d8bbwe") == 0) {
368         if (*count > 0 && !packageFullNames) return ERROR_INVALID_PARAMETER;
369         if (*bufferLength > 0 && !buffer) return ERROR_INVALID_PARAMETER;
370         if (*count > 1) return ERROR_INVALID_PARAMETER;
371         bool too_small = *count < 1 || *bufferLength < ARRAYSIZE(package_full_name);
372         *count = 1;
373         *bufferLength = ARRAYSIZE(package_full_name);
374         if (too_small) return ERROR_INSUFFICIENT_BUFFER;
375 
376         for (size_t i = 0; i < sizeof(package_full_name) / sizeof(wchar_t); i++) {
377             if (i >= *bufferLength) {
378                 break;
379             }
380             buffer[i] = package_full_name[i];
381         }
382         *packageFullNames = buffer;
383         return 0;
384     }
385     *count = 0;
386     *bufferLength = 0;
387     return 0;
388 }
389 
ShimGetPackagePathByFullName(_In_ PCWSTR packageFullName,_Inout_ UINT32 * pathLength,_Out_writes_opt_ (* pathLength)PWSTR path)390 LONG WINAPI ShimGetPackagePathByFullName(_In_ PCWSTR packageFullName, _Inout_ UINT32 *pathLength,
391                                          _Out_writes_opt_(*pathLength) PWSTR path) {
392     if (!packageFullName || !pathLength) return ERROR_INVALID_PARAMETER;
393     if (*pathLength > 0 && !path) return ERROR_INVALID_PARAMETER;
394     if (wcscmp(packageFullName, package_full_name) != 0) {
395         *pathLength = 0;
396         return 0;
397     }
398     if (*pathLength < platform_shim.app_package_path.size() + 1) {
399         *pathLength = static_cast<UINT32>(platform_shim.app_package_path.size() + 1);
400         return ERROR_INSUFFICIENT_BUFFER;
401     }
402     for (size_t i = 0; i < platform_shim.app_package_path.length(); i++) {
403         if (i >= *pathLength) {
404             break;
405         }
406         path[i] = platform_shim.app_package_path.c_str()[i];
407     }
408     return 0;
409 }
410 
411 using PFN_OutputDebugStringA = void(__stdcall *)(LPCSTR lpOutputString);
412 static PFN_OutputDebugStringA fp_OutputDebugStringA = OutputDebugStringA;
413 
intercept_OutputDebugStringA(LPCSTR lpOutputString)414 void __stdcall intercept_OutputDebugStringA(LPCSTR lpOutputString) {
415     if (lpOutputString != nullptr) {
416         platform_shim.fputs_stderr_log += lpOutputString;
417     }
418 }
419 
420 // Initialization
DetourFunctions()421 void WINAPI DetourFunctions() {
422     if (!gdi32_dll) {
423         gdi32_dll = LibraryWrapper("gdi32.dll");
424         fpEnumAdapters2 = gdi32_dll.get_symbol("D3DKMTEnumAdapters2");
425         if (fpEnumAdapters2 == nullptr) {
426             std::cerr << "Failed to load D3DKMTEnumAdapters2\n";
427             return;
428         }
429         fpQueryAdapterInfo = gdi32_dll.get_symbol("D3DKMTQueryAdapterInfo");
430         if (fpQueryAdapterInfo == nullptr) {
431             std::cerr << "Failed to load D3DKMTQueryAdapterInfo\n";
432             return;
433         }
434     }
435     if (!dxgi_module) {
436         TCHAR systemPath[MAX_PATH] = "";
437         GetSystemDirectory(systemPath, MAX_PATH);
438         StringCchCat(systemPath, MAX_PATH, TEXT("\\dxgi.dll"));
439         dxgi_module = LibraryWrapper(systemPath);
440         RealCreateDXGIFactory1 = dxgi_module.get_symbol("CreateDXGIFactory1");
441         if (RealCreateDXGIFactory1 == nullptr) {
442             std::cerr << "Failed to load CreateDXGIFactory1\n";
443         }
444     }
445 
446     DetourRestoreAfterWith();
447 
448     DetourTransactionBegin();
449     DetourUpdateThread(GetCurrentThread());
450     DetourAttach(&(PVOID &)fpGetSidSubAuthority, (PVOID)ShimGetSidSubAuthority);
451     DetourAttach(&(PVOID &)fpEnumAdapters2, (PVOID)ShimEnumAdapters2);
452     DetourAttach(&(PVOID &)fpQueryAdapterInfo, (PVOID)ShimQueryAdapterInfo);
453     DetourAttach(&(PVOID &)REAL_CM_Get_Device_ID_List_SizeW, (PVOID)SHIM_CM_Get_Device_ID_List_SizeW);
454     DetourAttach(&(PVOID &)REAL_CM_Get_Device_ID_ListW, (PVOID)SHIM_CM_Get_Device_ID_ListW);
455     DetourAttach(&(PVOID &)REAL_CM_Get_Device_ID_ListW, (PVOID)SHIM_CM_Get_Device_ID_ListW);
456     DetourAttach(&(PVOID &)REAL_CM_Locate_DevNodeW, (PVOID)SHIM_CM_Locate_DevNodeW);
457     DetourAttach(&(PVOID &)REAL_CM_Get_DevNode_Status, (PVOID)SHIM_CM_Get_DevNode_Status);
458     DetourAttach(&(PVOID &)REAL_CM_Get_Device_IDW, (PVOID)SHIM_CM_Get_Device_IDW);
459     DetourAttach(&(PVOID &)REAL_CM_Get_Child, (PVOID)SHIM_CM_Get_Child);
460     DetourAttach(&(PVOID &)REAL_CM_Get_DevNode_Registry_PropertyW, (PVOID)SHIM_CM_Get_DevNode_Registry_PropertyW);
461     DetourAttach(&(PVOID &)REAL_CM_Get_Sibling, (PVOID)SHIM_CM_Get_Sibling);
462     DetourAttach(&(PVOID &)RealCreateDXGIFactory1, (PVOID)ShimCreateDXGIFactory1);
463     DetourAttach(&(PVOID &)fpRegOpenKeyExA, (PVOID)ShimRegOpenKeyExA);
464     DetourAttach(&(PVOID &)fpRegQueryValueExA, (PVOID)ShimRegQueryValueExA);
465     DetourAttach(&(PVOID &)fpRegEnumValueA, (PVOID)ShimRegEnumValueA);
466     DetourAttach(&(PVOID &)fpRegCloseKey, (PVOID)ShimRegCloseKey);
467     DetourAttach(&(PVOID &)fpGetPackagesByPackageFamily, (PVOID)ShimGetPackagesByPackageFamily);
468     DetourAttach(&(PVOID &)fpGetPackagePathByFullName, (PVOID)ShimGetPackagePathByFullName);
469     DetourAttach(&(PVOID &)fp_OutputDebugStringA, (PVOID)intercept_OutputDebugStringA);
470     LONG error = DetourTransactionCommit();
471 
472     if (error != NO_ERROR) {
473         std::cerr << "simple" << DETOURS_STRINGIFY(DETOURS_BITS) << ".dll:"
474                   << " Error detouring function(): " << error << "\n";
475     }
476 }
477 
DetachFunctions()478 void DetachFunctions() {
479     DetourTransactionBegin();
480     DetourUpdateThread(GetCurrentThread());
481     DetourDetach(&(PVOID &)fpGetSidSubAuthority, (PVOID)ShimGetSidSubAuthority);
482     DetourDetach(&(PVOID &)fpEnumAdapters2, (PVOID)ShimEnumAdapters2);
483     DetourDetach(&(PVOID &)fpQueryAdapterInfo, (PVOID)ShimQueryAdapterInfo);
484     DetourDetach(&(PVOID &)REAL_CM_Get_Device_ID_List_SizeW, (PVOID)SHIM_CM_Get_Device_ID_List_SizeW);
485     DetourDetach(&(PVOID &)REAL_CM_Get_Device_ID_ListW, (PVOID)SHIM_CM_Get_Device_ID_ListW);
486     DetourDetach(&(PVOID &)REAL_CM_Locate_DevNodeW, (PVOID)SHIM_CM_Locate_DevNodeW);
487     DetourDetach(&(PVOID &)REAL_CM_Get_DevNode_Status, (PVOID)SHIM_CM_Get_DevNode_Status);
488     DetourDetach(&(PVOID &)REAL_CM_Get_Device_IDW, (PVOID)SHIM_CM_Get_Device_IDW);
489     DetourDetach(&(PVOID &)REAL_CM_Get_Child, (PVOID)SHIM_CM_Get_Child);
490     DetourDetach(&(PVOID &)REAL_CM_Get_DevNode_Registry_PropertyW, (PVOID)SHIM_CM_Get_DevNode_Registry_PropertyW);
491     DetourDetach(&(PVOID &)REAL_CM_Get_Sibling, (PVOID)SHIM_CM_Get_Sibling);
492     DetourDetach(&(PVOID &)RealCreateDXGIFactory1, (PVOID)ShimCreateDXGIFactory1);
493     DetourDetach(&(PVOID &)fpRegOpenKeyExA, (PVOID)ShimRegOpenKeyExA);
494     DetourDetach(&(PVOID &)fpRegQueryValueExA, (PVOID)ShimRegQueryValueExA);
495     DetourDetach(&(PVOID &)fpRegEnumValueA, (PVOID)ShimRegEnumValueA);
496     DetourDetach(&(PVOID &)fpRegCloseKey, (PVOID)ShimRegCloseKey);
497     DetourDetach(&(PVOID &)fpGetPackagesByPackageFamily, (PVOID)ShimGetPackagesByPackageFamily);
498     DetourDetach(&(PVOID &)fpGetPackagePathByFullName, (PVOID)ShimGetPackagePathByFullName);
499     DetourDetach(&(PVOID &)fp_OutputDebugStringA, (PVOID)intercept_OutputDebugStringA);
500     DetourTransactionCommit();
501 }
502 
DllMain(HINSTANCE hinst,DWORD dwReason,LPVOID reserved)503 BOOL WINAPI DllMain([[maybe_unused]] HINSTANCE hinst, DWORD dwReason, [[maybe_unused]] LPVOID reserved) {
504     if (DetourIsHelperProcess()) {
505         return TRUE;
506     }
507 
508     if (dwReason == DLL_PROCESS_ATTACH) {
509         DetourFunctions();
510     } else if (dwReason == DLL_PROCESS_DETACH) {
511         DetachFunctions();
512     }
513     return TRUE;
514 }
get_platform_shim(std::vector<fs::FolderManager> * folders)515 FRAMEWORK_EXPORT PlatformShim *get_platform_shim(std::vector<fs::FolderManager> *folders) {
516     platform_shim = PlatformShim(folders);
517     return &platform_shim;
518 }
519 }
520