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