VirtualBox

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

Last change on this file since 70341 was 70341, checked in by vboxsync, 7 years ago

IPRT: More NT 3.1 compatibility tweaking.

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

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