VirtualBox

source: vbox/trunk/src/VBox/HostDrivers/Support/win/SUPR3HardenedMainImports-win.cpp

Last change on this file was 107632, checked in by vboxsync, 4 months ago

SUPHardNt: Better use of SUPHNTIMP_ERROR's a_szWhere param when a_fReportErrors=false. bugref:3409

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 39.0 KB
Line 
1/* $Id: SUPR3HardenedMainImports-win.cpp 107632 2025-01-10 10:45:03Z vboxsync $ */
2/** @file
3 * VirtualBox Support Library - Hardened Main, Windows Import Trickery.
4 */
5
6/*
7 * Copyright (C) 2006-2024 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.215389.xyz.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * The contents of this file may alternatively be used under the terms
26 * of the Common Development and Distribution License Version 1.0
27 * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
28 * in the VirtualBox distribution, in which case the provisions of the
29 * CDDL are applicable instead of those of the GPL.
30 *
31 * You may elect to license modified versions of this file under the
32 * terms and conditions of either the GPL or the CDDL or both.
33 *
34 * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
35 */
36
37
38/*********************************************************************************************************************************
39* Header Files *
40*********************************************************************************************************************************/
41#include <iprt/nt/nt-and-windows.h>
42
43#include <VBox/sup.h>
44#include <VBox/err.h>
45#include <iprt/ctype.h>
46#include <iprt/initterm.h>
47#include <iprt/param.h>
48#include <iprt/string.h>
49#include <iprt/utf16.h>
50#ifdef RT_ARCH_ARM64
51# include <iprt/armv8.h>
52#endif
53
54#include "SUPLibInternal.h"
55#include "SUPHardenedVerify-win.h"
56
57
58/*********************************************************************************************************************************
59* Defined Constants And Macros *
60*********************************************************************************************************************************/
61#define SUPHARNT_COMMENT(a_Blah) /* nothing */
62
63#define VBOX_HARDENED_STUB_WITHOUT_IMPORTS
64#ifdef VBOX_HARDENED_STUB_WITHOUT_IMPORTS
65# define SUPHNTIMP_ERROR(a_fReportErrors, a_id, a_szWhere, a_enmOp, a_rc, ...) \
66 do { \
67 const char * const pszWhereError = (a_szWhere); \
68 if (a_fReportErrors) supR3HardenedFatalMsg(pszWhereError, a_enmOp, a_rc, __VA_ARGS__); \
69 else { *(uintptr_t *)(uintptr_t)(a_id) += (uintptr_t)pszWhereError; __debugbreak(); } \
70 } while (0)
71#else
72# define SUPHNTIMP_ERROR(a_fReportErrors, a_id, a_szWhere, a_enmOp, a_rc, ...) \
73 supR3HardenedFatalMsg(a_szWhere, a_enmOp, a_rc, __VA_ARGS__)
74
75#endif
76
77
78/*********************************************************************************************************************************
79* Defined Constants And Macros *
80*********************************************************************************************************************************/
81/**
82 * Import function entry.
83 */
84typedef struct SUPHNTIMPFUNC
85{
86 /** The name of the function we're importing. */
87 const char *pszName;
88 /** Where to store the function address (think __imp_ApiName). */
89 PFNRT *ppfnImport;
90 /** Pointer to an early dummy function for imports that aren't available
91 * during early process initialization. */
92 PFNRT pfnEarlyDummy;
93 /** Indicates whether this is an optional import and failure to locate it
94 * should set it to NULL instead of freaking out. */
95 bool fOptional;
96} SUPHNTIMPFUNC;
97/** Pointer to an import table entry. */
98typedef SUPHNTIMPFUNC const *PCSUPHNTIMPFUNC;
99
100/**
101 * Information for constructing a direct system call.
102 */
103typedef struct SUPHNTIMPSYSCALL
104{
105 /** Where to store the system call number.
106 * NULL if this import doesn't stupport direct system call. */
107 uint32_t *puApiNo;
108 /** Assembly system call routine, type 1. */
109 PFNRT pfnType1;
110#if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)
111 /** Assembly system call routine, type 2. */
112 PFNRT pfnType2;
113#endif
114#ifdef RT_ARCH_X86
115 /** The parameter size in bytes for a standard call. */
116 uint32_t cbParams;
117#endif
118} SUPHNTIMPSYSCALL;
119/** Pointer to a system call entry. */
120typedef SUPHNTIMPSYSCALL const *PCSUPHNTIMPSYSCALL;
121
122/**
123 * Import DLL.
124 *
125 * This contains both static (like name & imports) and runtime information (like
126 * load and export table locations).
127 *
128 * @sa RTDBGNTKRNLMODINFO
129 */
130typedef struct SUPHNTIMPDLL
131{
132 /** @name Static data.
133 * @{ */
134 const wchar_t *pwszName;
135 const char *pszName;
136 size_t cImports;
137 PCSUPHNTIMPFUNC paImports;
138 /** Array running parallel to paImports if present. */
139 PCSUPHNTIMPSYSCALL paSyscalls;
140 /** @} */
141
142
143 /** The image base. */
144 uint8_t const *pbImageBase;
145 /** The NT headers. */
146 PIMAGE_NT_HEADERS pNtHdrs;
147 /** The NT header offset/RVA. */
148 uint32_t offNtHdrs;
149 /** The end of the section headers. */
150 uint32_t offEndSectHdrs;
151 /** The end of the image. */
152 uint32_t cbImage;
153 /** Offset of the export directory. */
154 uint32_t offExportDir;
155 /** Size of the export directory. */
156 uint32_t cbExportDir;
157
158 /** Exported functions and data by ordinal (RVAs). */
159 uint32_t const *paoffExports;
160 /** The number of exports. */
161 uint32_t cExports;
162 /** The number of exported names. */
163 uint32_t cNamedExports;
164 /** Pointer to the array of exported names (RVAs to strings). */
165 uint32_t const *paoffNamedExports;
166 /** Array parallel to paoffNamedExports with the corresponding ordinals
167 * (indexes into paoffExports). */
168 uint16_t const *pau16NameOrdinals;
169
170 /** Number of patched export table entries. */
171 uint32_t cPatchedExports;
172
173} SUPHNTIMPDLL;
174/** Pointer to an import DLL entry. */
175typedef SUPHNTIMPDLL *PSUPHNTIMPDLL;
176
177
178
179/*
180 * Declare assembly symbols.
181 */
182#define SUPHARNT_IMPORT_STDCALL_EARLY(a_Name, a_cbParamsX86) \
183 extern PFNRT RT_CONCAT(g_pfn, a_Name);
184#define SUPHARNT_IMPORT_STDCALL_EARLY_OPTIONAL(a_Name, a_cbParamsX86) SUPHARNT_IMPORT_STDCALL_EARLY(a_Name, a_cbParamsX86)
185#if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)
186# define SUPHARNT_IMPORT_SYSCALL(a_Name, a_cbParamsX86) \
187 SUPHARNT_IMPORT_STDCALL_EARLY(a_Name, a_cbParamsX86) \
188 extern uint32_t RT_CONCAT(g_uApiNo, a_Name); \
189 extern FNRT RT_CONCAT(a_Name, _SyscallType1); \
190 extern FNRT RT_CONCAT(a_Name, _SyscallType2);
191#else
192# define SUPHARNT_IMPORT_SYSCALL(a_Name, a_cbParamsX86) \
193 SUPHARNT_IMPORT_STDCALL_EARLY(a_Name, a_cbParamsX86) \
194 extern uint32_t RT_CONCAT(g_uApiNo, a_Name); \
195 extern FNRT RT_CONCAT(a_Name, _Syscall);
196#endif
197#define SUPHARNT_IMPORT_STDCALL(a_Name, a_cbParamsX86) \
198 extern PFNRT RT_CONCAT(g_pfn, a_Name); \
199 extern FNRT RT_CONCAT(a_Name, _Early);
200#define SUPHARNT_IMPORT_STDCALL_OPTIONAL(a_Name, a_cbParamsX86) SUPHARNT_IMPORT_STDCALL(a_Name, a_cbParamsX86)
201
202RT_C_DECLS_BEGIN
203#include "import-template-ntdll.h"
204#include "import-template-kernel32.h"
205RT_C_DECLS_END
206
207/*
208 * Import functions.
209 */
210#undef SUPHARNT_IMPORT_SYSCALL
211#undef SUPHARNT_IMPORT_STDCALL_EARLY
212#undef SUPHARNT_IMPORT_STDCALL_EARLY_OPTIONAL
213#undef SUPHARNT_IMPORT_STDCALL
214#undef SUPHARNT_IMPORT_STDCALL_OPTIONAL
215#define SUPHARNT_IMPORT_SYSCALL(a_Name, a_cbParamsX86) \
216 { #a_Name, &RT_CONCAT(g_pfn, a_Name), NULL, false },
217#define SUPHARNT_IMPORT_STDCALL_EARLY(a_Name, a_cbParamsX86) \
218 { #a_Name, &RT_CONCAT(g_pfn, a_Name), NULL, false },
219#define SUPHARNT_IMPORT_STDCALL_EARLY_OPTIONAL(a_Name, a_cbParamsX86) \
220 { #a_Name, &RT_CONCAT(g_pfn, a_Name), NULL, true },
221#define SUPHARNT_IMPORT_STDCALL(a_Name, a_cbParamsX86) \
222 { #a_Name, &RT_CONCAT(g_pfn, a_Name), RT_CONCAT(a_Name,_Early), false },
223#define SUPHARNT_IMPORT_STDCALL_OPTIONAL(a_Name, a_cbParamsX86) \
224 { #a_Name, &RT_CONCAT(g_pfn, a_Name), RT_CONCAT(a_Name,_Early), true },
225static const SUPHNTIMPFUNC g_aSupNtImpNtDllFunctions[] =
226{
227#include "import-template-ntdll.h"
228};
229
230static const SUPHNTIMPFUNC g_aSupNtImpKernel32Functions[] =
231{
232#include "import-template-kernel32.h"
233};
234
235
236
237/*
238 * Syscalls in ntdll.
239 */
240#undef SUPHARNT_IMPORT_SYSCALL
241#undef SUPHARNT_IMPORT_STDCALL_EARLY
242#undef SUPHARNT_IMPORT_STDCALL_EARLY_OPTIONAL
243#undef SUPHARNT_IMPORT_STDCALL
244#undef SUPHARNT_IMPORT_STDCALL_OPTIONAL
245#ifdef RT_ARCH_AMD64
246# define SUPHARNT_IMPORT_STDCALL(a_Name, a_cbParamsX86) \
247 { NULL, NULL },
248# define SUPHARNT_IMPORT_SYSCALL(a_Name, a_cbParamsX86) \
249 { &RT_CONCAT(g_uApiNo, a_Name), &RT_CONCAT(a_Name, _SyscallType1), &RT_CONCAT(a_Name, _SyscallType2) },
250
251#elif defined(RT_ARCH_ARM64)
252# define SUPHARNT_IMPORT_STDCALL(a_Name, a_cbParamsX86) \
253 { NULL, NULL },
254# define SUPHARNT_IMPORT_SYSCALL(a_Name, a_cbParamsX86) \
255 { &RT_CONCAT(g_uApiNo, a_Name), &RT_CONCAT(a_Name, _Syscall) },
256
257#elif defined(RT_ARCH_X86)
258# define SUPHARNT_IMPORT_STDCALL(a_Name, a_cbParamsX86) \
259 { NULL, NULL, NULL, 0 },
260# define SUPHARNT_IMPORT_SYSCALL(a_Name, a_cbParamsX86) \
261 { &RT_CONCAT(g_uApiNo, a_Name), &RT_CONCAT(a_Name,_SyscallType1), &RT_CONCAT(a_Name, _SyscallType2), a_cbParamsX86 },
262
263#else
264# error "port me"
265#endif
266#define SUPHARNT_IMPORT_STDCALL_OPTIONAL(a_Name, a_cbParamsX86) SUPHARNT_IMPORT_STDCALL(a_Name, a_cbParamsX86)
267#define SUPHARNT_IMPORT_STDCALL_EARLY(a_Name, a_cbParamsX86) SUPHARNT_IMPORT_STDCALL(a_Name, a_cbParamsX86)
268#define SUPHARNT_IMPORT_STDCALL_EARLY_OPTIONAL(a_Name, a_cbParamsX86) SUPHARNT_IMPORT_STDCALL(a_Name, a_cbParamsX86)
269static const SUPHNTIMPSYSCALL g_aSupNtImpNtDllSyscalls[] =
270{
271#include "import-template-ntdll.h"
272};
273
274
275/**
276 * All the DLLs we import from.
277 * @remarks Code ASSUMES that ntdll is the first entry.
278 */
279static SUPHNTIMPDLL g_aSupNtImpDlls[] =
280{
281 { L"ntdll.dll", "ntdll.dll", RT_ELEMENTS(g_aSupNtImpNtDllFunctions), g_aSupNtImpNtDllFunctions, g_aSupNtImpNtDllSyscalls },
282 { L"kernelbase.dll", "kernelbase.dll", 0 /* optional module, forwarders only */, NULL, NULL },
283 { L"kernel32.dll", "kernel32.dll", RT_ELEMENTS(g_aSupNtImpKernel32Functions), g_aSupNtImpKernel32Functions, NULL },
284};
285
286
287static void supR3HardenedFindOrLoadModule(PSUPHNTIMPDLL pDll)
288{
289#ifdef VBOX_HARDENED_STUB_WITHOUT_IMPORTS
290 uint32_t const cbName = (uint32_t)RTUtf16Len(pDll->pwszName) * sizeof(WCHAR);
291 PPEB_LDR_DATA pLdrData = NtCurrentPeb()->Ldr;
292 LIST_ENTRY *pList = &pLdrData->InMemoryOrderModuleList;
293 LIST_ENTRY *pListEntry = pList->Flink;
294 uint32_t cLoops = 0;
295 while (pListEntry != pList && cLoops < 1024)
296 {
297 PLDR_DATA_TABLE_ENTRY pLdrEntry = RT_FROM_MEMBER(pListEntry, LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks);
298
299 if ( pLdrEntry->FullDllName.Length > cbName + sizeof(WCHAR)
300 && ( pLdrEntry->FullDllName.Buffer[(pLdrEntry->FullDllName.Length - cbName) / sizeof(WCHAR) - 1] == '\\'
301 || pLdrEntry->FullDllName.Buffer[(pLdrEntry->FullDllName.Length - cbName) / sizeof(WCHAR) - 1] == '/')
302 && RTUtf16ICmpAscii(&pLdrEntry->FullDllName.Buffer[(pLdrEntry->FullDllName.Length - cbName) / sizeof(WCHAR)],
303 pDll->pszName) == 0)
304 {
305 pDll->pbImageBase = (uint8_t *)pLdrEntry->DllBase;
306 return;
307 }
308
309 pListEntry = pListEntry->Flink;
310 cLoops++;
311 }
312
313 if (!pDll->cImports)
314 pDll->pbImageBase = NULL; /* optional */
315 else
316 SUPHNTIMP_ERROR(false, 1, "supR3HardenedFindOrLoadModule", kSupInitOp_Misc, VERR_MODULE_NOT_FOUND,
317 "Failed to locate %ls", pDll->pwszName);
318#else
319 HMODULE hmod = GetModuleHandleW(pDll->pwszName);
320 if (RT_UNLIKELY(!hmod && pDll->cImports))
321 SUPHNTIMP_ERROR(true, 1, "supR3HardenedWinInitImports", kSupInitOp_Misc, VERR_MODULE_NOT_FOUND,
322 "Failed to locate %ls", pDll->pwszName);
323 pDll->pbImageBase = (uint8_t *)hmod;
324#endif
325}
326
327
328/** @sa rtR0DbgKrnlNtParseModule */
329static void supR3HardenedParseModule(PSUPHNTIMPDLL pDll)
330{
331 /*
332 * Locate the PE header, do some basic validations.
333 */
334 IMAGE_DOS_HEADER const *pMzHdr = (IMAGE_DOS_HEADER const *)pDll->pbImageBase;
335 uint32_t offNtHdrs = 0;
336 PIMAGE_NT_HEADERS pNtHdrs;
337 if (pMzHdr->e_magic == IMAGE_DOS_SIGNATURE)
338 {
339 offNtHdrs = pMzHdr->e_lfanew;
340 if (offNtHdrs > _2K)
341 SUPHNTIMP_ERROR(false, 2, "supR3HardenedParseModule", kSupInitOp_Misc, VERR_MODULE_NOT_FOUND,
342 "%ls: e_lfanew=%#x, expected a lower value", pDll->pwszName, offNtHdrs);
343 }
344 pDll->pNtHdrs = pNtHdrs = (PIMAGE_NT_HEADERS)&pDll->pbImageBase[offNtHdrs];
345
346 if (pNtHdrs->Signature != IMAGE_NT_SIGNATURE)
347 SUPHNTIMP_ERROR(false, 3, "supR3HardenedParseModule", kSupInitOp_Misc, VERR_INVALID_EXE_SIGNATURE,
348 "%ls: Invalid PE signature: %#x", pDll->pwszName, pNtHdrs->Signature);
349 if (pNtHdrs->FileHeader.SizeOfOptionalHeader != sizeof(pNtHdrs->OptionalHeader))
350 SUPHNTIMP_ERROR(false, 4, "supR3HardenedParseModule", kSupInitOp_Misc, VERR_INVALID_EXE_SIGNATURE,
351 "%ls: Unexpected optional header size: %#x", pDll->pwszName, pNtHdrs->FileHeader.SizeOfOptionalHeader);
352 if (pNtHdrs->OptionalHeader.Magic != RT_CONCAT3(IMAGE_NT_OPTIONAL_HDR,ARCH_BITS,_MAGIC))
353 SUPHNTIMP_ERROR(false, 5, "supR3HardenedParseModule", kSupInitOp_Misc, VERR_INVALID_EXE_SIGNATURE,
354 "%ls: Unexpected optional header magic: %#x", pDll->pwszName, pNtHdrs->OptionalHeader.Magic);
355 if (pNtHdrs->OptionalHeader.NumberOfRvaAndSizes != IMAGE_NUMBEROF_DIRECTORY_ENTRIES)
356 SUPHNTIMP_ERROR(false, 6, "supR3HardenedParseModule", kSupInitOp_Misc, VERR_INVALID_EXE_SIGNATURE,
357 "%ls: Unexpected number of RVA and sizes: %#x", pDll->pwszName, pNtHdrs->OptionalHeader.NumberOfRvaAndSizes);
358
359 pDll->offNtHdrs = offNtHdrs;
360 pDll->offEndSectHdrs = offNtHdrs
361 + sizeof(*pNtHdrs)
362 + pNtHdrs->FileHeader.NumberOfSections * sizeof(IMAGE_SECTION_HEADER);
363 pDll->cbImage = pNtHdrs->OptionalHeader.SizeOfImage;
364
365 /*
366 * Find the export directory.
367 */
368 IMAGE_DATA_DIRECTORY ExpDir = pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
369 if ( ExpDir.Size < sizeof(IMAGE_EXPORT_DIRECTORY)
370 || ExpDir.VirtualAddress < pDll->offEndSectHdrs
371 || ExpDir.VirtualAddress >= pNtHdrs->OptionalHeader.SizeOfImage
372 || ExpDir.VirtualAddress + ExpDir.Size > pNtHdrs->OptionalHeader.SizeOfImage)
373 SUPHNTIMP_ERROR(false, 7, "supR3HardenedParseModule", kSupInitOp_Misc, VERR_INVALID_EXE_SIGNATURE,
374 "%ls: Missing or invalid export directory: %#lx LB %#x", pDll->pwszName, ExpDir.VirtualAddress, ExpDir.Size);
375 pDll->offExportDir = ExpDir.VirtualAddress;
376 pDll->cbExportDir = ExpDir.Size;
377
378 IMAGE_EXPORT_DIRECTORY const *pExpDir = (IMAGE_EXPORT_DIRECTORY const *)&pDll->pbImageBase[ExpDir.VirtualAddress];
379
380 if ( pExpDir->NumberOfFunctions >= _1M
381 || pExpDir->NumberOfFunctions < 1
382 || pExpDir->NumberOfNames >= _1M
383 || pExpDir->NumberOfNames < 1)
384 SUPHNTIMP_ERROR(false, 8, "supR3HardenedParseModule", kSupInitOp_Misc, VERR_INVALID_EXE_SIGNATURE,
385 "%ls: NumberOfNames or/and NumberOfFunctions are outside the expected range: nof=%#x non=%#x\n",
386 pDll->pwszName, pExpDir->NumberOfFunctions, pExpDir->NumberOfNames);
387 pDll->cNamedExports = pExpDir->NumberOfNames;
388 pDll->cExports = RT_MAX(pExpDir->NumberOfNames, pExpDir->NumberOfFunctions);
389
390 if ( pExpDir->AddressOfFunctions < pDll->offEndSectHdrs
391 || pExpDir->AddressOfFunctions >= pNtHdrs->OptionalHeader.SizeOfImage
392 || pExpDir->AddressOfFunctions + pDll->cExports * sizeof(uint32_t) > pNtHdrs->OptionalHeader.SizeOfImage)
393 SUPHNTIMP_ERROR(false, 9, "supR3HardenedParseModule", kSupInitOp_Misc, VERR_INVALID_EXE_SIGNATURE,
394 "%ls: Bad AddressOfFunctions: %#x\n", pDll->pwszName, pExpDir->AddressOfFunctions);
395 pDll->paoffExports = (uint32_t const *)&pDll->pbImageBase[pExpDir->AddressOfFunctions];
396
397 if ( pExpDir->AddressOfNames < pDll->offEndSectHdrs
398 || pExpDir->AddressOfNames >= pNtHdrs->OptionalHeader.SizeOfImage
399 || pExpDir->AddressOfNames + pExpDir->NumberOfNames * sizeof(uint32_t) > pNtHdrs->OptionalHeader.SizeOfImage)
400 SUPHNTIMP_ERROR(false, 10, "supR3HardenedParseModule", kSupInitOp_Misc, VERR_INVALID_EXE_SIGNATURE,
401 "%ls: Bad AddressOfNames: %#x\n", pDll->pwszName, pExpDir->AddressOfNames);
402 pDll->paoffNamedExports = (uint32_t const *)&pDll->pbImageBase[pExpDir->AddressOfNames];
403
404 if ( pExpDir->AddressOfNameOrdinals < pDll->offEndSectHdrs
405 || pExpDir->AddressOfNameOrdinals >= pNtHdrs->OptionalHeader.SizeOfImage
406 || pExpDir->AddressOfNameOrdinals + pExpDir->NumberOfNames * sizeof(uint32_t) > pNtHdrs->OptionalHeader.SizeOfImage)
407 SUPHNTIMP_ERROR(false, 11, "supR3HardenedParseModule", kSupInitOp_Misc, VERR_INVALID_EXE_SIGNATURE,
408 "%ls: Bad AddressOfNameOrdinals: %#x\n", pDll->pwszName, pExpDir->AddressOfNameOrdinals);
409 pDll->pau16NameOrdinals = (uint16_t const *)&pDll->pbImageBase[pExpDir->AddressOfNameOrdinals];
410}
411
412
413/** @sa rtR0DbgKrnlInfoLookupSymbol */
414static const char *supR3HardenedResolveImport(PSUPHNTIMPDLL pDll, PCSUPHNTIMPFUNC pImport, bool fReportErrors)
415{
416 /*
417 * Binary search.
418 */
419 uint32_t iStart = 0;
420 uint32_t iEnd = pDll->cNamedExports;
421 while (iStart < iEnd)
422 {
423 uint32_t iCur = iStart + (iEnd - iStart) / 2;
424 uint32_t offExpName = pDll->paoffNamedExports[iCur];
425 if (RT_UNLIKELY(offExpName < pDll->offEndSectHdrs || offExpName >= pDll->cbImage))
426 SUPHNTIMP_ERROR(fReportErrors, 12, "supR3HardenedResolveImport", kSupInitOp_Misc, VERR_SYMBOL_NOT_FOUND,
427 "%ls: Bad export name entry: %#x (iCur=%#x)", pDll->pwszName, offExpName, iCur);
428
429 const char *pszExpName = (const char *)&pDll->pbImageBase[offExpName];
430 int iDiff = strcmp(pszExpName, pImport->pszName);
431 if (iDiff > 0) /* pszExpName > pszSymbol: search chunck before i */
432 iEnd = iCur;
433 else if (iDiff < 0) /* pszExpName < pszSymbol: search chunk after i */
434 iStart = iCur + 1;
435 else /* pszExpName == pszSymbol */
436 {
437 uint16_t iExpOrdinal = pDll->pau16NameOrdinals[iCur];
438 if (iExpOrdinal < pDll->cExports)
439 {
440 uint32_t offExport = pDll->paoffExports[iExpOrdinal];
441
442 /* detect export table patching. */
443 if (offExport >= pDll->cbImage)
444 pDll->cPatchedExports++;
445
446 if (offExport - pDll->offExportDir >= pDll->cbExportDir)
447 {
448 *pImport->ppfnImport = (PFNRT)&pDll->pbImageBase[offExport];
449 return NULL;
450 }
451
452 /* Forwarder. */
453 return (const char *)&pDll->pbImageBase[offExport];
454 }
455 SUPHNTIMP_ERROR(fReportErrors, 14, "supR3HardenedResolveImport", kSupInitOp_Misc, VERR_BAD_EXE_FORMAT,
456 "%ls: Name ordinal for '%s' is out of bounds: %#x (max %#x)",
457 pDll->pwszName, iExpOrdinal, pDll->cExports);
458 return NULL;
459 }
460 }
461
462 if (!pImport->fOptional)
463 SUPHNTIMP_ERROR(fReportErrors, 15, "supR3HardenedResolveImport", kSupInitOp_Misc, VERR_SYMBOL_NOT_FOUND,
464 "%ls: Failed to resolve '%s'.", pDll->pwszName, pImport->pszName);
465 *pImport->ppfnImport = NULL;
466 return NULL;
467}
468
469
470static void supR3HardenedDirectSyscall(PSUPHNTIMPDLL pDll, PCSUPHNTIMPFUNC pImport, PCSUPHNTIMPSYSCALL pSyscall,
471 PSUPHNTLDRCACHEENTRY pLdrEntry, uint8_t *pbBits, bool fReportErrors)
472{
473 /*
474 * Skip non-syscall entries.
475 */
476 if (!pSyscall->puApiNo)
477 return;
478
479 /*
480 * Locate the virgin bits.
481 */
482 RTLDRADDR uValue;
483 int rc = RTLdrGetSymbolEx(pLdrEntry->hLdrMod, pbBits, (uintptr_t)pDll->pbImageBase, UINT32_MAX, pImport->pszName, &uValue);
484 if (RT_FAILURE(rc))
485 {
486 SUPHNTIMP_ERROR(fReportErrors, 16, "supR3HardenedDirectSyscall", kSupInitOp_Misc, rc,
487 "%s: RTLdrGetSymbolEx failed on %s: %Rrc", pDll->pszName, pImport->pszName, rc);
488 return;
489 }
490 uintptr_t offSymbol = (uintptr_t)uValue - (uintptr_t)pDll->pbImageBase;
491 uint8_t const * const pbFunction = &pbBits[offSymbol];
492
493 /*
494 * Parse the code and extract the API call number.
495 */
496#ifdef RT_ARCH_AMD64
497 /* Pattern #1: XP64/W2K3-64 thru Windows 10 build 10240.
498 0:000> u ntdll!NtCreateSection
499 ntdll!NtCreateSection:
500 00000000`779f1750 4c8bd1 mov r10,rcx
501 00000000`779f1753 b847000000 mov eax,47h
502 00000000`779f1758 0f05 syscall
503 00000000`779f175a c3 ret
504 00000000`779f175b 0f1f440000 nop dword ptr [rax+rax]
505
506 Pattern #2: Windows 10 build 10525+.
507 0:000> u ntdll_7ffc26300000!NtCreateSection
508 ntdll_7ffc26300000!ZwCreateSection:
509 00007ffc`263943e0 4c8bd1 mov r10,rcx
510 00007ffc`263943e3 b84a000000 mov eax,4Ah
511 00007ffc`263943e8 f604250803fe7f01 test byte ptr [SharedUserData+0x308 (00000000`7ffe0308)],1
512 00007ffc`263943f0 7503 jne ntdll_7ffc26300000!ZwCreateSection+0x15 (00007ffc`263943f5)
513 00007ffc`263943f2 0f05 syscall
514 00007ffc`263943f4 c3 ret
515 00007ffc`263943f5 cd2e int 2Eh
516 00007ffc`263943f7 c3 ret
517 */
518 if ( pbFunction[ 0] == 0x4c /* mov r10, rcx */
519 && pbFunction[ 1] == 0x8b
520 && pbFunction[ 2] == 0xd1
521 && pbFunction[ 3] == 0xb8 /* mov eax, 0000yyzzh */
522 //&& pbFunction[ 4] == 0xZZ
523 //&& pbFunction[ 5] == 0xYY
524 && pbFunction[ 6] == 0x00
525 && pbFunction[ 7] == 0x00)
526 {
527 if ( pbFunction[ 8] == 0x0f /* syscall */
528 && pbFunction[ 9] == 0x05
529 && pbFunction[10] == 0xc3 /* ret */ )
530 {
531 *pSyscall->puApiNo = RT_MAKE_U16(pbFunction[4], pbFunction[5]);
532 *pImport->ppfnImport = pSyscall->pfnType1;
533 return;
534 }
535 if ( pbFunction[ 8] == 0xf6 /* test byte ptr [SharedUserData+0x308 (00000000`7ffe0308)],1 */
536 && pbFunction[ 9] == 0x04
537 && pbFunction[10] == 0x25
538 && pbFunction[11] == 0x08
539 && pbFunction[12] == 0x03
540 && pbFunction[13] == 0xfe
541 && pbFunction[14] == 0x7f
542 && pbFunction[15] == 0x01
543 && pbFunction[16] == 0x75 /* jnz +3 */
544 && pbFunction[17] == 0x03
545 && pbFunction[18] == 0x0f /* syscall*/
546 && pbFunction[19] == 0x05
547 && pbFunction[20] == 0xc3 /* ret */
548 && pbFunction[21] == 0xcd /* int 2eh */
549 && pbFunction[22] == 0x2e
550 && pbFunction[23] == 0xc3 /* ret */ )
551 {
552 *pSyscall->puApiNo = RT_MAKE_U16(pbFunction[4], pbFunction[5]);
553 *pImport->ppfnImport = pSyscall->pfnType2;
554 return;
555 }
556 }
557
558#elif defined(RT_ARCH_X86)
559 /* Pattern #1: XP thru Windows 7
560 kd> u ntdll!NtCreateSection
561 ntdll!NtCreateSection:
562 7c90d160 b832000000 mov eax,32h
563 7c90d165 ba0003fe7f mov edx,offset SharedUserData!SystemCallStub (7ffe0300)
564 7c90d16a ff12 call dword ptr [edx]
565 7c90d16c c21c00 ret 1Ch
566 7c90d16f 90 nop
567 The variable bit is the value loaded into eax: XP=32h, W2K3=34h, Vista=4bh, W7=54h
568
569 Pattern #2: Windows 8.1
570 0:000:x86> u ntdll_6a0f0000!NtCreateSection
571 ntdll_6a0f0000!NtCreateSection:
572 6a15eabc b854010000 mov eax,154h
573 6a15eac1 e803000000 call ntdll_6a0f0000!NtCreateSection+0xd (6a15eac9)
574 6a15eac6 c21c00 ret 1Ch
575 6a15eac9 8bd4 mov edx,esp
576 6a15eacb 0f34 sysenter
577 6a15eacd c3 ret
578 The variable bit is the value loaded into eax: W81=154h
579 Note! One nice thing here is that we can share code pattern #1. */
580
581 if ( pbFunction[ 0] == 0xb8 /* mov eax, 0000yyzzh*/
582 //&& pbFunction[ 1] <= 0xZZ
583 //&& pbFunction[ 2] <= 0xYY
584 && pbFunction[ 3] == 0x00
585 && pbFunction[ 4] == 0x00)
586 {
587 *pSyscall->puApiNo = RT_MAKE_U16(pbFunction[1], pbFunction[2]);
588 if ( pbFunction[5] == 0xba /* mov edx, offset SharedUserData!SystemCallStub */
589 && pbFunction[ 6] == 0x00
590 && pbFunction[ 7] == 0x03
591 && pbFunction[ 8] == 0xfe
592 && pbFunction[ 9] == 0x7f
593 && pbFunction[10] == 0xff /* call [edx] */
594 && pbFunction[11] == 0x12
595 && ( ( pbFunction[12] == 0xc2 /* ret 1ch */
596 && pbFunction[13] == pSyscall->cbParams
597 && pbFunction[14] == 0x00)
598 || ( pbFunction[12] == 0xc3 /* ret */
599 && pSyscall->cbParams == 0)
600 )
601 )
602 {
603 *pImport->ppfnImport = pSyscall->pfnType1;
604 return;
605 }
606
607 if ( pbFunction[ 5] == 0xe8 /* call [$+3] */
608 && RT_ABS(*(int32_t *)&pbFunction[6]) < 0x10
609 && ( ( pbFunction[10] == 0xc2 /* ret 1ch */
610 && pbFunction[11] == pSyscall->cbParams
611 && pbFunction[12] == 0x00)
612 || ( pbFunction[10] == 0xc3 /* ret */
613 && pSyscall->cbParams == 0)
614 )
615 )
616 {
617 *pImport->ppfnImport = pSyscall->pfnType2;
618 return;
619 }
620 }
621
622#elif defined(RT_ARCH_ARM64)
623 /* Only pattern (W10-1709):
624 0000000180022950 <ZwCreateSection>:
625 180022950: d4000941 svc #0x4a
626 180022954: d65f03c0 ret
627 180022958: 00000000 udf #0x0
628 18002295c: 00000000 udf #0x0 */
629 uint32_t const * const pu32Function = (uint32_t const *)pbFunction;
630 if ( pu32Function[1] == ARMV8_A64_INSTR_RET
631 && (pu32Function[0] & ~(UINT32_C(0xffff) << 5)) == UINT32_C(0xd0000001))
632 {
633 *pSyscall->puApiNo = (pu32Function[0] >> 5) & UINT32_C(0xffff);
634 *pImport->ppfnImport = pSyscall->pfnType1;
635 return;
636 }
637
638#else
639# error "port me"
640#endif
641
642 /*
643 * Failed to parse it.
644 */
645 volatile uint8_t abCopy[16];
646 memcpy((void *)&abCopy[0], pbFunction, sizeof(abCopy));
647 SUPHNTIMP_ERROR(fReportErrors, 17, "supR3HardenedWinInitImports", kSupInitOp_Misc, rc,
648 "%ls: failed to parse syscall: '%s': %.16Rhxs",
649 pDll->pwszName, pImport->pszName, &abCopy[0]);
650}
651
652
653/**
654 * Check out system calls and do the directly instead of via NtDll.
655 *
656 * We need to have access to the on disk NTDLL.DLL file as we do not trust the
657 * stuff we find in memory. Too early to verify signatures though.
658 *
659 * @param fReportErrors Whether we've got the machinery for reporting
660 * errors going already.
661 * @param pErrInfo Buffer for gathering additional error info. This
662 * is mainly to avoid consuming lots of stacks with
663 * RTERRINFOSTATIC structures.
664 */
665DECLHIDDEN(void) supR3HardenedWinInitSyscalls(bool fReportErrors, PRTERRINFO pErrInfo)
666{
667 for (uint32_t iDll = 0; iDll < RT_ELEMENTS(g_aSupNtImpDlls); iDll++)
668 if (g_aSupNtImpDlls[iDll].paSyscalls)
669 {
670 PSUPHNTLDRCACHEENTRY pLdrEntry;
671 int rc = supHardNtLdrCacheOpen(g_aSupNtImpDlls[iDll].pszName, &pLdrEntry, pErrInfo);
672 if (RT_SUCCESS(rc))
673 {
674 uint8_t *pbBits;
675 rc = supHardNtLdrCacheEntryGetBits(pLdrEntry, &pbBits, (uintptr_t)g_aSupNtImpDlls[iDll].pbImageBase,
676 NULL, NULL, pErrInfo);
677 if (RT_SUCCESS(rc))
678 {
679 for (uint32_t i = 0; i < g_aSupNtImpDlls[iDll].cImports; i++)
680 supR3HardenedDirectSyscall(&g_aSupNtImpDlls[iDll], &g_aSupNtImpDlls[iDll].paImports[i],
681 &g_aSupNtImpDlls[iDll].paSyscalls[i], pLdrEntry, pbBits, fReportErrors);
682 }
683 else
684 SUPHNTIMP_ERROR(fReportErrors, 20, "supR3HardenedWinInitImports", kSupInitOp_Misc, rc,
685 "%ls: supHardNtLdrCacheEntryGetBits failed: %Rrc %s",
686 g_aSupNtImpDlls[iDll].pwszName, rc, pErrInfo ? pErrInfo->pszMsg : "");
687 }
688 else
689 SUPHNTIMP_ERROR(fReportErrors, 21, "supR3HardenedWinInitImports", kSupInitOp_Misc, rc,
690 "%ls: supHardNtLdrCacheOpen failed: %Rrc %s",
691 g_aSupNtImpDlls[iDll].pwszName, rc, pErrInfo ? pErrInfo->pszMsg : "");
692 }
693}
694
695
696/**
697 * Resolves a few NtDll functions we need before child purification is executed.
698 *
699 * We must not permanently modify any global data here.
700 *
701 * @param uNtDllAddr The address of the NTDLL.
702 * @param ppfnNtWaitForSingleObject Where to store the NtWaitForSingleObject
703 * address.
704 * @param ppfnNtSetEvent Where to store the NtSetEvent address.
705 */
706DECLHIDDEN(void) supR3HardenedWinGetVeryEarlyImports(uintptr_t uNtDllAddr,
707 PFNNTWAITFORSINGLEOBJECT *ppfnNtWaitForSingleObject,
708 PFNNTSETEVENT *ppfnNtSetEvent)
709{
710 /*
711 * NTDLL is the first entry in the list. Save it and do the parsing.
712 */
713 SUPHNTIMPDLL SavedDllEntry = g_aSupNtImpDlls[0];
714
715 g_aSupNtImpDlls[0].pbImageBase = (uint8_t const *)uNtDllAddr;
716 supR3HardenedParseModule(&g_aSupNtImpDlls[0]);
717
718 /*
719 * Create a temporary import table for the requested APIs and resolve them.
720 */
721 SUPHNTIMPFUNC aImports[] =
722 {
723 { "NtWaitForSingleObject", (PFNRT *)ppfnNtWaitForSingleObject, NULL, false },
724 { "NtSetEvent", (PFNRT *)ppfnNtSetEvent, NULL, false },
725 };
726
727 for (uint32_t i = 0; i < RT_ELEMENTS(aImports); i++)
728 {
729 const char *pszForwarder = supR3HardenedResolveImport(&g_aSupNtImpDlls[0], &aImports[i], false);
730 if (pszForwarder)
731 SUPHNTIMP_ERROR(false, 31, "supR3HardenedWinGetVeryEarlyImports", kSupInitOp_Misc, VERR_MODULE_NOT_FOUND,
732 "ntdll: Failed to resolve forwarder '%s'.", pszForwarder);
733 }
734
735 /*
736 * Restore the NtDll entry.
737 */
738 g_aSupNtImpDlls[0] = SavedDllEntry;
739}
740
741
742/**
743 * Resolves NtDll functions we can trust calling before process init.
744 *
745 * @param uNtDllAddr The address of the NTDLL.
746 */
747DECLHIDDEN(void) supR3HardenedWinInitImportsEarly(uintptr_t uNtDllAddr)
748{
749 /*
750 * NTDLL is the first entry in the list.
751 */
752 g_aSupNtImpDlls[0].pbImageBase = (uint8_t const *)uNtDllAddr;
753 supR3HardenedParseModule(&g_aSupNtImpDlls[0]);
754 for (uint32_t i = 0; i < g_aSupNtImpDlls[0].cImports; i++)
755 if (!g_aSupNtImpDlls[0].paImports[i].pfnEarlyDummy)
756 {
757 const char *pszForwarder = supR3HardenedResolveImport(&g_aSupNtImpDlls[0], &g_aSupNtImpDlls[0].paImports[i], false);
758 if (pszForwarder)
759 SUPHNTIMP_ERROR(false, 32, "supR3HardenedWinInitImports", kSupInitOp_Misc, VERR_MODULE_NOT_FOUND,
760 "ntdll: Failed to resolve forwarder '%s'.", pszForwarder);
761 }
762 else
763 *g_aSupNtImpDlls[0].paImports[i].ppfnImport = g_aSupNtImpDlls[0].paImports[i].pfnEarlyDummy;
764
765 /*
766 * Point the other imports at the early init stubs.
767 */
768 for (uint32_t iDll = 1; iDll < RT_ELEMENTS(g_aSupNtImpDlls); iDll++)
769 for (uint32_t i = 0; i < g_aSupNtImpDlls[iDll].cImports; i++)
770 if (!g_aSupNtImpDlls[iDll].paImports[i].fOptional)
771 *g_aSupNtImpDlls[iDll].paImports[i].ppfnImport = g_aSupNtImpDlls[iDll].paImports[i].pfnEarlyDummy;
772 else
773 *g_aSupNtImpDlls[iDll].paImports[i].ppfnImport = NULL;
774}
775
776
777/**
778 * Resolves imported functions, esp. system calls from NTDLL.
779 *
780 * This crap is necessary because there are sandboxing products out there that
781 * will mess with system calls we make, just like any other wannabe userland
782 * rootkit. Kudos to microsoft for not providing a generic system call hook API
783 * in the kernel mode, which I guess is what forcing these kind of products to
784 * do ugly userland hacks that doesn't really hold water.
785 */
786DECLHIDDEN(void) supR3HardenedWinInitImports(void)
787{
788 RTERRINFOSTATIC ErrInfo;
789
790 /*
791 * Find the DLLs we will be needing first (forwarders).
792 */
793 for (uint32_t iDll = 0; iDll < RT_ELEMENTS(g_aSupNtImpDlls); iDll++)
794 {
795 supR3HardenedFindOrLoadModule(&g_aSupNtImpDlls[iDll]);
796 if (g_aSupNtImpDlls[iDll].pbImageBase)
797 supR3HardenedParseModule(&g_aSupNtImpDlls[iDll]);
798 }
799
800 /*
801 * Resolve the functions.
802 */
803 for (uint32_t iDll = 0; iDll < RT_ELEMENTS(g_aSupNtImpDlls); iDll++)
804 for (uint32_t i = 0; i < g_aSupNtImpDlls[iDll].cImports; i++)
805 {
806 const char *pszForwarder = supR3HardenedResolveImport(&g_aSupNtImpDlls[iDll], &g_aSupNtImpDlls[iDll].paImports[i],
807 false);
808 if (pszForwarder)
809 {
810 const char *pszDot = strchr(pszForwarder, '.');
811 size_t cchDllName = pszDot - pszForwarder;
812 SUPHNTIMPFUNC Tmp = g_aSupNtImpDlls[iDll].paImports[i];
813 Tmp.pszName = pszDot + 1;
814 if (cchDllName == sizeof("ntdll") - 1 && RTStrNICmp(pszForwarder, RT_STR_TUPLE("ntdll")) == 0)
815 supR3HardenedResolveImport(&g_aSupNtImpDlls[0], &Tmp, false);
816 else if (cchDllName == sizeof("kernelbase") - 1 && RTStrNICmp(pszForwarder, RT_STR_TUPLE("kernelbase")) == 0)
817 supR3HardenedResolveImport(&g_aSupNtImpDlls[1], &Tmp, false);
818 else
819 SUPHNTIMP_ERROR(false, 18, "supR3HardenedWinInitImports", kSupInitOp_Misc, VERR_MODULE_NOT_FOUND,
820 "%ls: Failed to resolve forwarder '%s'.", g_aSupNtImpDlls[iDll].pwszName, pszForwarder);
821 }
822 }
823
824 /*
825 * Do system calls directly.
826 */
827 supR3HardenedWinInitSyscalls(false, RTErrInfoInitStatic(&ErrInfo));
828
829 /*
830 * Use the on disk image to avoid export table patching. Currently
831 * ignoring errors here as can live normally without this step.
832 */
833 for (uint32_t iDll = 0; iDll < RT_ELEMENTS(g_aSupNtImpDlls); iDll++)
834 if (g_aSupNtImpDlls[iDll].cPatchedExports > 0)
835 {
836 PSUPHNTLDRCACHEENTRY pLdrEntry;
837 int rc = supHardNtLdrCacheOpen(g_aSupNtImpDlls[iDll].pszName, &pLdrEntry, RTErrInfoInitStatic(&ErrInfo));
838 if (RT_SUCCESS(rc))
839 {
840 uint8_t *pbBits;
841 rc = supHardNtLdrCacheEntryGetBits(pLdrEntry, &pbBits, (uintptr_t)g_aSupNtImpDlls[iDll].pbImageBase, NULL, NULL,
842 RTErrInfoInitStatic(&ErrInfo));
843 if (RT_SUCCESS(rc))
844 for (uint32_t i = 0; i < g_aSupNtImpDlls[iDll].cImports; i++)
845 {
846 RTLDRADDR uValue;
847 rc = RTLdrGetSymbolEx(pLdrEntry->hLdrMod, pbBits, (uintptr_t)g_aSupNtImpDlls[iDll].pbImageBase,
848 UINT32_MAX, g_aSupNtImpDlls[iDll].paImports[i].pszName, &uValue);
849 if (RT_SUCCESS(rc))
850 *g_aSupNtImpDlls[iDll].paImports[i].ppfnImport = (PFNRT)(uintptr_t)uValue;
851 }
852 }
853 }
854
855
856#if 0 /* Win7/32 ntdll!LdrpDebugFlags. */
857 *(uint8_t *)&g_aSupNtImpDlls[0].pbImageBase[0xdd770] = 0x3;
858#endif
859}
860
861
862/**
863 * Gets the address of a procedure in a DLL, ignoring our own syscall
864 * implementations.
865 *
866 * Currently restricted to NTDLL and KERNEL32
867 *
868 * @returns The procedure address.
869 * @param pszDll The DLL name.
870 * @param pszProcedure The procedure name.
871 */
872DECLHIDDEN(PFNRT) supR3HardenedWinGetRealDllSymbol(const char *pszDll, const char *pszProcedure)
873{
874 RTERRINFOSTATIC ErrInfo;
875
876 /*
877 * Look the DLL up in the import DLL table.
878 */
879 for (uint32_t iDll = 0; iDll < RT_ELEMENTS(g_aSupNtImpDlls); iDll++)
880 if (RTStrICmp(g_aSupNtImpDlls[iDll].pszName, pszDll) == 0)
881 {
882
883 PSUPHNTLDRCACHEENTRY pLdrEntry;
884 int rc = supHardNtLdrCacheOpen(g_aSupNtImpDlls[iDll].pszName, &pLdrEntry, RTErrInfoInitStatic(&ErrInfo));
885 if (RT_SUCCESS(rc))
886 {
887 uint8_t *pbBits;
888 rc = supHardNtLdrCacheEntryGetBits(pLdrEntry, &pbBits, (uintptr_t)g_aSupNtImpDlls[iDll].pbImageBase, NULL, NULL,
889 RTErrInfoInitStatic(&ErrInfo));
890 if (RT_SUCCESS(rc))
891 {
892 RTLDRADDR uValue;
893 rc = RTLdrGetSymbolEx(pLdrEntry->hLdrMod, pbBits, (uintptr_t)g_aSupNtImpDlls[iDll].pbImageBase,
894 UINT32_MAX, pszProcedure, &uValue);
895 if (RT_SUCCESS(rc))
896 return (PFNRT)(uintptr_t)uValue;
897 SUP_DPRINTF(("supR3HardenedWinGetRealDllSymbol: Error getting %s in %s -> %Rrc\n", pszProcedure, pszDll, rc));
898 }
899 else
900 SUP_DPRINTF(("supR3HardenedWinGetRealDllSymbol: supHardNtLdrCacheEntryAllocBits failed on %s: %Rrc %s\n",
901 pszDll, rc, ErrInfo.Core.pszMsg));
902 }
903 else
904 SUP_DPRINTF(("supR3HardenedWinGetRealDllSymbol: supHardNtLdrCacheOpen failed on %s: %Rrc %s\n",
905 pszDll, rc, ErrInfo.Core.pszMsg));
906
907 /* Complications, just call GetProcAddress. */
908 if (g_enmSupR3HardenedMainState >= SUPR3HARDENEDMAINSTATE_WIN_IMPORTS_RESOLVED)
909 return (PFNRT)GetProcAddress(GetModuleHandleW(g_aSupNtImpDlls[iDll].pwszName), pszProcedure);
910 return NULL;
911 }
912
913 supR3HardenedFatal("supR3HardenedWinGetRealDllSymbol: Unknown DLL %s (proc: %s)\n", pszDll, pszProcedure);
914 /* not reached */
915}
916
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette