VirtualBox

source: vbox/trunk/src/VBox/Runtime/r0drv/nt/nt3fakes-r0drv-nt.cpp@ 94155

Last change on this file since 94155 was 93115, checked in by vboxsync, 3 years ago

scm --update-copyright-year

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 32.0 KB
Line 
1/* $Id: nt3fakes-r0drv-nt.cpp 93115 2022-01-01 11:31:46Z vboxsync $ */
2/** @file
3 * IPRT - NT 3.x fakes for NT 4.0 KPIs.
4 */
5
6/*
7 * Copyright (C) 2006-2022 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27
28/*********************************************************************************************************************************
29* Header Files *
30*********************************************************************************************************************************/
31#define _IMAGE_NT_HEADERS RT_CONCAT(_IMAGE_NT_HEADERS,ARCH_BITS)
32#include "the-nt-kernel.h"
33#include <iprt/mem.h>
34
35#include <iprt/assert.h>
36#include <iprt/asm.h>
37#include <iprt/ctype.h>
38#include <iprt/dbg.h>
39#include <iprt/err.h>
40#include <iprt/log.h>
41#include <iprt/string.h>
42#include <iprt/utf16.h>
43#include <iprt/x86.h>
44#include <iprt/formats/mz.h>
45#include <iprt/formats/pecoff.h>
46#include "internal-r0drv-nt.h"
47
48typedef uint32_t DWORD;
49#include <VerRsrc.h>
50
51
52/*********************************************************************************************************************************
53* Internal Functions *
54*********************************************************************************************************************************/
55DECLASM(void) rtNt3InitSymbolsAssembly(void); /* in nt3fakesA-r0drv-nt.asm */
56
57
58/*********************************************************************************************************************************
59* Global Variables *
60*********************************************************************************************************************************/
61static uint32_t g_uNt3MajorVer = 3;
62static uint32_t g_uNt3MinorVer = 51;
63static uint32_t g_uNt3BuildNo = 1057;
64static bool g_fNt3Checked = false;
65static bool g_fNt3Smp = false; /**< Not reliable. */
66static bool volatile g_fNt3VersionInitialized = false;
67
68static uint8_t *g_pbNt3OsKrnl = (uint8_t *)UINT32_C(0x80100000);
69static uint32_t g_cbNt3OsKrnl = 0x300000;
70static uint8_t *g_pbNt3Hal = (uint8_t *)UINT32_C(0x80400000);
71static uint32_t g_cbNt3Hal = _512K;
72static bool volatile g_fNt3ModuleInfoInitialized = false;
73
74
75RT_C_DECLS_BEGIN
76/** @name KPIs we provide fallback implementations for.
77 *
78 * The assembly init routine will point the __imp_xxx variable to the NT
79 * implementation if available, using the fallback if not.
80 * @{ */
81decltype(PsGetVersion) *g_pfnrtPsGetVersion;
82decltype(ZwQuerySystemInformation) *g_pfnrtZwQuerySystemInformation;
83decltype(KeSetTimerEx) *g_pfnrtKeSetTimerEx;
84decltype(IoAttachDeviceToDeviceStack) *g_pfnrtIoAttachDeviceToDeviceStack;
85decltype(PsGetCurrentProcessId) *g_pfnrtPsGetCurrentProcessId;
86decltype(ZwYieldExecution) *g_pfnrtZwYieldExecution;
87decltype(ExAcquireFastMutex) *g_pfnrtExAcquireFastMutex;
88decltype(ExReleaseFastMutex) *g_pfnrtExReleaseFastMutex;
89/** @} */
90
91/** @name Fastcall optimizations not present in NT 3.1.
92 *
93 * We try resolve both the stdcall and fastcall variants and patch it up in
94 * assembly. The last four routines are in the hal.
95 *
96 * @{ */
97decltype(IofCompleteRequest) *g_pfnrtIofCompleteRequest;
98decltype(ObfDereferenceObject) *g_pfnrtObfDereferenceObject;
99decltype(IofCallDriver) *g_pfnrtIofCallDriver;
100decltype(KfAcquireSpinLock) *g_pfnrtKfAcquireSpinLock;
101decltype(KfReleaseSpinLock) *g_pfnrtKfReleaseSpinLock;
102decltype(KefAcquireSpinLockAtDpcLevel) *g_pfnrtKefAcquireSpinLockAtDpcLevel;
103decltype(KefReleaseSpinLockFromDpcLevel) *g_pfnrtKefReleaseSpinLockFromDpcLevel;
104decltype(KfLowerIrql) *g_pfnrtKfLowerIrql;
105decltype(KfRaiseIrql) *g_pfnrtKfRaiseIrql;
106
107VOID (__stdcall *g_pfnrtIoCompleteRequest)(PIRP, CCHAR);
108LONG_PTR (__stdcall *g_pfnrtObDereferenceObject)(PVOID);
109NTSTATUS (__stdcall *g_pfnrtIoCallDriver)(PDEVICE_OBJECT, PIRP);
110KIRQL (__stdcall *g_pfnrtKeAcquireSpinLock)(PKSPIN_LOCK);
111VOID (__stdcall *g_pfnrtKeReleaseSpinLock)(PKSPIN_LOCK, KIRQL);
112KIRQL (__stdcall *g_pfnrtKeAcquireSpinLockAtDpcLevel)(PKSPIN_LOCK);
113VOID (__stdcall *g_pfnrtKeReleaseSpinLockFromDpcLevel)(PKSPIN_LOCK);
114VOID (__stdcall *g_pfnrtKeLowerIrql)(KIRQL);
115KIRQL (__stdcall *g_pfnrtKeRaiseIrql)(KIRQL);
116/** @} */
117
118/** @name DATA exports and associated stuff
119 * @{ */
120/** Import address table entry for KeTickCount (defined in asm). */
121extern KSYSTEM_TIME *_imp__KeTickCount;
122/** @} */
123
124RT_C_DECLS_END
125
126
127/*********************************************************************************************************************************
128* Internal Functions *
129*********************************************************************************************************************************/
130static void rtR0Nt3InitModuleInfo(void);
131
132
133/**
134 * Converts a string to a number, stopping at the first non-digit.
135 *
136 * @returns The value
137 * @param ppwcValue Pointer to the string pointer variable. Updated.
138 * @param pcwcValue Pointer to the string length variable. Updated.
139 */
140static uint32_t rtR0Nt3StringToNum(PCRTUTF16 *ppwcValue, size_t *pcwcValue)
141{
142 uint32_t uValue = 0;
143 PCRTUTF16 pwcValue = *ppwcValue;
144 size_t cwcValue = *pcwcValue;
145
146 while (cwcValue > 0)
147 {
148 RTUTF16 uc = *pwcValue;
149 unsigned uDigit = (unsigned)uc - (unsigned)'0';
150 if (uDigit < (unsigned)10)
151 {
152 uValue *= 10;
153 uValue += uDigit;
154 }
155 else
156 break;
157 pwcValue++;
158 cwcValue--;
159 }
160
161 *ppwcValue = pwcValue;
162 *pcwcValue = cwcValue;
163 return uValue;
164}
165
166
167/**
168 * Implements RTL_QUERY_REGISTRY_ROUTINE for processing
169 * 'HKLM/Software/Microsoft/Window NT/CurrentVersion/CurrentVersion'
170 */
171static NTSTATUS NTAPI rtR0Nt3VerEnumCallback_CurrentVersion(PWSTR pwszValueName, ULONG uValueType,
172 PVOID pvValue, ULONG cbValue, PVOID pvUser, PVOID pvEntryCtx)
173{
174 RT_NOREF(pwszValueName, pvEntryCtx);
175 if ( uValueType == REG_SZ
176 || uValueType == REG_EXPAND_SZ)
177 {
178 PCRTUTF16 pwcValue = (PCRTUTF16)pvValue;
179 size_t cwcValue = cbValue / sizeof(*pwcValue);
180 uint32_t uMajor = rtR0Nt3StringToNum(&pwcValue, &cwcValue);
181 uint32_t uMinor = 0;
182 if (cwcValue > 1)
183 {
184 pwcValue++;
185 cwcValue--;
186 uMinor = rtR0Nt3StringToNum(&pwcValue, &cwcValue);
187 }
188
189 if (uMajor >= 3)
190 {
191 g_uNt3MajorVer = uMajor;
192 g_uNt3MinorVer = uMinor;
193 RTLogBackdoorPrintf("rtR0Nt3VerEnumCallback_CurrentVersion found: uMajor=%u uMinor=%u\n", uMajor, uMinor);
194 *(uint32_t *)pvUser |= RT_BIT_32(0);
195 return STATUS_SUCCESS;
196 }
197
198 RTLogBackdoorPrintf("rtR0Nt3VerEnumCallback_CurrentVersion: '%.*ls'\n", cbValue / sizeof(RTUTF16), pvValue);
199 }
200 else
201 RTLogBackdoorPrintf("rtR0Nt3VerEnumCallback_CurrentVersion: uValueType=%u %.*Rhxs\n", uValueType, cbValue, pvValue);
202 return STATUS_SUCCESS;
203}
204
205
206/**
207 * Implements RTL_QUERY_REGISTRY_ROUTINE for processing
208 * 'HKLM/Software/Microsoft/Window NT/CurrentVersion/CurrentBuildNumber'
209 */
210static NTSTATUS NTAPI rtR0Nt3VerEnumCallback_CurrentBuildNumber(PWSTR pwszValueName, ULONG uValueType,
211 PVOID pvValue, ULONG cbValue, PVOID pvUser, PVOID pvEntryCtx)
212{
213 RT_NOREF(pwszValueName, pvEntryCtx);
214 if ( uValueType == REG_SZ
215 || uValueType == REG_EXPAND_SZ)
216 {
217 PCRTUTF16 pwcValue = (PCRTUTF16)pvValue;
218 size_t cwcValue = cbValue / sizeof(*pwcValue);
219 uint32_t uBuildNo = rtR0Nt3StringToNum(&pwcValue, &cwcValue);
220
221 if (uBuildNo >= 100 && uBuildNo < _1M)
222 {
223 g_uNt3BuildNo = uBuildNo;
224 RTLogBackdoorPrintf("rtR0Nt3VerEnumCallback_CurrentBuildNumber found: uBuildNo=%u\n", uBuildNo);
225 *(uint32_t *)pvUser |= RT_BIT_32(1);
226 return STATUS_SUCCESS;
227 }
228
229 RTLogBackdoorPrintf("rtR0Nt3VerEnumCallback_CurrentBuildNumber: '%.*ls'\n", cbValue / sizeof(RTUTF16), pvValue);
230 }
231 else
232 RTLogBackdoorPrintf("rtR0Nt3VerEnumCallback_CurrentBuildNumber: uValueType=%u %.*Rhxs\n", uValueType, cbValue, pvValue);
233 return STATUS_SUCCESS;
234}
235
236
237/**
238 * Implements RTL_QUERY_REGISTRY_ROUTINE for processing
239 * 'HKLM/Software/Microsoft/Window NT/CurrentVersion/CurrentType'
240 */
241static NTSTATUS NTAPI rtR0Nt3VerEnumCallback_CurrentType(PWSTR pwszValueName, ULONG uValueType,
242 PVOID pvValue, ULONG cbValue, PVOID pvUser, PVOID pvEntryCtx)
243{
244 RT_NOREF(pwszValueName, pvEntryCtx);
245 if ( uValueType == REG_SZ
246 || uValueType == REG_EXPAND_SZ)
247 {
248 PCRTUTF16 pwcValue = (PCRTUTF16)pvValue;
249 size_t cwcValue = cbValue / sizeof(*pwcValue);
250
251 int fSmp = -1;
252 if (cwcValue >= 12 && RTUtf16NICmpAscii(pwcValue, "Uniprocessor", 12) == 0)
253 {
254 cwcValue -= 12;
255 pwcValue += 12;
256 fSmp = 0;
257 }
258 else if (cwcValue >= 14 && RTUtf16NICmpAscii(pwcValue, "Multiprocessor", 14) == 0)
259 {
260 cwcValue -= 14;
261 pwcValue += 14;
262 fSmp = 1;
263 }
264 if (fSmp != -1)
265 {
266 while (cwcValue > 0 && RT_C_IS_SPACE(*pwcValue))
267 cwcValue--, pwcValue++;
268
269 int fChecked = -1;
270 if (cwcValue >= 4 && RTUtf16NICmpAscii(pwcValue, "Free", 4) == 0)
271 fChecked = 0;
272 else if (cwcValue >= 7 && RTUtf16NICmpAscii(pwcValue, "Checked", 7) == 0)
273 fChecked = 1;
274 if (fChecked != -1)
275 {
276 g_fNt3Smp = fSmp != 0;
277 g_fNt3Checked = fChecked != 0;
278 RTLogBackdoorPrintf("rtR0Nt3VerEnumCallback_CurrentType found: fSmp=%d fChecked=%d\n", fSmp, fChecked);
279 *(uint32_t *)pvUser |= RT_BIT_32(2);
280 return STATUS_SUCCESS;
281 }
282 }
283
284 RTLogBackdoorPrintf("rtR0Nt3VerEnumCallback_CurrentType: '%.*ls'\n", cbValue / sizeof(RTUTF16), pvValue);
285 }
286 else
287 RTLogBackdoorPrintf("rtR0Nt3VerEnumCallback_CurrentType: uValueType=%u %.*Rhxs\n", uValueType, cbValue, pvValue);
288 return STATUS_SUCCESS;
289}
290
291
292/**
293 * Figure out the NT 3 version from the registry.
294 *
295 * @note this will be called before the rtR0Nt3InitSymbols is called.
296 */
297static void rtR0Nt3InitVersion(void)
298{
299 /*
300 * No PsGetVersion, so try the registry. Unfortunately not necessarily
301 * initialized when we're loaded.
302 */
303 RTL_QUERY_REGISTRY_TABLE aQuery[4];
304 RT_ZERO(aQuery);
305 aQuery[0].QueryRoutine = rtR0Nt3VerEnumCallback_CurrentVersion;
306 aQuery[0].Flags = 0;
307 aQuery[0].Name = L"CurrentVersion";
308 aQuery[0].EntryContext = NULL;
309 aQuery[0].DefaultType = REG_NONE;
310
311 aQuery[1].QueryRoutine = rtR0Nt3VerEnumCallback_CurrentBuildNumber;
312 aQuery[1].Flags = 0;
313 aQuery[1].Name = L"CurrentBuildNumber";
314 aQuery[1].EntryContext = NULL;
315 aQuery[1].DefaultType = REG_NONE;
316
317 aQuery[2].QueryRoutine = rtR0Nt3VerEnumCallback_CurrentType;
318 aQuery[2].Flags = 0;
319 aQuery[2].Name = L"CurrentType";
320 aQuery[2].EntryContext = NULL;
321 aQuery[2].DefaultType = REG_NONE;
322
323 uint32_t fFound = 0;
324 //NTSTATUS rcNt = RtlQueryRegistryValues(RTL_REGISTRY_WINDOWS_NT, NULL, &aQuery[0], &fFound, NULL /*Environment*/);
325 NTSTATUS rcNt = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
326 L"\\Registry\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion",
327 &aQuery[0], &fFound, NULL /*Environment*/);
328 if (!NT_SUCCESS(rcNt))
329 RTLogBackdoorPrintf("rtR0Nt3InitVersion: RtlQueryRegistryValues failed: %#x\n", rcNt);
330 else
331 RTLogBackdoorPrintf("rtR0Nt3InitVersion: Didn't get all values: fFound=%#x\n", fFound);
332
333 /*
334 * We really need the version number. Build, type and SMP is off less importance.
335 * Derive it from the NT kernel PE header.
336 */
337 if (!(fFound & RT_BIT_32(0)))
338 {
339 if (!g_fNt3ModuleInfoInitialized)
340 rtR0Nt3InitModuleInfo();
341
342 PIMAGE_DOS_HEADER pMzHdr = (PIMAGE_DOS_HEADER)g_pbNt3OsKrnl;
343 PIMAGE_NT_HEADERS32 pNtHdrs = (PIMAGE_NT_HEADERS32)&g_pbNt3OsKrnl[pMzHdr->e_lfanew];
344 if (pNtHdrs->OptionalHeader.MajorOperatingSystemVersion == 1)
345 {
346 /* NT 3.1 and NT 3.50 both set OS version to 1.0 in the optional header. */
347 g_uNt3MajorVer = 3;
348 if ( pNtHdrs->OptionalHeader.MajorLinkerVersion == 2
349 && pNtHdrs->OptionalHeader.MinorLinkerVersion < 50)
350 g_uNt3MinorVer = 10;
351 else
352 g_uNt3MinorVer = 50;
353 }
354 else
355 {
356 g_uNt3MajorVer = pNtHdrs->OptionalHeader.MajorOperatingSystemVersion;
357 g_uNt3MinorVer = pNtHdrs->OptionalHeader.MinorOperatingSystemVersion;
358 }
359 RTLogBackdoorPrintf("rtR0Nt3InitVersion: guessed %u.%u from PE header\n", g_uNt3MajorVer, g_uNt3MinorVer);
360
361 /* Check out the resource section, looking for VS_FIXEDFILEINFO. */
362 __try /* (pointless) */
363 {
364 PIMAGE_SECTION_HEADER paShdrs = (PIMAGE_SECTION_HEADER)(pNtHdrs + 1);
365 uint32_t const cShdrs = pNtHdrs->FileHeader.NumberOfSections;
366 uint32_t iShdr = 0;
367 while (iShdr < cShdrs && memcmp(paShdrs[iShdr].Name, ".rsrc", 6) != 0)
368 iShdr++;
369 if (iShdr < cShdrs)
370 {
371 if ( paShdrs[iShdr].VirtualAddress > 0
372 && paShdrs[iShdr].VirtualAddress < pNtHdrs->OptionalHeader.SizeOfImage)
373 {
374 uint32_t const cbRsrc = RT_MIN(paShdrs[iShdr].Misc.VirtualSize
375 ? paShdrs[iShdr].Misc.VirtualSize : paShdrs[iShdr].SizeOfRawData,
376 pNtHdrs->OptionalHeader.SizeOfImage - paShdrs[iShdr].VirtualAddress);
377 uint8_t const *pbRsrc = &g_pbNt3OsKrnl[paShdrs[iShdr].VirtualAddress];
378 uint32_t const *puDwords = (uint32_t const *)pbRsrc;
379 uint32_t cDWords = (cbRsrc - sizeof(VS_FIXEDFILEINFO) + sizeof(uint32_t)) / sizeof(uint32_t);
380 while (cDWords-- > 0)
381 {
382 if ( puDwords[0] == VS_FFI_SIGNATURE
383 && puDwords[1] == VS_FFI_STRUCVERSION)
384 {
385 VS_FIXEDFILEINFO const *pVerInfo = (VS_FIXEDFILEINFO const *)puDwords;
386 g_uNt3MajorVer = pVerInfo->dwProductVersionMS >> 16;
387 g_uNt3MinorVer = pVerInfo->dwProductVersionMS >> 16;
388 g_uNt3BuildNo = pVerInfo->dwProductVersionLS >> 16;
389 RTLogBackdoorPrintf("rtR0Nt3InitVersion: Found version info %u.%u build %u\n",
390 g_uNt3MajorVer, g_uNt3MinorVer, g_uNt3BuildNo);
391 break;
392 }
393 puDwords++;
394 }
395 }
396 }
397 }
398 __except(EXCEPTION_EXECUTE_HANDLER)
399 {
400 RTLogBackdoorPrintf("rtR0Nt3InitVersion: Exception scanning .rsrc section for version info!\n");
401 }
402 }
403
404 /*
405 * If we've got PsGetVersion, use it to override the above finding!
406 * (We may end up here for reasons other than the PsGetVersion fallback.)
407 */
408 if (g_pfnrtPsGetVersion)
409 {
410 WCHAR wszCsd[64];
411 UNICODE_STRING UniStr;
412 UniStr.Buffer = wszCsd;
413 UniStr.MaximumLength = sizeof(wszCsd) - sizeof(WCHAR);
414 UniStr.Length = 0;
415 RT_ZERO(wszCsd);
416 ULONG uMajor = 3;
417 ULONG uMinor = 51;
418 ULONG uBuildNo = 1057;
419 BOOLEAN fChecked = g_pfnrtPsGetVersion(&uMajor, &uMinor, &uBuildNo, &UniStr);
420
421 g_uNt3MajorVer = uMajor;
422 g_uNt3MinorVer = uMinor;
423 g_uNt3BuildNo = uBuildNo;
424 g_fNt3Checked = fChecked != FALSE;
425 }
426
427 g_fNt3VersionInitialized = true;
428}
429
430
431extern "C" DECLEXPORT(BOOLEAN) __stdcall
432Nt3Fb_PsGetVersion(ULONG *puMajor, ULONG *puMinor, ULONG *puBuildNo, UNICODE_STRING *pCsdStr)
433{
434 if (!g_fNt3VersionInitialized)
435 rtR0Nt3InitVersion();
436 if (puMajor)
437 *puMajor = g_uNt3MajorVer;
438 if (puMinor)
439 *puMinor = g_uNt3MinorVer;
440 if (puBuildNo)
441 *puBuildNo = g_uNt3BuildNo;
442 if (pCsdStr)
443 {
444 pCsdStr->Buffer[0] = '\0';
445 pCsdStr->Length = 0;
446 }
447 return g_fNt3Checked;
448}
449
450
451/**
452 * Worker for rtR0Nt3InitModuleInfo.
453 */
454static bool rtR0Nt3InitModuleInfoOne(const char *pszImage, uint8_t const *pbCode, uint8_t **ppbModule, uint32_t *pcbModule)
455{
456 uintptr_t const uImageAlign = _4K; /* XP may put the kernel at */
457
458 /* Align pbCode. */
459 pbCode = (uint8_t const *)((uintptr_t)pbCode & ~(uintptr_t)(uImageAlign - 1));
460
461 /* Scan backwards till we find a PE signature. */
462 for (uint32_t cbChecked = 0; cbChecked < _64M; cbChecked += uImageAlign, pbCode -= uImageAlign)
463 {
464 if (!MmIsAddressValid((void *)pbCode))
465 continue;
466
467 uint32_t uZero = 0;
468 uint32_t offNewHdr = 0;
469 __try /* pointless */
470 {
471 uZero = *(uint32_t const *)pbCode;
472 offNewHdr = *(uint32_t const *)&pbCode[RT_UOFFSETOF(IMAGE_DOS_HEADER, e_lfanew)];
473 }
474 __except(EXCEPTION_EXECUTE_HANDLER)
475 {
476 RTLogBackdoorPrintf("rtR0Nt3InitModuleInfo: Exception at %p scanning for DOS header...\n", pbCode);
477 continue;
478 }
479 if ( (uint16_t)uZero == IMAGE_DOS_SIGNATURE
480 && offNewHdr < _2K
481 && offNewHdr >= sizeof(IMAGE_DOS_HEADER))
482 {
483 RT_CONCAT(IMAGE_NT_HEADERS,ARCH_BITS) NtHdrs;
484 __try /* pointless */
485 {
486 NtHdrs = *(decltype(NtHdrs) const *)&pbCode[offNewHdr];
487 }
488 __except(EXCEPTION_EXECUTE_HANDLER)
489 {
490 RTLogBackdoorPrintf("rtR0Nt3InitModuleInfo: Exception at %p reading NT headers...\n", pbCode);
491 continue;
492 }
493 if ( NtHdrs.Signature == IMAGE_NT_SIGNATURE
494 && NtHdrs.FileHeader.SizeOfOptionalHeader == sizeof(NtHdrs.OptionalHeader)
495 && NtHdrs.FileHeader.NumberOfSections > 2
496 && NtHdrs.FileHeader.NumberOfSections < _4K
497 && NtHdrs.OptionalHeader.Magic == RT_CONCAT3(IMAGE_NT_OPTIONAL_HDR,ARCH_BITS,_MAGIC))
498 {
499 *ppbModule = (uint8_t *)pbCode;
500 *pcbModule = NtHdrs.OptionalHeader.SizeOfImage;
501 RTLogBackdoorPrintf("rtR0Nt3InitModuleInfo: Found %s at %#p LB %#x\n",
502 pszImage, pbCode, NtHdrs.OptionalHeader.SizeOfImage);
503 return true;
504 }
505 }
506 }
507 RTLogBackdoorPrintf("rtR0Nt3InitModuleInfo: Warning! Unable to locate %s...\n");
508 return false;
509}
510
511
512/**
513 * Initializes the module information (NTOSKRNL + HAL) using exported symbols.
514 * This only works as long as noone is intercepting the symbols.
515 */
516static void rtR0Nt3InitModuleInfo(void)
517{
518 rtR0Nt3InitModuleInfoOne("ntoskrnl.exe", (uint8_t const *)(uintptr_t)IoGetCurrentProcess, &g_pbNt3OsKrnl, &g_cbNt3OsKrnl);
519 rtR0Nt3InitModuleInfoOne("hal.dll", (uint8_t const *)(uintptr_t)HalGetBusData, &g_pbNt3Hal, &g_cbNt3Hal);
520 g_fNt3ModuleInfoInitialized = true;
521}
522
523
524extern "C" DECLEXPORT(NTSTATUS) __stdcall
525Nt3Fb_ZwQuerySystemInformation(SYSTEM_INFORMATION_CLASS enmClass, PVOID pvBuf, ULONG cbBuf, PULONG pcbActual)
526{
527 switch (enmClass)
528 {
529 case SystemModuleInformation:
530 {
531 PRTL_PROCESS_MODULES pInfo = (PRTL_PROCESS_MODULES)pvBuf;
532 ULONG cbNeeded = RT_UOFFSETOF(RTL_PROCESS_MODULES, Modules[2]);
533 if (pcbActual)
534 *pcbActual = cbNeeded;
535 if (cbBuf < cbNeeded)
536 return STATUS_INFO_LENGTH_MISMATCH;
537
538 if (!g_fNt3ModuleInfoInitialized)
539 rtR0Nt3InitModuleInfo();
540
541 pInfo->NumberOfModules = 2;
542
543 /* ntoskrnl.exe */
544 pInfo->Modules[0].Section = NULL;
545 pInfo->Modules[0].MappedBase = g_pbNt3OsKrnl;
546 pInfo->Modules[0].ImageBase = g_pbNt3OsKrnl;
547 pInfo->Modules[0].ImageSize = g_cbNt3OsKrnl;
548 pInfo->Modules[0].Flags = 0;
549 pInfo->Modules[0].LoadOrderIndex = 0;
550 pInfo->Modules[0].InitOrderIndex = 0;
551 pInfo->Modules[0].LoadCount = 1024;
552 pInfo->Modules[0].OffsetToFileName = sizeof("\\SystemRoot\\System32\\") - 1;
553 memcpy(pInfo->Modules[0].FullPathName, RT_STR_TUPLE("\\SystemRoot\\System32\\ntoskrnl.exe"));
554
555 /* hal.dll */
556 pInfo->Modules[1].Section = NULL;
557 pInfo->Modules[1].MappedBase = g_pbNt3Hal;
558 pInfo->Modules[1].ImageBase = g_pbNt3Hal;
559 pInfo->Modules[1].ImageSize = g_cbNt3Hal;
560 pInfo->Modules[1].Flags = 0;
561 pInfo->Modules[1].LoadOrderIndex = 1;
562 pInfo->Modules[1].InitOrderIndex = 0;
563 pInfo->Modules[1].LoadCount = 1024;
564 pInfo->Modules[1].OffsetToFileName = sizeof("\\SystemRoot\\System32\\") - 1;
565 memcpy(pInfo->Modules[1].FullPathName, RT_STR_TUPLE("\\SystemRoot\\System32\\hal.dll"));
566
567 return STATUS_SUCCESS;
568 }
569
570 default:
571 return STATUS_INVALID_INFO_CLASS;
572 }
573}
574
575/**
576 * Calculates the length indicated by an ModR/M sequence.
577 *
578 * @returns Length, including RM byte.
579 * @param bRm The RM byte.
580 */
581static uint32_t rtR0Nt3CalcModRmLength(uint8_t bRm)
582{
583 uint32_t cbRm = 1;
584
585 if ( (bRm & X86_MODRM_MOD_MASK) == (3 << X86_MODRM_MOD_SHIFT)
586 || (bRm & (X86_MODRM_MOD_MASK | X86_MODRM_RM_MASK)) == 5)
587 cbRm += 4; /* disp32 */
588 else if ((bRm & X86_MODRM_MOD_MASK) == (1 << X86_MODRM_MOD_SHIFT))
589 cbRm += 1; /* disp8 */
590 else if ((bRm & X86_MODRM_MOD_MASK) == (2 << X86_MODRM_MOD_SHIFT))
591 cbRm += 2; /* disp16 */
592
593 if ((bRm & X86_MODRM_RM_MASK) == 4 && (bRm & X86_MODRM_MOD_MASK) != (3 << X86_MODRM_MOD_SHIFT))
594 cbRm += 1; /* SIB */
595
596 return cbRm;
597}
598
599
600/**
601 * Init symbols.
602 *
603 * This is called after both ZwQuerySystemInformation and PsGetVersion are used
604 * for the first time.
605 *
606 * @returns IPRT status code
607 * @param hKrnlInfo Kernel symbol digger handle.
608 */
609DECLHIDDEN(int) rtR0Nt3InitSymbols(RTDBGKRNLINFO hKrnlInfo)
610{
611 /*
612 * Resolve symbols. (We set C variables (g_pfnrtXxx) here, not the __imp__Xxx ones.)
613 */
614#define GET_SYSTEM_ROUTINE(a_fnName) do { \
615 RT_CONCAT(g_pfnrt, a_fnName) = (decltype(RT_CONCAT(g_pfnrt, a_fnName)))RTR0DbgKrnlInfoGetSymbol(hKrnlInfo, NULL, #a_fnName); \
616 } while (0)
617
618 GET_SYSTEM_ROUTINE(PsGetVersion);
619 GET_SYSTEM_ROUTINE(ZwQuerySystemInformation);
620 GET_SYSTEM_ROUTINE(KeSetTimerEx);
621 GET_SYSTEM_ROUTINE(IoAttachDeviceToDeviceStack);
622 GET_SYSTEM_ROUTINE(PsGetCurrentProcessId);
623 GET_SYSTEM_ROUTINE(ZwYieldExecution);
624 GET_SYSTEM_ROUTINE(ExAcquireFastMutex);
625 GET_SYSTEM_ROUTINE(ExReleaseFastMutex);
626
627#define GET_FAST_CALL_SYSTEM_ROUTINE(a_fnFastcall, a_fnStdcall) do { \
628 GET_SYSTEM_ROUTINE(a_fnFastcall); \
629 GET_SYSTEM_ROUTINE(a_fnStdcall); \
630 AssertLogRelReturn(RT_CONCAT(g_pfnrt,a_fnFastcall) || RT_CONCAT(g_pfnrt,a_fnStdcall), VERR_INTERNAL_ERROR_3); \
631 } while (0)
632 GET_FAST_CALL_SYSTEM_ROUTINE(IofCompleteRequest, IoCompleteRequest);
633 GET_FAST_CALL_SYSTEM_ROUTINE(ObfDereferenceObject, ObDereferenceObject);
634 GET_FAST_CALL_SYSTEM_ROUTINE(IofCallDriver, IoCallDriver);
635 GET_FAST_CALL_SYSTEM_ROUTINE(KfAcquireSpinLock, KeAcquireSpinLock);
636 GET_FAST_CALL_SYSTEM_ROUTINE(KfReleaseSpinLock, KeReleaseSpinLock);
637 GET_FAST_CALL_SYSTEM_ROUTINE(KfLowerIrql, KeLowerIrql);
638 GET_FAST_CALL_SYSTEM_ROUTINE(KfRaiseIrql, KeRaiseIrql);
639 GET_FAST_CALL_SYSTEM_ROUTINE(KefAcquireSpinLockAtDpcLevel, KeAcquireSpinLockAtDpcLevel);
640 GET_FAST_CALL_SYSTEM_ROUTINE(KefReleaseSpinLockFromDpcLevel, KeReleaseSpinLockFromDpcLevel);
641
642 /*
643 * We need to call assembly to update the __imp__Xxx entries, since C
644 * doesn't allow '@' in symbols.
645 */
646 rtNt3InitSymbolsAssembly();
647
648 /*
649 * Tick count data. We disassemble KeQueryTickCount until we find the
650 * first absolute address referenced in it.
651 * %80105b70 8b 44 24 04 mov eax, dword [esp+004h]
652 * %80105b74 c7 40 04 00 00 00 00 mov dword [eax+004h], 000000000h
653 * %80105b7b 8b 0d 88 70 19 80 mov ecx, dword [080197088h]
654 * %80105b81 89 08 mov dword [eax], ecx
655 * %80105b83 c2 04 00 retn 00004h
656 */
657 _imp__KeTickCount = (decltype(_imp__KeTickCount))RTR0DbgKrnlInfoGetSymbol(hKrnlInfo, NULL, "KeTickCount");
658 if (!_imp__KeTickCount)
659 {
660 if (!g_fNt3VersionInitialized)
661 rtR0Nt3InitVersion();
662 Assert(g_uNt3MajorVer == 3 && g_uNt3MinorVer < 50);
663
664 uint8_t const *pbCode = (uint8_t const *)RTR0DbgKrnlInfoGetSymbol(hKrnlInfo, NULL, "KeQueryTickCount");
665 AssertLogRelReturn(pbCode, VERR_INTERNAL_ERROR_2);
666
667 for (uint32_t off = 0; off < 128 && _imp__KeTickCount == NULL;)
668 {
669 uint8_t const b1 = pbCode[off++];
670 switch (b1)
671 {
672 case 0x8b: /* mov reg, r/m ; We're looking for absolute address in r/m. */
673 if ((pbCode[off] & (X86_MODRM_MOD_MASK | X86_MODRM_RM_MASK)) == 5 /*disp32*/)
674 _imp__KeTickCount = *(KSYSTEM_TIME **)&pbCode[off + 1];
675 RT_FALL_THRU();
676 case 0x89: /* mov r/m, reg */
677 off += rtR0Nt3CalcModRmLength(pbCode[off]);
678 break;
679
680 case 0xc7:
681 if ((pbCode[off] & X86_MODRM_REG_MASK) == 0) /* mov r/m, imm32 */
682 off += rtR0Nt3CalcModRmLength(pbCode[off]) + 4;
683 else
684 {
685 RTLogBackdoorPrintf("rtR0Nt3InitSymbols: Failed to find KeTickCount! Encountered unknown opcode at %#x! %.*Rhxs\n",
686 off - 1, RT_MAX(off + 16, RT_MIN(PAGE_SIZE - ((uintptr_t)pbCode & PAGE_OFFSET_MASK), 128)), pbCode);
687 return VERR_INTERNAL_ERROR_3;
688 }
689 break;
690
691 case 0xc2: /* ret iw */
692 RTLogBackdoorPrintf("rtR0Nt3InitSymbols: Failed to find KeTickCount! Encountered RET! %.*Rhxs\n",
693 off + 2, pbCode);
694 return VERR_INTERNAL_ERROR_3;
695
696 default:
697 RTLogBackdoorPrintf("rtR0Nt3InitSymbols: Failed to find KeTickCount! Encountered unknown opcode at %#x! %.*Rhxs\n",
698 off - 1, RT_MAX(off + 16, RT_MIN(PAGE_SIZE - ((uintptr_t)pbCode & PAGE_OFFSET_MASK), 128)), pbCode);
699 return VERR_INTERNAL_ERROR_3;
700
701 /* Just in case: */
702
703 case 0xa1: /* mov eax, [m32] */
704 _imp__KeTickCount = *(KSYSTEM_TIME **)&pbCode[off];
705 off += 4;
706 break;
707
708 case 50: case 51: case 52: case 53: case 54: case 55: case 56: case 57: /* push reg */
709 break;
710 }
711 }
712 if (!_imp__KeTickCount)
713 {
714 RTLogBackdoorPrintf("rtR0Nt3InitSymbols: Failed to find KeTickCount after 128 bytes! %.*Rhxs\n", 128, pbCode);
715 return VERR_INTERNAL_ERROR_3;
716 }
717 }
718
719 return VINF_SUCCESS;
720}
721
722
723extern "C" DECLEXPORT(VOID)
724Nt3Fb_KeInitializeTimerEx(PKTIMER pTimer, TIMER_TYPE enmType)
725{
726 KeInitializeTimer(pTimer);
727 NOREF(enmType);
728 /** @todo Default is NotificationTimer, for SyncrhonizationTimer we need to
729 * do more work. timer-r0drv-nt.cpp is using the latter. :/ */
730}
731
732
733extern "C" DECLEXPORT(BOOLEAN) __stdcall
734Nt3Fb_KeSetTimerEx(PKTIMER pTimer, LARGE_INTEGER DueTime, LONG cMsPeriod, PKDPC pDpc)
735{
736 AssertReturn(cMsPeriod == 0, FALSE);
737 return KeSetTimer(pTimer, DueTime, pDpc);
738}
739
740
741extern "C" DECLEXPORT(PDEVICE_OBJECT)
742Nt3Fb_IoAttachDeviceToDeviceStack(PDEVICE_OBJECT pSourceDevice, PDEVICE_OBJECT pTargetDevice)
743{
744 NOREF(pSourceDevice); NOREF(pTargetDevice);
745 return NULL;
746}
747
748
749extern "C" DECLEXPORT(HANDLE)
750Nt3Fb_PsGetCurrentProcessId(void)
751{
752 if (!g_fNt3VersionInitialized)
753 rtR0Nt3InitVersion();
754
755 uint8_t const *pbProcess = (uint8_t const *)IoGetCurrentProcess();
756 if ( g_uNt3MajorVer > 3
757 || g_uNt3MinorVer >= 50)
758 return *(HANDLE const *)&pbProcess[0x94];
759 return *(HANDLE const *)&pbProcess[0xb0];
760}
761
762
763extern "C" DECLEXPORT(NTSTATUS)
764Nt3Fb_ZwYieldExecution(VOID)
765{
766 LARGE_INTEGER Interval;
767 Interval.QuadPart = 0;
768 KeDelayExecutionThread(KernelMode, FALSE, &Interval);
769 return STATUS_SUCCESS;
770}
771
772
773/**
774 * This is a simple implementation of the fast mutex api introduced in 3.50.
775 */
776extern "C" DECLEXPORT(VOID) FASTCALL
777Nt3Fb_ExAcquireFastMutex(PFAST_MUTEX pFastMtx)
778{
779 PETHREAD pSelf = PsGetCurrentThread();
780 KIRQL OldIrql;
781 KeRaiseIrql(APC_LEVEL, &OldIrql);
782
783 /* The Count member is initialized to 1. So if we decrement it to zero, we're
784 the first locker and owns the mutex. Otherwise we must wait for our turn. */
785 int32_t cLockers = ASMAtomicDecS32((int32_t volatile *)&pFastMtx->Count);
786 if (cLockers != 0)
787 {
788 ASMAtomicIncU32((uint32_t volatile *)&pFastMtx->Contention);
789 KeWaitForSingleObject(&pFastMtx->Event, Executive, KernelMode, FALSE /*fAlertable*/, NULL /*pTimeout*/);
790 }
791
792 pFastMtx->Owner = (PKTHREAD)pSelf;
793 pFastMtx->OldIrql = OldIrql;
794}
795
796
797/**
798 * This is a simple implementation of the fast mutex api introduced in 3.50.
799 */
800extern "C" DECLEXPORT(VOID) FASTCALL
801Nt3Fb_ExReleaseFastMutex(PFAST_MUTEX pFastMtx)
802{
803 AssertMsg(pFastMtx->Owner == (PKTHREAD)PsGetCurrentThread(), ("Owner=%p, expected %p\n", pFastMtx->Owner, PsGetCurrentThread()));
804
805 KIRQL OldIrql = pFastMtx->OldIrql;
806 pFastMtx->Owner = NULL;
807 int32_t cLockers = ASMAtomicIncS32((int32_t volatile *)&pFastMtx->Count);
808 if (cLockers <= 0)
809 KeSetEvent(&pFastMtx->Event, EVENT_INCREMENT, FALSE /*fWait*/);
810 if (OldIrql != APC_LEVEL)
811 KeLowerIrql(OldIrql);
812}
813
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