1 /*
2 * PROJECT:     appshim_apitest
3 * LICENSE:     GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4 * PURPOSE:     Tests for IgnoreLoadLibrary shim
5 * COPYRIGHT:   Copyright 2019 Mark Jansen (mark.jansen@reactos.org)
6 */
7 
8 #include <ntstatus.h>
9 #define WIN32_NO_STATUS
10 #include <windows.h>
11 #include <ntndk.h>
12 #include "wine/test.h"
13 
14 #include "appshim_apitest.h"
15 
16 static DWORD g_WinVersion;
17 static tGETHOOKAPIS pGetHookAPIs;
18 static HMODULE g_hSentinelModule = (HMODULE)&pGetHookAPIs;  /* Not a valid hmodule, so a nice sentinel */
19 static HMODULE g_h123 = (HMODULE)123;
20 static HMODULE g_h111 = (HMODULE)111;
21 static HMODULE g_h0 = (HMODULE)0;
22 
23 typedef HMODULE(WINAPI* LOADLIBRARYAPROC)(LPCSTR lpLibFileName);
24 typedef HMODULE(WINAPI* LOADLIBRARYWPROC)(LPCWSTR lpLibFileName);
25 typedef HMODULE(WINAPI* LOADLIBRARYEXAPROC)(LPCSTR lpLibFileName, HANDLE hFile, DWORD dwFlags);
26 typedef HMODULE(WINAPI* LOADLIBRARYEXWPROC)(LPCWSTR lpLibFileName, HANDLE hFile, DWORD dwFlags);
27 
28 
29 UINT
30 WINAPI
31 GetErrorMode(VOID)
32 {
33     NTSTATUS Status;
34     UINT ErrMode;
35 
36     /* Query the current setting */
37     Status = NtQueryInformationProcess(NtCurrentProcess(),
38                                        ProcessDefaultHardErrorMode,
39                                        &ErrMode,
40                                        sizeof(ErrMode),
41                                        NULL);
42     if (!NT_SUCCESS(Status))
43     {
44         /* Fail if we couldn't query */
45         return 0;
46     }
47 
48     /* Check if NOT failing critical errors was requested */
49     if (ErrMode & SEM_FAILCRITICALERRORS)
50     {
51         /* Mask it out, since the native API works differently */
52         ErrMode &= ~SEM_FAILCRITICALERRORS;
53     }
54     else
55     {
56         /* OR it if the caller didn't, due to different native semantics */
57         ErrMode |= SEM_FAILCRITICALERRORS;
58     }
59 
60     /* Return the mode */
61     return ErrMode;
62 }
63 
64 static HMODULE WINAPI my_LoadLibraryA(PCSTR Name)
65 {
66     DWORD dwErrorMode = GetErrorMode();
67     ok(dwErrorMode == (SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX),
68        "Unexpected error mode: 0x%x\n", dwErrorMode);
69     return g_hSentinelModule;
70 }
71 
72 static HMODULE WINAPI my_LoadLibraryExA(PCSTR Name, HANDLE hFile, DWORD dwFlags)
73 {
74     DWORD dwErrorMode = GetErrorMode();
75     ok(dwErrorMode == (SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX),
76        "Unexpected error mode: 0x%x\n", dwErrorMode);
77     return g_hSentinelModule;
78 }
79 
80 static HMODULE WINAPI my_LoadLibraryW(PCWSTR Name)
81 {
82     DWORD dwErrorMode = GetErrorMode();
83     ok(dwErrorMode == (SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX),
84        "Unexpected error mode: 0x%x\n", dwErrorMode);
85     return g_hSentinelModule;
86 }
87 
88 static HMODULE WINAPI my_LoadLibraryExW(PCWSTR Name, HANDLE hFile, DWORD dwFlags)
89 {
90     DWORD dwErrorMode = GetErrorMode();
91     ok(dwErrorMode == (SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX),
92        "Unexpected error mode: 0x%x\n", dwErrorMode);
93     return g_hSentinelModule;
94 }
95 
96 
97 static void test_LoadLibraryA(PHOOKAPI hook)
98 {
99     LOADLIBRARYAPROC proc;
100     DWORD dwErrorMode, dwOldErrorMode;
101 
102     hook->OriginalFunction = my_LoadLibraryA;
103     proc = hook->ReplacementFunction;
104 
105     dwOldErrorMode = GetErrorMode();
106 
107     /* Exact names return what is specified */
108     ok_ptr(proc("test123.dll"), g_h123);
109     ok_ptr(proc("test111"), g_h111);
110     /* Extension is not added */
111     ok_ptr(proc("test111.dll"), g_hSentinelModule);
112     /* Zero can be specified */
113     ok_ptr(proc("Something.mark"), g_h0);
114     /* Or default returned */
115     ok_ptr(proc("empty"), g_h0);
116 
117     /* Paths, do not have to be valid */
118     ok_ptr(proc("\\test123.dll"), g_h123);
119     ok_ptr(proc("/test123.dll"), g_h123);
120     ok_ptr(proc("\\\\\\\\test123.dll"), g_h123);
121     ok_ptr(proc("////test123.dll"), g_h123);
122     ok_ptr(proc("mypath:something\\does\\not\\matter\\test123.dll"), g_h123);
123     ok_ptr(proc("/put/whatever/you/want/here/test123.dll"), g_h123);
124 
125     /* path separator is checked, not just any point in the path */
126     ok_ptr(proc("-test123.dll"), g_hSentinelModule);
127     ok_ptr(proc("test123.dll-"), g_hSentinelModule);
128 
129     dwErrorMode = GetErrorMode();
130     ok(dwErrorMode == dwOldErrorMode, "ErrorMode changed, was 0x%x, is 0x%x\n", dwOldErrorMode, dwErrorMode);
131 }
132 
133 static void test_LoadLibraryW(PHOOKAPI hook)
134 {
135     LOADLIBRARYWPROC proc;
136     DWORD dwErrorMode, dwOldErrorMode;
137 
138     hook->OriginalFunction = my_LoadLibraryW;
139     proc = hook->ReplacementFunction;
140 
141     dwOldErrorMode = GetErrorMode();
142 
143     /* Exact names return what is specified */
144     ok_ptr(proc(L"test123.dll"), g_h123);
145     ok_ptr(proc(L"test111"), g_h111);
146     /* Extension is not added */
147     ok_ptr(proc(L"test111.dll"), g_hSentinelModule);
148     /* Zero can be specified */
149     ok_ptr(proc(L"Something.mark"), g_h0);
150     /* Or default returned */
151     ok_ptr(proc(L"empty"), g_h0);
152 
153     /* Paths, do not have to be valid */
154     ok_ptr(proc(L"\\test123.dll"), g_h123);
155     ok_ptr(proc(L"/test123.dll"), g_h123);
156     ok_ptr(proc(L"\\\\\\\\test123.dll"), g_h123);
157     ok_ptr(proc(L"////test123.dll"), g_h123);
158     ok_ptr(proc(L"mypath:something\\does\\not\\matter\\test123.dll"), g_h123);
159     ok_ptr(proc(L"/put/whatever/you/want/here/test123.dll"), g_h123);
160 
161     /* path separator is checked, not just any point in the path */
162     ok_ptr(proc(L"-test123.dll"), g_hSentinelModule);
163     ok_ptr(proc(L"test123.dll-"), g_hSentinelModule);
164 
165     dwErrorMode = GetErrorMode();
166     ok(dwErrorMode == dwOldErrorMode, "ErrorMode changed, was 0x%x, is 0x%x\n", dwOldErrorMode, dwErrorMode);
167 }
168 
169 static void test_LoadLibraryExA(PHOOKAPI hook)
170 {
171     LOADLIBRARYEXAPROC proc;
172     DWORD dwErrorMode, dwOldErrorMode;
173 
174     hook->OriginalFunction = my_LoadLibraryExA;
175     proc = hook->ReplacementFunction;
176 
177     dwOldErrorMode = GetErrorMode();
178 
179     /* Exact names return what is specified */
180     ok_ptr(proc("test123.dll", INVALID_HANDLE_VALUE, 0), g_h123);
181     ok_ptr(proc("test111", INVALID_HANDLE_VALUE, 0), g_h111);
182     /* Extension is not added */
183     ok_ptr(proc("test111.dll", INVALID_HANDLE_VALUE, 0), g_hSentinelModule);
184     /* Zero can be specified */
185     ok_ptr(proc("Something.mark", INVALID_HANDLE_VALUE, 0), g_h0);
186     /* Or default returned */
187     ok_ptr(proc("empty", INVALID_HANDLE_VALUE, 0), g_h0);
188 
189     /* Paths, do not have to be valid */
190     ok_ptr(proc("\\test123.dll", INVALID_HANDLE_VALUE, 0), g_h123);
191     ok_ptr(proc("/test123.dll", INVALID_HANDLE_VALUE, 0), g_h123);
192     ok_ptr(proc("\\\\\\\\test123.dll", INVALID_HANDLE_VALUE, 0), g_h123);
193     ok_ptr(proc("////test123.dll", INVALID_HANDLE_VALUE, 0), g_h123);
194     ok_ptr(proc("mypath:something\\does\\not\\matter\\test123.dll", INVALID_HANDLE_VALUE, 0), g_h123);
195     ok_ptr(proc("/put/whatever/you/want/here/test123.dll", INVALID_HANDLE_VALUE, 0), g_h123);
196 
197     /* path separator is checked, not just any point in the path */
198     ok_ptr(proc("-test123.dll", INVALID_HANDLE_VALUE, 0), g_hSentinelModule);
199     ok_ptr(proc("test123.dll-", INVALID_HANDLE_VALUE, 0), g_hSentinelModule);
200 
201     dwErrorMode = GetErrorMode();
202     ok(dwErrorMode == dwOldErrorMode, "ErrorMode changed, was 0x%x, is 0x%x\n", dwOldErrorMode, dwErrorMode);
203 }
204 
205 static void test_LoadLibraryExW(PHOOKAPI hook)
206 {
207     LOADLIBRARYEXWPROC proc;
208     DWORD dwErrorMode, dwOldErrorMode;
209 
210     hook->OriginalFunction = my_LoadLibraryExW;
211     proc = hook->ReplacementFunction;
212 
213     dwOldErrorMode = GetErrorMode();
214 
215     /* Exact names return what is specified */
216     ok_ptr(proc(L"test123.dll", INVALID_HANDLE_VALUE, 0), g_h123);
217     ok_ptr(proc(L"test111", INVALID_HANDLE_VALUE, 0), g_h111);
218     /* Extension is not added */
219     ok_ptr(proc(L"test111.dll", INVALID_HANDLE_VALUE, 0), g_hSentinelModule);
220     /* Zero can be specified */
221     ok_ptr(proc(L"Something.mark", INVALID_HANDLE_VALUE, 0), g_h0);
222     /* Or default returned */
223     ok_ptr(proc(L"empty", INVALID_HANDLE_VALUE, 0), g_h0);
224 
225     /* Paths, do not have to be valid */
226     ok_ptr(proc(L"\\test123.dll", INVALID_HANDLE_VALUE, 0), g_h123);
227     ok_ptr(proc(L"/test123.dll", INVALID_HANDLE_VALUE, 0), g_h123);
228     ok_ptr(proc(L"\\\\\\\\test123.dll", INVALID_HANDLE_VALUE, 0), g_h123);
229     ok_ptr(proc(L"////test123.dll", INVALID_HANDLE_VALUE, 0), g_h123);
230     ok_ptr(proc(L"mypath:something\\does\\not\\matter\\test123.dll", INVALID_HANDLE_VALUE, 0), g_h123);
231     ok_ptr(proc(L"/put/whatever/you/want/here/test123.dll", INVALID_HANDLE_VALUE, 0), g_h123);
232 
233     /* path separator is checked, not just any point in the path */
234     ok_ptr(proc(L"-test123.dll", INVALID_HANDLE_VALUE, 0), g_hSentinelModule);
235     ok_ptr(proc(L"test123.dll-", INVALID_HANDLE_VALUE, 0), g_hSentinelModule);
236 
237     dwErrorMode = GetErrorMode();
238     ok(dwErrorMode == dwOldErrorMode, "ErrorMode changed, was 0x%x, is 0x%x\n", dwOldErrorMode, dwErrorMode);
239 }
240 
241 /* versionlie.c */
242 DWORD get_host_winver(void);
243 
244 START_TEST(ignoreloadlib)
245 {
246     DWORD num_shims = 0, n, dwErrorMode;
247     PHOOKAPI hook;
248 
249     g_WinVersion = get_host_winver();
250 
251     if (g_WinVersion < _WIN32_WINNT_WIN8)
252         pGetHookAPIs = LoadShimDLL2(L"aclayers.dll");
253     else
254         pGetHookAPIs = LoadShimDLL2(L"acgenral.dll");
255 
256     if (!pGetHookAPIs)
257     {
258         skip("GetHookAPIs not found\n");
259         return;
260     }
261 
262     hook = pGetHookAPIs("test123.dll:123;test111:111;Something.mark:0;empty", L"IgnoreLoadLibrary", &num_shims);
263 
264     ok(hook != NULL, "Expected hook to be a valid pointer\n");
265     ok(num_shims == 4, "Expected num_shims to be 0, was: %u\n", num_shims);
266 
267     if (!hook || num_shims != 4)
268         return;
269 
270     dwErrorMode = GetErrorMode();
271     trace("Error mode: 0x%x\n", dwErrorMode);
272 
273     for (n = 0; n < num_shims; ++n)
274     {
275         ok_str(hook[n].LibraryName, "KERNEL32.DLL");
276         if (!_stricmp(hook[n].FunctionName, "LoadLibraryA"))
277         {
278             ok_int(n, 0);
279             test_LoadLibraryA(hook + n);
280         }
281         else if (!_stricmp(hook[n].FunctionName, "LoadLibraryExA"))
282         {
283             ok_int(n, 1);
284             test_LoadLibraryExA(hook + n);
285         }
286         else if (!_stricmp(hook[n].FunctionName, "LoadLibraryW"))
287         {
288             ok_int(n, 2);
289             test_LoadLibraryW(hook + n);
290         }
291         else if (!_stricmp(hook[n].FunctionName, "LoadLibraryExW"))
292         {
293             ok_int(n, 3);
294             test_LoadLibraryExW(hook + n);
295         }
296         else
297         {
298             ok(0, "Unknown function %s\n", hook[n].FunctionName);
299         }
300     }
301 }
302