VirtualBox

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

Last change on this file since 106893 was 106893, checked in by vboxsync, 2 months ago

SUPHardNt: Rough and untested port of the C code to win.arm64 so the extpack builds. VBP-1447

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

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