VirtualBox

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

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

nt3fakes-r0drv-nt.cpp: Get version from registry. Just for fun/completeness try find the modules via symbols we import from them.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 16.8 KB
Line 
1/* $Id: nt3fakes-r0drv-nt.cpp 70210 2017-12-18 20:43:19Z 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 PsGetVersion PsGetVersion_Nt4Plus
32#define ZwQuerySystemInformation ZwQuerySystemInformation_Nt4Plus
33#define KeInitializeTimerEx KeInitializeTimerEx_Nt4Plus
34#define KeSetTimerEx KeSetTimerEx_Nt4Plus
35#define IoAttachDeviceToDeviceStack IoAttachDeviceToDeviceStack_Nt4Plus
36#define PsGetCurrentProcessId PsGetCurrentProcessId_Nt4Plus
37#define ZwYieldExecution ZwYieldExecution_Nt4Plus
38
39#define _IMAGE_NT_HEADERS RT_CONCAT(_IMAGE_NT_HEADERS,ARCH_BITS)
40#include "the-nt-kernel.h"
41#include <iprt/mem.h>
42
43#include <iprt/assert.h>
44#include <iprt/ctype.h>
45#include <iprt/err.h>
46#include <iprt/log.h>
47#include <iprt/string.h>
48#include <iprt/formats/mz.h>
49#include <iprt/formats/pecoff.h>
50#include "internal-r0drv-nt.h"
51
52#undef PsGetVersion
53#undef ZwQuerySystemInformation
54#undef KeInitializeTimerEx
55#undef KeSetTimerEx
56#undef IoAttachDeviceToDeviceStack
57#undef PsGetCurrentProcessId
58#undef ZwYieldExecution
59
60
61/*********************************************************************************************************************************
62* Global Variables *
63*********************************************************************************************************************************/
64static uint32_t g_uNt3MajorVer = 3;
65static uint32_t g_uNt3MinorVer = 51;
66static uint32_t g_uNt3BuildNo = 1057;
67static bool g_fNt3Checked = false;
68static bool g_fNt3Smp = false;
69static bool volatile g_fNt3VersionInitialized = false;
70
71static uint8_t *g_pbNt3OsKrnl = (uint8_t *)UINT32_C(0x80100000);
72static uint32_t g_cbNt3OsKrnl = 0x300000;
73static uint8_t *g_pbNt3Hal = (uint8_t *)UINT32_C(0x80400000);
74static uint32_t g_cbNt3Hal = _512K;
75static bool volatile g_fNt3ModuleInfoInitialized = false;
76
77
78/**
79 * Converts a string to a number, stopping at the first non-digit.
80 *
81 * @returns The value
82 * @param ppwcValue Pointer to the string pointer variable. Updated.
83 * @param pcwcValue Pointer to the string length variable. Updated.
84 */
85static uint32_t rtR0Nt3StringToNum(PCRTUTF16 *ppwcValue, size_t *pcwcValue)
86{
87 uint32_t uValue = 0;
88 PCRTUTF16 pwcValue = *ppwcValue;
89 size_t cwcValue = *pcwcValue;
90
91 while (cwcValue > 0)
92 {
93 RTUTF16 uc = *pwcValue;
94 unsigned uDigit = (unsigned)uc - (unsigned)'0';
95 if (uDigit < (unsigned)10)
96 {
97 uValue *= 10;
98 uValue += uDigit;
99 }
100 else
101 break;
102 pwcValue++;
103 cwcValue--;
104 }
105
106 *ppwcValue = pwcValue;
107 *pcwcValue = cwcValue;
108 return uValue;
109}
110
111
112/**
113 * Implements RTL_QUERY_REGISTRY_ROUTINE for processing
114 * 'HKLM/Software/Microsoft/Window NT/CurrentVersion/CurrentVersion'
115 */
116static NTSTATUS NTAPI rtR0Nt3VerEnumCallback_CurrentVersion(PWSTR pwszValueName, ULONG uValueType,
117 PVOID pvValue, ULONG cbValue, PVOID pvUser, PVOID pvEntryCtx)
118{
119 RT_NOREF(pwszValueName, pvEntryCtx);
120 if ( uValueType == REG_SZ
121 || uValueType == REG_EXPAND_SZ)
122 {
123 PCRTUTF16 pwcValue = (PCRTUTF16)pvValue;
124 size_t cwcValue = cbValue / sizeof(*pwcValue);
125 uint32_t uMajor = rtR0Nt3StringToNum(&pwcValue, &cwcValue);
126 uint32_t uMinor = 0;
127 if (cwcValue > 1)
128 {
129 pwcValue++;
130 cwcValue--;
131 uMinor = rtR0Nt3StringToNum(&pwcValue, &cwcValue);
132 }
133
134 if (uMajor >= 3)
135 {
136 g_uNt3MajorVer = uMajor;
137 g_uNt3MinorVer = uMinor;
138 RTLogBackdoorPrintf("rtR0Nt3VerEnumCallback_CurrentVersion found: uMajor=%u uMinor=%u\n", uMajor, uMinor);
139 *(uint32_t *)pvUser |= RT_BIT_32(0);
140 return STATUS_SUCCESS;
141 }
142
143 RTLogBackdoorPrintf("rtR0Nt3VerEnumCallback_CurrentVersion: '%.*ls'\n", cbValue / sizeof(RTUTF16), pvValue);
144 }
145 else
146 RTLogBackdoorPrintf("rtR0Nt3VerEnumCallback_CurrentVersion: uValueType=%u %.*Rhxs\n", uValueType, cbValue, pvValue);
147 return STATUS_SUCCESS;
148}
149
150
151/**
152 * Implements RTL_QUERY_REGISTRY_ROUTINE for processing
153 * 'HKLM/Software/Microsoft/Window NT/CurrentVersion/CurrentBuildNumber'
154 */
155static NTSTATUS NTAPI rtR0Nt3VerEnumCallback_CurrentBuildNumber(PWSTR pwszValueName, ULONG uValueType,
156 PVOID pvValue, ULONG cbValue, PVOID pvUser, PVOID pvEntryCtx)
157{
158 RT_NOREF(pwszValueName, pvEntryCtx);
159 if ( uValueType == REG_SZ
160 || uValueType == REG_EXPAND_SZ)
161 {
162 PCRTUTF16 pwcValue = (PCRTUTF16)pvValue;
163 size_t cwcValue = cbValue / sizeof(*pwcValue);
164 uint32_t uBuildNo = rtR0Nt3StringToNum(&pwcValue, &cwcValue);
165
166 if (uBuildNo >= 100 && uBuildNo < _1M)
167 {
168 g_uNt3BuildNo = uBuildNo;
169 RTLogBackdoorPrintf("rtR0Nt3VerEnumCallback_CurrentBuildNumber found: uBuildNo=%u\n", uBuildNo);
170 *(uint32_t *)pvUser |= RT_BIT_32(1);
171 return STATUS_SUCCESS;
172 }
173
174 RTLogBackdoorPrintf("rtR0Nt3VerEnumCallback_CurrentBuildNumber: '%.*ls'\n", cbValue / sizeof(RTUTF16), pvValue);
175 }
176 else
177 RTLogBackdoorPrintf("rtR0Nt3VerEnumCallback_CurrentBuildNumber: uValueType=%u %.*Rhxs\n", uValueType, cbValue, pvValue);
178 return STATUS_SUCCESS;
179}
180
181
182/**
183 * Implements RTL_QUERY_REGISTRY_ROUTINE for processing
184 * 'HKLM/Software/Microsoft/Window NT/CurrentVersion/CurrentType'
185 */
186static NTSTATUS NTAPI rtR0Nt3VerEnumCallback_CurrentType(PWSTR pwszValueName, ULONG uValueType,
187 PVOID pvValue, ULONG cbValue, PVOID pvUser, PVOID pvEntryCtx)
188{
189 RT_NOREF(pwszValueName, pvEntryCtx);
190 if ( uValueType == REG_SZ
191 || uValueType == REG_EXPAND_SZ)
192 {
193 PCRTUTF16 pwcValue = (PCRTUTF16)pvValue;
194 size_t cwcValue = cbValue / sizeof(*pwcValue);
195
196 int fSmp = -1;
197 if (cwcValue >= 12 && RTUtf16NICmpAscii(pwcValue, "Uniprocessor", 12) == 0)
198 {
199 cwcValue -= 12;
200 pwcValue += 12;
201 fSmp = 0;
202 }
203 else if (cwcValue >= 14 && RTUtf16NICmpAscii(pwcValue, "Multiprocessor", 14) == 0)
204 {
205 cwcValue -= 14;
206 pwcValue += 14;
207 fSmp = 1;
208 }
209 if (fSmp != -1)
210 {
211 while (cwcValue > 0 && RT_C_IS_SPACE(*pwcValue))
212 cwcValue--, pwcValue++;
213
214 int fChecked = -1;
215 if (cwcValue >= 4 && RTUtf16NICmpAscii(pwcValue, "Free", 4) == 0)
216 fChecked = 0;
217 else if (cwcValue >= 7 && RTUtf16NICmpAscii(pwcValue, "Checked", 7) == 0)
218 fChecked = 1;
219 if (fChecked != -1)
220 {
221 g_fNt3Smp = fSmp != 0;
222 g_fNt3Checked = fChecked != 0;
223 RTLogBackdoorPrintf("rtR0Nt3VerEnumCallback_CurrentType found: fSmp=%d fChecked=%d\n", fSmp, fChecked);
224 *(uint32_t *)pvUser |= RT_BIT_32(2);
225 return STATUS_SUCCESS;
226 }
227 }
228
229 RTLogBackdoorPrintf("rtR0Nt3VerEnumCallback_CurrentType: '%.*ls'\n", cbValue / sizeof(RTUTF16), pvValue);
230 }
231 else
232 RTLogBackdoorPrintf("rtR0Nt3VerEnumCallback_CurrentType: uValueType=%u %.*Rhxs\n", uValueType, cbValue, pvValue);
233 return STATUS_SUCCESS;
234}
235
236
237/**
238 * Figure out the NT 3 version from the registry.
239 */
240static void rtR0Nt3InitVersion(void)
241{
242 RTL_QUERY_REGISTRY_TABLE aQuery[4];
243 RT_ZERO(aQuery);
244 aQuery[0].QueryRoutine = rtR0Nt3VerEnumCallback_CurrentVersion;
245 aQuery[0].Flags = 0;
246 aQuery[0].Name = L"CurrentVersion";
247 aQuery[0].EntryContext = NULL;
248 aQuery[0].DefaultType = REG_NONE;
249
250 aQuery[1].QueryRoutine = rtR0Nt3VerEnumCallback_CurrentBuildNumber;
251 aQuery[1].Flags = 0;
252 aQuery[1].Name = L"CurrentBuildNumber";
253 aQuery[1].EntryContext = NULL;
254 aQuery[1].DefaultType = REG_NONE;
255
256 aQuery[2].QueryRoutine = rtR0Nt3VerEnumCallback_CurrentType;
257 aQuery[2].Flags = 0;
258 aQuery[2].Name = L"CurrentType";
259 aQuery[2].EntryContext = NULL;
260 aQuery[2].DefaultType = REG_NONE;
261
262 uint32_t fFound = 0;
263 //NTSTATUS rcNt = RtlQueryRegistryValues(RTL_REGISTRY_WINDOWS_NT, NULL, &aQuery[0], &fFound, NULL /*Environment*/);
264 NTSTATUS rcNt = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
265 L"\\Registry\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion",
266 &aQuery[0], &fFound, NULL /*Environment*/);
267 if (!NT_SUCCESS(rcNt))
268 RTLogBackdoorPrintf("rtR0Nt3InitVersion: RtlQueryRegistryValues failed: %#x\n", rcNt);
269 else if (fFound != 7)
270 RTLogBackdoorPrintf("rtR0Nt3InitVersion: Didn't get all values: fFound=%#x\n", fFound);
271
272 g_fNt3VersionInitialized = true;
273}
274
275
276extern "C" DECLEXPORT(BOOLEAN) __stdcall
277PsGetVersion(ULONG *puMajor, ULONG *puMinor, ULONG *puBuildNo, UNICODE_STRING *pCsdStr)
278{
279 if (!g_fNt3VersionInitialized)
280 rtR0Nt3InitVersion();
281 if (puMajor)
282 *puMajor = g_uNt3MajorVer;
283 if (puMinor)
284 *puMinor = g_uNt3MinorVer;
285 if (puBuildNo)
286 *puBuildNo = g_uNt3BuildNo;
287 if (pCsdStr)
288 {
289 pCsdStr->Buffer[0] = '\0';
290 pCsdStr->Length = 0;
291 }
292 return g_fNt3Checked;
293}
294
295
296/**
297 * Worker for rtR0Nt3InitModuleInfo.
298 */
299static bool rtR0Nt3InitModuleInfoOne(const char *pszImage, uint8_t const *pbCode, uint8_t **ppbModule, uint32_t *pcbModule)
300{
301 uintptr_t const uImageAlign = _64K;
302
303 /* Align pbCode. */
304 pbCode = (uint8_t const *)((uintptr_t)pbCode & ~(uintptr_t)(uImageAlign - 1));
305
306 /* Scan backwards till we find a PE signature. */
307 for (uint32_t cbChecked = 0; cbChecked < _64M; cbChecked += uImageAlign, pbCode -= uImageAlign)
308 {
309 uint32_t uZero = 0;
310 uint32_t offNewHdr = 0;
311 __try
312 {
313 uZero = *(uint32_t const *)pbCode;
314 offNewHdr = *(uint32_t const *)&pbCode[RT_OFFSETOF(IMAGE_DOS_HEADER, e_lfanew)];
315 }
316 __except(EXCEPTION_EXECUTE_HANDLER)
317 {
318 RTLogBackdoorPrintf("rtR0Nt3InitModuleInfo: Exception at %p scanning for DOS header...\n", pbCode);
319 continue;
320 }
321 if ( (uint16_t)uZero == IMAGE_DOS_SIGNATURE
322 && offNewHdr < _2K
323 && offNewHdr >= sizeof(IMAGE_DOS_HEADER))
324 {
325 RT_CONCAT(IMAGE_NT_HEADERS,ARCH_BITS) NtHdrs;
326 __try
327 {
328 NtHdrs = *(decltype(NtHdrs) const *)&pbCode[offNewHdr];
329 }
330 __except(EXCEPTION_EXECUTE_HANDLER)
331 {
332 RTLogBackdoorPrintf("rtR0Nt3InitModuleInfo: Exception at %p reading NT headers...\n", pbCode);
333 continue;
334 }
335 if ( NtHdrs.Signature == IMAGE_NT_SIGNATURE
336 && NtHdrs.FileHeader.SizeOfOptionalHeader == sizeof(NtHdrs.OptionalHeader)
337 && NtHdrs.FileHeader.NumberOfSections > 2
338 && NtHdrs.FileHeader.NumberOfSections < _4K
339 && NtHdrs.OptionalHeader.Magic == RT_CONCAT3(IMAGE_NT_OPTIONAL_HDR,ARCH_BITS,_MAGIC))
340 {
341 *ppbModule = (uint8_t *)pbCode;
342 *pcbModule = NtHdrs.OptionalHeader.SizeOfImage;
343 RTLogBackdoorPrintf("rtR0Nt3InitModuleInfo: Found %s at %#p LB %#x\n",
344 pszImage, pbCode, NtHdrs.OptionalHeader.SizeOfImage);
345 return true;
346 }
347 }
348 }
349 RTLogBackdoorPrintf("rtR0Nt3InitModuleInfo: Warning! Unable to locate %s...\n");
350 return false;
351}
352
353
354/**
355 * Initializes the module information (NTOSKRNL + HAL) using exported symbols.
356 * This only works as long as noone is intercepting the symbols.
357 */
358static void rtR0Nt3InitModuleInfo(void)
359{
360 rtR0Nt3InitModuleInfoOne("ntoskrnl.exe", (uint8_t const *)(uintptr_t)IoGetCurrentProcess, &g_pbNt3OsKrnl, &g_cbNt3OsKrnl);
361 rtR0Nt3InitModuleInfoOne("hal.dll", (uint8_t const *)(uintptr_t)HalGetBusData, &g_pbNt3Hal, &g_cbNt3Hal);
362 g_fNt3ModuleInfoInitialized = true;
363}
364
365
366extern "C" DECLEXPORT(NTSTATUS) __stdcall
367ZwQuerySystemInformation(SYSTEM_INFORMATION_CLASS enmClass, PVOID pvBuf, ULONG cbBuf, PULONG pcbActual)
368{
369 switch (enmClass)
370 {
371 case SystemModuleInformation:
372 {
373 PRTL_PROCESS_MODULES pInfo = (PRTL_PROCESS_MODULES)pvBuf;
374 ULONG cbNeeded = RT_UOFFSETOF(RTL_PROCESS_MODULES, Modules[2]);
375 if (pcbActual)
376 *pcbActual = cbNeeded;
377 if (cbBuf < cbNeeded)
378 return STATUS_INFO_LENGTH_MISMATCH;
379
380 if (!g_fNt3ModuleInfoInitialized)
381 rtR0Nt3InitModuleInfo();
382
383 pInfo->NumberOfModules = 2;
384
385 /* ntoskrnl.exe */
386 pInfo->Modules[0].Section = NULL;
387 pInfo->Modules[0].MappedBase = g_pbNt3OsKrnl;
388 pInfo->Modules[0].ImageBase = g_pbNt3OsKrnl;
389 pInfo->Modules[0].ImageSize = g_cbNt3OsKrnl;
390 pInfo->Modules[0].Flags = 0;
391 pInfo->Modules[0].LoadOrderIndex = 0;
392 pInfo->Modules[0].InitOrderIndex = 0;
393 pInfo->Modules[0].LoadCount = 1024;
394 pInfo->Modules[0].OffsetToFileName = sizeof("\\SystemRoot\\System32\\") - 1;
395 memcpy(pInfo->Modules[0].FullPathName, RT_STR_TUPLE("\\SystemRoot\\System32\\ntoskrnl.exe"));
396
397 /* hal.dll */
398 pInfo->Modules[1].Section = NULL;
399 pInfo->Modules[1].MappedBase = g_pbNt3Hal;
400 pInfo->Modules[1].ImageBase = g_pbNt3Hal;
401 pInfo->Modules[1].ImageSize = g_cbNt3Hal;
402 pInfo->Modules[1].Flags = 0;
403 pInfo->Modules[1].LoadOrderIndex = 1;
404 pInfo->Modules[1].InitOrderIndex = 0;
405 pInfo->Modules[1].LoadCount = 1024;
406 pInfo->Modules[1].OffsetToFileName = sizeof("\\SystemRoot\\System32\\") - 1;
407 memcpy(pInfo->Modules[1].FullPathName, RT_STR_TUPLE("\\SystemRoot\\System32\\hal.dll"));
408
409 return STATUS_SUCCESS;
410 }
411
412 default:
413 return STATUS_INVALID_INFO_CLASS;
414 }
415}
416
417
418extern "C" DECLEXPORT(VOID)
419KeInitializeTimerEx(PKTIMER pTimer, TIMER_TYPE enmType)
420{
421 KeInitializeTimer(pTimer);
422 NOREF(enmType);
423 /** @todo Default is NotificationTimer, for SyncrhonizationTimer we need to
424 * do more work. timer-r0drv-nt.cpp is using the latter. :/ */
425}
426
427
428extern "C" DECLEXPORT(BOOLEAN) __stdcall
429KeSetTimerEx(PKTIMER pTimer, LARGE_INTEGER DueTime, LONG cMsPeriod, PKDPC pDpc)
430{
431 AssertReturn(cMsPeriod == 0, FALSE);
432 return KeSetTimer(pTimer, DueTime, pDpc);
433}
434
435
436extern "C" DECLEXPORT(PDEVICE_OBJECT)
437IoAttachDeviceToDeviceStack(PDEVICE_OBJECT pSourceDevice, PDEVICE_OBJECT pTargetDevice)
438{
439 NOREF(pSourceDevice); NOREF(pTargetDevice);
440 return NULL;
441}
442
443
444extern "C" DECLEXPORT(HANDLE)
445PsGetCurrentProcessId(void)
446{
447 if (!g_fNt3VersionInitialized)
448 rtR0Nt3InitVersion();
449
450 uint8_t const *pbProcess = (uint8_t const *)IoGetCurrentProcess();
451 if ( g_uNt3MajorVer > 3
452 || g_uNt3MinorVer >= 50)
453 return *(HANDLE const *)&pbProcess[0x94];
454 return *(HANDLE const *)&pbProcess[0xb0];
455}
456
457
458extern "C" DECLEXPORT(NTSTATUS)
459ZwYieldExecution(VOID)
460{
461 LARGE_INTEGER Interval;
462 Interval.QuadPart = 0;
463 KeDelayExecutionThread(KernelMode, FALSE, &Interval);
464 return STATUS_SUCCESS;
465}
466
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